Commits

Michael Ludwig committed 04e488c

Simplify light components, complete spot light influence algorithm, and remove ffp2 cruft.

  • Participants
  • Parent commits 6ef0e4e

Comments (0)

Files changed (15)

File ferox-math/src/main/java/com/ferox/math/bounds/Frustum.java

 
 import com.ferox.math.AxisAlignedBox;
 import com.ferox.math.Const;
+import com.ferox.math.Matrix3;
 import com.ferox.math.Matrix4;
 import com.ferox.math.Vector3;
 import com.ferox.math.Vector4;
         this.location.set(location);
         this.direction.set(direction);
         this.up.set(up);
+        update();
+    }
+    
+    /**
+     * Set the orientation of this Frustum based on the affine
+     * <tt>transform</tt>. The 4th column's first 3 values encode the
+     * transformation. The 3rd column holds the direction vector, and the 2nd
+     * column defines the up vector.
+     * 
+     * @param transform The new transform of the frustum
+     * @throws NullPointerException if transform is null
+     */
+    public void setOrientation(@Const Matrix4 transform) {
+        if (transform == null)
+            throw new NullPointerException("Transform cannot be null");
         
+        this.location.set(transform.m03, transform.m13, transform.m23);
+        this.direction.set(transform.m02, transform.m12, transform.m22);
+        this.up.set(transform.m01, transform.m11, transform.m21);
+        update();
+    }
+    
+    /**
+     * Set the orientation of this Frustum based on the given location vector
+     * and 3x3 rotation matrix. Together the vector and rotation represent an
+     * affine transform that is treated the same as in
+     * {@link #setOrientation(Matrix4)}.
+     * 
+     * @param location The location of the frustum
+     * @param rotation The rotation of the frustum
+     * @throws NullPointerException if location or rotation are null
+     */
+    public void setOrientation(@Const Vector3 location, @Const Matrix3 rotation) {
+        if (location == null)
+            throw new NullPointerException("Location cannot be null");
+        if (rotation == null)
+            throw new NullPointerException("Rotation matrix cannot be null");
+        
+        this.location.set(location);
+        this.direction.set(rotation.m02, rotation.m12, rotation.m22);
+        this.up.set(rotation.m01, rotation.m11, rotation.m21);
         update();
     }
 

File ferox-scene/src/main/java/com/ferox/scene/AbstractPlacedLight.java

 package com.ferox.scene;
 
-import com.ferox.math.Const;
-import com.ferox.math.Vector3;
-import com.ferox.math.entreri.Vector3Property;
-import com.lhkbob.entreri.Unmanaged;
 import com.lhkbob.entreri.property.DoubleProperty;
 import com.lhkbob.entreri.property.DoubleProperty.DefaultDouble;
 
 /**
+ * <p>
  * An intermediate light type that is shared by {@link PointLight} and
  * {@link SpotLight}. Although it is common to represent a point and spot light
  * as the same object (such as by using a cutoff angle of 180 degrees to
  * represent a point light), it was decided to have them be separate components
  * because they are often treated fundamentally different in rendering engines.
+ * </p>
+ * <p>
+ * Placed lights should be combined with a {@link Transform} component to
+ * control the position (and possibly direction). A placed light without a
+ * transform defaults to the default transform.
+ * </p>
  * 
  * @author Michael Ludwig
  * @param <T> The component light type
 public abstract class AbstractPlacedLight<T extends AbstractPlacedLight<T>> extends Light<T> {
     @DefaultDouble(-1.0)
     private DoubleProperty falloffDistance;
-    
-    private Vector3Property position;
-    
-    @Unmanaged
-    private final Vector3 posCache = new Vector3();
 
     protected AbstractPlacedLight() { }
 
     /**
-     * Return the local position of this light with respect to the owning
-     * entity's coordinate space. If the entity has no defined coordinate space,
-     * its in world space. The returned Vector3 instance
-     * is reused by this Light instance so it should be cloned before
-     * changing which Component is referenced
-     * 
-     * @return The position of the light
-     */
-    public final @Const Vector3 getPosition() {
-        return posCache;
-    }
-
-    /**
-     * Copy <tt>pos</tt> into this component's position vector. The provided
-     * position is in the entity's local space, which is usually defined by a
-     * {@link Transform} component.
-     * 
-     * @param pos The new position
-     * @return This light for chaining purposes
-     * @throws NullPointerException if pos is null
-     */
-    @SuppressWarnings("unchecked")
-    public final T setPosition(@Const Vector3 pos) {
-        if (pos == null)
-            throw new NullPointerException("Position cannot be null");
-        posCache.set(pos);
-        position.set(pos, getIndex());
-        return (T) this;
-    }
-
-    /**
      * Set the distance to where the light's energy has fallen to zero and no
      * longer contributes to the lighting of a scene. If this is negative, the
      * light has no energy falloff and all lit objects will be lit with the same
     public final double getFalloffDistance() {
         return falloffDistance.get(getIndex(), 0);
     }
-    
-    @Override
-    protected void onSet(int index) {
-        position.get(index, posCache);
-    }
 }

File ferox-scene/src/main/java/com/ferox/scene/DirectionLight.java

 package com.ferox.scene;
 
-import com.ferox.math.Const;
-import com.ferox.math.Vector3;
-import com.ferox.math.entreri.Vector3Property;
-import com.ferox.math.entreri.Vector3Property.DefaultVector3;
 import com.lhkbob.entreri.TypeId;
-import com.lhkbob.entreri.Unmanaged;
 
 /**
  * <p>
  * DirectionLight represents an direction light (or infinite point light), where
  * objects see light coming from the same direction, regardless of their
- * position. An example of a direction light is the sun. Combining a direction
- * light with a transform can be used to transform its direction vector, but any
- * translation will have no affect on the lighting equations. It is possible
- * that a position transform on a DirectionLight could be used to limit its
- * influence, but this all depends on the components used and the controller
- * implementations.
+ * position. An example of a direction light is the sun.
+ * </p>
+ * <p>
+ * DirectionLight should be combined with a {@link Transform} component to
+ * specify its orientation. The direction is encoded in the 3rd column of the
+ * 4x4 affine matrix. If there is no transform component present on an entity,
+ * the direction defaults to the positive z axis.
  * </p>
  * 
  * @author Michael Ludwig
      * The shared TypedId representing DirectionLight.
      */
     public static final TypeId<DirectionLight> ID = TypeId.get(DirectionLight.class);
-    
-    @DefaultVector3(x=0.0, y=0.0, z=1.0)
-    private Vector3Property direction;
-    
-    @Unmanaged
-    private final Vector3 dirCache = new Vector3();
 
     private DirectionLight() { }
-    
-    /**
-     * Set the direction of this light. This copies <tt>dir</tt>, so any future
-     * changes to the input vector will not affect this DirectionLight. If this
-     * DirectionLight is in an Entity with a transform or rotation-based
-     * component, the direction should be interpreted as a local vector.
-     * 
-     * @param dir The new light direction, before being transformed by any
-     *            transform component (if one exists on the owner)
-     * @return The new version, via {@link #notifyChange()}
-     * @throws NullPointerException if dir is null
-     * @throws ArithmeticException if dir cannot be normalized
-     */
-    public DirectionLight setDirection(@Const Vector3 dir) {
-        if (dir == null)
-            throw new NullPointerException("Direction vector cannot be null");
-        dirCache.set(dir);
-        direction.set(dir.normalize(null), getIndex());
-        return this;
-    }
-
-    /**
-     * Get the normalized direction vector for this light. If this
-     * DirectionLight is combined with another transform, this vector should be
-     * transformed by it before used in lighting calculations. The returned
-     * Vector3 instance is reused by this Light instance so it should be cloned
-     * before changing which Component is referenced.
-     * 
-     * @return The normalized direction vector
-     */
-    public @Const Vector3 getDirection() {
-        return dirCache;
-    }
-    
-    @Override
-    protected void onSet(int index) {
-        direction.get(index, dirCache);
-    }
 }

File ferox-scene/src/main/java/com/ferox/scene/SpotLight.java

 package com.ferox.scene;
 
-import com.ferox.math.Const;
-import com.ferox.math.Vector3;
-import com.ferox.math.entreri.Vector3Property;
-import com.ferox.math.entreri.Vector3Property.DefaultVector3;
 import com.lhkbob.entreri.TypeId;
-import com.lhkbob.entreri.Unmanaged;
 import com.lhkbob.entreri.property.DoubleProperty;
 import com.lhkbob.entreri.property.DoubleProperty.DefaultDouble;
 
  * describes how wide or narrow the cone is.
  * </p>
  * <p>
- * It is intended that SpotLight be combined with a transform component to
- * provide the position and direction information. Like {@link DirectionLight},
- * though, it does provide a direction vector that represents the local
- * direction before being transformed by any transform component. This is
- * provided to make it easier to manipulate the direction of the light.
+ * A SpotLight should be combined with a {@link Transform} component to specify
+ * its position and direction. The direction is stored in the 3rd column of the
+ * 4x4 affine matrix. If there is no transform component, the direction vector
+ * defaults to the positive z axis.
  * </p>
  * 
  * @author Michael Ludwig
      */
     public static final TypeId<SpotLight> ID = TypeId.get(SpotLight.class);
     
-    @DefaultVector3(x=0.0, y=0.0, z=1.0)
-    private Vector3Property direction;
-    
     @DefaultDouble(30.0)
     private DoubleProperty cutoffAngle;
-    
-    @Unmanaged
-    private final Vector3 dirCache = new Vector3();
 
     private SpotLight() { }
     
         cutoffAngle.set(angle, getIndex(), 0);
         return this;
     }
-
-    /**
-     * Set the direction of this light. This copies <tt>dir</tt>, so any future
-     * changes to the input vector will not affect this SpotLight. If this
-     * SpotLight is in an Entity with a transform or rotation-based component,
-     * the direction should be interpreted as a local vector.
-     * 
-     * @param dir The new light direction, before being transformed by any
-     *            transform component (if one exists on the owner)
-     * @return This light for chaining purposes
-     * @throws NullPointerException if dir is null
-     * @throws ArithmeticException if dir cannot be normalized
-     */
-    public SpotLight setDirection(@Const Vector3 dir) {
-        if (dir == null)
-            throw new NullPointerException("Direction vector cannot be null");
-        dirCache.set(dir);
-        direction.set(dir.normalize(null), getIndex());
-        return this;
-    }
-
-    /**
-     * Get the normalized direction vector for this light. If this SpotLight is
-     * combined with another transform, this vector should be transformed by it
-     * before used in lighting calculations. The returned vector is a cached
-     * instance shared within the component's EntitySystem, so it should be
-     * cloned before accessing another component of this type.
-     * 
-     * @return The normalized direction vector
-     */
-    public @Const Vector3 getDirection() {
-        return dirCache;
-    }
-    
-    @Override
-    protected void onSet(int index) {
-        direction.get(index, dirCache);
-    }
 }
 

File ferox-scene/src/main/java/com/ferox/scene/controller/ffp2/FixedFunctionRenderController.java

-package com.ferox.scene.controller.ffp2;
-
-public class FixedFunctionRenderController {
-
-}

File ferox-scene/src/main/java/com/ferox/scene/controller/ffp2/LightAtom.java

-package com.ferox.scene.controller.ffp2;
-
-import com.ferox.math.Color3f;
-import com.ferox.math.Vector3f;
-import com.ferox.math.Vector4f;
-
-public class LightAtom {
-    public final Color3f color;
-    public final Vector4f position; // or direction for direction lights
-    public final Vector3f spotlightDirection;
-    public float cutoffAngle;
-    
-    public LightAtom() {
-        color = new Color3f();
-        position = new Vector4f();
-        spotlightDirection = new Vector3f();
-    }
-}

File ferox-scene/src/main/java/com/ferox/scene/controller/ffp2/OpaqueLightingPass.java

-package com.ferox.scene.controller.ffp2;
-
-public class OpaqueLightingPass {
-
-}

File ferox-scene/src/main/java/com/ferox/scene/controller/ffp2/OpaqueShadowedLightingPass.java

-package com.ferox.scene.controller.ffp2;
-
-public class OpaqueShadowedLightingPass {
-
-}

File ferox-scene/src/main/java/com/ferox/scene/controller/ffp2/RenderAtom.java

-package com.ferox.scene.controller.ffp2;
-
-import com.ferox.math.Color3f;
-import com.ferox.math.Matrix4f;
-import com.ferox.renderer.Renderer.PolygonType;
-import com.ferox.resource.Texture;
-import com.ferox.resource.VertexAttribute;
-import com.ferox.resource.VertexBufferObject;
-
-public class RenderAtom {
-    // geometry
-    public VertexAttribute vertices;
-    public VertexAttribute normals;
-    public VertexAttribute texCoords;
-    
-    public VertexBufferObject indices;
-    public int offset;
-    public int count;
-    public PolygonType polyType;
-    
-    // material
-    // FIXME: these might need to change to Vector4's
-    public final Color3f diffuse;
-    public final Color3f specular;
-    public final Color3f emissive;
-    
-    public float shininess;
-    public float alpha;
-    
-    // textures
-    public Texture diffuseTexture;
-    public Texture emittedTexture;
-    // NOTE: FFP doesn't have support for specular textures
-    // FIXME: are you sure? might be able to combine with normal some how like DOT_RGB?
-    
-    // transform
-    public final Matrix4f transform;
-    
-    // lighting
-    // FIXME: are these necessary?
-    public boolean enableLighting;
-    public boolean castsShadows;
-    public boolean receivesShadows;
-    
-    public final LightAtom[] lights;
-    
-    public final Color3f ambientLight;
-    
-    public RenderAtom(int maxLights) {
-        diffuse = new Color3f();
-        specular = new Color3f();
-        emissive = new Color3f();
-        
-        transform = new Matrix4f();
-        
-        lights = new LightAtom[maxLights];
-        ambientLight = new Color3f();
-    }
-}

File ferox-scene/src/main/java/com/ferox/scene/controller/ffp2/ShadowMapController.java

-package com.ferox.scene.controller.ffp2;
-
-public class ShadowMapController {
-
-}

File ferox-scene/src/main/java/com/ferox/scene/controller/ffp2/ShadowMapGeneratorPass.java

-package com.ferox.scene.controller.ffp2;
-
-public class ShadowMapGeneratorPass {
-
-}

File ferox-scene/src/main/java/com/ferox/scene/controller/ffp2/TransparentLightingPass.java

-package com.ferox.scene.controller.ffp2;
-
-public class TransparentLightingPass {
-
-}

File ferox-scene/src/main/java/com/ferox/scene/controller/ffp2/TransparentShadowedLightingPass.java

-package com.ferox.scene.controller.ffp2;
-
-public class TransparentShadowedLightingPass {
-
-}

File ferox-scene/src/main/java/com/ferox/scene/controller/light/PointLightInfluence.java

         } else {
             // make sure the bounds intersects with the bounding sphere centered
             // on the light with a radius equal to the falloff distance
-            lightPos.set(lightTransform.m03, lightTransform.m13, lightTransform.m23)
-                    .add(light.getPosition());
+            lightPos.set(lightTransform.m03, lightTransform.m13, lightTransform.m23);
             
             // center of aabb
             objectPos.add(bounds.min, bounds.max).scale(0.5);

File ferox-scene/src/main/java/com/ferox/scene/controller/light/SpotLightInfluence.java

 import com.ferox.math.AxisAlignedBox;
 import com.ferox.math.Const;
 import com.ferox.math.Matrix4;
+import com.ferox.math.bounds.Frustum;
+import com.ferox.math.bounds.Frustum.FrustumIntersection;
 import com.ferox.scene.SpotLight;
 import com.lhkbob.entreri.TypeId;
 
 public class SpotLightInfluence implements LightInfluence<SpotLight> {
-
+    private final Frustum cone = new Frustum(60.0, 1.0, 0.1, 1.0);
+    
     @Override
     public boolean influences(SpotLight light, @Const Matrix4 lightTransform, @Const AxisAlignedBox bounds) {
-        // FIXME: make sure the bounds are within the cone of light.
-        // FIXME: should I do distance or cone check first? I feel like it should
-        // be the cone check since that will exclude more
-        if (light.getFalloffDistance() > 0.0) {
-            // check distance
-        }
-        return true;
+        // construct a Frustum that approximates the cone of the light
+        double zfar = (light.getFalloffDistance() < 0 ? Double.MAX_VALUE : light.getFalloffDistance());
+        cone.setPerspective(light.getCutoffAngle(), 1.0, 0.00001, zfar);
+        cone.setOrientation(lightTransform);
+        
+        return cone.intersects(bounds, null) != FrustumIntersection.OUTSIDE;
     }
 
     @Override