我的计算着色器(Compute Shader)数组索引异常是什么原因?
计算着色器无法正确读取输入数组指定索引元素问题
我目前遇到了计算着色器无法正确获取输入数组指定索引位置元素的问题。
我使用NVIDIA NSight手动读取缓冲区后确认数据输入正常,问题大概率出在索引逻辑环节。
该着色器的功能是在网格上绘制体素:红色高亮区域是预期绘制结果,蓝色区域是实际得到的渲染结果,NSight捕获的转置后SSBO缓冲区数据确认输入内容正常。
我当前使用的计算着色器代码如下:
#version 430 layout(local_size_x = 1, local_size_y = 1) in; layout(rgba32f, binding = 0) uniform image2D img_output; layout(std430) buffer; layout(binding = 0) buffer Input0 { ivec2 mapSize; }; layout(binding = 1) buffer Input1 { bool mapGrid[]; }; void main() { // 图像基础像素颜色 vec4 pixel = vec4(1, 1, 1, 1); // 获取全局工作组中的索引,即x,y坐标位置 ivec2 pixel_coords = ivec2(gl_GlobalInvocationID.xy); vec2 normalizedPixCoords = vec2(gl_GlobalInvocationID.xy) / gl_NumWorkGroups.xy; ivec2 voxel = ivec2(int(normalizedPixCoords.x * mapSize.x), int(normalizedPixCoords.y * mapSize.y)); float distanceFromMiddle = length(normalizedPixCoords - vec2(0.5, 0.5)); pixel = vec4(0, 0, mapGrid[voxel.x * mapSize.x + voxel.y], 1); // <--- 问题出在这里 // 我在CPU代码中用完全相同的方式索引体素,运行正常 // 输出到图像中的指定像素位置 //imageStore(img_output, pixel_coords, pixel * vec4(vignettecolor, 1) * imageLoad(img_output, pixel_coords)); imageStore(img_output, pixel_coords, pixel); }
问题原因与解决方案
- 数组索引顺序错误
你当前的索引计算逻辑voxel.x * mapSize.x + voxel.y不符合常规二维数组的行优先存储规则。如果你的CPU侧是按行优先(即先存完第一行所有元素再存第二行)存储mapGrid,正确的索引计算应该是:
int gridIdx = voxel.y * mapSize.x + voxel.x;
如果你的CPU侧是按列优先存储,那索引应该改为:
int gridIdx = voxel.x * mapSize.y + voxel.y;
- 归一化坐标越界风险
当gl_GlobalInvocationID.x等于gl_NumWorkGroups.x时,normalizedPixCoords.x会等于1,乘以mapSize.x后得到的结果正好等于mapSize.x,会触发数组越界访问。可以改为如下写法避免:
ivec2 voxel = ivec2( clamp(int(normalizedPixCoords.x * mapSize.x), 0, mapSize.x - 1), clamp(int(normalizedPixCoords.y * mapSize.y), 0, mapSize.y - 1) );
- 可选优化:你当前把
local_size_x和local_size_y都设为1会极大降低计算着色器的执行效率,建议改为layout(local_size_x = 8, local_size_y = 8) in;,调度工作组的时候按(输出宽度/8, 输出高度/8)调度即可。
内容的提问来源于stack exchange,提问作者rokoblox
相关产品推荐
相关产品推荐

