OpenGL在ComputeShader中误读UniformBuffer

问题描述 投票:0回答:1

出于某种原因,我正在测试计算着色器中变换顶点位置的新方法,但遇到了问题。我想要的只是将顶点(其 id 为 2)向上变换 1.0f,但在计算着色器之后,顶点始终以相同的高度向右变换 1.2f。

我通过 Nvidia Nsight 检查了着色器存储缓冲区和统一缓冲区几次,缓冲区数据看起来不错。

计算着色器

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

主要.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;
        }
    }
}

测试1

#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 并将大小更改为 mat4 的大小时,它起作用了!另一方面,我不知道为什么它不能与 u_id 一起使用,而我必须使用它。请帮忙!

这是统一缓冲存储器

这是计算着色器之后的着色器存储缓冲区内存

opengl buffer transform compute-shader uniform
1个回答
1
投票

使用

std140
标准,
mat4
vec4
类型的成员与 16 字节对齐。这是在 OpenGL 规范中指定的,请参阅 Uniform Blocks:

  1. 如果成员是一个二分量或四分量向量,其分量消耗 N 个基本机器单元,则基本对齐分别为 2N 或 4N。
    [...]
  2. 如果成员是标量或向量数组,则基本对齐和数组 stride 设置为匹配单个数组元素的基本对齐方式,根据 符合规则 (1)、(2) 和 (3),并向上舍入到 vec4 的基本对齐方式。这 数组末尾可能有填充;以下成员的基本偏移量 数组向上舍入到基本对齐的下一个倍数。
  3. 如果成员是具有 C 列和 R 行的列主矩阵,则 根据规则 (4),矩阵的存储方式与每个具有 R 个分量的 C 列向量数组相同。
© www.soinside.com 2019 - 2024. All rights reserved.