使用usampler2D采样R16_UINT图像时是否支持插值?
采样R16_UINT纹理无插值的问题分析与解决
你用usampler2D采样R16_UINT格式图像时遇到了无插值的问题,代码如下:
uvec4 upix_color = texture(usampler2D(utextures[nonuniformEXT(idx_of_height_map)], samplers[0]), result.uvs);
问题原因
GLSL中的无符号整数采样器(usampler2D)不支持硬件原生的纹理过滤插值。多数GPU的硬件设计中,整数格式纹理的采样仅默认支持最近邻模式,线性插值等过滤操作对整数纹理无效——硬件不会对整数像素值进行插值计算,只会返回距离采样点最近的整数像素。
解决办法
1. 改用R16_UNORM格式(推荐)
将纹理格式改为R16_UNORM,使用普通sampler2D采样,硬件会原生支持线性插值。采样得到的归一化浮点数可再转换回0-65535的整数:
vec4 pix_color = texture(sampler2D(textures[idx_of_height_map], samplers[0]), result.uvs); uint height_value = uint(pix_color.r * 65535.0);
这种方式性能最优,是最常用的方案。
2. 手动实现整数插值(仅当必须保留R16_UINT时)
如果必须使用R16_UINT格式,只能在着色器中手动计算插值逻辑。以双线性插值为例,步骤为:获取采样点周围4个像素的整数取值,再根据UV的小数部分完成插值:
vec2 uv = result.uvs; // 获取纹理尺寸 vec2 tex_size = textureSize(utextures[idx_of_height_map], 0); // 计算纹理坐标的整数部分和小数偏移 vec2 tex_coord = uv * tex_size; vec2 int_coord = floor(tex_coord); vec2 frac_coord = fract(tex_coord); // 采样周围4个像素(需加0.5取像素中心) uvec4 tl = texture(usampler2D(utextures[idx_of_height_map], samplers[0]), (int_coord + vec2(0.5)) / tex_size); uvec4 tr = texture(usampler2D(utextures[idx_of_height_map], samplers[0]), (int_coord + vec2(1.5, 0.5)) / tex_size); uvec4 bl = texture(usampler2D(utextures[idx_of_height_map], samplers[0]), (int_coord + vec2(0.5, 1.5)) / tex_size); uvec4 br = texture(usampler2D(utextures[idx_of_height_map], samplers[0]), (int_coord + vec2(1.5, 1.5)) / tex_size); // 双线性插值计算最终值 uint interpolated_r = uint(mix(mix(float(tl.r), float(tr.r), frac_coord.x), mix(float(bl.r), float(br.r), frac_coord.x), frac_coord.y)); // 其他通道同理处理 uvec4 final_color = uvec4(interpolated_r, tl.g, tl.b, tl.a);
注意手动插值会增加着色器计算开销,性能不如原生浮点插值。
内容的提问来源于stack exchange,提问作者Zebrafish
相关产品推荐
相关产品推荐

