沃梦达 / IT编程 / 前端开发 / 正文

WebGL 多重纹理的使用介绍

请听我详细介绍“WebGL 多重纹理的使用介绍”的攻略。

请听我详细介绍“WebGL 多重纹理的使用介绍”的攻略。

简介

WebGL 多重纹理是用于在 WebGL 应用程序中使用多个纹理的技术。通过多重纹理,可以在同一对象上一次性使用多个纹理图像,并在每个图像之间进行混合或叠加。这为绘制更逼真的 3D 场景提供了更多的灵活性和可能性。

多重纹理的基本概念

在 WebGL 中,多重纹理主要涉及两个核心概念:纹理单元和纹理坐标。

纹理单元

纹理单元表示每个纹理图像在 WebGL 中的一个唯一标识符。通常,WebGL 支持最少 8 个纹理单元,您可以使用它们分别用于不同的纹理图像。例如,您可以使用第一纹理单元为一个物体的底面绘制一个纹理图像,使用第二纹理单元绘制物体的侧面另一个纹理图像。纹理单元通常通过 gl.activeTexture() 函数进行选择。

纹理坐标

纹理坐标是一个用于指定 WebGL 模型表面上的特定纹理图像的横向和纵向位置的向量。这是一个二维向量,通常表示 (s,t) 坐标,其中 s 坐标表示距离纹理图像的左侧,t 坐标表示距离纹理图像的顶部。纹理坐标可用于在与模型表面的顶点相关联的每个绘制操作中指定纹理图像上的位置。

多重纹理的实现过程

当您使用多重纹理绘制 3D 场景时,可以遵循以下的步骤:

  1. 创建多个纹理对象

首先,您需要通过调用 gl.createTexture() 函数创建多个 WebGL 纹理对象。每个纹理对象都可以与一个纹理单元相对应。

  1. 激活不同的纹理单元

接下来,您需要使用 gl.activeTexture() 函数来激活不同的纹理单元,以便将纹理对象绑定到每个单元上。

  1. 绑定和加载纹理图像

使用 gl.bindTexture() 函数并指定纹理对象和纹理类型(通常是 gl.TEXTURE_2D),可以将纹理对象绑定到激活的纹理单元上。您可以使用 gl.texImage2D() 或 gl.texSubImage2D() 函数将图像数据加载到纹理对象中。

  1. 设置纹理类型和纹理参数

在将纹理对象用于绘制操作之前,您需要使用 gl.texParameteri() 函数设置纹理对象的过滤和重复选项。

  1. 使用多重纹理绘制 3D 场景

当您已经准备好了多个纹理对象并将它们绑定到不同的纹理单元上,可以在绘制 3D 场景时使用多重纹理。通过 gl.uniform1i() 函数,将您以前创建的纹理单元与 GLSL 着色器程序中的纹理采样器变量相关联。随后,可以在 gl_FragColor 中通过混合或组合图像实现多重纹理的效果。

示例

接下来,我将通过两个实例示例,介绍如何在 WebGL 中使用多重纹理。

实例一:混合多个纹理

在此示例中,我们将创建两个纹理并混合它们。首先,我们需要加载两个纹理图像,并将它们绑定到不同的纹理单元上。在 GLSL 着色器程序中,我们需要使用两个采样器变量来接收这两个纹理。最后,我们将混合这两个纹理图像。

<script>
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');

const program = gl.createProgram();
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
const vertexShaderSource = `
    attribute vec2 a_position;
    attribute vec2 a_texCoord;
    varying vec2 v_texCoord;
    void main() {
        gl_Position = vec4(a_position, 0.0, 1.0);
        v_texCoord = a_texCoord;
    }
`;
const fragmentShaderSource = `
    precision mediump float;
    uniform sampler2D u_texture1;
    uniform sampler2D u_texture2;
    varying vec2 v_texCoord;
    void main() {
        vec4 color1 = texture2D(u_texture1, v_texCoord);
        vec4 color2 = texture2D(u_texture2, v_texCoord);
        gl_FragColor = color1 * 0.5 + color2 * 0.5;
    }
`;
gl.shaderSource(vertexShader, vertexShaderSource);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

const vertices = new Float32Array([
    -0.5, -0.5,
    0.5, -0.5,
    -0.5, 0.5,
    0.5, 0.5,
]);
const texCoords = new Float32Array([
    0, 0,
    1, 0,
    0, 1,
    1, 1,
]);
const positionBuffer = gl.createBuffer();
const texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const aPosition = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(aPosition);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW);
const aTexCoord = gl.getAttribLocation(program, 'a_texCoord');
gl.enableVertexAttribArray(aTexCoord);
gl.vertexAttribPointer(aTexCoord, 2, gl.FLOAT, false, 0, 0);

const texture1 = gl.createTexture();
const texture2 = gl.createTexture();
const image1 = new Image();
const image2 = new Image();
image1.onload = () => {
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture1);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image1);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    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);
};
image1.src = 'image1.png';
image2.onload = () => {
    gl.activeTexture(gl.TEXTURE1);
    gl.bindTexture(gl.TEXTURE_2D, texture2);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image2);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    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);
};
image2.src = 'image2.png';

const uTexture1 = gl.getUniformLocation(program, 'u_texture1');
gl.uniform1i(uTexture1, 0);
const uTexture2 = gl.getUniformLocation(program, 'u_texture2');
gl.uniform1i(uTexture2, 1);

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
</script>

示例二:组合多个纹理

在此示例中,我们将在同一对象上组合三个纹理图像。首先,我们需要加载三个纹理图像,并将它们绑定到对应的纹理单元上。在 GLSL 着色器程序中,我们需要使用三个采样器变量来接收这三个纹理。然后,我们根据每个纹理图像的亮度值,将其乘以一个权重系数,将它们组合起来。

<script>
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');

const program = gl.createProgram();
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
const vertexShaderSource = `
    attribute vec2 a_position;
    attribute vec2 a_texCoord;
    varying vec2 v_texCoord;
    void main() {
        gl_Position = vec4(a_position, 0.0, 1.0);
        v_texCoord = a_texCoord;
    }
`;
const fragmentShaderSource = `
    precision mediump float;
    uniform sampler2D u_texture1;
    uniform sampler2D u_texture2;
    uniform sampler2D u_texture3;
    varying vec2 v_texCoord;
    void main() {
        float brightness1 = texture2D(u_texture1, v_texCoord).r;
        float brightness2 = texture2D(u_texture2, v_texCoord).g;
        float brightness3 = texture2D(u_texture3, v_texCoord).b;
        gl_FragColor = vec4(
            brightness1 * 0.3 + brightness2 * 0.6 + brightness3 * 0.1,
            brightness1 * 0.5 + brightness2 * 0.4 + brightness3 * 0.1,
            brightness1 * 0.1 + brightness2 * 0.2 + brightness3 * 0.7,
            1.0
        );
    }
`;
gl.shaderSource(vertexShader, vertexShaderSource);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(vertexShader);
gl.compileShader(fragmentShader);
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

const vertices = new Float32Array([
    -0.5, -0.5,
    0.5, -0.5,
    -0.5, 0.5,
    0.5, 0.5,
]);
const texCoords = new Float32Array([
    0, 0,
    1, 0,
    0, 1,
    1, 1,
]);
const positionBuffer = gl.createBuffer();
const texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const aPosition = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(aPosition);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, texCoords, gl.STATIC_DRAW);
const aTexCoord = gl.getAttribLocation(program, 'a_texCoord');
gl.enableVertexAttribArray(aTexCoord);
gl.vertexAttribPointer(aTexCoord, 2, gl.FLOAT, false, 0, 0);

const texture1 = gl.createTexture();
const texture2 = gl.createTexture();
const texture3 = gl.createTexture();
const image1 = new Image();
const image2 = new Image();
const image3 = new Image();
image1.onload = () => {
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture1);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image1);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    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);
};
image1.src = 'image1.png';
image2.onload = () => {
    gl.activeTexture(gl.TEXTURE1);
    gl.bindTexture(gl.TEXTURE_2D, texture2);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image2);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    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);
};
image2.src = 'image2.png';
image3.onload = () => {
    gl.activeTexture(gl.TEXTURE2);
    gl.bindTexture(gl.TEXTURE_2D, texture3);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image3);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    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);
};
image3.src = 'image3.png';

const uTexture1 = gl.getUniformLocation(program, 'u_texture1');
gl.uniform1i(uTexture1, 0);
const uTexture2 = gl.getUniformLocation(program, 'u_texture2');
gl.uniform1i(uTexture2, 1);
const uTexture3 = gl.getUniformLocation(program, 'u_texture3');
gl.uniform1i(uTexture3, 2);

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
</script>

这就是WebGL 多重纹理的使用介绍。希望这个完整攻略对你有所帮助!

本文标题为:WebGL 多重纹理的使用介绍