I have raycasting code for emitting rays from every visible voxel and shade it a different darkness, with falloff applied for distance. This is all done on the CPU for now but I would like to use the GPU if possible. Here is a visual example of the ray casting stepped in cubes.
The code still has the limitation of not being able to check voxels of neighbor chunks, but the falloff of shade is so great you'd hardly notice these inconsistencies unless you look straight up at the bottom of an overhang (such as under a tree). I want to correct that later.
Also, some normal-based ambient lighting! It is simple but can have a drastic effect on the image. Each side of the cube can be lit with a different ambient color, so it is like sampling indirect lighting from a sky box texture but much simpler since cubes have only 6 sides. This Wolfire article gives a simple explanation of how it works. It looks much better than having the same dull gray color on all sides. Diffuse colors are also gamma corrected on the shader.
Here is a scene showing just the ambient lighting added to the regular shading from the normals:
And the same scene with the diffuse color multiplied:
Colors pop out a lot more now, everything looks more vivid which is the look I am going for. The ambient colors are hardcoded for now, but will be dynamic when I get a day/night system going. Colors are still too bright, but that was fixed. The lighting was adjusted some more.
Also you may notice that the trees are a bit more complex in shape, at least with the leaves. I generate the "boughs" in random sizes from the center, going in a fixed radial pattern. Each tree can have from 4 to 7 of them. This makes better looking trees than just randomly positioning them from the center, which made some trees look very unbalanced.
Shader code is also refined and the vertex data as well. Up until yesterday, all the chunk meshes are rendered with the absolute positions sent to the shader. Now I just send the local positions and transform with a matrix. To be honest, I peeked at the graphics in Cube World for an idea on how it does things, using PIX. Its approach is interesting, because none of the vertices in view exceeded absolute values of 300 in world coordinates, after the vertex shader is applied. It seems that not only does it just use local coordinates but also makes the world "scroll" around the character so as to keep everything near the origin.
Since the cubes are all located in integer coordinates and chunks are all 32 units in size I was able to greatly reduce the number of vertex data to pass to the shader. Each coordinate is now stored in a Byte4 instead of a Vector3, as was the color and normal information. This reduces the vertex size to a svelte 8 bytes. The fourth byte, usually the w component, can be used to store additional information such as AO shading, and possibly material properties that affect how it reflects color. So now the AO is added to the color in the shader instead of "baked in" the vertex. This makes lighting much more flexible to change.
First Collision Detection
Another important step forward in the engine is built-in collision detection. So far all I have to show for it is keeping the camera above the surface of the ground. A bounding box is made around the camera, the code compares the position of the box in the world to get the nearby blocks and checks if any of them is solid for a collision. See, just like 2D tile collision. The collision response is crude- it just moves the camera one unit up when the box collides with the ground. Later on I will add intersection functions to test the depth of intersection, needed to do some meaningful physics with characters and other objects.
The way I get the blocks from the world is kind of crazy. It is a function that actually re-generates all the procedural data required to find out what type of block is in a specific location. For now that just means getting the height value from the noise functions at a particular location, but I'll add in somehow to check if other objects are being built that will occupy that block so that the camera can collide with the trees as well. The reason it's done this way is to save time (for now) but also because when chunks are generated, all the block/voxel data stored in the cache falls out of scope after the mesh is made, and is replaced with the data from the next chunk. The chunk objects are mostly left with just the index and vertex buffers to render it.
This way of getting the blocks is actually very quick because the bounding box doesn't intersect with a lot of them. I'm curious at how well it will work with many moving things on the screen, especially ones almost as big as trees. Fortunately my game will not feature a lot of block creation or destruction, so that helps as well. Eventually, though, I want to store another cache for the nearby block data.
Later on, I'll start work on the Player class, its collision detection, and also code a camera that can be moved around the player for easy navigation.