在OpenGL SC 2.0中能否将两个双通道纹理合并为四通道纹理使用?
问题描述
我需要在片段着色器中使用两个带多级渐远(mipmap)的纹理,这两个纹理来自不同文件,无法在加载前合并。渲染时要根据一个属性值选择其中一个采样器的纹理数据,且这两幅都是双通道图像(红色通道为亮度,绿色通道为透明度)。
由于在非一致条件块(无法编译时求值的条件)中访问多级渐远纹理会得到未定义值,目前我采用的方案是:先对两个纹理完成采样,再通过条件或无分支方式选择正确的纹理数据(方案1代码见下文)。
现在想知道另一种方案是否可行:在初始化阶段将这两幅双通道图像合并为一幅四通道图像(前两个通道对应第一幅图的亮度、透明度,后两个通道对应第二幅图的亮度、透明度),之后直接采样全部四个通道,以此消除方案1中两次采样的额外开销?
方案1的片段着色器示例(原代码含bug)
#version 100 precision mediump float; varying vec2 v_objectTexCoord; varying vec3 v_objectColorRGB; varying float v_objectType; // 0.0 == 第一幅纹理, 1.0 == 第二幅纹理 uniform sampler2D u_tex_sampler_1; uniform sampler2D u_tex_sampler_2; // 注:此 shader 当前仅兼容 OpenGL ES 2.0 void main() { // 纹理红色通道为亮度,绿色通道为透明度 vec4 object_texture_1 = texture2D(u_tex_sampler_1, v_objectTexCoord); vec4 object_texture_2 = texture2D(u_tex_sampler_2, v_objectTexCoord); // 原代码存在bug:两处都使用了object_texture_1,正确应分别取两个纹理的对应通道 float luminance = object_texture_1.r * (1.0 - v_objectType) + object_texture_1.r * v_objectType; float alpha = object_texture_1.g * (1.0 - v_objectType) + object_texture_1.g * v_objectType; // 透明度低于阈值则丢弃片段 if (alpha < 0.01) { discard; } // 物体颜色 = 属性颜色 * 亮度 + 透明度 vec4 color = vec4(v_objectColorRGB * luminance, alpha); gl_FragColor = color; }
解答
这个合并方案完全可行,且能有效减少采样开销。
可行性说明
初始化阶段将两幅双通道图像合并为四通道纹理的操作,本质是把第一幅图的亮度、透明度分别存入新纹理的R、G通道,第二幅图的亮度、透明度存入B、A通道。合并后只需绑定一个纹理采样器,在片段着色器中仅需一次采样就能获取两组纹理数据,再通过v_objectType选择对应的通道组合即可。
这种方式既避开了非一致条件中访问mipmap的未定义行为,又减少了一次纹理采样操作,在性能上比方案1更优。
合并方案的片段着色器示例
#version 100 precision mediump float; varying vec2 v_objectTexCoord; varying vec3 v_objectColorRGB; varying float v_objectType; // 0.0 == 第一组通道(R/G), 1.0 == 第二组通道(B/A) uniform sampler2D u_combined_tex_sampler; void main() { // 一次采样获取四通道数据 vec4 combined_texture = texture2D(u_combined_tex_sampler, v_objectTexCoord); // 无分支选择对应通道:v_objectType为0时取R/G,为1时取B/A float luminance = mix(combined_texture.r, combined_texture.b, v_objectType); float alpha = mix(combined_texture.g, combined_texture.a, v_objectType); if (alpha < 0.01) { discard; } vec4 color = vec4(v_objectColorRGB * luminance, alpha); gl_FragColor = color; }
额外提示
- 合并纹理时需确保两幅输入图像的分辨率、mipmap层级完全一致,否则采样后的坐标对应关系会出错。
- 使用
mix函数实现无分支选择,比条件判断更适配GPU的并行执行特性,能进一步优化性能。
内容的提问来源于stack exchange,提问作者Michael Buerger
相关产品推荐
相关产品推荐

