WebGLTexture 读写数据

600 阅读3分钟

和 WebGLBuffer 类似,不过 WebGLTexture 是存储传输纹理数据的,纹理数据通常来自一个 Image 对象。

一、写入数据

往着色器中传递纹理数据我们需要使用 WebGLTexture 这个对象,通过texImage2D这个方法可以把 Javascript 里的图像数据存到 WebGLTexture中,会自动存储放到片元着色器的第0个纹理单元。

大致步骤如下:

  1. 通过createTexture创建 WebGLTexture;
  2. 激活纹理单元(默认是第0和纹理单元,可以省略这步);
  3. 通过bindTexture绑定 WebGLTexture;
  4. 通过texParameteri设置纹理裁剪和采样属性;
  5. 通过texImage2D指定二维图像,写入纹理;

在这里,gl.TEXTURE_2DARRAY_BUFFER有点类似,可以看作是一个临时的数据桥梁🌉或者数据转运卡车🚚一样,把Javascript环境下的的Image转达给WebGLWebGLTexture,不同的是,在转运前要设置一些裁剪和采样属性。

WebGLTexture大多数情况存放的是图像数据(来自Image或者数组),其本质上是存放的是一个数据序列,因此也可以随意存放除了颜色数据以外的其它数据。纹理往往需要搭配纹理坐标来使用(需要注意纹理坐标系和顶点坐标系不一致),纹理坐标一般是顶点着色器插值生成传给片元着色器的,通过纹理坐标获取对应片元的颜色。

// 创建纹理对象
let texture = gl.createTexture();

// 绑定纹理,会默认绑定到WebGL的纹理单元0,在片元着色器中定义的sampler2D默认也是纹理单元0
// gl.activeTexture(gl.TEXTURE6); // 激活纹理到单元 
gl.bindTexture(gl.TEXTURE_2D, texture);

// 设置纹理裁剪规则,有重复、镜像、按最大值、最小值处理
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

// 将图像上传到纹理(image是JS中的Image对象,也可以是颜色数组)
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

二、读取数据

当二维图像被传入WebGLTexture后,不需要像Buffer读取数据那样手动指定读取规则,纹理会数据会默认读取并存到到 WebGL 的第0个纹理单元在片元着色器中通过sampler2D类型的uniform变量就可以直接获取。同时,可以在着色程序运行中随意读取其中的数据。

WebGL 环境中,在片元着色器中至少有8个纹理单元,顶点着色器中可以是0个。

如果使用了超过8个纹理单元就应该调用gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)查看单元个数;

或者调用gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)查看顶点着色器中可以用几个纹理单元;

超过 99% 的 GPU 硬件在顶点着色器中至少有4个纹理单元。

  let fragmentShaderSource = `
      precision mediump float;   // 中等精度
      uniform sampler2D u_image; // 其默认值是0,表示第0个纹理单元,会直接从webGLTexture中取数据
      varying vec2 v_texCoord;   // 从顶点着色器传入的纹理坐标

      void main() {
         gl_FragColor = texture2D(u_image, v_texCoord);
      }
  `;

这是WebGL 系列的入门文章,免费订阅,如有帮助请点赞收藏,纰漏之处欢迎指正!

qrcode_for_gh_3695c3ae18f4_258.jpg

也欢迎关注公众号交流知识哇😄