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?