8
\$\begingroup\$

How does one handle shading in a 3D game?

I have a directional light source that shades one side of a tree made of cubes. The remaining 3 sides all get ambient shading only. So the 3D effect is lost when looking at two ambient shaded sides.

Am I missing something? Should I be shading the side furthest from the light source even darker? I tried looking at Fallout 3 and it kind of looks like this is what they do, however Minecraft appears to shade a grass mound with two opposite sides light and the remaining two opposite sides dark, giving the effect that there are two directional lights for the two light shaded sides and ambient light for the dark shaded sides.

\$\endgroup\$

4 Answers 4

10
\$\begingroup\$

Many effects use a standard lighting rig which uses 3 lights similar to how a movie company would film a movie.

Here is a wiki link: http://en.wikipedia.org/wiki/Three-point_lighting

here is an XNA specific blog about it (concepts can be applied to OpenGL too): Link

\$\endgroup\$
5
\$\begingroup\$

Your problem is that your ambient light is a constant color. In reality ambient light tends to be bright from the top and dark from the bottom, because light typically comes from above.

There is much you can do to fix this. At the very least, you should have a "top ambient color", "bottom ambient color", and "top ambient direction" vertex shader constants.

In your vertex shader, take the dot product of the "top ambient direction" and the vertex normal, and use the result to lerp between the "top ambient color" and "bottom ambient color:"

float value = dot( vertex_normal, top_ambient_direction ) * 0.5 + 0.5;
ambient_color = lerp( bottom_ambient_color, top_ambient_color, value );

That is one of the simpler ways to make ambient look better, and was used often in PS2 and XBOX1 games. Contemporary games go further by using an "ambient cubemap" or "ambient spherical harmonic coefficients."

\$\endgroup\$
3
\$\begingroup\$

This is a complex topic, and I'm barely qualified to talk about it, but I'll give it a shot. Many games use a pre-baked light map that takes into account light bouncing off of multiple surfaces, then combine that with dynamic lighting to produce a fast, realistic, and good-looking environment. There are probably modern games that do light bouncing in real-time.

Something to keep in mind is that light attenuates with distance; if your lamp is at an angle to a surface, the closer edge will be brighter than the farther edge. Things tend to look very fake if a lamp is shining on them straight-on rather than at an angle.

Minecraft's lighting is special, because it uses a weird system where light is treated almost like heat diffusing through the world: http://www.minecraftwiki.net/wiki/Light It's not easily extended to a general-purpose solution.

The most cool-looking effect I've seen used is called ambient occlusion. It's expensive, and is usually only used in a pre-baked solution, but it takes into account how corners of the room are darker because the walls occlude the ambient light; the middle of the wall has a hemisphere's worth of light hitting it, while the corner where three surfaces meet has only a hemidemisemisphere's (1/8 sphere's) worth of light. https://secure.wikimedia.org/wikipedia/en/wiki/Ambient_occlusion

There's tons and tons of writing out there on lighting systems; searching around will probably serve you well.

\$\endgroup\$
0
\$\begingroup\$

Lighting/shading needs to be more advanced than just a binary decision. Blocks are not either lit or unlit completely by a light, they can be partially lit. Sometimes the face should be totally shiny, in which case it is being hit directly by the light. Sometimes you only want the ambient light, if it is completely untouched by the light. However, when it is partially obscured, you need to give it a light value between fully lit and fully unlit.

The standard basic lighting method shifts from zero light to maximum light based on the difference in angle between the incoming light ray and the surface normal of the face you are lighting.

If the normal of the surface is equal (or opposite, depending upon how you're looking at it) then you have maximum brightness. As the angle between the incoming light and the surface normal increases, you get less and less light on that face from that light.

This way, with two lights, each face should receive a brightness that is a combination of how much brightness each light puts on each face based on its angle.

This should be much more natural than trying to determine if a single face is lit or not. You'll have a natural gradient as surfaces get further away from the light, and you'll get balancing for surfaces effected by more than one light.

\$\endgroup\$

You must log in to answer this question.

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