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 0dc3425fd..04e99a92c 100644 --- a/jme3-core/src/main/java/com/jme3/light/SpotLight.java +++ b/jme3-core/src/main/java/com/jme3/light/SpotLight.java @@ -35,6 +35,7 @@ import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingVolume; import com.jme3.export.*; import com.jme3.math.FastMath; +import com.jme3.math.Plane; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.scene.Spatial; @@ -66,8 +67,8 @@ public class SpotLight extends Light implements Savable { protected float packedAngleCos=0; protected float outerAngleCosSqr, outerAngleSinSqr; - protected float outerAngleSinRcp; - + protected float outerAngleSinRcp, outerAngleSin; + public SpotLight() { super(); computeAngleParameters(); @@ -90,10 +91,10 @@ public class SpotLight extends Light implements Savable { } // compute parameters needed for cone vs sphere check. - float outerSin = FastMath.sin(spotOuterAngle); + outerAngleSin = FastMath.sin(spotOuterAngle); outerAngleCosSqr = outerCos * outerCos; - outerAngleSinSqr = outerSin * outerSin; - outerAngleSinRcp = 1.0f / outerSin; + outerAngleSinSqr = outerAngleSin * outerAngleSin; + outerAngleSinRcp = 1.0f / outerAngleSin; } @Override @@ -143,9 +144,29 @@ public class SpotLight extends Light implements Savable { if (this.spotRange == 0) { return true; } else { - // Do a frustum v. sphere test against the spot range. + // Do a frustum v. OBB test. + + // Determine OBB extents assuming OBB center is the middle + // point between the cone's vertex and its range. + float sideExtent = spotRange * 0.5f * outerAngleSin; + float forwardExtent = spotRange * 0.5f; + + // Create OBB axes via direction and Y up vector. + Vector3f xAxis = Vector3f.UNIT_Y.cross(direction, vars.vect1).normalizeLocal(); + Vector3f yAxis = direction.cross(xAxis, vars.vect2).normalizeLocal(); + Vector3f obbCenter = direction.mult(spotRange * 0.5f, vars.vect3).addLocal(position); + for (int i = 5; i >= 0; i--) { - if (camera.getWorldPlane(i).pseudoDistance(position) <= -spotRange) { + Plane plane = camera.getWorldPlane(i); + Vector3f planeNormal = plane.getNormal(); + + // OBB v. plane intersection + float radius = FastMath.abs(sideExtent * (planeNormal.dot(xAxis))) + + FastMath.abs(sideExtent * (planeNormal.dot(yAxis))) + + FastMath.abs(forwardExtent * (planeNormal.dot(direction))); + + float distance = plane.pseudoDistance(obbCenter); + if (distance <= -radius) { return false; } }