Afin de permettre aux graphiques d'obtenir des effets de matière proches des objets réels, les textures sont généralement utilisées. Il existe deux principaux types de textures : les cartes de réflexion diffuse et les cartes de surbrillance spéculaire. La carte de réflexion diffuse peut obtenir simultanément les effets de la lumière de réflexion diffuse et de la lumière ambiante.
Veuillez consulter la démo pour l'effet réel : Carte de texture
Pour implémenter la carte , vous devez utiliser la texture , les formats de texture couramment utilisés sont : texture 2D, texture cubique, texture 3D. Nous pouvons utiliser la texture 2D la plus basique pour obtenir les effets requis dans cette section. Jetons un coup d'œil aux API requises pour utiliser les textures. Tutoriels associés : Tutoriel vidéo js
Étant donné que l'origine des coordonnées de la texture se trouve dans le coin inférieur gauche, ce qui est exactement à l'opposé de notre origine des coordonnées habituelle dans le coin supérieur gauche, ce qui suit est pour l'inverser selon l'axe Y, ce qui est pratique Nous définissons les coordonnées.
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
active et lie les textures, gl.TEXTURE0 représente la texture n°0, qui peut augmenter de 0 jusqu'en haut. TEXTURE_2D représente une texture 2D.
gl.activeTexture(gl.TEXTURE0);//激活纹理 gl.bindTexture(gl.TEXTURE_2D, texture);//绑定纹理
L'étape suivante consiste à définir les paramètres de la texture. Cette API est très importante et constitue également la partie la plus complexe de la texture.
gl.texParameteri(target, pname, param) , attribuez la valeur de param au paramètre pname de l'objet de texture lié à la cible. Paramètres :
cible : gl.TEXTURE_2D ou gl.TEXTURE_CUBE_MAP
pname : Oui Spécifiez 4 paramètres de texture
param : La valeur du paramètre de texture
peut être assignée à gl.TEXTURE_MAP_FILTER et gl .TEXTURE_MIN_FILTER Valeur du paramètre
gl.NEAREST : Utilisez la valeur de couleur du pixel sur la texture d'origine la plus proche du centre du pixel mappé comme valeur du nouveau pixel.
gl.LINEAR : Utilisez la moyenne pondérée des valeurs de couleur des quatre pixels les plus proches du centre du nouveau pixel comme valeur du nouveau pixel (par rapport à gl. LE PLUS PROCHE, cette méthode a une meilleure qualité d'image Mieux, mais aussi plus chère)
peut être affecté aux constantes de gl.TEXTURE_WRAP_S et gl.TEXTURE_WRAP_T :
gl.REPEAT : Texture répétée de carrelage
gl.MIRRORED_REPEAT : Texture répétée symétrique en miroir
gl.CLAMP_TO_EDGE : Utiliser la valeur du bord de l'image de texture
L'exemple de réglage est le suivant :
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl .texImage2D, attribue des pixels à l'objet de texture lié. Cette API a plus d'une douzaine de fonctions surchargées dans WebGL1 et WebGL2, et les types de formats sont très divers. Le paramètre pixels peut être une image, un canevas ou une vidéo. Nous regardons uniquement le formulaire appelant dans WebGL1.
// WebGL1: void gl.texImage2D(target, level, internalformat, width, height, border, format, type, ArrayBufferView? pixels); void gl.texImage2D(target, level, internalformat, format, type, ImageData? pixels); void gl.texImage2D(target, level, internalformat, format, type, HTMLImageElement? pixels); void gl.texImage2D(target, level, internalformat, format, type, HTMLCanvasElement? pixels); void gl.texImage2D(target, level, internalformat, format, type, HTMLVideoElement? pixels); void gl.texImage2D(target, level, internalformat, format, type, ImageBitmap? pixels); // WebGL2: //...
J'ai encapsulé une fonction de chargement de texture. Le format d'appel de chaque API peut être visualisé. Nous devons d'abord obtenir l'effet souhaité.
function loadTexture(url) { const texture = gl.createTexture(); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); let textureInfo = { width: 1, height: 1, texture: texture, }; const img = new Image(); return new Promise((resolve,reject) => { img.onload = function() { textureInfo.width = img.width; textureInfo.height = img.height; gl.bindTexture(gl.TEXTURE_2D, textureInfo.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img); resolve(textureInfo); }; img.src = url; }); }
Implantez d'abord la carte de lumière de réflexion diffuse et téléchargez une carte d'étage sur Internet, qui contient différents types de cartes.
Le tampon doit ajouter les coordonnées de texture correspondant aux sommets, afin que les pixels de texture correspondants, appelés texels, puissent être trouvés grâce aux coordonnées de texture.
const arrays = { position: [ -1, 0, -1, -1, 0, 1, 1, 0, -1, 1, 0, 1 ], texcoord: [ 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0 ], normal: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1 ], };
La seule différence dans le vertex shader est l'ajout de coordonnées de texture, qui doivent être interpolées et transmises au fragment shader
//... attribute vec2 a_texcoord; varying vec2 v_texcoord; void main() { //... v_texcoord = a_texcoord; }
Le fragment shader nécessite plus de modifications. Utilisez principalement texture2D pour obtenir le texel aux coordonnées correspondantes et remplacer la couleur précédente. Voici le code lié au fragment shader
//... vec3 normal = normalize(v_normal); vec4 diffMap = texture2D(u_samplerD, v_texcoord); //光线方向 vec3 lightDirection = normalize(u_lightPosition - v_position); // 计算光线方向和法向量夹角 float nDotL = max(dot(lightDirection, normal), 0.0); // 漫反射光亮度 vec3 diffuse = u_diffuseColor * nDotL * diffMap.rgb; // 环境光亮度 vec3 ambient = u_ambientColor * diffMap.rgb; //...
La partie js charge l'image correspondant à la texture, passe l'unité de texture, puis restitue l'effet
//... (async function (){ const ret = await loadTexture('/model/floor_tiles_06_diff_1k.jpg') setUniforms(program, { u_samplerD: 0//0号纹理 }); //... draw(); })()
comme suit. La partie mise en évidence semble trop éblouissante car le sol est Il n'y aura pas de reflet lisse et fort comme un miroir.
为了实现更逼真的高光效果,继续实现Web Learning : Comment utiliser les cartes de texture,实现原理和漫反射一样,把对应的高光颜色替换成Web Learning : Comment utiliser les cartes de texture纹素就可以了。
下面就是片元着色器增加修改高光部分
//... vec3 normal = normalize(v_normal); vec4 diffMap = texture2D(u_samplerD, v_texcoord); vec4 specMap = texture2D(u_samplerS, v_texcoord); //光线方向 vec3 lightDirection = normalize(u_lightPosition - v_position); // 计算光线方向和法向量夹角 float nDotL = max(dot(lightDirection, normal), 0.0); // 漫反射光亮度 vec3 diffuse = u_diffuseColor * nDotL * diffMap.rgb; // 环境光亮度 vec3 ambient = u_ambientColor * diffMap.rgb; // 镜面高光 vec3 eyeDirection = normalize(u_viewPosition - v_position);// 反射方向 vec3 halfwayDir = normalize(lightDirection + eyeDirection); float specularIntensity = pow(max(dot(normal, halfwayDir), 0.0), u_shininess); vec3 specular = (vec3(0.2,0.2,0.2) + specMap.rgb) * specularIntensity; //...
js同时加载漫反射和Web Learning : Comment utiliser les cartes de texture
//... (async function (){ const ret = await Promise.all([ loadTexture('/model/floor_tiles_06_diff_1k.jpg'), loadTexture('/model/floor_tiles_06_spec_1k.jpg',1) ]); setUniforms(program, { u_samplerD: 0,//0号纹理 u_samplerS: 1 //1号纹理 }); //... draw(); })()
最后实现的效果如下,明显更加接近真实的地板
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!