Merge pull request #364 from Dokthar/light

Lights : added light v. sphere intersection
experimental
Kirill Vainer 9 years ago
commit edaf49c00c
  1. 6
      jme3-core/src/main/java/com/jme3/light/AmbientLight.java
  2. 7
      jme3-core/src/main/java/com/jme3/light/DefaultLightFilter.java
  3. 6
      jme3-core/src/main/java/com/jme3/light/DirectionalLight.java
  4. 15
      jme3-core/src/main/java/com/jme3/light/Light.java
  5. 12
      jme3-core/src/main/java/com/jme3/light/PointLight.java
  6. 43
      jme3-core/src/main/java/com/jme3/light/SpotLight.java
  7. 92
      jme3-core/src/test/java/com/jme3/light/LightFilterTest.java

@ -32,6 +32,7 @@
package com.jme3.light; package com.jme3.light;
import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
@ -62,6 +63,11 @@ public class AmbientLight extends Light {
return true; return true;
} }
@Override
public boolean intersectsSphere(BoundingSphere sphere, TempVars vars) {
return true;
}
@Override @Override
public boolean intersectsFrustum(Camera camera, TempVars vars) { public boolean intersectsFrustum(Camera camera, TempVars vars) {
return true; return true;

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2009-2014 jMonkeyEngine * Copyright (c) 2009-2015 jMonkeyEngine
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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) { } else if (bv instanceof BoundingSphere) {
if (!Float.isInfinite( ((BoundingSphere)bv).getRadius() )) { if (!Float.isInfinite( ((BoundingSphere)bv).getRadius() )) {
// Non-infinite bounding sphere... Not supported yet. if (!light.intersectsSphere((BoundingSphere)bv, vars)) {
throw new UnsupportedOperationException("Only AABB supported for now"); continue;
}
} }
} }

@ -32,6 +32,7 @@
package com.jme3.light; package com.jme3.light;
import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.export.InputCapsule; import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter; import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
@ -116,6 +117,11 @@ public class DirectionalLight extends Light {
return true; return true;
} }
@Override
public boolean intersectsSphere(BoundingSphere sphere, TempVars vars) {
return true;
}
@Override @Override
public boolean intersectsFrustum(Camera camera, TempVars vars) { public boolean intersectsFrustum(Camera camera, TempVars vars) {
return true; return true;

@ -32,6 +32,7 @@
package com.jme3.light; package com.jme3.light;
import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.export.*; import com.jme3.export.*;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
@ -196,6 +197,20 @@ public abstract class Light implements Savable, Cloneable {
*/ */
public abstract boolean intersectsBox(BoundingBox box, TempVars vars); public abstract boolean intersectsBox(BoundingBox box, TempVars vars);
/**
* Determines if the light intersects with the given bounding sphere.
* <p>
* 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. * Determines if the light intersects with the given camera frustum.
* *

@ -32,12 +32,14 @@
package com.jme3.light; package com.jme3.light;
import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.bounding.BoundingVolume; import com.jme3.bounding.BoundingVolume;
import com.jme3.bounding.Intersection; import com.jme3.bounding.Intersection;
import com.jme3.export.InputCapsule; import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter; import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter; import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule; import com.jme3.export.OutputCapsule;
import com.jme3.math.FastMath;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera; 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 Intersection.intersect(sphere, position, radius);
}
}
@Override @Override
public boolean intersectsFrustum(Camera camera, TempVars vars) { public boolean intersectsFrustum(Camera camera, TempVars vars) {
if (this.radius == 0) { if (this.radius == 0) {

@ -32,7 +32,9 @@
package com.jme3.light; package com.jme3.light;
import com.jme3.bounding.BoundingBox; import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.bounding.BoundingVolume; import com.jme3.bounding.BoundingVolume;
import com.jme3.bounding.Intersection;
import com.jme3.export.*; import com.jme3.export.*;
import com.jme3.math.ColorRGBA; import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
@ -188,9 +190,7 @@ public class SpotLight extends Light {
if (this.spotRange > 0f) { if (this.spotRange > 0f) {
// Check spot range first. // Check spot range first.
// Sphere v. box collision // Sphere v. box collision
if (FastMath.abs(box.getCenter().x - position.x) >= spotRange + box.getXExtent() if (!Intersection.intersect(box, position, spotRange)) {
|| FastMath.abs(box.getCenter().y - position.y) >= spotRange + box.getYExtent()
|| FastMath.abs(box.getCenter().z - position.z) >= spotRange + box.getZExtent()) {
return false; return false;
} }
} }
@ -225,6 +225,43 @@ public class SpotLight extends Light {
return false; return false;
} }
@Override
public boolean intersectsSphere(BoundingSphere sphere, TempVars vars) {
if (this.spotRange > 0f) {
// Check spot range first.
// Sphere v. sphere collision
if (!Intersection.intersect(sphere, position, spotRange)) {
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 @Override
public boolean intersectsFrustum(Camera cam, TempVars vars) { public boolean intersectsFrustum(Camera cam, TempVars vars) {
if (spotRange == 0) { if (spotRange == 0) {

@ -31,6 +31,7 @@
*/ */
package com.jme3.light; package com.jme3.light;
import com.jme3.bounding.BoundingSphere;
import com.jme3.math.FastMath; import com.jme3.math.FastMath;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera; import com.jme3.renderer.Camera;
@ -81,12 +82,20 @@ public class LightFilterTest {
public void testAmbientFiltering() { public void testAmbientFiltering() {
geom.addLight(new AmbientLight()); geom.addLight(new AmbientLight());
checkFilteredLights(1); // Ambient lights must never be filtered checkFilteredLights(1); // Ambient lights must never be filtered
// Test for bounding Sphere
geom.setModelBound(new BoundingSphere(0.5f, Vector3f.ZERO));
checkFilteredLights(1); // Ambient lights must never be filtered
} }
@Test @Test
public void testDirectionalFiltering() { public void testDirectionalFiltering() {
geom.addLight(new DirectionalLight(Vector3f.UNIT_Y)); geom.addLight(new DirectionalLight(Vector3f.UNIT_Y));
checkFilteredLights(1); // Directional lights must never be filtered checkFilteredLights(1); // Directional lights must never be filtered
// Test for bounding Sphere
geom.setModelBound(new BoundingSphere(0.5f, Vector3f.ZERO));
checkFilteredLights(1); // Directional lights must never be filtered
} }
@Test @Test
@ -127,6 +136,45 @@ public class LightFilterTest {
// Rotate the camera so it is up, light is outside frustum. // Rotate the camera so it is up, light is outside frustum.
cam.lookAtDirection(Vector3f.UNIT_Y, Vector3f.UNIT_Y); cam.lookAtDirection(Vector3f.UNIT_Y, Vector3f.UNIT_Y);
checkFilteredLights(0); checkFilteredLights(0);
// ==================================
// Tests for bounding Sphere
geom.setModelBound(new BoundingSphere(1f, Vector3f.ZERO));
geom.setLocalTranslation(0, 0, 2);
pl.setPosition(new Vector3f(0, 0, 2f));
// Infinite point lights must never be filtered
pl.setRadius(0);
checkFilteredLights(1);
pl.setRadius(1f);
// Put the light at the very close to the geom,
// the very edge of the sphere touches the other bounding sphere
// Still not considered an intersection though.
pl.setPosition(new Vector3f(0, 0, 0));
checkFilteredLights(0);
// And more close - now its an intersection.
pl.setPosition(new Vector3f(0, 0, 0f + FastMath.ZERO_TOLERANCE));
checkFilteredLights(1);
geom.setLocalTranslation(0, 0, 0);
// In this case its an intersection for pointLight v. box
// But not for pointLight v. sphere
// Vector3f(0, 0.5f, 0.5f).normalize().mult(2) ~ >= (0.0, 1.4142135, 1.4142135)
//pl.setPosition(new Vector3f(0, 0.5f, 0.5f).normalizeLocal().multLocal(2 + FastMath.ZERO_TOLERANCE));
pl.setPosition(new Vector3f(0f, 1.4142135f, 1.4142135f).multLocal(1+FastMath.ZERO_TOLERANCE));
checkFilteredLights(0);
// Make the distance a wee bit closer, now its an intersection
//pl.setPosition(new Vector3f(0, 0.5f, 0.5f).normalizeLocal().multLocal(2 - FastMath.ZERO_TOLERANCE));
pl.setPosition(new Vector3f(0f, 1.4142135f, 1.4142135f).multLocal(1-FastMath.ZERO_TOLERANCE));
checkFilteredLights(1);
// it's a point light, also test for the other corner
pl.setPosition(new Vector3f(0f, -1.4142135f, -1.4142135f).multLocal(1-FastMath.ZERO_TOLERANCE));
checkFilteredLights(0);
} }
@Test @Test
@ -175,5 +223,49 @@ public class LightFilterTest {
// now, the spot will touch the box. // now, the spot will touch the box.
geom.setMesh(new Box(5, 1, 1)); geom.setMesh(new Box(5, 1, 1));
checkFilteredLights(1); checkFilteredLights(1);
// ==================================
// Tests for bounding sphere, with a radius of 1f (in the box geom)
sl.setPosition(Vector3f.ZERO);
sl.setDirection(Vector3f.UNIT_Z);
geom.setLocalTranslation(Vector3f.ZERO);
geom.setModelBound(new BoundingSphere(1f, Vector3f.ZERO));
// Infinit spot lights are only filtered
// if the geometry is outside the infinite cone.
sl.setSpotRange(0);
checkFilteredLights(1);
//the geommetry is outside the infinit cone (cone direction going away from the geom)
sl.setPosition(Vector3f.UNIT_Z.mult(1+FastMath.ZERO_TOLERANCE));
checkFilteredLights(0);
//place the spote ligth in the corner of the box geom, (in order to test bounding sphere)
sl.setDirection(new Vector3f(1, 1, 0).normalizeLocal());
geom.setLocalTranslation(0, 0, 10);
sl.setPosition(sl.getDirection().mult(-2f).add(geom.getLocalTranslation()));
// make it barely reach the sphere, incorect with a box
sl.setSpotRange(1f - FastMath.ZERO_TOLERANCE);
checkFilteredLights(0);
// make it reach the sphere
sl.setSpotRange(1f + FastMath.ZERO_TOLERANCE);
checkFilteredLights(1);
// extent the range
sl.setPosition(Vector3f.ZERO);
sl.setDirection(Vector3f.UNIT_Z);
sl.setSpotRange(20);
checkFilteredLights(1);
// rotate the cone a bit so it no longer faces the geom
sl.setDirection(new Vector3f(0, 0.3f, 0.7f).normalizeLocal());
checkFilteredLights(0);
// Create sphere of size X=10 (double the radius)
// now, the spot will touch the sphere.
geom.setModelBound(new BoundingSphere(5f, Vector3f.ZERO));
checkFilteredLights(1);
} }
} }

Loading…
Cancel
Save