Class Light


  • public class Light
    extends Object
    Adds light to a scene which allows shading the Geometry's colors according to the angle between the light and the Geometry, which is required to perceive the volume of an object. You do not instantiate a light but rather invoke Chart.addLight(Coord3d) or Chart.addLightOnCamera() which return a light instance. A chart can deal with up to 8 lights, which can be switched on or off with :
     Light light = chart.getScene().getLightSet().get(0); // light ID in [0;7]
     light.setEnabled(false);
     

    The important thing to do is to allow a drawable to reflect light, which requires to compute its normals. This is achieved by Geometry.setReflectLight(boolean), which is false by default to avoid processing normals for the majority of chart that do not require lighting.

    Then you can tune both the light colors and the drawable reflection colors. The below documentation are taken from the GL Red Book documentation and a great website for learning OpenGL (see references below).

    Light effect on coloring

    Light settings

    • Ambient illumination is light that's been scattered so much by the environment that its direction is impossible to determine - it seems to come from all directions. Backlighting in a room has a large ambient component, since most of the light that reaches your eye has first bounced off many surfaces. A spotlight outdoors has a tiny ambient component; most of the light travels in the same direction, and since you're outdoors, very little of the light reaches your eye after bouncing off other objects. When ambient light strikes a surface, it's scattered equally in all directions.
    • The diffuse component is the light that comes from one direction, so it's brighter if it comes squarely down on a surface than if it barely glances off the surface. Once it hits a surface, however, it's scattered equally in all directions, so it appears equally bright, no matter where the eye is located. Any light coming from a particular position or direction probably has a diffuse component.
    • Finally, specular light comes from a particular direction, and it tends to bounce off the surface in a preferred direction. A well-collimated laser beam bouncing off a high-quality mirror produces almost 100 percent specular reflection. Shiny metal or plastic has a high specular component, and chalk or carpet has almost none. You can think of specularity as shininess.
    Although a light source delivers a single distribution of frequencies, the ambient, diffuse, and specular components might be different. For example, if you have a white light in a room with red walls, the scattered light tends to be red, although the light directly striking objects is white. OpenGL allows you to set the red, green, and blue values for each component of light independently.

    Object material settings

    The OpenGL lighting model makes the approximation that a material's color depends on the percentages of the incoming red, green, and blue light it reflects. For example, a perfectly red ball reflects all the incoming red light and absorbs all the green and blue light that strikes it. If you view such a ball in white light (composed of equal amounts of red, green, and blue light), all the red is reflected, and you see a red ball. If the ball is viewed in pure red light, it also appears to be red. If, however, the red ball is viewed in pure green light, it appears black (all the green is absorbed, and there's no incoming red, so no light is reflected).

    Like lights, materials have different ambient, diffuse, and specular colors, which determine the ambient, diffuse, and specular reflectances of the material. A material's ambient reflectance is combined with the ambient component of each incoming light source, the diffuse reflectance with the light's diffuse component, and similarly for the specular reflectance and component. Ambient and diffuse reflectances define the color of the material and are typically similar if not identical. Specular reflectance is usually white or gray, so that specular highlights end up being the color of the light source's specular intensity. If you think of a white light shining on a shiny red plastic sphere, most of the sphere appears red, but the shiny highlight is white.

    In addition to ambient, diffuse, and specular colors, materials have an emissive color, which simulates light originating from an object. In the OpenGL lighting model, the emissive color of a surface adds intensity to the object, but is unaffected by any light sources. Also, the emissive color does not introduce any additional light into the overall scene.

    RGB Values for Lights and Materials

    The color components specified for lights mean something different than for materials. For a light, the numbers correspond to a percentage of full intensity for each color. If the R, G, and B values for a light's color are all 1.0, the light is the brightest possible white. If the values are 0.5, the color is still white, but only at half intensity, so it appears gray. If R=G=1 and B=0 (full red and green with no blue), the light appears yellow.

    For materials, the numbers correspond to the reflected proportions of those colors. So if R=1, G=0.5, and B=0 for a material, that material reflects all the incoming red light, half the incoming green, and none of the incoming blue light. In other words, if an OpenGL light has components (LR, LG, LB), and a material has corresponding components (MR, MG, MB), then, ignoring all other reflectivity effects, the light that arrives at the eye is given by (LR*MR, LG*MG, LB*MB).

    Similarly, if you have two lights that send (R1, G1, B1) and (R2, G2, B2) to the eye, OpenGL adds the components, giving (R1+R2, G1+G2, B1+B2). If any of the sums are greater than 1 (corresponding to a color brighter than the equipment can display), the component is clamped to 1.

    Light type

    As previously mentioned, you can choose whether to have a light source that's treated as though it's located infinitely far away from the scene or one that's nearer to the scene. The first type is referred to as a directional light source; the effect of an infinite location is that the rays of light can be considered parallel by the time they reach an object. An example of a real-world directional light source is the sun. The second type is called a positional light source, since its exact position within the scene determines the effect it has on a scene and, specifically, the direction from which the light rays come. A desk lamp is an example of a positional light source. To switch type, simply invoke :
     
     light.setType(Type.DIRECTIONAL);
     
     
    Note: Remember that the colors across the face of a smooth-shaded polygon are determined by the colors calculated for the vertices. Because of this, you probably want to avoid using large polygons with local lights. If you locate the light near the middle of the polygon, the vertices might be too far away to receive much light, and the whole polygon will look darker than you intended. To avoid this problem, break up the large polygon into smaller ones.

    Light attenuation

    For real-world lights, the intensity of light decreases as distance from the light increases. Since a directional light is infinitely far away, it doesn't make sense to attenuate its intensity over distance, so attenuation is disabled for a directional light. However, you might want to attenuate the light from a positional light. OpenGL attenuates a light source by multiplying the contribution of that source by an attenuation factor:

    where
    • d = distance between the light's position and the vertex
    • kc = GL_CONSTANT_ATTENUATION
    • kl = GL_LINEAR_ATTENUATION
    • kq = GL_QUADRATIC_ATTENUATION
    By default in OpenGL, kc is 1.0 and both kl and kq are zero, but you can give these parameters different values:
     
     glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0); 
     glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0); 
     glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5); 
     
     
    By default in Jzy3D, no attenuation is defined for a light. To specify an attenuation, simply call
     
     Attenuation attenuation = new Attenuation();
     attenuation.setConstant(1);
     attenuation.setLinear(1);
     attenuation.setQuadratic(1);
     
     Light light = new Light();
     light.setAttenuation(attenuation);
     
     
    Note that the ambient, diffuse, and specular contributions are all attenuated. Only the emission and global ambient values aren't attenuated. Also note that since attenuation requires an additional division (and possibly more math) for each calculated color, using attenuated lights may slow down application performance.

    Light Model

    The OpenGL notion of a lighting model has three components:
    • The global ambient light intensity
    • Whether the viewpoint position is local to the scene or whether it should be considered to be an infinite distance away
    • Whether lighting calculations should be performed differently for both the front and back faces of objects

    Global Ambient Light

    Each light source can contribute ambient light to a scene. In addition, there can be other ambient light that's not from any particular source. To specify the RGBA intensity of such global ambient light, use the GL_LIGHT_MODEL_AMBIENT parameter as follows:
     
     float[] ambiant = { 0.2f, 0.2f, 0.2f, 1.0f }; 
     painter.glLightModel(LightModel.LIGHT_MODEL_AMBIENT, ambiant);
     
     
    In this example, the values used for lmodel_ambient are the default values for GL_LIGHT_MODEL_AMBIENT. Since these numbers yield a small amount of white ambient light, even if you don't add a specific light source to your scene, you can still see the objects in the scene. "Plate 14" in Appendix I shows the effect of different amounts of global ambient light.

    Local or Infinite Viewpoint

    The location of the viewpoint affects the calculations for highlights produced by specular reflectance. More specifically, the intensity of the highlight at a particular vertex depends on the normal at that vertex, the direction from the vertex to the light source, and the direction from the vertex to the viewpoint. Keep in mind that the viewpoint isn't actually being moved by calls to lighting commands (you need to change the projection transformation, as described in "Projection Transformations" in Chapter 3); instead, different assumptions are made for the lighting calculations as if the viewpoint were moved. With an infinite viewpoint, the direction between it and any vertex in the scene remains constant. A local viewpoint tends to yield more realistic results, but since the direction has to be calculated for each vertex, overall performance is decreased with a local viewpoint. By default, an infinite viewpoint is assumed. Here's how to change to a local viewpoint:
     
     painter.glLightModel(LightModel.LIGHT_MODEL_LOCAL_VIEWER, true);
     
     
    This call places the viewpoint at (0, 0, 0) in eye coordinates. To switch back to an infinite viewpoint, pass in false as the argument.

    Two-sided Lighting

    Lighting calculations are performed for all polygons, whether they're front-facing or back-facing. Since you usually set up lighting conditions with the front-facing polygons in mind, however, the back-facing ones typically aren't correctly illuminated. In Example 5-1 where the object is a sphere, only the front faces are ever seen, since they're the ones on the outside of the sphere. So, in this case, it doesn't matter what the back-facing polygons look like. If the sphere is going to be cut away so that its inside surface will be visible, however, you might want to have the inside surface be fully lit according to the lighting conditions you've defined; you might also want to supply a different material description for the back faces. When you turn on two-sided lighting with
     
     painter.glLightModel(LightModel.LIGHT_MODEL_TWO_SIDE, true);
     
     
    OpenGL reverses the surface normals for back-facing polygons; typically, this means that the surface normals of visible back- and front-facing polygons face the viewer, rather than pointing away. As a result, all polygons are illuminated correctly. However, these additional operations usually make two-sided lighting perform more slowly than the default one-sided lighting. To turn two-sided lighting off, pass in false as the argument in the preceding call. (See "Defining Material Properties" for information about how to supply material properties for both faces.) You can also control which faces OpenGL considers to be front-facing with the command glFrontFace(). (See "Reversing and Culling Polygon Faces" in Chapter 2 for more information.)
    Author:
    Martin Pernollet
    See Also:
    OpenGL Red book chapter about lighting which was copied to make this javadoc closest to the OpenGL documentation.
    • Field Detail

      • DEFAULT_COLOR

        public static final Color DEFAULT_COLOR
      • lightId

        protected int lightId
      • enabled

        protected boolean enabled
      • ambiantColor

        protected Color ambiantColor
      • diffuseColor

        protected Color diffuseColor
      • specularColor

        protected Color specularColor
      • position

        protected Coord3d position
      • glPositionAndType

        protected float[] glPositionAndType
      • representationDisplayed

        protected boolean representationDisplayed
      • representationRadius

        protected float representationRadius
      • representationColor

        protected Color representationColor
      • lightCount

        protected static int lightCount
    • Constructor Detail

      • Light

        public Light()
      • Light

        public Light​(int id)
      • Light

        public Light​(int id,
                     boolean representationDisplayed)
      • Light

        public Light​(int id,
                     boolean enabled,
                     boolean representationDisplayed)
    • Method Detail

      • resetCounter

        public static void resetCounter()
      • configureLight

        protected void configureLight​(IPainter painter,
                                      int lightId)
      • setRepresentationDisplayed

        public void setRepresentationDisplayed​(boolean status)
        Indicates if a square is drawn to show the light position.
      • getRepresentationDisplayed

        public boolean getRepresentationDisplayed()
      • getRepresentationRadius

        public float getRepresentationRadius()
      • setRepresentationRadius

        public void setRepresentationRadius​(float representationRadius)
      • getId

        public int getId()
      • setPosition

        public void setPosition​(Coord3d position)
      • getPosition

        public Coord3d getPosition()
      • isEnabled

        public boolean isEnabled()
      • setEnabled

        public void setEnabled​(boolean enabled)
      • getAmbiantColor

        public Color getAmbiantColor()
      • setAmbiantColor

        public void setAmbiantColor​(Color ambiantColor)
      • getDiffuseColor

        public Color getDiffuseColor()
      • setDiffuseColor

        public void setDiffuseColor​(Color diffuseColor)
      • getSpecularColor

        public Color getSpecularColor()
      • setSpecularColor

        public void setSpecularColor​(Color specularColor)
      • setType

        public void setType​(Light.Type type)
      • setAttenuation

        public void setAttenuation​(Attenuation attenuation)