OpenGL误读ComputeShader中的UniformBuffer

q35jwt9p  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(111)

我正在做一个测试的新方法转换顶点位置的计算着色器出于某种原因,我遇到了一个问题。我想要的只是将顶点(其id为2)向上变换1.0f,但在计算着色器之后,顶点总是以相同的高度向右变换1.2f。
我用Nvidia Nsight检查了着色器存储缓冲区和均匀缓冲区几次,缓冲区数据看起来很好。
ComputeShader

#version 460 core

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

layout(std140, binding = 0) uniform Matrix 
{
    float u_id;
    mat4 modelM;
};

struct VertexLayout 
{
    vec3 positions;
    float v_id;
};

layout(std430, binding = 1) buffer VertexBuffer 
{
    VertexLayout vertex[];
};

void main() 
{
    if(vertex[gl_GlobalInvocationID.x].v_id == u_id) 
    {
        vertex[gl_GlobalInvocationID.x].positions = vec3(modelM * vec4(vertex[gl_GlobalInvocationID.x].positions, 1.0));
    }
}

Main.cpp

#include "main.h"
#include "Test1.h"

Renderer* renderer;

int main()
{
    if (!InitGLFW())
        return -1;
    
    renderer = new Renderer();
    renderer->loadMatrix();
    

    while (!glfwWindowShouldClose(window))
    {
        glClear(GL_COLOR_BUFFER_BIT);

        renderer->Render();

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    delete renderer;
    glfwTerminate();
    return 0;
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (action == GLFW_PRESS)
    {
        switch (key)
        {
        case GLFW_KEY_ESCAPE:
            glfwSetWindowShouldClose(window, true);
            break;

        case GLFW_KEY_KP_1:
            glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
            break;

        case GLFW_KEY_KP_2:
            glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
            break;

        case GLFW_KEY_KP_4:
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
            break;

        case GLFW_KEY_KP_5:
            glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
            break;

        case GLFW_KEY_KP_6:
            renderer->Transform();
            break;
        }
    }
}

Test1

#pragma once
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

struct Data
{
    float id;
    glm::mat4 modelM;
};

class Renderer
{
public:
    Renderer();
    ~Renderer();

    void loadMatrix();
    void Render();
    void Transform();
    Data data;

private:
    unsigned int shaderID;
    unsigned int programID;
    unsigned int vertexBufferID;
    unsigned int vertexArrayID;
    unsigned int uniformBufferID;

    unsigned int vertexShader;
    unsigned int fragmentShader;
    unsigned int prog;

};


#include "Test1.h"
#include "IO.h"
#include "glad/glad.h"
#include <iostream>

Renderer::Renderer()
{
    shaderID = ShaderIO::loadShaderFromFile("resource\\shaders\\Test1\\compute.glsl", GL_COMPUTE_SHADER);

    vertexShader = ShaderIO::loadShaderFromFile("resource\\shaders\\Test1\\vertex.glsl", GL_VERTEX_SHADER);
    fragmentShader = ShaderIO::loadShaderFromFile("resource\\shaders\\Test1\\fragment.glsl", GL_FRAGMENT_SHADER);

    prog = glCreateProgram();
    glAttachShader(prog, vertexShader);
    glAttachShader(prog, fragmentShader);
    glLinkProgram(prog);
    glValidateProgram(prog);

    programID = glCreateProgram();
    glAttachShader(programID, shaderID);
    glLinkProgram(programID);
    glValidateProgram(programID);

    int isValid;
    glGetProgramiv(programID, GL_VALIDATE_STATUS, &isValid);
    if (!isValid)
    {
        std::cout << "[ERROR]: Program is not valid!" << std::endl;
        glDeleteProgram(programID);
        glDeleteShader(shaderID);
    }

    float positions[] = 
    {
        -0.5f, -0.5f, 0.0f, 1.0f,
         0.0f,  0.5f, 0.0f, 2.0f,
         0.5f, -0.5f, 0.0f, 3.0f
    };

    glCreateVertexArrays(1, &vertexArrayID);
    glEnableVertexArrayAttrib(vertexArrayID, 0);
    glVertexArrayAttribBinding(vertexArrayID, 0, 0);
    glVertexArrayAttribFormat(vertexArrayID, 0, 3, GL_FLOAT, GL_FALSE, 0);

    glCreateBuffers(1, &vertexBufferID);
    glNamedBufferData(vertexBufferID, sizeof(positions), positions, GL_DYNAMIC_DRAW);

    glVertexArrayVertexBuffer(vertexArrayID, 0, vertexBufferID, 0, 4 * sizeof(float));

    glBindVertexArray(vertexArrayID);
    glUseProgram(prog);

    glCreateBuffers(1, &uniformBufferID);
    glNamedBufferData(uniformBufferID, sizeof(Data), nullptr, GL_DYNAMIC_DRAW);

    glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniformBufferID);
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vertexBufferID);

    data.id = 2;
    data.modelM = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 1.0f, 0.0f));
}

Renderer::~Renderer()
{
    glDeleteProgram(programID);
    glDeleteShader(shaderID);
    glDeleteBuffers(1, &vertexBufferID);
    glDeleteBuffers(1, &uniformBufferID);
    glDeleteVertexArrays(1, &vertexArrayID);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
    glDeleteProgram(prog);
}

void Renderer::loadMatrix()
{
    glNamedBufferSubData(uniformBufferID, 0, sizeof(Data), &data);
}

void Renderer::Render()
{
    glDrawArrays(GL_TRIANGLES, 0, 3);
}

void Renderer::Transform()
{
    glUseProgram(programID);
    glDispatchCompute(3, 1, 1);
    glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
    glUseProgram(prog);
}

我已经尝试了很多东西,最后我发现,当我排除了u_id从统一缓冲区,并改变大小只是mat 4的大小,它的工作!另一方面,我不知道为什么它不能与u_id一起工作,我必须使用它。请帮帮忙!
这是统一缓冲存储器x1c 0d1x
这是计算着色器

之后的着色器stroge缓冲区内存

yrefmtwq

yrefmtwq1#

std140标准中,mat4vec4类型的成员按16个字节对齐。这是在OpenGL规范中指定的,请参阅均匀块:
1.如果成员是两个或四个分量的向量,其分量消耗N个基本机器单元,则基本对齐分别为2N或4 N。
[...]
1.如果成员是标量或向量数组,则根据规则(1)、(2)和(3),将基对齐和数组步幅设置为匹配单个数组元素的基对齐,并向上舍入为vec 4的基对齐。数组可以在末尾有填充;跟随阵列的成员的基准偏移被向上舍入到基准对齐的下一个倍数。
1.如果成员是具有C列和R行的列为主矩阵,则根据规则(4),该矩阵被存储为与每个具有R个分量的C列向量的数组相同。

相关问题