FreshRSS

Normální zobrazení

Jsou dostupné nové články, klikněte pro obnovení stránky.
PředevčíremHlavní kanál

Is it possible to use a pre-existing texture buffer containing vertex data to initialise a vertex buffer for rendering in OpenGL v4.6?

I'm generating a heightmap in a compute shader in OpenGL v4.6 and storing it to a texture.

Lets say I actually store the full vertex data in that texture instead of just the height, which is a trivial change, and that I could easily also create an index buffer in a separate texture/SSBO at the same time.

Is there a way to use this pre-existing texture/SSBO data to create a vertex and index buffer directly if I made sure the memory layouts were correct?

It seems wasteful to pull the data back from GPU just to copy it to a new vertex array on CPU and then push back to GPU, when I could just get the CPU code to tell the GPU that this data is the vertex array instead and never have the data leave the GPU... But I have no idea how I'd tell OpenGL to map one to the other.

Development:

I've found info about copying buffer data from the one arbitrary buffer type to another, so I've given that a go. It's not as efficient as simply calling the texture buffer a vertex buffer, but this only needs to happen once, so it's a good enough solution. However, I'm getting a black screen...

This is my VAO setup code:


    const size_t num_vertices = _map_terrain_texture_shape.x * _map_terrain_texture_shape.y;
    const size_t total_vertex_position_bytes = num_vertices * sizeof(glm::vec4);
    const size_t total_vertex_colour_bytes = num_vertices * sizeof(glm::vec4);
    const size_t total_vertex_bytes = total_vertex_position_bytes + total_vertex_colour_bytes;

    std::vector<uint32_t> indices = _make_indices(_map_terrain_texture_shape);
    const size_t total_index_bites = indices.size() * sizeof(uint32_t);
    enter code here
    glGenVertexArrays(1, &_vao);
    glGenBuffers(1, &_vbo);
    glGenBuffers(1, &_ebo);

    glBindVertexArray(_vao);

    glBindBuffer(GL_ARRAY_BUFFER, _vbo);
    glBufferData(GL_ARRAY_BUFFER, total_vertex_bytes, nullptr, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, total_index_bites, indices.data(), GL_STATIC_DRAW);

    glEnableVertexAttribArray(VERTEX_POSITION_ATTRIB_INDEX);
    glEnableVertexAttribArray(VERTEX_COLOUR_ATTRIB_INDEX);

    // vertex draw positions
    glVertexAttribPointer(VERTEX_POSITION_ATTRIB_INDEX, glm::vec4::length(), GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void*)0);
    // vertex colours
    glVertexAttribPointer(VERTEX_COLOUR_ATTRIB_INDEX, glm::vec4::length(), GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void*)total_vertex_position_bytes);

    glDisableVertexAttribArray(VERTEX_POSITION_ATTRIB_INDEX);
    glDisableVertexAttribArray(VERTEX_COLOUR_ATTRIB_INDEX);

    glBindVertexArray(0);

And the code running the compute shader that populates the texture buffers (image2Ds) that I copy into vertex buffer looks like this:

    _map_terrain_mesh_shader->use();

    _main_state.terrain_generator->map_terrain_heightmap_texture->bind_for_active_shader(_map_terrain_mesh_shader->id, 0, "i_heightmap_texture");
    _main_state.terrain_generator->map_terrain_vertex_position_texture->bind_for_active_shader(_map_terrain_mesh_shader->id, 1, "o_vertex_position_texture");
    _main_state.terrain_generator->map_terrain_vertex_colour_texture->bind_for_active_shader(_map_terrain_mesh_shader->id, 2, "o_vertex_colour_texture");

    _map_terrain_mesh_shader->dispatch(glm::uvec3{ _map_terrain_texture_shape, 1});

    const size_t num_vertices = _map_terrain_texture_shape.x * _map_terrain_texture_shape.y;
    const size_t total_vertex_position_bytes = num_vertices * sizeof(glm::vec4);
    const size_t total_vertex_colour_bytes = num_vertices * sizeof(glm::vec4);

    const auto position_texture_id = _main_state.terrain_generator->map_terrain_vertex_position_texture->id;
    const auto colour_texture_id = _main_state.terrain_generator->map_terrain_vertex_colour_texture->id;

    glBindBuffer(GL_COPY_WRITE_BUFFER, _vbo);

    glBindBuffer(GL_COPY_READ_BUFFER, position_texture_id);
    glCopyBufferSubData(position_texture_id, _vbo,
                        0, 0,
                        total_vertex_position_bytes);

    glBindBuffer(GL_COPY_READ_BUFFER, colour_texture_id);
    glCopyBufferSubData(colour_texture_id, _vbo,
                        0, total_vertex_position_bytes,
                        total_vertex_colour_bytes);

    glBindBuffer(GL_COPY_READ_BUFFER, 0);
    glBindBuffer(GL_COPY_WRITE_BUFFER, 0);

I have checked that this compute shader produces the correct results by using these buffers in a raytracing renderer I already had setup. That is now using this data instead of the original heightmap data.

I've gone for vec4 for each just to be sure I don't run into packing issues or whatever while I get it working, and I'm purposely not interlacing the position/colour data. I'm keeping it as a block of each.

Now assuming my compute shader is doing it's job correctly, can anyone tell me if I'm doing this right?

❌
❌