• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.light;
33 
34 import com.jme3.bounding.BoundingVolume;
35 import com.jme3.export.*;
36 import com.jme3.math.FastMath;
37 import com.jme3.math.Vector3f;
38 import com.jme3.scene.Spatial;
39 import java.io.IOException;
40 
41 /**
42  * Represents a spot light.
43  * A spot light emmit a cone of light from a position and in a direction.
44  * It can be used to fake torch lights or car's lights.
45  * <p>
46  * In addition to a position and a direction, spot lights also have a range which
47  * can be used to attenuate the influence of the light depending on the
48  * distance between the light and the effected object.
49  * Also the angle of the cone can be tweaked by changing the spot inner angle and the spot outer angle.
50  * the spot inner angle determin the cone of light where light has full influence.
51  * the spot outer angle determin the cone global cone of light of the spot light.
52  * the light intensity slowly decrease between the inner cone and the outer cone.
53  *  @author Nehon
54  */
55 public class SpotLight extends Light implements Savable {
56 
57     protected Vector3f position = new Vector3f();
58     protected Vector3f direction = new Vector3f(0,-1,0);
59     protected float spotInnerAngle = FastMath.QUARTER_PI / 8;
60     protected float spotOuterAngle = FastMath.QUARTER_PI / 6;
61     protected float spotRange = 100;
62     protected float invSpotRange = 1 / 100;
63     protected float packedAngleCos=0;
64 
SpotLight()65     public SpotLight() {
66         super();
67         computePackedCos();
68     }
69 
computePackedCos()70     private void computePackedCos() {
71         float innerCos=FastMath.cos(spotInnerAngle);
72         float outerCos=FastMath.cos(spotOuterAngle);
73         packedAngleCos=(int)(innerCos*1000);
74         packedAngleCos+=outerCos;
75     }
76 
77     @Override
computeLastDistance(Spatial owner)78     protected void computeLastDistance(Spatial owner) {
79         if (owner.getWorldBound() != null) {
80             BoundingVolume bv = owner.getWorldBound();
81             lastDistance = bv.distanceSquaredTo(position);
82         } else {
83             lastDistance = owner.getWorldTranslation().distanceSquared(position);
84         }
85     }
86 
87     @Override
getType()88     public Type getType() {
89         return Type.Spot;
90     }
91 
getDirection()92     public Vector3f getDirection() {
93         return direction;
94     }
95 
setDirection(Vector3f direction)96     public void setDirection(Vector3f direction) {
97         this.direction.set(direction);
98     }
99 
getPosition()100     public Vector3f getPosition() {
101         return position;
102     }
103 
setPosition(Vector3f position)104     public void setPosition(Vector3f position) {
105         this.position.set(position);
106     }
107 
getSpotRange()108     public float getSpotRange() {
109         return spotRange;
110     }
111 
112     /**
113      * Set the range of the light influence.
114      * <p>
115      * Setting a non-zero range indicates the light should use attenuation.
116      * If a pixel's distance to this light's position
117      * is greater than the light's range, then the pixel will not be
118      * effected by this light, if the distance is less than the range, then
119      * the magnitude of the influence is equal to distance / range.
120      *
121      * @param spotRange the range of the light influence.
122      *
123      * @throws IllegalArgumentException If spotRange is negative
124      */
setSpotRange(float spotRange)125     public void setSpotRange(float spotRange) {
126         if (spotRange < 0) {
127             throw new IllegalArgumentException("SpotLight range cannot be negative");
128         }
129         this.spotRange = spotRange;
130         if (spotRange != 0) {
131             this.invSpotRange = 1 / spotRange;
132         } else {
133             this.invSpotRange = 0;
134         }
135     }
136 
137     /**
138      * for internal use only
139      * @return the inverse of the spot range
140      */
getInvSpotRange()141     public float getInvSpotRange() {
142         return invSpotRange;
143     }
144 
145     /**
146      * returns the spot inner angle
147      * @return the spot inner angle
148      */
getSpotInnerAngle()149     public float getSpotInnerAngle() {
150         return spotInnerAngle;
151     }
152 
153     /**
154      * Sets the inner angle of the cone of influence.
155      * This angle is the angle between the spot direction axis and the inner border of the cone of influence.
156      * @param spotInnerAngle
157      */
setSpotInnerAngle(float spotInnerAngle)158     public void setSpotInnerAngle(float spotInnerAngle) {
159         this.spotInnerAngle = spotInnerAngle;
160         computePackedCos();
161     }
162 
163     /**
164      * returns the spot outer angle
165      * @return the spot outer angle
166      */
getSpotOuterAngle()167     public float getSpotOuterAngle() {
168         return spotOuterAngle;
169     }
170 
171     /**
172      * Sets the outer angle of the cone of influence.
173      * This angle is the angle between the spot direction axis and the outer border of the cone of influence.
174      * this should be greater than the inner angle or the result will be unexpected.
175      * @param spotOuterAngle
176      */
setSpotOuterAngle(float spotOuterAngle)177     public void setSpotOuterAngle(float spotOuterAngle) {
178         this.spotOuterAngle = spotOuterAngle;
179         computePackedCos();
180     }
181 
182     /**
183      * for internal use only
184      * @return the cosines of the inner and outter angle packed in a float
185      */
getPackedAngleCos()186     public float getPackedAngleCos() {
187         return packedAngleCos;
188     }
189 
190 
191 
192     @Override
write(JmeExporter ex)193     public void write(JmeExporter ex) throws IOException {
194         super.write(ex);
195         OutputCapsule oc = ex.getCapsule(this);
196         oc.write(direction, "direction", new Vector3f());
197         oc.write(position, "position", new Vector3f());
198         oc.write(spotInnerAngle, "spotInnerAngle", FastMath.QUARTER_PI / 8);
199         oc.write(spotOuterAngle, "spotOuterAngle", FastMath.QUARTER_PI / 6);
200         oc.write(spotRange, "spotRange", 100);
201     }
202 
203     @Override
read(JmeImporter im)204     public void read(JmeImporter im) throws IOException {
205         super.read(im);
206         InputCapsule ic = im.getCapsule(this);
207         spotInnerAngle = ic.readFloat("spotInnerAngle", FastMath.QUARTER_PI / 8);
208         spotOuterAngle = ic.readFloat("spotOuterAngle", FastMath.QUARTER_PI / 6);
209         direction = (Vector3f) ic.readSavable("direction", new Vector3f());
210         position = (Vector3f) ic.readSavable("position", new Vector3f());
211         spotRange = ic.readFloat("spotRange", 100);
212         if (spotRange != 0) {
213             this.invSpotRange = 1 / spotRange;
214         } else {
215             this.invSpotRange = 0;
216         }
217     }
218 }
219