我想在计算着色器中更改多个着色器之间共享的缓冲区的内容。特别是在这种情况下的法线。
无论我将缓冲区中一个或多个顶点的值设置为什么,它似乎都不会在其他任何着色器中生效。可能我只是忘记了一些东西或什么都没看到(我是计算着色器的新手)
这是代码的相关部分。如果您需要代码的更多部分,请询问。请理解,尽管很难给出一段有效的代码,因为这需要安静的代码,而不仅仅是几行。
utils_createComputeProgram(&g_simulateWaterProgram, "content/shaders/simulatewater/simulatewater.comp");
// Initialize first position buffer
{
glGenBuffers(1, &app->positionBufferOne);
glBindBuffer(GL_ARRAY_BUFFER, app->positionBufferOne);
glBufferData(GL_ARRAY_BUFFER, NUM_VERTICES*sizeof(MLvec4), NULL, GL_STATIC_DRAW);
MLvec4* positions = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
for (int i = 0; i < NUM_VERTICES; ++i) {
...
positions[i] = mlMakeVec4(x, y, z, v);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// Initialize second position buffer with 0
{
glGenBuffers(1, &app->positionBufferTwo);
glBindBuffer(GL_ARRAY_BUFFER, app->positionBufferTwo);
glBufferData(GL_ARRAY_BUFFER, NUM_VERTICES*sizeof(MLvec4), NULL, GL_STATIC_DRAW);
MLvec4* positions = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
for (int i = 0; i < NUM_VERTICES; ++i) {
positions[i] = mlMakeVec4(0, 0, 0, 0);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// initialize normal buffer
{
glGenBuffers(1, &app->normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, app->normalBuffer);
glBufferData(GL_ARRAY_BUFFER, NUM_VERTICES*sizeof(MLvec4), NULL, GL_STATIC_DRAW);
MLvec4* normals = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
for (int i = 0; i < NUM_VERTICES; ++i) {
normals[i] = mlMakeVec4(0, 0, 1, 0);
}
glUnmapBuffer(GL_ARRAY_BUFFER);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
// Attach buffers to program
{
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, app->positionBufferOne);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, app->positionBufferTwo);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, app->normalBuffer);
}
utils_createProgramVertexFragment(&g_renderWaterProgram, "content/shaders/renderwater/renderwater.vert", "content/shaders/renderwater/renderwater.frag");
// initialize VAO
{
glGenVertexArrays(1, &g_waterVertexArrayObject);
utils_setAttributePointer(g_waterVertexArrayObject, app->positionBufferOne, 0, 4, GL_FLOAT, GL_FALSE, 0, 0);
utils_setAttributePointer(g_waterVertexArrayObject, app->positionBufferTwo, 1, 4, GL_FLOAT, GL_FALSE, 0, 0);
utils_setAttributePointer(g_waterVertexArrayObject, app->normalBuffer, 2, 4, GL_FLOAT, GL_FALSE, 0, 0);
}
// initialize index array
{
...
glBindVertexArray(g_waterVertexArrayObject);
glGenBuffers(1, &g_elementArrayBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_elementArrayBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * NUM_INDICES, g_waterIndices, GL_STATIC_DRAW);
}
void rendering_render(Application* app, int framebufferWidth, int framebufferHeight) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, framebufferWidth, framebufferHeight);
MLvec3 center = mlMakeVec3(app->camera.cx, app->camera.cy, app->camera.cz);
MLvec3 eye = positionOfCamera(app->camera);
MLmat4 modelMatrix = mlIdentity4;
MLmat4 projectionMatrix = mlMakePerspectiveFromFOV(100, (float)framebufferWidth / framebufferHeight, 0.01, 100.0);
MLmat4 viewMatrix = mlMakeLookAt(eye, center, mlMakeVec3(0, 1, 0));
// Hier muss gewartet werden, bis der Compute Shader alle Schreiboperationen auf die Shader Storage Buffer ausgeführt hat.
//glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
glUseProgram(g_renderWaterProgram);
utils_setUniformMat4(renderWaterProgram_ProjectionMatrix, &projectionMatrix);
utils_setUniformMat4(renderWaterProgram_ViewMatrix, &viewMatrix);
utils_setUniformMat4(renderWaterProgram_ModelMatrix, &modelMatrix);
if (app->debug) {
glDrawElements(GL_POINTS, NUM_INDICES, GL_UNSIGNED_INT, NULL);
}
else {
glDrawElements(GL_TRIANGLES, NUM_INDICES, GL_UNSIGNED_INT, NULL);
}
glUseProgram(0);
}
计算着色器:
layout (local_size_x = 1000, local_size_y = 1, local_size_z = 1) in;
layout (location = 0) uniform float Dt;
layout (std430, binding = 0) buffer PositionBufferOne {
vec4 positions[];
};
layout (std430, binding = 1) buffer PositionBufferTwo {
vec4 positionsNew[];
};
layout (std430, binding = 2) buffer NormalBuffer {
vec4 normals[];
};
vec3 calcNormal() {
return normalize(vec3(1, 1, 1));
}
void main() {
uint index = gl_GlobalInvocationID.x;
normals[index] = vec4(calcNormal(), 0.0);
}
实用程序:
GLuint utils_createShader(GLenum shaderType, const char* filename) {
GLuint shader = glCreateShader(shaderType);
const char* sources[2];
sources[0] = common_readfile("content/shaders/utils.glsl");
sources[1] = common_readfile(filename);
glShaderSource(shader, 2, sources, NULL);
free((void*)sources[0]);
free((void*)sources[1]);
glCompileShader(shader);
utils_checkShaderLog(filename, shader);
return shader;
}
void utils_createComputeProgram(GLuint *program, const char* computeShaderFilename) {
glDeleteProgram(*program);
GLuint computeShader = utils_createShader(GL_COMPUTE_SHADER, computeShaderFilename);
*program = glCreateProgram();
glAttachShader(*program, computeShader);
glLinkProgram(*program);
utils_checkProgramLog(*program);
glDeleteShader(computeShader);
}
void utils_setAttributePointer(GLuint vertexArrayObject, GLuint buffer, GLint location, GLint size, GLenum type, GLboolean normalized, GLsizei stride, unsigned offset) {
GLint previousVertexArrayObject;
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &previousVertexArrayObject);
GLint previousArrayBuffer;
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &previousArrayBuffer);
glBindVertexArray(vertexArrayObject);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glEnableVertexAttribArray(location);
glVertexAttribPointer(location, size, type, normalized, stride, (void*)(intptr_t)offset);
glBindBuffer(GL_ARRAY_BUFFER, previousArrayBuffer);
glBindVertexArray(previousVertexArrayObject);
}
void utils_setUniformMat4(GLuint location, MLmat4* m) {
glUniformMatrix4fv(location, 1, GL_FALSE, (GLfloat*)m);
}
我使用法线作为片段的颜色来测试更改。
在此示例中,我在初始化期间将法线设置为0/0/0,并且在计算着色器中,我将每个法线的值更改为归一化的1/1/1,因此可以这样看,所以请看一下呈灰色的几何图形,但它保持黑色。
//编辑
从头开始并基本上在我添加的每一行代码之后测试结果之后,我发现问题出在这一行:glDispatchCompute(NUM_VERTICES / NUM_PARTICLES_PER_LOCAL_WORK_GROUP,1,1);我猜这算为零,这是有意义的,因为“顶点”数量“少”,每个工作组的粒子数量相对较多。
这导致我在计算着色器中所做的任何操作都从未真正执行过,因此没有更改缓冲区内容。