首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何绘制存储在SSBO中的顶点?

如何绘制存储在SSBO中的顶点?
EN

Stack Overflow用户
提问于 2020-01-07 22:29:40
回答 1查看 1.2K关注 0票数 3

这是OpenGL和AoSoA (混合SoA)格式的数据加载/读取后面的一个问题。

我试图使用着色存储缓冲区对象(SSBO)来存储顶点数据,这是以AoSoA格式表示的。我在绘制顶点时遇到了困难,这显然意味着我在某个地方做错了什么。问题是我似乎弄不清楚是什么或者在哪里。上面最初问题的答案似乎表明,我不应该使用顶点属性数组,所以问题是,考虑到我将要呈现的代码,如何呈现这个SSBO?

VertexData结构

代码语言:javascript
复制
constexpr auto VECTOR_WIDTH = 4;
constexpr auto VERTEX_COUNT = 16;

struct VertexData
{
    std::array<float, VECTOR_WIDTH> px;
    std::array<float, VECTOR_WIDTH> py;
};
// Later stored in a std::vector
std::vector<VertexData> vertices(VERTEX_COUNT / VECTOR_WIDTH);

顶点着色器(这真的应该是一个计算着色器吗?)

代码语言:javascript
复制
struct Vertex4
{
    float px[4]; // position x
    float py[4]; // position y
};

layout(std430, binding=0) buffer VertexData
{
    Vertex4 vertices[];
};

void main()
{
  int dataIx = gl_VertexID / 4;
  int vertexIx = gl_VertexID % 4;
  vec2 vertexPosition = vec2(vertices[dataIx].px[vertexIx], vertices[dataIx].py[vertexIx]);
}

vertexPosition 指定索引

代码语言:javascript
复制
// Do I need this? Where do I use it? glEnableVertexAttribArray(position_attrib_index)?
const GLuint position_attrib_index = 0;
glBindAttribLocation(program, position_attrib_index, "vertexPosition");

SSBO设置

代码语言:javascript
复制
const GLuint ssbo_binding_point = 0;
GLuint ssbo{};
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
//glBufferStorage(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_MAP_WRITE_BIT);
glBufferData(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_STATIC_DRAW);
const auto block_index = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "VertexData");
glShaderStorageBlockBinding(program, block_index, ssbo_binding_point);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, ssbo_binding_point, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

呈现循环

代码语言:javascript
复制
while (!glfwWindowShouldClose(window)) {
    process_input(window);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(program);

    // ???

    glfwSwapBuffers(window);
    glfwPollEvents();
}

我只是不知道这该怎么做。在抓取吸管时,我还尝试创建一个VAO,随后调用glDrawArrays(GL_POINTS, 0, VERTEX_COUNT),但是它也没有工作:

代码语言:javascript
复制
GLuint vao{};
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnableVertexAttribArray(position_attrib_index);
glVertexAttribPointer(position_attrib_index, 2, GL_FLOAT, GL_FALSE, 0, nullptr);

在我看来,我应该使用position_attrib_index (它应该指向vertexPosition)来做一些事情,问题是什么?

完整示例代码

  • 需要OpenGL 4.3、格鲁GLFW
  • 构建命令示例:g++ -std=c++17 main.cpp -lGLEW -lglfw -lGL -o ssbo
代码语言:javascript
复制
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <array>
#include <iostream>
#include <vector>

void process_input(GLFWwindow *window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
        glfwSetWindowShouldClose(window, true);
    }
}

void glfw_error_callback(int error_code, const char *description)
{
    std::cerr << "GLFW Error: [" << error_code << "] " << description << '\n';
}

void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
    glViewport(0, 0, width, height);
}

auto create_glfw_window()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    return glfwCreateWindow(800, 600, "OpenGL and AoSoA layout", nullptr, nullptr);
}

void set_callbacks(GLFWwindow *window)
{
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    glfwSetErrorCallback(glfw_error_callback);
}

void print_versions()
{
    std::cout << "Using GLFW " << glfwGetVersionString() << '\n';
    std::cout << "Using GLEW " << glewGetString(GLEW_VERSION) << '\n';
}

bool init_loader()
{
    GLenum err = glewInit();
    if (GLEW_OK != err) {
        std::cerr << "GLEW error: " << glewGetErrorString(err);
    }
    return err == GLEW_OK;
}

void GLAPIENTRY MessageCallback(
    GLenum source,
    GLenum type,
    GLuint id,
    GLenum severity,
    GLsizei length,
    const GLchar* message,
    const void* userParam = nullptr)
{
    std::cerr << "[GL DEBUG] " << (type == GL_DEBUG_TYPE_ERROR ? "Error: " : "") << message << '\n';
}

constexpr auto VECTOR_WIDTH = 4;
constexpr auto VERTEX_COUNT = 16;

struct VertexData
{
    std::array<float, VECTOR_WIDTH> px;
    std::array<float, VECTOR_WIDTH> py;
};

static const char* vertex_shader_source =
    "#version 430\n"
    "struct Vertex4\n"
    "{\n"
    "    float px[4]; // position x\n"
    "    float py[4]; // position y\n"
    "};\n"
    "layout(std430, binding=0) buffer VertexData\n"
    "{\n"
    "    Vertex4 vertices[];\n"
    "};\n"
    "void main()\n"
    "{\n"
    "  int dataIx = gl_VertexID / 4;\n"
    "  int vertexIx = gl_VertexID % 4;\n"
    "  vec2 vertexPosition = vec2(vertices[dataIx].px[vertexIx], vertices[dataIx].py[vertexIx]);\n"
    "}\n";

static const char* fragment_shader_source =
    "#version 430\n"
    "out vec4 out_color;\n"
    "void main()\n"
    "{\n"
    "    out_color = vec4(1.0, 0.5, 0.5, 0.25);\n"
    "}\n";

int main(int argc, char *argv[])
{
    glewExperimental = GL_TRUE;

    auto window = create_glfw_window();

    if (window == nullptr) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);

    set_callbacks(window);
    init_loader();
    print_versions();

    glEnable(GL_DEBUG_OUTPUT);
    glDebugMessageCallback(MessageCallback, nullptr);

    std::vector<VertexData> vertices(VERTEX_COUNT / VECTOR_WIDTH);

    vertices[0] = {
        {-0.75f, 0.75f, 0.75f, -0.75f},
        {-0.75f, -0.75f, 0.75f, 0.75f}
    };
    vertices[1] = {
        {-0.50f, 0.50f, 0.50f, -0.50f},
        {-0.50f, -0.50f, 0.50f, 0.50f},
    };
    vertices[2] = {
        {-0.25f, 0.25f, 0.25f, -0.25f},
        {-0.25f, -0.25f, 0.25f, 0.25f},
    };
    vertices[3] = {
        {-0.05f, 0.05f, 0.05f, -0.05f},
        {-0.05f, -0.05f, 0.05f, 0.05f},
    };

    auto vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex_shader, 1, &vertex_shader_source, nullptr);
    glCompileShader(vertex_shader);

    auto fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment_shader, 1, &fragment_shader_source, nullptr);
    glCompileShader(fragment_shader);

    auto program = glCreateProgram();
    glAttachShader(program, vertex_shader);
    glAttachShader(program, fragment_shader);

    const GLuint position_attrib_index = 0;
    glBindAttribLocation(program, position_attrib_index, "vertexPosition");

    glLinkProgram(program);

    //glUseProgram(program);

    glDeleteShader(vertex_shader);
    glDeleteShader(fragment_shader);

    //
    // SSBO
    //
    const GLuint ssbo_binding_point = 0;
    GLuint ssbo{};
    glGenBuffers(1, &ssbo);
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
    //glBufferStorage(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_MAP_WRITE_BIT);
    glBufferData(GL_SHADER_STORAGE_BUFFER, vertices.size() * sizeof(VertexData), vertices.data(), GL_STATIC_DRAW);
    const auto block_index = glGetProgramResourceIndex(program, GL_SHADER_STORAGE_BLOCK, "VertexData");
    glShaderStorageBlockBinding(program, block_index, ssbo_binding_point);
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, ssbo_binding_point, ssbo);
    glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

    //
    // VAO
    //
    //GLuint vao{};
    //glGenVertexArrays(1, &vao);
    //glBindVertexArray(vao);
    //glEnableVertexAttribArray(position_attrib_index);
    //glVertexAttribPointer(position_attrib_index, 2, GL_FLOAT, GL_FALSE, 0, nullptr);

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);
    glClearColor(0.15f, 0.15f, 0.2f, 1.0f);
    glPointSize(10.0f);

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

        glUseProgram(program);
        //glDrawArrays(GL_POINTS, 0, VERTEX_COUNT);

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-07 22:43:47

这是使用您拥有的数据进行抽签的正确方法:

代码语言:javascript
复制
glBindVertexArray(vao);
glDrawArrays(GL_POINTS, 0, VERTEX_COUNT);

但是,您的问题是顶点着色器没有写入gl_Position,因此没有任何东西会被光栅化(无论发生什么未定义的行为)。您应该将着色器中顶点的位置设置为:

代码语言:javascript
复制
//...
out gl_PerVertex {
    vec4 gl_Position;
};
void main()
{
    int dataIx = gl_VertexID / 4;
    int vertexIx = gl_VertexID % 4;
    vec2 vertexPosition = vec2(vertices[dataIx].px[vertexIx], vertices[dataIx].py[vertexIx]);
    gl_Position = vec4(vertexPosition, 0, 1);
}

您可以去掉“分配vertexPosition索引”,并且您的VAO不需要任何属性。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59637006

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档