I know you can only pass the same variables for all vertex/fragments, but how can you pass an entire array of voxel data into a shader?
Here's some methods I can think of:
- As part of the vertices. This means you have to rewrite the vertices whenever the block lighting changes (but time of day can be handled by a uniform, via the multiplication you mentioned).
- In a 3D texture that stores the light value in a texel for each. This requires storing a lot of invisible data, but it is cheap per block.
- In a buffer, organized in whatever format you like. (In OpenGL I believe it would be a “SSBO” specifically, but I haven't used that myself.) For example, you could assign a unique number to each currently visible block surface, put that number in the vertices, and use it as an index to look up the light for that surface in an array stored in the buffer. That would store data efficiently in memory but require lots of bookkeeping.
I've personally used option 2 with some success, but I haven't tried option 3. Option 1 requires lots of mesh updates and isn't good for “smooth” lighting.
All three of these options are, in some way, providing the data as some kind of large array to the shader. Such things are always some kind of explicitly-created GPU object separate from simple
glUniforms, which you will have to update as the world is modified.
does each fragment know what voxel corresponds to it when the shader only has a knowledge of its 2D placement on the screen?
You can pass any information you want from the vertex shader to the fragment shader. That can be the 3-dimensional voxel position, or it could be the light data already fetched from wherever you stored it.
In my implementation I pass voxel coordinates from the vertex shader to the fragment shader, and have the fragment shader look up the values in the light data texture.