Trying to keep questions and answers simpler, I will reduce my problem from 3d to 2d.
I have a 2d grid with X*Y cells in 2d space. It is defined simply by X, Y, bBoxMin2d and bBoxMax2d.
On the GPU (currently in a VBO), I have X*Y (unsigned 8 bit) integers, which define the brightness of the cells. So, for X=Y=3, if the VBO contains {4, 7, 3, 2, 9, 4, 7, 2, 1}, the grid should be rendered using patches of the following brightness:
4 7 3
2 9 4
7 2 1
I know I could create another VBO containing the world-position of the center of each cell and use the geometry shader to create a patch to be passed on to the fragment shader.
However, I want to be more efficient and do without a second VBO. My thinking is that if every instance of the geometry shader had its own thread index (similar to CUDA), it could create the cell’s patch using only that index, and bBoxMin2d and bBoxMax2d from e.g. a UBO. The fragment shader would then read the color from the VBO and I’d be happy.
But it seems there is no geometry-shader thread-index. So, how can I solve my problem?
Please don’t tell me to use another VBO with the positions – that would increase memory requirements from sizeof(uint8_t) = 1 byte per cell to at least sizeof(float3) + sizeof(uint8_t) = 13 bytes. And I have lots of cells 😐
OK, let’s deal with the Elephant in the Room. You have a large grid of 3D cells that you’re rendering. You’re making a Minecraft clone; it’s best to be up-front about this.
What you’re trying to do will in no way be efficient. Using a geometry shader to generate squares/cubes from a single number and
gl_PrimitiveIDInis not an efficient way to render a bunch of cubes. The efficient way to do so is to do what Minecraft does: creates buffer object(s) containing the visible terrain and render that. This will take up more memory, but you’ll be a lot more likely to get reasonable performance out of rendering “lots of cells”.If you want to know how to make your current method work, presumably (I have to presume because you didn’t say), your GS takes as its input
pointsand converts this into severaltriangle_stripoutputs. So each vertex input becomes an output quad/cube.This is simple to deal with: use
gl_PrimitiveIDIn. Because you’re taking points as input, the primitive count is the same as the vertex count. So if you have a space of 3×3, andgl_PrimitiveIDInis 4, you know that you’re in the (1, 1) part of that space:That’s the XY index where you are in your abstract space. Note that
spaceshould be anivec2uniform variable somewhere, which defines the number of indices in X and Y you have. The 3D version is slightly more complex, but also doable.Once you have your abstract space index, you can compute vertex positions based on that. I’ll assume you know how to do that.