多幅纹理

WebGL 可以把多个纹理图像合并在一起。原理是它们对应的 r、g、b、a 分别相乘。下面是两张图跟上一篇文章叠加后的结果,可以看到, 越白的部分,也就是 r、g、b、a 约接近1.0的时候,越明亮清晰;而越黑的部分,也就是 r、g、b、a 约接近0.0的时候,越暗淡模糊。

实现方法是在 Fragment Shader 中声明两个 sampler2Duniform 变量, 用两个 texture2D() 来取不同的纹理的像素颜色,然后再把颜色值相乘。图片加载后激活的 gl.activeTexture( ) 中的纹理单元, 第一张图对应 gl.TEXTURE0,第二张图对应 gl.TEXTURE1。当两张图片都加载完成后,再清除颜色缓冲区 gl.clear( gl.COLOR_BUFFER_BIT ) 和进行绘图 gl.drawArrays( gl.TRIANGLE_STRIP, 0, 4 )

<script id="vertexShader" type="x-shader/x-vertex"> attribute vec4 a_Position; attribute vec2 a_TexCoord; varying vec2 v_TexCoord; void main(){ gl_Position = a_Position; v_TexCoord = a_TexCoord; } </script> <script id="fragmentShader" type="x-shader/x-fragment"> precision mediump float; uniform sampler2D u_Sampler0; // 采样器 uniform sampler2D u_Sampler1; varying vec2 v_TexCoord; void main(){ vec4 color0 = texture2D(u_Sampler0, v_TexCoord); vec4 color1 = texture2D(u_Sampler1, v_TexCoord); gl_FragColor = color0 * color1; } </script> function init(){ var canvas = document.getElementById('canvas'); gl = canvas.getContext('webgl'); if (!gl) { console.log('Failed to get WebGL.'); return; } if (!initShaders(gl, "vertexShader", "fragmentShader")) { console.log('Failed to initShaders.'); return; } gl.clearColor( 0.0, 0.0, 0.0, 1.0); initVertexBuffer(gl); // a_Position, a_TexCoord initTexture(gl); // u_Sampler } function initVertexBuffer(gl){ var verticesTexCoords = new Float32Array([ // 顶点 纹理 -1.0, 1.0, 0.0, 1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 0.0 ]), element_size = verticesTexCoords.BYTES_PER_ELEMENT; var verticesTexCoordBuffer = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, verticesTexCoordBuffer ); gl.bufferData( gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW); var a_Position = gl.getAttribLocation( gl.program, 'a_Position' ); gl.vertexAttribPointer( a_Position, 2, gl.FLOAT, false, element_size * 4, 0 ); gl.enableVertexAttribArray( a_Position ); var a_TexCoord = gl.getAttribLocation( gl.program, 'a_TexCoord' ); gl.vertexAttribPointer( a_TexCoord, 2, gl.FLOAT, false, element_size * 4, element_size * 2 ); gl.enableVertexAttribArray( a_TexCoord ); } function initTexture(gl){ var texture0 = gl.createTexture(), texture1 = gl.createTexture(); var u_Sampler0 = gl.getUniformLocation( gl.program, 'u_Sampler0'), u_Sampler1 = gl.getUniformLocation( gl.program, 'u_Sampler1'); var image0 = new Image(); image0.onload = function(){ loadTexture(gl, texture0, u_Sampler0, image0, 0); }; image0.src = '../assets/textures/view.png'; var image1 = new Image(); image1.onload = function(){ loadTexture(gl, texture1, u_Sampler1, image1, 1); }; image1.src = '../assets/textures/texture2.png'; } var texUnit0 = false, texUnit1 = false; function loadTexture(gl, texture, u_Sampler, image, texUnit){ gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, true ); if(texUnit == 0){ gl.activeTexture( gl.TEXTURE0 ); texUnit0 = true; } else{ gl.activeTexture( gl.TEXTURE1 ); texUnit1 = true; } gl.bindTexture( gl.TEXTURE_2D, texture ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR ); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); gl.uniform1i( u_Sampler, texUnit ); if( texUnit0 && texUnit1 ){ gl.clear( gl.COLOR_BUFFER_BIT ); gl.drawArrays( gl.TRIANGLE_STRIP, 0, 4 ); } }