Вычислительный шейдер OpenGL не меняет буфер - PullRequest
0 голосов
/ 09 марта 2019

Я хочу изменить содержимое буфера, который я разделяю между несколькими шейдерами, в вычислительном шейдере.В частности, нормали в этом случае.

Независимо от того, на что я установил значение одной или нескольких вершин в буфере, похоже, оно не действует ни в одном из других шейдеров.Возможно, я просто что-то забыл или что-то не вижу (я новичок в вычислении шейдеров)

Вот соответствующая часть кода.Если вам нужно больше частей кода, просто спросите.Пожалуйста, поймите, что трудно дать работающий кусок кода, потому что для этого требуется немного больше кода, чем несколько строк.

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 во время инициализации и в вычислительном шейдере i.измените значение каждой нормали на нормализованную 1/1/1, поэтому ожидайте, так что смотрите геометрию сероватого цвета, но она остается черной.

// РЕДАКТИРОВАНИЕ

После начала с нуляи проверяя результат в основном после каждой строки кода, которую я добавил, я обнаружил, что проблема заключается в этой строке: glDispatchCompute (NUM_VERTICES / NUM_PARTICLES_PER_LOCAL_WORK_GROUP, 1, 1);я предполагаю, что это равно нулю, что имеет смысл с «небольшим» числом вершин и относительно большим числом частиц на рабочую группу.

Это привело к тому, что все, что я делал в вычислительном шейдере, на самом деле никогда не быловыполняется таким образом, не изменяя содержимое буфера.

...