WebGL 1.0中如何将纹理用作屏幕尺寸位图?像素坐标映射至gl_FragCoord
用全屏纹理做深度索引的WebGL实现思路
嘿,这个思路相当巧妙——靠gl_FragCoord.xy直接采样全屏纹理来做深度索引,完全跳过属性和UV坐标的设置,确实能简化批量绘制的流程!我来给你拆解下具体怎么实现:
核心步骤
1. 极简顶点着色器(无需任何属性)
因为我们要绘制的是覆盖整个窗口的全屏区域,完全不需要从缓冲区读取顶点数据。用一个全屏三角形是最高效的方式,顶点着色器可以直接生成覆盖裁剪空间的顶点:
precision mediump float; void main() { // 生成全屏三角形的三个顶点(裁剪空间坐标) vec2 pos = vec2(gl_VertexID % 2, gl_VertexID / 2) * 4.0 - 2.0; gl_Position = vec4(pos, 0.0, 1.0); }
你甚至不用创建顶点缓冲区,直接调用gl.drawArrays(gl.TRIANGLES, 0, 3)就能渲染全屏画面。
2. 片段着色器中采样纹理做深度索引
这里要注意一个关键细节:WebGL的纹理坐标原点是左下角,但gl_FragCoord.xy的原点是左上角,所以必须先翻转Y轴坐标,再做采样:
precision mediump float; uniform sampler2D u_depthIndexTex; uniform vec2 u_screenSize; void main() { // 转换gl_FragCoord到纹理坐标(翻转Y轴) vec2 texCoord = gl_FragCoord.xy / u_screenSize; texCoord.y = 1.0 - texCoord.y; // 采样纹理获取深度索引 float depthIndex = texture2D(u_depthIndexTex, texCoord).r; // 这里根据depthIndex做后续处理,比如设置自定义深度值 gl_FragDepth = depthIndex; // 或者根据索引输出对应颜色/执行其他逻辑 gl_FragColor = vec4(depthIndex, 0.0, 0.0, 1.0); }
3. 纹理的创建与更新
- 创建纹理时,要确保尺寸和当前窗口一致:
const depthIndexTex = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, depthIndexTex); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, window.innerWidth, window.innerHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null ); // 因为是索引数据,禁用纹理过滤避免插值错误 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 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);
- 当窗口大小变化时,记得重新调整纹理尺寸,避免采样错位。
关键注意事项
- 纹理格式选择:如果深度索引只需要8位精度,用
GL_RED格式比GL_RGBA更节省显存;如果需要更高精度,可以用GL_RGB16F之类的浮点纹理。 gl_FragDepth的性能影响:如果使用gl_FragDepth自定义深度值,部分GPU可能会关闭深度测试的优化,若对性能敏感可以测试对比。- 坐标精度:当窗口尺寸极大时,
gl_FragCoord的整数坐标转换为纹理坐标可能会有微小精度误差,但在绝大多数场景下可以忽略。
内容的提问来源于stack exchange,提问作者synchronizer
相关产品推荐
相关产品推荐

