OpenGL计算着色器调用

6

我有一个与新的计算着色器相关的问题。我目前正在开发一个粒子系统。我将所有粒子存储在着色器存储缓冲区中,以便在计算着色器中访问它们。然后我分派一个一维工作组。

#define WORK_GROUP_SIZE 128
_shaderManager->useProgram("computeProg");
glDispatchCompute((_numParticles/WORK_GROUP_SIZE), 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);

我的计算着色器:

#version 430
struct particle{
         vec4 currentPos;
         vec4 oldPos;
};

layout(std430, binding=0) buffer particles{
         struct particle p[];
};

layout (local_size_x = 128, local_size_y = 1, local_size_z = 1) in;
void main(){
         uint gid = gl_GlobalInvocationID.x;

         p[gid].currentPos.x += 100;
}

但是,某些粒子并没有受到影响。我按照这个例子的方式进行操作,但它不起作用。 http://education.siggraph.org/media/conference/S2012_Materials/ComputeShader_6pp.pdf

编辑:

在调用glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT)之后,我会继续进行以下操作:

_shaderManager->useProgram("shaderProg"); 
glBindBuffer(GL_ARRAY_BUFFER, shaderStorageBufferID); 
glVertexPointer(4,GL_FLOAT,sizeof(glm::vec4), (void*)0);
glEnableClientState(GL_VERTEX_ARRAY); 
glDrawArrays(GL_POINTS, 0, _numParticles); 
glDisableClientState(GL_VERTEX_ARRAY);

那么在这种情况下应该使用哪一部分?
2个回答

8
你把屏障戴反了。这是一个常见的问题。
你提供给屏障的位描述了你打算如何使用已写入的数据,而不是数据的写入方式。只有通过图像加载/存储(或存储缓冲区/原子计数器)向缓冲对象写入数据的某个过程,然后使用存储缓冲区读取该缓冲对象数据时,才适用于GL_SHADER_STORAGE_BARRIER_BIT
由于您正在将缓冲区作为顶点属性数组缓冲区读取,因此应使用巧妙命名的GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT

2
我解决了这个问题。问题只是我分配的工作组数量。 numParticles / WORK_GROUP_SIZE会四舍五入,因为两个变量都是整数。这导致派发了太少的工作组,这些工作组有不同数量的粒子。
当我有1000个粒子时,只有7个工作组被派遣,每个工作组的大小为128。这意味着我得到了7 * 128 = 896个线程,因此104个粒子根本不会移动。 由于numParticles%128可能在0 ... 128范围内,所以我只派发了一个额外的工作组:
glDispatchCompute((_numParticles/WORK_GROUP_SIZE)+1, 1, 1);

现在每个粒子都开始运动了。 :)


我不建议这样做,因为你正在分派访问输入缓冲区之外的workItems。你应该始终请求_numParticles的值是WORK_GROUP_SIZE的倍数,这样除法就永远不会四舍五入。 - Rockcat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接