WebGL2片段着色器读取3D纹理值异常求助
问题分析与解决思路
你遇到的核心问题是整数纹理的采样方式错误,以及没有正确将原始整数数据映射到0-1的浮点范围。让我一步步拆解:
1. 整数纹理不能用texture()函数采样
你创建的是gl.R16I格式的整数纹理,但在片段着色器里用了普通的texture()函数——这个函数是为浮点纹理设计的,会自动对纹理值做归一化处理,但对于整数纹理,它的行为不符合预期,导致你拿到的不是真实的整数数值,而是异常的浮点值。
针对整数纹理,你需要用texelFetch()函数直接获取纹理单元的整数数据(需要传入纹理坐标的整数位置),或者用textureFetch()支持归一化坐标采样整数纹理(GLSL 300 ES版本支持)。
2. 原始数据的范围映射
你的纹理数据是Int16Array,范围是**-32768到32767**。要把这个范围映射到0-1的浮点区间,需要做线性转换:
float normalizedValue = (float(textureValue.r) + 32768.0) / 65535.0;
这样就能把最小的-32768转成0,最大的32767转成1,中间值按比例映射。
修正后的片段着色器
下面是调整后的代码,我保留了你的颜色判断逻辑,同时修复了采样和数据转换的问题:
#version 300 es precision highp float; precision highp int; precision highp sampler3D; uniform isampler3D in_texture; // 注意这里要用isampler3D,对应整数纹理 in vec3 v_texcoord; out vec4 color; void main() { // 用textureFetch支持归一化坐标采样整数纹理,返回整数类型结果 ivec4 textureValue = textureFetch(in_texture, v_texcoord, 0); float floatValue = float(textureValue.r); // 映射到0-1范围(如果需要后续使用归一化值的话) // float normalized = (floatValue + 32768.0) / 65535.0; // 基于真实数值的颜色判断逻辑 if(floatValue == 0.0){ color = vec4(1.0,0.0,0.0,1.0); } else if(floatValue > 0.0){ color = vec4(0.0,1.0,0.0,1.0); } else if(floatValue < 0.0){ color = vec4(0.0,0.0,1.0,1.0); } else { color = vec4(0.5,0.5,0.5,1.0); } }
注意几个关键点:
- 采样器类型改成
isampler3D(i代表integer),对应整数纹理格式 - 使用
textureFetch()采样整数纹理,确保拿到原始整数数据 - 把整数转换成float后,再做数值判断
额外检查点
- 确保你的
v_texcoord是正确的归一化坐标(0到1之间),如果是纹理像素的整数坐标,替换为texelFetch(in_texture, ivec3(v_texcoord), 0) - 你的JavaScript纹理创建代码是正确的:
gl.R16I、gl.RED_INTEGER、gl.SHORT的搭配符合整数纹理要求,过滤方式用NEAREST也是整数纹理的正确选择(线性过滤对整数纹理通常不支持)
这样修改后,你应该能正确获取到纹理的数值,并且看到预期的颜色分布了。
内容的提问来源于stack exchange,提问作者Dexylon
相关产品推荐
相关产品推荐

