/* Copyright 2006 by Sean Luke and George Mason University Licensed under the Academic Free License version 3.0 See the file "LICENSE" for more information */ package sim.portrayal3d.simple; import sim.portrayal3d.*; import javax.media.j3d.*; import javax.vecmath.*; import sim.util.*; import java.awt.*; /** A simple Portrayal3D which provides ambient, directional, or point light to the scene. While this could be used in a FieldPortrayal to represent its objects, it's more likely to be dropped directly into the Display3D itself. Your light can be any color, and it will have infinite bounds -- it irradiates everything regardless of where it is -- meaning there's no such thing as a shadow. LightPortrayals aren't selectable: how can you catch a moonbeam in your hand? <ul> <li><b>Ambient Light</b> is light which seems to come from all around and has no direct source. <li><b>Directional Light</b> comes from a point light source located infinitely far away. Thus there is a <i>direction</i> in which the light is shining. The classic example: sunlight. <li><b>Point Light</b> comes from a point light source located at a finite position (like a light bulb). If you place a point light source in a field portrayal, the position you'd specified here will get scaled and translated just like any other object. Point light also has an <i>attenuation</i> -- a degree to which its strength drops off. The attenuation is calculated as an equation on the distance <i>d</i> that the object is from the light source: q^2 * d + l * d + c, where q is the <i>quadratic attenuation</i>, l is the <i>linear attenuation</i> and c is the <i>constant attenuation</i>. A good default is c=1,l=0,q=0. </ul> <p>In fact, the default objects provided in the simulator (such as SpherePortrayal3D) don't respond to light at all -- they just display themselves with their given color as if there were a magical light source. To get them to respond in a different fashion, you'll need to provide them with a different Appearance object, and set that Appearance's ColoringAttributes and Material. Here's an example which makes a green sphere that's harshly lit only on the side where it receives light, else it's jet black. <tt><pre> <i>import javax.media.j3d.*; import javax.vecmath.*;</i> Color3f color = new Color3f(Color.green); Appearance appearance = new Appearance(); appearance.setColoringAttributes( new ColoringAttributes(color, ColoringAttributes.SHADE_GOURAUD)); Material m= new Material(); m.setAmbientColor(color); m.setEmissiveColor(0f,0f,0f); m.setDiffuseColor(color); m.setSpecularColor(1f,1f,1f); m.setShininess(128f); appearance.setMaterial(m); SpherePortrayal3D sphere = new SpherePortrayal3D(appearance, 1.0f); </pre></tt> */ public class LightPortrayal3D extends SimplePortrayal3D { Light light; Vector3f double3DToVector3f(Double3D d) { Vector3f v = new Vector3f(); v.x = (float)d.x; v.y = (float)d.y; v.z = (float)d.z; return v; } /** Directional Light */ public LightPortrayal3D(Color color, Double3D direction) { light = new DirectionalLight(new Color3f(color),double3DToVector3f(direction)); light.setInfluencingBounds(new BoundingSphere(new Point3d(0,0,0), Double.POSITIVE_INFINITY)); } /** Ambient Light */ public LightPortrayal3D(Color color) { light = new AmbientLight(new Color3f(color)); light.setInfluencingBounds(new BoundingSphere(new Point3d(0,0,0), Double.POSITIVE_INFINITY)); } /** Point Light. If you don't know what to provide for attenutation, you can't go wrong with 1,0,0. */ public LightPortrayal3D(Color color, Double3D position, float constantAttenuation, float linearAttenuation, float quadraticAttenuation) { PointLight p = new PointLight(); p.setAttenuation(constantAttenuation, linearAttenuation, quadraticAttenuation); p.setPosition((float)position.x,(float)position.y,(float)position.z); light = p; light.setColor(new Color3f(color)); light.setInfluencingBounds(new BoundingSphere(new Point3d(0,0,0), Double.POSITIVE_INFINITY)); } /** Provide your own Light! */ public LightPortrayal3D(Light light) { this.light = light; } public TransformGroup getModel(Object obj, TransformGroup j3dModel) { if(j3dModel==null) { j3dModel = new TransformGroup(); j3dModel.setCapability(Group.ALLOW_CHILDREN_READ); Light l = (Light)(light.cloneTree(false)); clearPickableFlags(l); // make un-pickable. How do you catch a moonbeam in your hand? j3dModel.addChild(l); } return j3dModel; } }