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

Posted

技术标签:

【中文标题】着色器存储缓冲区中的 OpenGL 顶点【英文标题】:OpenGL vertices in shader storage buffer 【发布时间】:2012-10-05 18:47:39 【问题描述】:

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

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);

【问题讨论】:

您的代码是现代 OpenGL 和传统 OpenGL 的惊人集合。您如何足够先进以使用计算着色器并对内存同步问题有所了解(顺便说一句,您仍在使用错误的屏障。仅仅因为您的代码恰好可以运行并不意味着它可以保证这样做),但是你使用了像glVertexPointer这样过时的函数? 我在过去使用过 DirectX 11 并编写了一个粒子系统,该系统也使用了计算着色器。但现在我想切换到 OpenGL。所以这是我上周刚开始的第一个使用这个 API 的项目。所以我还是要学很多东西。 :) 由于没有真正有用的文档或有用的教程来涵盖有关计算着色器的所有细节,因此我使用了这个示例并且使用了 glVertexPointer。 education.siggraph.org/media/conference/S2012_Materials/… 【参考方案1】:

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

这一行:

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

告诉 OpenGL 你正在传递一个vec4s 的数组。你不是。您正在传递一个数组,其中每个元素都是 two vec4s。而你想跳过第二个。

因此,通过提供适当的步幅来告诉 OpenGL:

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

哦,顺便说一句:你仍然是using the wrong barrier。仅仅因为您的代码恰好运行并不意味着它是有保证的。除非您做的一切都正确,否则不同步的加载/存储操作可能会很棘手。

【讨论】:

天哪!我想我应该多休息一下!谢谢,现在一切正常。很抱歉用这种平庸的方式打扰您。

以上是关于着色器存储缓冲区中的 OpenGL 顶点的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL:着色器存储缓冲区映射/绑定

OpenGL - 告诉顶点着色器 VBO 已经改变

✠OpenGL-2-图像管线

将 C++ 容器提供给 OpenGL?

OpenGL ES 渲染立体图形

打开 gl 计算着色器和帧缓冲区