WebGL 添加背景图

时间:2024-10-24 11:42:46

1. 纹理坐标(st坐标)简介

ST纹理坐标(也称为UV坐标)是一种二维坐标系统,用于在三维模型的表面上精确地定位二维纹理图像。这种坐标系统通常将纹理的左下角映射到(0,0),而右上角映射到(1,1)。

  • S坐标(U坐标):通常对应纹理图像的水平方向,即纹理的宽度。
  • T坐标(V坐标):通常对应纹理图像的垂直方向,即纹理的高度。

1.1 纹理坐标的工作原理

  • 纹理坐标的范围通常是从0.0到1.0,其中(0.0, 0.0)代表纹理的左下角,而(1.0, 1.0)代表右上角。
  • 在WebGL中,纹理坐标系统的t轴(垂直轴)与传统图像文件的y轴方向相反,这意味着当你在WebGL中使用纹理时,通常需要翻转图像的Y轴以确保正确的映射。
  • 这可以通过设置gl.UNPACK_FLIP_Y_WEBGL为1来实现。

2. 基本步骤

​​​​2.1 创建纹理对象

  • 使用gl.createTexture()创建一个新的纹理对象。
  • 可以通过 gl.deleteTexture(textrue)来删除纹理对象。
 const texture = gl.createTexture();

2.2 翻转图片Y轴

gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); 

2.3 开启纹理单元

gl.activeTexture(gl.TEXTURE0)

2.4绑定纹理对象

使用gl.bindTexture(type, texture)将纹理对象绑定到纹理单元上。type 参数有以下两种:

  • gI.TEXTURE_2D:二维纹理
  • gI.TEXTURE_CUBE_MAP:立方体纹理
gl.bindTexture(gl.TEXTURE_2D, texture);

2.5 配置纹理参数

设置纹理的过滤方式(gl.TEXTURE_MIN_FILTER和gl.TEXTURE_MAG_FILTER)、包裹方式(gl.TEXTURE_WRAP_S和gl.TEXTURE_WRAP_T)等参数。

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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);

2.6 上传纹理图像数据

使用gl.texImage2D(type, level,internalformat, format,dataType, image)将图像数据上传到纹理对象中。

2.6.1 type参数:
  • gI.TEXTURE_2D:二维纹理
  • gI.TEXTURE_CUBE_MAP:立方体纹理
2.6.2 level参数:
  • 默认为0
2.6.3 internalformat参数
  • gI.RGB
  • gI.RGBA
  • gI.ALPHA
  • gI.LUMINANCE 使用物体表面的红绿蓝 分量的加权平均值来计算
  • gI.LUMINANCE ALPHA
2.6.4 format参数
  • format 纹理的内部格式,必须和internalformat 相同
2.6.5 dataType参数
  • 9I.UNSIGNED_BYTE
  • gI.UNSIGNED_SHORT_5_6_5
  • gI.UNSIGNED_SHORT_4_4_4_4
  • gI.UNSIGNED_SHORT_5_5_5_1
 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);

3. 实例代码

以下是一个简单的WebGL示例,展示了如何给一个简单的四边形添加背景图:

/** @type {HTMLCanvasElement} */
        const ctx = document.getElementById('canvas')
        const gl = ctx.getContext('webgl')
        // 顶点着色器源码
        const vertexShaderSource = `
            attribute vec4 aPosition;
            attribute vec4 aTex;
            varying vec2 vTex;

            void main() {
                gl_Position = aPosition;
                vTex = vec2(aTex.x, aTex.y);
            }`

        // 片源着色器源码
        const fragmentShaderSource = `
            precision lowp float;
            uniform sampler2D uSampler;
            varying vec2 vTex;

            void main() {
                gl_FragColor = texture2D(uSampler, vTex);
            }`
        const program = initShader(gl, vertexShaderSource, fragmentShaderSource);
        const aPosition = gl.getAttribLocation(program, 'aPosition');
        const aTex = gl.getAttribLocation(program, 'aTex');
        const uSampler = gl.getUniformLocation(program, 'uSampler');//赋值

        const points = new Float32Array([
            -0.5, 0.5, 0.0, 1.0,
            -0.5, -0.5, 0.0, 0.0,
            0.5, 0.5, 1.0, 1.0,
            0.5, -0.5, 1.0, 0.0,
        ])
        const buffer = gl.createBuffer();
        const BYTES = points.BYTES_PER_ELEMENT; // 偏移字节
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
        gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, BYTES * 4, 0);
        gl.enableVertexAttribArray(aPosition);
        gl.vertexAttribPointer(aTex, 2, gl.FLOAT, false, BYTES * 4, BYTES * 2);
        gl.enableVertexAttribArray(aTex);

        const img = new Image();
        img.onload = function () {
            // 创建纹理对象并加载图片
            const texture = gl.createTexture();
            // 翻转图片Y轴
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
            // 开启一个单元纹理
            gl.activeTexture(gl.TEXTURE0)
            // 绑定纹理对象
            gl.bindTexture(gl.TEXTURE_2D, texture);
            // 配置纹理参数
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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);
            // 传纹理图像数据
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);
            gl.uniform1i(uSampler, 0);
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
        }
        img.src = './images/img2.png';

4.效果如下:

 ​​​​​​​