0
\$\begingroup\$

I am working on a voxel game, and I approached the point where I need to add day/night in my world. Apparently, I should just be able to pass the torch and sunlight values into my shader and multiply the sunlight variable by the amount of sunlight I have.

I have no idea how to do this. 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?

  • How would I know what voxel data is seen by the shader, and what data is not?
  • Most importantly: how does each fragment know what voxel corresponds to it when the shader only has a knowledge of its 2D placement on the screen?
\$\endgroup\$
1
  • \$\begingroup\$ Fragments "know" what you tell them. If you want them to know their position in world space, from which you can look up the corresponding voxel, take that information in the vertex shader (which needs it to put the triangle at the right place on the screen anyway), and pass it through an interpolated attribute for the fragment shader to receive and use. \$\endgroup\$
    – DMGregory
    Sep 27, 2022 at 17:28

1 Answer 1

1
\$\begingroup\$

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:

  1. 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).
  2. 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.
  3. 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.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .