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 多重纹理的使用介绍 - Python技术站

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

相关文章

  • JavaScript 开发规范要求(图文并茂)

    JavaScript开发规范要求(图文并茂) 简介 JavaScript是一门非常灵活的语言,灵活性也为其带来了使用难度,所以为了保证代码的品质和可维护性,一些好的JavaScript开发规范是必不可少的。 为此,本文将详细介绍旨在提高JavaScript代码品质和可维护性的开发规范要求。 代码组织 引入顺序 首先,我们应该根据引入类型将脚本分成3个部分: …

    JavaScript 2023年5月27日
    00
  • JS内部事件机制之单线程原理

    JS内部事件机制是指JavaScript在运行时的一种消息传递机制。其基本原理是采用单线程模型,即所有的任务都在同一个线程中执行,并且采用事件循环的机制来管理和调度任务。以下是JS内部事件机制之单线程原理的完整攻略: 什么是JS内部事件机制? JS内部事件机制是指JavaScript运行时的一种机制,用于管理和调度任务,其原理是采用单线程模型,即所有的任务都…

    JavaScript 2023年6月11日
    00
  • 使用JavaScript保存文本文件到本地的两种方法

    下面是使用JavaScript保存文本文件到本地的两种方法的详细攻略: 1. 使用Blob对象保存文本文件 Blob对象简介 Blob是Binary Large Object的缩写,表示二进制大对象。它是一种类文件对象,可以存储任意的二进制数据,如图片、视频、文本等。我们可以利用Blob对象来保存文本文件到本地。 实现步骤 创建Blob对象:可以使用Blob…

    JavaScript 2023年5月27日
    00
  • javascript使用输出语句实现网页特效代码

    请听我详细讲解。 在 JavaScript 中,我们可以使用输出语句实现网页特效代码。主要有两种方法:通过console.log向浏览器控制台输出信息或直接操作网页DOM元素来实现特效效果。 通过 console.log 输出信息 console.log 是 JavaScript 中常用的控制台输出方式,它可以输出文本信息或变量的值,并可以跟着一些格式化标记…

    JavaScript 2023年5月28日
    00
  • 正则表达式搭配js轻松处理json文本方便而老古

    正则表达式搭配JS轻松处理JSON文本方便而老古 什么是正则表达式? 正则表达式是一种用于描述字符串模式的语法,通过使用简洁而强大的语法规则,可以在文本匹配、搜索、替换、验证等方面提供非常高效和灵活的处理方式。 如何在JavaScript中使用正则表达式处理JSON文本? JSON(JavaScript Object Notation)是一种轻量级的数据交换…

    JavaScript 2023年5月27日
    00
  • js判断上传文件类型判断FileUpload文件类型代码

    下面是详细讲解“js判断上传文件类型判断FileUpload文件类型代码”的完整攻略。 1. 判断上传文件类型 在前端上传文件时,通常需要对上传的文件类型进行限制,以保证服务器端能正确处理文件。在JavaScript中,可以通过判断FileInput元素的文件类型来实现对上传文件类型的限制。 具体实现步骤如下: 1.1 获取上传文件的类型 使用File AP…

    JavaScript 2023年5月27日
    00
  • url中的特殊符号有什么含义(推荐)

    完整攻略:URL中的特殊符号有什么含义? 一、URL的基本结构 在讲解URL中的特殊符号之前,我们先来了解一下URL的基本结构。一个URL的基本格式如下: scheme://host:port/path?query#fragment 具体的说明如下: scheme:协议,如http、https、ftp等。 host:主机名或IP地址。 port:端口号,如果…

    JavaScript 2023年6月11日
    00
  • JavaScript中本地存储(LocalStorage)和会话存储(SessionStorage)的使用

    当涉及到JavaScript中本地存储(LocalStorage)和会话存储(SessionStorage)时,我们需要首先了解这两种存储方式的概念和用途。 本地存储(LocalStorage)和会话存储(SessionStorage) 本地存储(LocalStorage)和会话存储(SessionStorage)都是HTML5中Web StorageAPI…

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