2012-10-05 100 views
4

我正在使用计算着色器工作在粒子系统上。我把我所有的粒子放在着色器 - 存储缓冲区中。一个粒子包含两个顶点,即当前位置和前一个位置。着色器存储缓冲区中的OpenGL顶点

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属性。我的错误在哪里?

也许我初始化我着色器存储缓冲器的方式是很重要的:

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); 
} 
+0

您的代码是现代OpenGL和传统OpenGL的惊人集合。它是如何进步到足以使用计算着色器并对内存同步问题有所了解的(你仍然在使用错误的屏障,顺便说一句,因为你的代码碰巧运行并不意味着它会保证这样做),但你使用像'glVertexPointer'这样的过时函数? –

+0

我在过去使用了DirectX 11,并编写了一个粒子系统,该系统也使用了计算着色器。但是现在我想切换到OpenGL。所以这是我上个星期刚开始使用这个API的第一个项目。所以我仍然需要学习很多东西。 :) 由于没有真正有用的文档或有用的教程,其中涵盖了有关计算着色器的每个细节,所以我使用了这个例子,并且使用了glVertexPointer。 http://education.siggraph.org/media/conference/S2012_Materials/ComputeShader_6pp.pdf – Stan

回答

6

Particle结构包含两个vec4的。您的compute shader为每个数组元素写入两个vec4

然而,这条线:

glVertexPointer(4,GL_FLOAT, sizeof(glm::vec4), (GLvoid*)0); 

告诉您传递的vec4秒的阵列的OpenGL。你不是。您正在传递一个数组,其中每个元素都是两个vec4 s。而你想跳过第二个。

所以告诉OpenGL的是,通过提供合适的步幅:

glVertexPointer(4, GL_FLOAT, sizeof(Particle), (GLvoid*)0); 

哦,顺便说一句:你还是using the wrong barrier。仅仅因为你的代码碰巧起作用并不意味着它是有保证的。除非你正确地做了所有事情,否则不同步的加载/存储操作可能会非常棘手。

+0

哦,亲爱的!我想我应该休息一下了!谢谢,现在一切正常。对不起,以这样的平庸来打扰你。 – Stan