十四、使用多幅纹理

253 阅读1分钟

一、介绍

WebGL可以同时处理多幅纹理,纹理单元就是为了这个目的而设置。 我们需要对每一幅纹理分别进行前一节所述的将纹理图像映射到图形表面的操作。

二、关键代码

本节代码与上节示例代码相似,主要有以下三点不同:
(1)片元着色器能够访问两个纹理
(2)最终的片元颜色由两个纹理上的纹素颜色共同决定
(3)initTextures()函数创建了两个纹理对象

#片元着色器
var FSHADER_SOURCE =
    '#ifdef GL_ES\n' +
    'precision mediump float;\n' +
    '#endif\n' +
    'uniform sampler2D u_Sampler0;\n' +
    'uniform sampler2D u_Sampler1;\n' +
    'varying vec2 v_TexCoord;\n' +
    'void main() {\n' +
    #从两个纹理中取出纹素颜色,分别存储在变量color0和color1中
    '  vec4 color0 = texture2D(u_Sampler0, v_TexCoord);\n' +
    '  vec4 color1 = texture2D(u_Sampler1, v_TexCoord);\n' +
    #使用颜色矢量的分量乘法计算最终的片元颜色
    '  gl_FragColor = color0 * color1;\n' +
    '}\n';
 
 ···

#配置和加载纹理
function initTextures(gl, n) {
    #创建两个纹理对象
    var texture0 = gl.createTexture();  
    var texture1 = gl.createTexture();  
    
    var u_Sampler0 = gl.getUniformLocation(gl.program, 'u_Sampler0');
    var u_Sampler1 = gl.getUniformLocation(gl.program, 'u_Sampler1');
    
    var image0 = new Image();  
    var image1 = new Image();  
    
    image0.onload = function(){ loadTexture(gl, n, texture0, u_Sampler0, image0, 0); };
    image1.onload = function(){ loadTexture(gl, n, texture1, u_Sampler1, image1, 1); };
    
    image0.src = '../resources/sky.jpg';
    image1.src = '../resources/circle.png';
    
    return true;
}

function loadTexture(gl, n, texture, u_Sampler, image, texUnit) {
    #(1)
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); 
    
    if (texUnit == 0) {
        #(2)
        gl.activeTexture(gl.TEXTURE0);
        g_texUnit0 = true;
    } else {
        #(2)
        gl.activeTexture(gl.TEXTURE1);
        g_texUnit1 = true;
    }
 
    #(3)
    gl.bindTexture(gl.TEXTURE_2D, texture);
    #(4)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    #(5)
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    #(6)
    gl.uniform1i(u_Sampler, texUnit);

    gl.clear(gl.COLOR_BUFFER_BIT);
    if (g_texUnit0 && g_texUnit1) {
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); 
    }
}