|
|
|
@ -32,7 +32,9 @@ |
|
|
|
|
package com.jme3.shadow; |
|
|
|
|
|
|
|
|
|
import com.jme3.bounding.BoundingBox; |
|
|
|
|
import com.jme3.bounding.BoundingSphere; |
|
|
|
|
import com.jme3.bounding.BoundingVolume; |
|
|
|
|
import com.jme3.collision.UnsupportedCollisionException; |
|
|
|
|
import com.jme3.math.FastMath; |
|
|
|
|
import com.jme3.math.Matrix4f; |
|
|
|
|
import com.jme3.math.Transform; |
|
|
|
@ -42,6 +44,7 @@ import com.jme3.renderer.Camera; |
|
|
|
|
import com.jme3.renderer.ViewPort; |
|
|
|
|
import com.jme3.renderer.queue.GeometryList; |
|
|
|
|
import com.jme3.renderer.queue.RenderQueue; |
|
|
|
|
import com.jme3.renderer.queue.RenderQueue.ShadowMode; |
|
|
|
|
import com.jme3.scene.Geometry; |
|
|
|
|
import com.jme3.scene.Node; |
|
|
|
|
import com.jme3.scene.Spatial; |
|
|
|
@ -295,46 +298,64 @@ public class ShadowUtil { |
|
|
|
|
return casterCount; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private boolean intersectsIgnoreNearZ(BoundingBox splitBB, BoundingSphere occSphere) { |
|
|
|
|
float distSqr = occSphere.getRadius() * occSphere.getRadius(); |
|
|
|
|
|
|
|
|
|
float minX = splitBB.getCenter().x - splitBB.getXExtent(); |
|
|
|
|
float maxX = splitBB.getCenter().x + splitBB.getXExtent(); |
|
|
|
|
|
|
|
|
|
float minY = splitBB.getCenter().y - splitBB.getYExtent(); |
|
|
|
|
float maxY = splitBB.getCenter().y + splitBB.getYExtent(); |
|
|
|
|
|
|
|
|
|
float maxZ = splitBB.getCenter().z + splitBB.getZExtent(); |
|
|
|
|
|
|
|
|
|
if (occSphere.getCenter().x < minX) distSqr -= FastMath.sqr(occSphere.getCenter().x - minX); |
|
|
|
|
else if (occSphere.getCenter().x > maxX) distSqr -= FastMath.sqr(occSphere.getCenter().x - maxX); |
|
|
|
|
|
|
|
|
|
if (occSphere.getCenter().y < minY) distSqr -= FastMath.sqr(occSphere.getCenter().y - minY); |
|
|
|
|
else if (occSphere.getCenter().y > maxY) distSqr -= FastMath.sqr(occSphere.getCenter().y - maxY); |
|
|
|
|
|
|
|
|
|
if (occSphere.getCenter().z > maxZ) distSqr -= FastMath.sqr(occSphere.getCenter().z - maxZ); |
|
|
|
|
|
|
|
|
|
return distSqr > 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private boolean intersectsIgnoreNearZ(BoundingBox splitBB, BoundingBox occBB) { |
|
|
|
|
if (splitBB.getCenter().x + splitBB.getXExtent() < occBB.getCenter().x - occBB.getXExtent() |
|
|
|
|
|| splitBB.getCenter().x - splitBB.getXExtent() > occBB.getCenter().x + occBB.getXExtent()) { |
|
|
|
|
return false; |
|
|
|
|
} else if (splitBB.getCenter().y + splitBB.getYExtent() < occBB.getCenter().y - occBB.getYExtent() |
|
|
|
|
|| splitBB.getCenter().y - splitBB.getYExtent() > occBB.getCenter().y + occBB.getYExtent()) { |
|
|
|
|
return false; |
|
|
|
|
} else if (splitBB.getCenter().z + splitBB.getZExtent() < occBB.getCenter().z - occBB.getZExtent()) { |
|
|
|
|
return false; |
|
|
|
|
} else { |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private boolean intersectsIgnoreNearZ(BoundingBox splitBB, BoundingVolume occBV) { |
|
|
|
|
if (occBV instanceof BoundingBox) { |
|
|
|
|
return intersectsIgnoreNearZ(splitBB, (BoundingBox) occBV); |
|
|
|
|
} else if (occBV instanceof BoundingSphere) { |
|
|
|
|
return intersectsIgnoreNearZ(splitBB, (BoundingSphere) occBV); |
|
|
|
|
} else { |
|
|
|
|
throw new UnsupportedCollisionException("With: " + occBV.getClass().getSimpleName()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void process(Spatial scene) { |
|
|
|
|
if (scene.getCullHint() == Spatial.CullHint.Always) return; |
|
|
|
|
|
|
|
|
|
RenderQueue.ShadowMode shadowMode = scene.getShadowMode(); |
|
|
|
|
if ( scene instanceof Geometry ) |
|
|
|
|
{ |
|
|
|
|
if (scene instanceof Geometry) { |
|
|
|
|
// convert bounding box to light's viewproj space
|
|
|
|
|
Geometry occluder = (Geometry)scene; |
|
|
|
|
if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive |
|
|
|
|
&& !occluder.isGrouped() && occluder.getWorldBound()!=null) { |
|
|
|
|
Geometry occluder = (Geometry) scene; |
|
|
|
|
ShadowMode shadowMode = scene.getShadowMode(); |
|
|
|
|
if (shadowMode != ShadowMode.Off && shadowMode != ShadowMode.Receive |
|
|
|
|
&& !occluder.isGrouped()) { |
|
|
|
|
BoundingVolume bv = occluder.getWorldBound(); |
|
|
|
|
BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox); |
|
|
|
|
|
|
|
|
|
boolean intersects = splitBB.intersects(occBox); |
|
|
|
|
if (!intersects && occBox instanceof BoundingBox) { |
|
|
|
|
BoundingBox occBB = (BoundingBox) occBox; |
|
|
|
|
//Kirill 01/10/2011
|
|
|
|
|
// Extend the occluder further into the frustum
|
|
|
|
|
// This fixes shadow dissapearing issues when
|
|
|
|
|
// the caster itself is not in the view camera
|
|
|
|
|
// but its shadow is in the camera
|
|
|
|
|
// The number is in world units
|
|
|
|
|
occBB.setZExtent(occBB.getZExtent() + 50); |
|
|
|
|
occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25)); |
|
|
|
|
if (splitBB.intersects(occBB)) { |
|
|
|
|
//Nehon : prevent NaN and infinity values to screw the final bounding box
|
|
|
|
|
if (!Float.isNaN(occBox.getCenter().x) && !Float.isInfinite(occBox.getCenter().x)) { |
|
|
|
|
// To prevent extending the depth range too much
|
|
|
|
|
// We return the bound to its former shape
|
|
|
|
|
// Before adding it
|
|
|
|
|
occBB.setZExtent(occBB.getZExtent() - 50); |
|
|
|
|
occBB.setCenter(occBB.getCenter().subtractLocal(0, 0, 25)); |
|
|
|
|
casterBB.mergeLocal(occBox); |
|
|
|
|
casterCount++; |
|
|
|
|
} |
|
|
|
|
if (splitOccluders != null) { |
|
|
|
|
splitOccluders.add(occluder); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else if (intersects) { |
|
|
|
|
if (intersectsIgnoreNearZ(splitBB, occBox)) { |
|
|
|
|
casterBB.mergeLocal(occBox); |
|
|
|
|
casterCount++; |
|
|
|
|
if (splitOccluders != null) { |
|
|
|
@ -342,30 +363,10 @@ public class ShadowUtil { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if ( scene instanceof Node && ((Node)scene).getWorldBound()!=null ) |
|
|
|
|
{ |
|
|
|
|
Node nodeOcc = (Node)scene; |
|
|
|
|
boolean intersects = false; |
|
|
|
|
// some
|
|
|
|
|
BoundingVolume bv = nodeOcc.getWorldBound(); |
|
|
|
|
} else if (scene instanceof Node) { |
|
|
|
|
BoundingVolume bv = scene.getWorldBound(); |
|
|
|
|
BoundingVolume occBox = bv.transform(viewProjMatrix, vars.bbox); |
|
|
|
|
|
|
|
|
|
intersects = splitBB.intersects(occBox); |
|
|
|
|
if (!intersects && occBox instanceof BoundingBox) { |
|
|
|
|
BoundingBox occBB = (BoundingBox) occBox; |
|
|
|
|
//Kirill 01/10/2011
|
|
|
|
|
// Extend the occluder further into the frustum
|
|
|
|
|
// This fixes shadow dissapearing issues when
|
|
|
|
|
// the caster itself is not in the view camera
|
|
|
|
|
// but its shadow is in the camera
|
|
|
|
|
// The number is in world units
|
|
|
|
|
occBB.setZExtent(occBB.getZExtent() + 50); |
|
|
|
|
occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25)); |
|
|
|
|
intersects = splitBB.intersects(occBB); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ( intersects ) { |
|
|
|
|
if (intersectsIgnoreNearZ(splitBB, occBox)) { |
|
|
|
|
for (Spatial child : ((Node)scene).getChildren()) { |
|
|
|
|
process(child); |
|
|
|
|
} |
|
|
|
|