Home | History | Annotate | Download | only in light
      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 
     65     public SpotLight() {
     66         super();
     67         computePackedCos();
     68     }
     69 
     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
     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
     88     public Type getType() {
     89         return Type.Spot;
     90     }
     91 
     92     public Vector3f getDirection() {
     93         return direction;
     94     }
     95 
     96     public void setDirection(Vector3f direction) {
     97         this.direction.set(direction);
     98     }
     99 
    100     public Vector3f getPosition() {
    101         return position;
    102     }
    103 
    104     public void setPosition(Vector3f position) {
    105         this.position.set(position);
    106     }
    107 
    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      */
    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      */
    141     public float getInvSpotRange() {
    142         return invSpotRange;
    143     }
    144 
    145     /**
    146      * returns the spot inner angle
    147      * @return the spot inner angle
    148      */
    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      */
    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      */
    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      */
    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      */
    186     public float getPackedAngleCos() {
    187         return packedAngleCos;
    188     }
    189 
    190 
    191 
    192     @Override
    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
    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