diff --git a/jme3-core/src/main/java/com/jme3/light/AmbientLight.java b/jme3-core/src/main/java/com/jme3/light/AmbientLight.java index 58676851c..a2dc1cd38 100644 --- a/jme3-core/src/main/java/com/jme3/light/AmbientLight.java +++ b/jme3-core/src/main/java/com/jme3/light/AmbientLight.java @@ -32,6 +32,7 @@ package com.jme3.light; import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingSphere; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; @@ -62,6 +63,11 @@ public class AmbientLight extends Light { return true; } + @Override + public boolean intersectsSphere(BoundingSphere sphere, TempVars vars) { + return true; + } + @Override public boolean intersectsFrustum(Camera camera, TempVars vars) { return true; diff --git a/jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java b/jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java index c8456529d..5d07e1a8d 100644 --- a/jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java +++ b/jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 jMonkeyEngine + * Copyright (c) 2009-2015 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -78,8 +78,9 @@ public final class DefaultLightFilter implements LightFilter { } } else if (bv instanceof BoundingSphere) { if (!Float.isInfinite( ((BoundingSphere)bv).getRadius() )) { - // Non-infinite bounding sphere... Not supported yet. - throw new UnsupportedOperationException("Only AABB supported for now"); + if (!light.intersectsSphere((BoundingSphere)bv, vars)) { + continue; + } } } diff --git a/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java b/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java index b8e1a1979..b1abb65cf 100644 --- a/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java +++ b/jme3-core/src/main/java/com/jme3/light/DirectionalLight.java @@ -32,6 +32,7 @@ package com.jme3.light; import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingSphere; import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; @@ -116,6 +117,11 @@ public class DirectionalLight extends Light { return true; } + @Override + public boolean intersectsSphere(BoundingSphere sphere, TempVars vars) { + return true; + } + @Override public boolean intersectsFrustum(Camera camera, TempVars vars) { return true; diff --git a/jme3-core/src/main/java/com/jme3/light/Light.java b/jme3-core/src/main/java/com/jme3/light/Light.java index bac775aeb..39a30980b 100644 --- a/jme3-core/src/main/java/com/jme3/light/Light.java +++ b/jme3-core/src/main/java/com/jme3/light/Light.java @@ -32,6 +32,7 @@ package com.jme3.light; import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingSphere; import com.jme3.export.*; import com.jme3.math.ColorRGBA; import com.jme3.renderer.Camera; @@ -196,6 +197,20 @@ public abstract class Light implements Savable, Cloneable { */ public abstract boolean intersectsBox(BoundingBox box, TempVars vars); + /** + * Determines if the light intersects with the given bounding sphere. + *

+ * For non-local lights, such as {@link DirectionalLight directional lights}, + * {@link AmbientLight ambient lights}, or {@link PointLight point lights} + * without influence radius, this method should always return true. + * + * @param sphere The sphere to check intersection against. + * @param vars TempVars in case it is needed. + * + * @return True if the light intersects the sphere, false otherwise. + */ + public abstract boolean intersectsSphere(BoundingSphere sphere, TempVars vars); + /** * Determines if the light intersects with the given camera frustum. * diff --git a/jme3-core/src/main/java/com/jme3/light/PointLight.java b/jme3-core/src/main/java/com/jme3/light/PointLight.java index 1f515e71c..1468d1ba1 100644 --- a/jme3-core/src/main/java/com/jme3/light/PointLight.java +++ b/jme3-core/src/main/java/com/jme3/light/PointLight.java @@ -32,12 +32,14 @@ package com.jme3.light; import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingSphere; import com.jme3.bounding.BoundingVolume; import com.jme3.bounding.Intersection; import com.jme3.export.InputCapsule; import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; +import com.jme3.math.FastMath; import com.jme3.math.ColorRGBA; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; @@ -195,6 +197,16 @@ public class PointLight extends Light { } } + @Override + public boolean intersectsSphere(BoundingSphere sphere, TempVars vars) { + if (this.radius == 0) { + return true; + } else { + // Sphere v. sphere collision + return sphere.getCenter().subtract(position).lengthSquared() < FastMath.sqr(radius + sphere.getRadius()); + } + } + @Override public boolean intersectsFrustum(Camera camera, TempVars vars) { if (this.radius == 0) { diff --git a/jme3-core/src/main/java/com/jme3/light/SpotLight.java b/jme3-core/src/main/java/com/jme3/light/SpotLight.java index de24280ab..444d58b3a 100644 --- a/jme3-core/src/main/java/com/jme3/light/SpotLight.java +++ b/jme3-core/src/main/java/com/jme3/light/SpotLight.java @@ -32,6 +32,7 @@ package com.jme3.light; import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingSphere; import com.jme3.bounding.BoundingVolume; import com.jme3.export.*; import com.jme3.math.ColorRGBA; @@ -225,12 +226,49 @@ public class SpotLight extends Light { return false; } + @Override + public boolean intersectsSphere(BoundingSphere sphere, TempVars vars) { + if (this.spotRange > 0f) { + // Check spot range first. + // Sphere v. sphere collision + if (sphere.getCenter().subtract(position).lengthSquared() >= FastMath.sqr(spotRange + sphere.getRadius())) { + return false; + } + } + + float otherRadiusSquared = FastMath.sqr(sphere.getRadius()); + float otherRadius = sphere.getRadius(); + + // Check if sphere is within spot angle. + // Cone v. sphere collision. + Vector3f E = direction.mult(otherRadius * outerAngleSinRcp, vars.vect1); + Vector3f U = position.subtract(E, vars.vect2); + Vector3f D = sphere.getCenter().subtract(U, vars.vect3); + + float dsqr = D.dot(D); + float e = direction.dot(D); + + if (e > 0f && e * e >= dsqr * outerAngleCosSqr) { + D = sphere.getCenter().subtract(position, vars.vect3); + dsqr = D.dot(D); + e = -direction.dot(D); + + if (e > 0f && e * e >= dsqr * outerAngleSinSqr) { + return dsqr <= otherRadiusSquared; + } else { + return true; + } + } + + return false; + } + @Override public boolean intersectsFrustum(Camera cam, TempVars vars) { if (spotRange == 0) { // The algorithm below does not support infinite spot range. - return true; - } + return true; + } Vector3f farPoint = vars.vect1.set(position).addLocal(vars.vect2.set(direction).multLocal(spotRange)); for (int i = 5; i >= 0; i--) { //check origin against the plane