OpenGL着色器存储缓冲区中的顶点

5

我现在正在使用计算着色器开发粒子系统。我将所有的粒子都放在了一个着色器存储缓冲区中。每个粒子包含两个顶点,当前位置和之前的位置。

struct Particle{
    glm::vec4   _currPosition;
    glm::vec4   _prevPosition;
};

在我调度计算着色器之后,我希望直接从着色器存储缓冲区中绘制所有的粒子。因此,我这样做:

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBufferID);
_shaderManager->useProgram("computeProg");
glDispatchCompute((_numParticles/WORK_GROUP_SIZE)+1, 1, 1);
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
_shaderManager->useProgram("shaderProg");
glBindBuffer(GL_ARRAY_BUFFER, shaderStorageBufferID);
glVertexPointer(4,GL_FLOAT, sizeof(glm::vec4), (GLvoid*)0);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_POINTS, 0, _numParticles);
glDisableClientState(GL_VERTEX_ARRAY);

问题在于屏幕上显示了_numParticles,但是我的粒子结构的_prevPosition属性渲染了一半。这意味着一个粒子被解释成两个顶点,在屏幕上绘制。但我想让它跳过每个粒子结构中的_prevPosition属性。我的错误在哪里?
也许我初始化shader-storage-buffer的方法很重要:
GLuint shaderStorageBufferID;

glGenBuffers(1, &shaderStorageBufferID);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBufferID);
glBufferData(GL_SHADER_STORAGE_BUFFER, numParticles*sizeof(Particle), NULL ,GL_STATIC_DRAW);
struct Particle* particles = (struct Particle*) glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, numParticles*sizeof(Particle), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);
for(int i = 0; i < numParticles; ++i){
    particles[i]._currPosition = glm::vec4(i, 0, 0.0, 1.0f);
    particles[i]._prevPosition = glm::vec4(i, 0, 1.0, 1.0f);
}

你的代码是现代OpenGL和传统OpenGL的惊人集合。你如何能够先进到使用计算着色器并且对内存同步问题有一定的理解(顺便说一句,你仍在使用错误的屏障。仅仅因为你的代码恰好能够运行,并不意味着它保证会这样做),但你却使用像glVertexPointer这样过时的函数? - Nicol Bolas
我之前曾经稍微接触过DirectX 11,并编写了一个使用计算着色器的粒子系统。但现在我想转向OpenGL。所以这是我第一个使用这个API的项目,我上周刚刚开始。因此我还需要学习很多东西。:) 由于没有真正有用的文档或涵盖计算着色器每个细节的有用教程,我使用了这个示例,其中使用了glVertexPointer。http://education.siggraph.org/media/conference/S2012_Materials/ComputeShader_6pp.pdf - Stan
1个回答

8
你的Particle结构包含两个vec4。你的计算着色器每个数组元素写入两个vec4
然而,这一行:
glVertexPointer(4,GL_FLOAT, sizeof(glm::vec4), (GLvoid*)0);

告诉OpenGL,你正在传递一个vec4数组。但实际上,你正在传递一个数组,其中每个元素都是两个vec4。而且你想跳过第二个vec4
因此,通过提供正确的步幅告诉OpenGL:
glVertexPointer(4, GL_FLOAT, sizeof(Particle), (GLvoid*)0);

顺便说一句:你仍然使用了错误的屏障。仅仅因为你的代码偶然能够正常运行并不意味着它是有保障的。未同步的加载/存储操作可能会很棘手,除非你做到了一切正确。


亲爱的!我想我应该多休息一下!谢谢,现在一切都正常了。很抱歉打扰你处理这样的琐事。 - Stan

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