The proper lighting of a scene is one of the most important yet under-utilized techniques for adding a sense of immersion and realism in a 3D scene. A single directional light source exerts a powerful influence over wayfinding (navigation) in animals and should be incorporated into any virtual environment in which navigation is critical.
A great deal of current research in 3D graphics is centered around developing new lighting algorithms. The entire research enterprise is mathematically intense and relies on a knowledge of physics. However, proper use of lighting can be learned by getting a basic understanding of the basic forms of lighting and then doing experimentation to get the desired effect.
Only a reduced lighting model is currently practical for use with interactive graphics anyway. These limitations will be discussed shortly. For now, consider that Java 3D supports four fundamental lighting types (listed in Table 11.7).
All these classes are subclasses of the common parent Light. Light serves as a node to contain parameters that are common to all four of these subclasses (and others that can be created through extension). The common parameters shared by all light in Java 3D are color, enable/disable, region of influence, and scope.
Java 3D's lighting model is based on three key vector values pointing from a vertex on the object and pointing to 1) the viewer's eye, 2) back in the direction of the light, and 3) along the surface normal. These three vectors provide an important subset of the information necessary to render object shadings in Java 3D.
Three basic reflections are calculated in Java 3D: ambient, diffuse, and specular. Refer to Chapter 10 for a description of these from a more general computer graphics standpoint.
Beginning to use lighting in Java 3D presents some potential pitfalls that you must be cautious to avoid. These pitfalls are related to not having the appropriate objects in the scene in order to see the effects of lighting.
First and foremost, you must remember that without objects in a scene, you cannot see a light. Lights are only visible when they interact with 3D surfaces.
The second prerequisite for implementing lighting effects is that all objects to be shaded must have surface normals and material properties.
Because an ambient light source projects light uniformly throughout the environment, it is impossible to determine the origin of the source. For this reason, the AmbientLight node is the simplest light to use because you don't have to specify the direction of light. To create an instance of an AmbientLight, use on the following three constructors:
public AmbientLight() public AmbientLight(Color3f color) public AmbientLight(Boolean lighton, Color3f color)
It is possible to change the color of the light or turn it on or off using setColor() and setEnable(). Note that as with many other scene elements, it is necessary to set the proper capability bits in order to make post-instantiation changes to lights.
As mentioned previously, one of the strongest spatial cues that is used by animals for navigation is the perception of a directional light. Given that Virtual Reality is a perceptually degraded form of navigation, it is highly recommended that at least one directional light be placed in any environment.
Instantiating a DirectionalLight is similar to instantiating an AmbientLight with one additional step. When specifying a DirectionalLight, it is necessary to add a directional vector indicating the source and target locations of the light.
Vector3f light = new Vector3f(3.f, 3.f, 3.f);
A PointLight is basically like a light bulb in the real world; it radiates in all directions and attenuates with distance from the source. In Java 3D, the programmer must specify the attenuation through three parameters that contribute to the calculation of the falloff from the PointLight. The attenuation parameters can be set dynamically (given that the programmer has set the proper capability bits) or specified at the time of instantiation using the following constructors:
public PointLight() public PointLight(Boolean lightOn, Color3f color, Point3f position, Point3f attenuation) public PointLight(Color3f color, Point3f position, Point3f attenuation)
To set the attenuation during runtime, use the setAttenuation() method.
Note that the attenuation is specified as a Point3f in which the three coordinates represent color, linear, and quadratic attenuation parameters, respectively.
A SpotLight is similar to a DirectionalLight except that it radiates from a point inside a cone. The diameter of the cone can be specified in order to control whether the light is wide or narrow. In addition, the programmer can set the focus from sharp to soft in a range of 128.f to 0.f. Instantiation is the same as for a PointLight with two additional parameters for controlling the spread and focus of the light. Use the following constructors to create a SpotLight:
SpotLight() SpotLight(Boolean lightOn, Color3f color, Point3f position, Point3f attenutation, Vector3f direction, float spreadAngle, float concentration) SpotLight(Color3f color, Point3f position, Point3f attenutation, Vector3f direction, float spreadAngle, float concentration);
It is possible to specify a scope (in terms of the scene graph) to use for lights. The scope, in this case, refers a list of Group nodes (called the scope list) that are influenced by a light. If the scope list is empty or not specified, the scope covers the entire universe. Otherwise, only those Leaf nodes that belong to the Groups in the scope list are influenced by the scoped light.
One sometimes confusing aspect of using influencing bounds is that there are two choices for specifying bounds that reflect subtle differences in how the lights are applied to the scene. The more commonly used bounds is for applying the light over the entire scene and works in light centered coordinates (that is, when the light moves, so do the bounds).
The BoundingLeaf doesn't move with the light. To move the influencing bounds, you must move the BoundingLeaf.
Listing 11.13 shows an example of two DirectionalLights with one of the lights attached to a TransformGroup and rotation Behavior. In Figure 11.10, by rotating the red light with the MouseRotate Behavior, the user can observe the different effects of mixing and influence with the static blue light.