WebGL 多重纹理的使用介绍

yizhihongxing

请听我详细介绍“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 多重纹理的使用介绍 - Python技术站

(0)
上一篇 2023年6月11日
下一篇 2023年6月11日

相关文章

  • 详解JavaScript作用域和作用域链

    我来详细讲解一下“详解JavaScript作用域和作用域链”的完整攻略。

    JavaScript 2023年6月11日
    00
  • Javascript Global undefined 属性

    JavaScript中的undefined是一个全局属性,表示一个未定义的值。如果一个变量没有被赋值,则该变量的值为undefined。以下是关于undefined全局属性的完整攻略,包括两个示例。 JavaScript Global对象中的undefined属性 JavaScript Global对象中的undefined属性表示一个未定义的值。如果一个变…

    JavaScript 2023年5月11日
    00
  • JavaScript 高效运行代码分析

    当我们编写 JavaScript 代码时,我们希望它具有良好的性能,以避免网页加载过慢或出现卡顿等问题。因此需要学会分析和优化 JavaScript 的运行效率。 1. 分析代码 a. 使用工具 我们可以使用浏览器自带的开发者工具或其他第三方开发者工具来诊断 JavaScript 代码的性能瓶颈。其中,Chrome 浏览器自带的开发者工具能够提供我们耗时最长…

    JavaScript 2023年5月27日
    00
  • JavaScript探测CSS动画是否已经完成的方法

    前置知识: 在 JavaScript 中,我们可以使用 addEventListener() 方法给元素添加事件监听器,使用 animationstart、animationiteration 和 animationend 事件来侦测 CSS 动画的开始、循环和结束。 方法一:监听 animationend 事件 当 CSS 动画结束时,会触发元素的 ani…

    JavaScript 2023年6月10日
    00
  • 一行代码实现纯数据json对象的深度克隆实现思路

    一行代码实现纯数据JSON对象的深度克隆实现思路,这个问题需要理解深浅拷贝的概念,然后利用JSON对象的序列化与反序列化特性进行实现。 深度克隆和浅拷贝的区别 两者之间的主要区别是,在深度克隆的情况下,如果原对象的某个属性值是引用类型,那么克隆后的新对象中对应的属性值如果发生改变,也不会影响原对象,这是因为新对象是重新创建了一份内存。浅拷贝则不同,它只是将原…

    JavaScript 2023年5月27日
    00
  • js自调用匿名函数的三种写法(推荐)

    下面是JS自调用匿名函数的三种写法攻略: 1. 包裹执行 最常见的自调用匿名函数就是包裹执行(也称为自调用函数表达式,IIFE)。这种写法在函数表达式后紧跟一个括号,表示调用这个函数。其主要目的是防止变量污染全局作用域。 标准写法: (function() { // 在这里编写你的代码 })(); 可以使用 arrow function (ES6+)简化写法…

    JavaScript 2023年5月27日
    00
  • javascript中encodeURI和decodeURI方法使用介绍

    JavaScript 中 encodeURI 和 decodeURI 方法使用介绍 在 JavaScript 中,encodeURI 和 decodeURI 方法可以用于编码和解码 URI,以便在 URL 中传输特殊字符或非 ASCII 字符。本文将详细介绍这两种方法的使用。 encodeURI 方法 encodeURI 可以将 URL 中除了 字母、数字、…

    JavaScript 2023年5月19日
    00
  • JS中注入eval, Function等系统函数截获动态代码

    注入eval、Function等系统函数可以使攻击者截获JS代码的执行过程,从而实现对网站的控制。以下是JS中注入eval、Function等系统函数的完整攻略: 针对eval的注入攻击 步骤1: 攻击者在代码中构造出可执行代码(即包含函数或变量)的字符串,然后通过eval这一系统函数来执行 eval("console.log(‘Hello, Wo…

    JavaScript 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部