|
@@ -44,6 +44,7 @@ import com.jme3.export.Savable;
|
|
import com.jme3.material.Material;
|
|
import com.jme3.material.Material;
|
|
import com.jme3.math.ColorRGBA;
|
|
import com.jme3.math.ColorRGBA;
|
|
import com.jme3.math.Matrix4f;
|
|
import com.jme3.math.Matrix4f;
|
|
|
|
+import com.jme3.math.Vector2f;
|
|
import com.jme3.math.Vector3f;
|
|
import com.jme3.math.Vector3f;
|
|
import com.jme3.post.SceneProcessor;
|
|
import com.jme3.post.SceneProcessor;
|
|
import com.jme3.renderer.Camera;
|
|
import com.jme3.renderer.Camera;
|
|
@@ -109,11 +110,17 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|
protected GeometryList shadowMapOccluders = new GeometryList(new OpaqueComparator());
|
|
protected GeometryList shadowMapOccluders = new GeometryList(new OpaqueComparator());
|
|
private String[] shadowMapStringCache;
|
|
private String[] shadowMapStringCache;
|
|
private String[] lightViewStringCache;
|
|
private String[] lightViewStringCache;
|
|
|
|
+ /**
|
|
|
|
+ * fade shadows at distance
|
|
|
|
+ */
|
|
|
|
+ protected float zFarOverride = 0;
|
|
|
|
+ protected Vector2f fadeInfo;
|
|
|
|
+ protected float fadeLength;
|
|
|
|
+ protected Camera frustumCam;
|
|
/**
|
|
/**
|
|
* true to skip the post pass when there are no shadow casters
|
|
* true to skip the post pass when there are no shadow casters
|
|
*/
|
|
*/
|
|
protected boolean skipPostPass;
|
|
protected boolean skipPostPass;
|
|
-
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
* used for serialization
|
|
* used for serialization
|
|
@@ -319,7 +326,15 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|
} else {
|
|
} else {
|
|
postTechniqueName = "PostShadow";
|
|
postTechniqueName = "PostShadow";
|
|
}
|
|
}
|
|
|
|
+ if(zFarOverride>0 && frustumCam == null){
|
|
|
|
+ initFrustumCam();
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * delegates the initialization of the frustum cam to child renderers
|
|
|
|
+ */
|
|
|
|
+ protected abstract void initFrustumCam();
|
|
|
|
|
|
/**
|
|
/**
|
|
* Test whether this shadow renderer has been initialized.
|
|
* Test whether this shadow renderer has been initialized.
|
|
@@ -373,25 +388,25 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|
GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
|
|
GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
|
|
sceneReceivers = rq.getShadowQueueContent(ShadowMode.Receive);
|
|
sceneReceivers = rq.getShadowQueueContent(ShadowMode.Receive);
|
|
skipPostPass = false;
|
|
skipPostPass = false;
|
|
- if (sceneReceivers.size() == 0 || occluders.size() == 0) {
|
|
|
|
|
|
+ if (sceneReceivers.size() == 0 || occluders.size() == 0 || !checkCulling(viewPort.getCamera())) {
|
|
skipPostPass = true;
|
|
skipPostPass = true;
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
updateShadowCams(viewPort.getCamera());
|
|
updateShadowCams(viewPort.getCamera());
|
|
-
|
|
|
|
|
|
+
|
|
Renderer r = renderManager.getRenderer();
|
|
Renderer r = renderManager.getRenderer();
|
|
renderManager.setForcedMaterial(preshadowMat);
|
|
renderManager.setForcedMaterial(preshadowMat);
|
|
renderManager.setForcedTechnique("PreShadow");
|
|
renderManager.setForcedTechnique("PreShadow");
|
|
|
|
|
|
for (int shadowMapIndex = 0; shadowMapIndex < nbShadowMaps; shadowMapIndex++) {
|
|
for (int shadowMapIndex = 0; shadowMapIndex < nbShadowMaps; shadowMapIndex++) {
|
|
|
|
|
|
- if (debugfrustums) {
|
|
|
|
- doDisplayFrustumDebug(shadowMapIndex);
|
|
|
|
- }
|
|
|
|
- renderShadowMap(shadowMapIndex, occluders, sceneReceivers);
|
|
|
|
|
|
+ if (debugfrustums) {
|
|
|
|
+ doDisplayFrustumDebug(shadowMapIndex);
|
|
|
|
+ }
|
|
|
|
+ renderShadowMap(shadowMapIndex, occluders, sceneReceivers);
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
|
|
debugfrustums = false;
|
|
debugfrustums = false;
|
|
if (flushQueues) {
|
|
if (flushQueues) {
|
|
@@ -402,7 +417,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|
renderManager.setForcedMaterial(null);
|
|
renderManager.setForcedMaterial(null);
|
|
renderManager.setForcedTechnique(null);
|
|
renderManager.setForcedTechnique(null);
|
|
renderManager.setCamera(viewPort.getCamera(), false);
|
|
renderManager.setCamera(viewPort.getCamera(), false);
|
|
-
|
|
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
protected void renderShadowMap(int shadowMapIndex, GeometryList occluders, GeometryList receivers) {
|
|
protected void renderShadowMap(int shadowMapIndex, GeometryList occluders, GeometryList receivers) {
|
|
@@ -512,6 +527,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|
for (int j = 1; j < nbShadowMaps; j++) {
|
|
for (int j = 1; j < nbShadowMaps; j++) {
|
|
mat.clearParam(shadowMapStringCache[j]);
|
|
mat.clearParam(shadowMapStringCache[j]);
|
|
}
|
|
}
|
|
|
|
+ mat.clearParam("FadeInfo");
|
|
clearMaterialParameters(mat);
|
|
clearMaterialParameters(mat);
|
|
}
|
|
}
|
|
//No need to clear the postShadowMat params as the instance is locale to each renderer
|
|
//No need to clear the postShadowMat params as the instance is locale to each renderer
|
|
@@ -559,7 +575,9 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|
mat.setInt("FilterMode", edgeFilteringMode.getMaterialParamValue());
|
|
mat.setInt("FilterMode", edgeFilteringMode.getMaterialParamValue());
|
|
mat.setFloat("PCFEdge", edgesThickness);
|
|
mat.setFloat("PCFEdge", edgesThickness);
|
|
mat.setFloat("ShadowIntensity", shadowIntensity);
|
|
mat.setFloat("ShadowIntensity", shadowIntensity);
|
|
-
|
|
|
|
|
|
+ if (fadeInfo != null) {
|
|
|
|
+ mat.setVector2("FadeInfo", fadeInfo);
|
|
|
|
+ }
|
|
setMaterialParameters(mat);
|
|
setMaterialParameters(mat);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -580,9 +598,86 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable
|
|
postshadowMat.setMatrix4(lightViewStringCache[j], lightViewProjectionsMatrices[j]);
|
|
postshadowMat.setMatrix4(lightViewStringCache[j], lightViewProjectionsMatrices[j]);
|
|
postshadowMat.setTexture(shadowMapStringCache[j], shadowMaps[j]);
|
|
postshadowMat.setTexture(shadowMapStringCache[j], shadowMaps[j]);
|
|
}
|
|
}
|
|
|
|
+ if (fadeInfo != null) {
|
|
|
|
+ postshadowMat.setVector2("FadeInfo", fadeInfo);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * How far the shadows are rendered in the view
|
|
|
|
+ *
|
|
|
|
+ * @see #setShadowZExtend(float zFar)
|
|
|
|
+ * @return shadowZExtend
|
|
|
|
+ */
|
|
|
|
+ public float getShadowZExtend() {
|
|
|
|
+ return zFarOverride;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Set the distance from the eye where the shadows will be rendered default
|
|
|
|
+ * value is dynamicaly computed to the shadow casters/receivers union bound
|
|
|
|
+ * zFar, capped to view frustum far value.
|
|
|
|
+ *
|
|
|
|
+ * @param zFar the zFar values that override the computed one
|
|
|
|
+ */
|
|
|
|
+ public void setShadowZExtend(float zFar) {
|
|
|
|
+ this.zFarOverride = zFar;
|
|
|
|
+ if(zFarOverride == 0){
|
|
|
|
+ fadeInfo = null;
|
|
|
|
+ frustumCam = null;
|
|
|
|
+ }else{
|
|
|
|
+ if (fadeInfo != null) {
|
|
|
|
+ fadeInfo.set(zFarOverride - fadeLength, 1f / fadeLength);
|
|
|
|
+ }
|
|
|
|
+ if(frustumCam == null && viewPort != null){
|
|
|
|
+ initFrustumCam();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Define the length over which the shadow will fade out when using a
|
|
|
|
+ * shadowZextend This is useful to make dynamic shadows fade into baked
|
|
|
|
+ * shadows in the distance.
|
|
|
|
+ *
|
|
|
|
+ * @param length the fade length in world units
|
|
|
|
+ */
|
|
|
|
+ public void setShadowZFadeLength(float length) {
|
|
|
|
+ if (length == 0) {
|
|
|
|
+ fadeInfo = null;
|
|
|
|
+ fadeLength = 0;
|
|
|
|
+ postshadowMat.clearParam("FadeInfo");
|
|
|
|
+ } else {
|
|
|
|
+ if (zFarOverride == 0) {
|
|
|
|
+ fadeInfo = new Vector2f(0, 0);
|
|
|
|
+ } else {
|
|
|
|
+ fadeInfo = new Vector2f(zFarOverride - length, 1.0f / length);
|
|
|
|
+ }
|
|
|
|
+ fadeLength = length;
|
|
|
|
+ postshadowMat.setVector2("FadeInfo", fadeInfo);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * get the length over which the shadow will fade out when using a
|
|
|
|
+ * shadowZextend
|
|
|
|
+ *
|
|
|
|
+ * @return the fade length in world units
|
|
|
|
+ */
|
|
|
|
+ public float getShadowZFadeLength() {
|
|
|
|
+ if (fadeInfo != null) {
|
|
|
|
+ return zFarOverride - fadeInfo.x;
|
|
|
|
+ }
|
|
|
|
+ return 0f;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * returns true if the light source bounding box is in the view frustum
|
|
|
|
+ * @return
|
|
|
|
+ */
|
|
|
|
+ protected abstract boolean checkCulling(Camera viewCam);
|
|
|
|
|
|
- public void preFrame(float tpf) {
|
|
|
|
|
|
+ public void preFrame(float tpf) {
|
|
}
|
|
}
|
|
|
|
|
|
public void cleanup() {
|
|
public void cleanup() {
|