如何用WebGL实现局部马赛克的复杂疑问?
摘要:在Canvas2D中通过调用`drawImage` API就能将图像绘制到画布上,在WebGL中我们也可以绘制图像,在绘制时我们需要用到WebGL中的纹理对象,在之前实现网格背景的视频中,我使用了一个叫做纹理坐标的配置,现在要完成纹理的加载
前言
接触过Canvas的小伙伴应该都知道,在Canvas2D中我们要加载一个图片很简单,通过调用drawImage API就能将图像绘制到画布上,当然在WebGL中我们也可以绘制图像,在绘制时我们需要用到WebGL中的纹理对象,在之前WebGL实现网格背景的文章中,我使用了一个叫做纹理坐标的配置,现在要完成纹理的加载我们也需要用到纹理坐标,并且我们可以通过对纹理坐标处理实现简单的”马赛克“效果。通过对纹理的使用学习,我感觉自己对纹理坐标的认知,和之前学习网格背景时,有点不一样了,这大概就是学习的过程吧,不断更新自己的认知。
接下来我会介绍纹理的基础使用,并在此基础上实现简单的局部“马赛克”效果。
创建纹理并绑定到上下文
在Shader中使用纹理之前,我们需要先在JavaScript中创建纹理对象。
// 创建纹理对象
const texture = gl.createTexture();
// 坐标翻转
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
// 将纹理绑定到当前上下文
gl.bindTexture(gl.TEXTURE_2D, texture);
// 在图片加载完毕后,指定纹理图像
gl.texImage2D(
gl.TEXTURE_2D,
level,
internalFormat,
srcFormat,
srcType,
image,
);
// 设置纹理的一些参数
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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
上述代码中pixelStorei方法设置了像素存储格式,它的作用是将图片坐标进行翻转,因为GIF、JPEG和PNG图片使用的坐标系统以左上角为原点,X轴水平向右,Y轴垂直向下,而纹理坐标是左下角为原点,Y轴垂直向上,两者Y轴的方向相反,所以为了使图片在WebGL中正常显示,需要这一步操作。
还有一点需要注意的是,在WebGL中使用的图片需要和当前页面同源。
使用纹理
完成纹理的创建后,我们就可以通过纹理单元编号激活指定纹理,来在WebGL中使用。
// 按照单元编号激活纹理
gl.activeTexture(gl.TEXTURE0);
// 将纹理绑定到上下文
gl.bindTexture(gl.TEXTURE_2D, texture);
// 获取Shader中纹理变量
const loc = gl.getUniformLocation(program, "tMap");
// 将对应的纹理单元写入Shader变量
gl.uniform1i(loc, 0);
默认情况下WebGL会使用第一个纹理,所以如果我们只有一个纹理的话,不调用activeTexture方法也能正常使用纹理。
激活纹理后,我们就可以将对应的纹理单元写入Shader变量,这样就可以在Shader中使用纹理了,可以看到这里向Shader传递的并不是纹理对象,而是纹理单元编号。
加载纹理
等到JavaScript传递纹理信息后,Shader就可以使用这个纹理了。
precision mediump float; // 添加如下精度描述
uniform sampler2D tMap; // 纹理相关
varying vec2 vUv;
void main() {
gl_FragColor = texture2D(tMap, vUv);
}
在片元着色器中,我们使用sampler2D类型的变量接收纹理信息。
可以看到在GLSL代码中,我们使用了一个叫texture2D的函数,这个函数的作用是根据纹理坐标,从纹理中提取颜色。
通过对纹理的简单使用,我目前的理解是,纹理坐标是与顶点坐标存在一个对应的关系。
