In Minecraft when you look at water the deeper you view the darker it gets. Does anyone know how to code something like that?
Minecraft with effect

similar game without effect

|
In Minecraft when you look at water the deeper you view the darker it gets. Does anyone know how to code something like that? Minecraft with effect
similar game without effect
|
|||||||||||||||
|
|
There are essentially two different approaches for lighting water based on depth: Voxel-LightingMinecraft uses voxel-based lighting, wich works by propagating light to adjacent cubes, lowering the brightness depending on the block type. Dark oceans are a side effect of this system. Water blocks sunlight and reduces the light by 3 levels per block (instead of the default 1 level), wich means the brightness in an ocean for each distance from the surface is:
Source: Minecraft Wiki - Light Distance-Based ShadowingIn games with a traditional lighting model, this effect can be created by measuring the amount of water that is between the light source and the ocean floor. The light is then faded based on this distance. There are a few methods for doing this: Direct CalculationIf you have a flat surface, you can easily calculate the distance the light travels in the water if you pass the surface normal away from body of water The effective water distance is
where At sunset, If you're using a heightmap on a surface parallel to the water, With a fixed water level or a fixed light direction, parts of the equation are constant and shouldn't be calculated in the shader for performance reasons. Pros:
Cons:
Shadow MappingIf you render the water surface to a separate depth map (as seen from the light source), you can use that depth texture to calculate the distance the light travels in the water before hitting the surface. If the surface is relatively flat, you should use a refracted light origin for better results. Pros:
Cons:
*You can determine the amount of water in front of the nearest solid surface by counting the depth from the light's POV as follows:
The result texture now contains the amount of water in front of the light in light-view-space, so the value must be transformed back before you use it. This method works to calculate the directional light (minus refraction), but will lead to incorrect ambient light if the surfaces are very irregular and there's a large amount of air between to bodies of water affecting the same fragments. Ray-TracingRay tracing is by far the most accurate but also the most expensive solution for rendering transparent volumes. There are two ways of doing this: 1. Tracing from the ocean floor towards the surface and 2. Tracing from the light source towards the water. Multiple rays are needed for each point on the floor to calculate the brightness. Pros:
Cons:
Additional effectsThere are a few more things to take into account when rendering water: FogLight in water is scattered again while travelling to the observer, so you should blend it towards a solid color. If the observer is submerged, you can just render fog based on the final result of the depth buffer. The fog color, but not its density should change with the observer's distance from the surface! (Minecraft only uses this part of the effect.) If the observer looks at the water from above, you need to calculate the fog based on the depth difference between the surface and the geometry under water. The fog colour should get slightly darker with larger depth differences, but should only change to the point where the fog is fully opaque. The fog colour should also depend on the view direction for each pixel, so it's slightly darker when looking down in both cases. Faking CausticsIf you use a seamless tiling 3D-Texture instead of a decal for fake caustics, you can avoid stretching on vertical surfaces. The strength of scattered light near the surface varies in three dimensions, so using a 2D-Texture usually produces stretching somewhere in the scene. You can model changing light angles by projecting the vertex positions of the floor into a different coordinate system. Another possibility is to calculate the light density based on the surface position in the light's coordinate system, although that would most likely cost some performance. The caustics should fade faster than the diffuse light with increasing depth. Colour GradientColours are scattered differently, so the light colour should change with increasing depth. This also prevents abrupt edges where, for example, a beach intersects the water surface. Angle of IncidenceBecause of refraction, the light hits the ocean floor much steeper than it normally would. The Wikipedia article about Snell's law has formulae for angles and vectors. |
||||
|
|
|
I believe that the sky lighting effect in Minecraft is straight down - things get shaded by what is above them no matter where the sun is. Then local lighting from torches, etc. is applied with a dropoff effect - the farther away from the light source, the less light a cube gets. If done this way, each layer of water would cumulatively shadow the layer below it, so each becomes progressively darker. Tree foliage provides shade like this, however it is not cumulative. You get the same shade under a tree whether it's 1 or 100 foliage cubes. One clue that this is the method being used is that water doesn't get darker when farther away from the viewer - only as you go down. Yes, the fog effect does kick in at distance, but not the water dark effect. So the basic formula for calculating lighting would be something like this in pseudo-code...
This isn't perfect for calculating lighting under overhangs or in caves, as it would be pitch dark under an overhang using this method. But one could add in both local light sources (torches, fires, etc.) as well as treating sun lit blocks as light sources. Something like this might do it...
The idea here is that if a cube is lit by the sun or a torch, the cube next to it is going to also be lit in some way. And the farther away you are from that lit cube, the less light there will be. It's sort of a kludge way to estimate diffuse lighting but I think (?) it would work. |
|||||||||
|
|
Perhaps I'm misunderstanding the question, but why can't you just change the colour of the blocks depending on their depth? If you have the depth d (in blocks, starting at 0) then a reasonable equation for brightness would be: L = (1-m) e-kd+ m Code: k controls how fast it gets darker (higher = faster). A reasonable value would be 0.5. If you don't know how to change the colour of the blocks in whatever graphics API you are using then please ask that as a separate question (stating what API you use, and whether or not you are using shaders). |
|||||||||||||
|