Implemented stable shadows for DirectionalLightShadowRenderer

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10515 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 12 years ago
parent 107b3f2b88
commit b5014c5fbc
  1. 5
      engine/src/core/com/jme3/shadow/BasicShadowRenderer.java
  2. 19
      engine/src/core/com/jme3/shadow/DirectionalLightShadowFilter.java
  3. 25
      engine/src/core/com/jme3/shadow/DirectionalLightShadowRenderer.java
  4. 2
      engine/src/core/com/jme3/shadow/PssmShadowRenderer.java
  5. 143
      engine/src/core/com/jme3/shadow/ShadowUtil.java
  6. 31
      engine/src/test/jme3test/light/TestDirectionalLightShadow.java
  7. 26
      engine/src/test/jme3test/light/TestPointLightShadows.java
  8. 68
      engine/src/test/jme3test/light/TestTransparentShadow.java

@ -69,6 +69,7 @@ public class BasicShadowRenderer implements SceneProcessor {
private Vector3f[] points = new Vector3f[8];
private Vector3f direction = new Vector3f();
protected Texture2D dummyTex;
private float shadowMapSize;
/**
* Creates a BasicShadowRenderer
@ -84,7 +85,7 @@ public class BasicShadowRenderer implements SceneProcessor {
//DO NOT COMMENT THIS (it prevent the OSX incomplete read buffer crash)
dummyTex = new Texture2D(size, size, Format.RGBA8);
shadowFB.setColorTexture(dummyTex);
shadowMapSize = (float)size;
preshadowMat = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");
postshadowMat = new Material(manager, "Common/MatDefs/Shadow/BasicPostShadow.j3md");
postshadowMat.setTexture("ShadowMap", shadowMap);
@ -177,7 +178,7 @@ public class BasicShadowRenderer implements SceneProcessor {
shadowCam.updateViewProjection();
// render shadow casters to shadow map
ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points);
ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, shadowMapSize);
Renderer r = renderManager.getRenderer();
renderManager.setCamera(shadowCam, false);

@ -37,7 +37,6 @@ import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import java.io.IOException;
/**
@ -155,6 +154,24 @@ public class DirectionalLightShadowFilter extends AbstractShadowFilter<Direction
public float getShadowZFadeLength() {
return shadowRenderer.getShadowZFadeLength();
}
/**
* retruns true if stabilization is enabled
* @return
*/
public boolean isEnabledStabilization() {
return shadowRenderer.isEnabledStabilization();
}
/**
* Enables the stabilization of the shadows's edges. (default is true)
* This prevents shadows' edges to flicker when the camera moves
* However it can lead to some shadow quality loss in some particular scenes.
* @param stabilize
*/
public void setEnabledStabilization(boolean stabilize) {
shadowRenderer.setEnabledStabilization(stabilize);
}
@Override
public void write(JmeExporter ex) throws IOException {

@ -69,6 +69,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
//Holding the info for fading shadows in the far distance
protected Vector2f fadeInfo;
protected float fadeLength;
private boolean stabilize = true;
/**
* Used for serialzation use
@ -166,15 +167,15 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
}
}
@Override
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders) {
// update frustum points based on current camera and split
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], 1.0f, points);
//Updating shadow cam with curent split frustra
ShadowUtil.updateShadowCamera(sceneOccluders, sceneReceivers, shadowCam, points, shadowMapOccluders);
//Updating shadow cam with curent split frustra
ShadowUtil.updateShadowCamera(sceneOccluders, sceneReceivers, shadowCam, points, shadowMapOccluders, stabilize?shadowMapSize:0);
return shadowMapOccluders;
}
@ -283,6 +284,24 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
return 0f;
}
/**
* retruns true if stabilization is enabled
* @return
*/
public boolean isEnabledStabilization() {
return stabilize;
}
/**
* Enables the stabilization of the shadows's edges. (default is true)
* This prevents shadows' edges to flicker when the camera moves
* However it can lead to some shadow quality loss in some particular scenes.
* @param stabilize
*/
public void setEnabledStabilization(boolean stabilize) {
this.stabilize = stabilize;
}
@Override
public void read(JmeImporter im) throws IOException {
super.read(im);

@ -437,7 +437,7 @@ public class PssmShadowRenderer implements SceneProcessor {
ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], 1.0f, points);
//Updating shadow cam with curent split frustra
ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, splitOccluders);
ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, splitOccluders, shadowMapSize);
//saving light view projection matrix for this split
lightViewProjectionsMatrices[i].set(shadowCam.getViewProjectionMatrix());

@ -33,6 +33,7 @@ package com.jme3.shadow;
import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingVolume;
import com.jme3.math.FastMath;
import com.jme3.math.Matrix4f;
import com.jme3.math.Transform;
import com.jme3.math.Vector2f;
@ -44,7 +45,6 @@ import com.jme3.util.TempVars;
import static java.lang.Math.max;
import static java.lang.Math.min;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
@ -67,12 +67,12 @@ public class ShadowUtil {
public static void updateFrustumPoints2(Camera viewCam, Vector3f[] points) {
int w = viewCam.getWidth();
int h = viewCam.getHeight();
points[0].set(viewCam.getWorldCoordinates(new Vector2f(0, 0), 0));
points[1].set(viewCam.getWorldCoordinates(new Vector2f(0, h), 0));
points[2].set(viewCam.getWorldCoordinates(new Vector2f(w, h), 0));
points[3].set(viewCam.getWorldCoordinates(new Vector2f(w, 0), 0));
points[4].set(viewCam.getWorldCoordinates(new Vector2f(0, 0), 1));
points[5].set(viewCam.getWorldCoordinates(new Vector2f(0, h), 1));
points[6].set(viewCam.getWorldCoordinates(new Vector2f(w, h), 1));
@ -95,23 +95,23 @@ public class ShadowUtil {
float farOverride,
float scale,
Vector3f[] points) {
Vector3f pos = viewCam.getLocation();
Vector3f dir = viewCam.getDirection();
Vector3f up = viewCam.getUp();
float depthHeightRatio = viewCam.getFrustumTop() / viewCam.getFrustumNear();
float near = nearOverride;
float far = farOverride;
float ftop = viewCam.getFrustumTop();
float fright = viewCam.getFrustumRight();
float ratio = fright / ftop;
float near_height;
float near_width;
float far_height;
float far_width;
if (viewCam.isParallelProjection()) {
near_height = ftop;
near_width = near_height * ratio;
@ -123,30 +123,30 @@ public class ShadowUtil {
far_height = depthHeightRatio * far;
far_width = far_height * ratio;
}
Vector3f right = dir.cross(up).normalizeLocal();
Vector3f temp = new Vector3f();
temp.set(dir).multLocal(far).addLocal(pos);
Vector3f farCenter = temp.clone();
temp.set(dir).multLocal(near).addLocal(pos);
Vector3f nearCenter = temp.clone();
Vector3f nearUp = temp.set(up).multLocal(near_height).clone();
Vector3f farUp = temp.set(up).multLocal(far_height).clone();
Vector3f nearRight = temp.set(right).multLocal(near_width).clone();
Vector3f farRight = temp.set(right).multLocal(far_width).clone();
points[0].set(nearCenter).subtractLocal(nearUp).subtractLocal(nearRight);
points[1].set(nearCenter).addLocal(nearUp).subtractLocal(nearRight);
points[2].set(nearCenter).addLocal(nearUp).addLocal(nearRight);
points[3].set(nearCenter).subtractLocal(nearUp).addLocal(nearRight);
points[4].set(farCenter).subtractLocal(farUp).subtractLocal(farRight);
points[5].set(farCenter).addLocal(farUp).subtractLocal(farRight);
points[6].set(farCenter).addLocal(farUp).addLocal(farRight);
points[7].set(farCenter).subtractLocal(farUp).addLocal(farRight);
if (scale != 1.0f) {
// find center of frustum
Vector3f center = new Vector3f();
@ -154,7 +154,7 @@ public class ShadowUtil {
center.addLocal(points[i]);
}
center.divideLocal(8f);
Vector3f cDir = new Vector3f();
for (int i = 0; i < 8; i++) {
cDir.set(points[i]).subtractLocal(center);
@ -231,7 +231,7 @@ public class ShadowUtil {
Vector3f temp = new Vector3f();
for (int i = 0; i < pts.length; i++) {
transform.transformVector(pts[i], temp);
min.minLocal(temp);
max.maxLocal(temp);
}
@ -251,15 +251,15 @@ public class ShadowUtil {
Vector3f max = new Vector3f(Vector3f.NEGATIVE_INFINITY);
TempVars vars = TempVars.get();
Vector3f temp = vars.vect1;
for (int i = 0; i < pts.length; i++) {
float w = mat.multProj(pts[i], temp);
temp.x /= w;
temp.y /= w;
// Why was this commented out?
temp.z /= w;
min.minLocal(temp);
max.maxLocal(temp);
}
@ -280,20 +280,20 @@ public class ShadowUtil {
public static void updateShadowCamera(Camera shadowCam, Vector3f[] points) {
boolean ortho = shadowCam.isParallelProjection();
shadowCam.setProjectionMatrix(null);
if (ortho) {
shadowCam.setFrustum(-1, 1, -1, 1, 1, -1);
} else {
shadowCam.setFrustumPerspective(45, 1, 1, 150);
}
Matrix4f viewProjMatrix = shadowCam.getViewProjectionMatrix();
Matrix4f projMatrix = shadowCam.getProjectionMatrix();
BoundingBox splitBB = computeBoundForPoints(points, viewProjMatrix);
TempVars vars = TempVars.get();
Vector3f splitMin = splitBB.getMin(vars.vect1);
Vector3f splitMax = splitBB.getMax(vars.vect2);
@ -302,25 +302,25 @@ public class ShadowUtil {
// Create the crop matrix.
float scaleX, scaleY, scaleZ;
float offsetX, offsetY, offsetZ;
scaleX = 2.0f / (splitMax.x - splitMin.x);
scaleY = 2.0f / (splitMax.y - splitMin.y);
offsetX = -0.5f * (splitMax.x + splitMin.x) * scaleX;
offsetY = -0.5f * (splitMax.y + splitMin.y) * scaleY;
scaleZ = 1.0f / (splitMax.z - splitMin.z);
offsetZ = -splitMin.z * scaleZ;
Matrix4f cropMatrix = vars.tempMat4;
cropMatrix.set(scaleX, 0f, 0f, offsetX,
0f, scaleY, 0f, offsetY,
0f, 0f, scaleZ, offsetZ,
0f, 0f, 0f, 1f);
Matrix4f result = new Matrix4f();
result.set(cropMatrix);
result.multLocal(projMatrix);
vars.release();
shadowCam.setProjectionMatrix(result);
}
@ -337,8 +337,9 @@ public class ShadowUtil {
public static void updateShadowCamera(GeometryList occluders,
GeometryList receivers,
Camera shadowCam,
Vector3f[] points) {
updateShadowCamera(occluders, receivers, shadowCam, points, null);
Vector3f[] points,
float shadowMapSize) {
updateShadowCamera(occluders, receivers, shadowCam, points, null, shadowMapSize);
}
/**
@ -353,40 +354,41 @@ public class ShadowUtil {
GeometryList receivers,
Camera shadowCam,
Vector3f[] points,
GeometryList splitOccluders) {
GeometryList splitOccluders,
float shadowMapSize) {
boolean ortho = shadowCam.isParallelProjection();
shadowCam.setProjectionMatrix(null);
if (ortho) {
shadowCam.setFrustum(-1, 1, -1, 1, 1, -1);
}
// create transform to rotate points to viewspace
Matrix4f viewProjMatrix = shadowCam.getViewProjectionMatrix();
BoundingBox splitBB = computeBoundForPoints(points, viewProjMatrix);
ArrayList<BoundingVolume> visRecvList = new ArrayList<BoundingVolume>();
for (int i = 0; i < receivers.size(); i++) {
// convert bounding box to light's viewproj space
Geometry receiver = receivers.get(i);
BoundingVolume bv = receiver.getWorldBound();
BoundingVolume recvBox = bv.transform(viewProjMatrix, null);
if (splitBB.intersects(recvBox)) {
visRecvList.add(recvBox);
}
}
ArrayList<BoundingVolume> visOccList = new ArrayList<BoundingVolume>();
for (int i = 0; i < occluders.size(); i++) {
// convert bounding box to light's viewproj space
Geometry occluder = occluders.get(i);
BoundingVolume bv = occluder.getWorldBound();
BoundingVolume occBox = bv.transform(viewProjMatrix, null);
boolean intersects = splitBB.intersects(occBox);
if (!intersects && occBox instanceof BoundingBox) {
BoundingBox occBB = (BoundingBox) occBox;
@ -416,7 +418,7 @@ public class ShadowUtil {
}
}
}
BoundingBox casterBB = computeUnionBound(visOccList);
BoundingBox receiverBB = computeUnionBound(visRecvList);
@ -426,18 +428,18 @@ public class ShadowUtil {
casterBB.setYExtent(casterBB.getYExtent() + 2.0f);
casterBB.setZExtent(casterBB.getZExtent() + 2.0f);
}
TempVars vars = TempVars.get();
Vector3f casterMin = casterBB.getMin(vars.vect1);
Vector3f casterMax = casterBB.getMax(vars.vect2);
Vector3f receiverMin = receiverBB.getMin(vars.vect3);
Vector3f receiverMax = receiverBB.getMax(vars.vect4);
Vector3f splitMin = splitBB.getMin(vars.vect5);
Vector3f splitMax = splitBB.getMax(vars.vect6);
splitMin.z = 0;
// if (!ortho) {
@ -445,17 +447,17 @@ public class ShadowUtil {
// }
Matrix4f projMatrix = shadowCam.getProjectionMatrix();
Vector3f cropMin = vars.vect7;
Vector3f cropMax = vars.vect8;
// IMPORTANT: Special handling for Z values
cropMin.x = max(max(casterMin.x, receiverMin.x), splitMin.x);
cropMax.x = min(min(casterMax.x, receiverMax.x), splitMax.x);
cropMin.y = max(max(casterMin.y, receiverMin.y), splitMin.y);
cropMax.y = min(min(casterMax.y, receiverMax.y), splitMax.y);
cropMin.z = min(casterMin.z, splitMin.z);
cropMax.z = min(receiverMax.z, splitMax.z);
@ -463,33 +465,52 @@ public class ShadowUtil {
// Create the crop matrix.
float scaleX, scaleY, scaleZ;
float offsetX, offsetY, offsetZ;
scaleX = (2.0f) / (cropMax.x - cropMin.x);
scaleY = (2.0f) / (cropMax.y - cropMin.y);
//Shadow map stabilization approximation from shaderX 7
//from Practical Cascaded Shadow maps adapted to PSSM
//scale stabilization
float halfTextureSize = shadowMapSize * 0.5f;
if (halfTextureSize != 0) {
float scaleQuantizer = 0.1f;
scaleX = 1.0f / FastMath.ceil(1.0f / scaleX * scaleQuantizer) * scaleQuantizer;
scaleY = 1.0f / FastMath.ceil(1.0f / scaleY * scaleQuantizer) * scaleQuantizer;
}
offsetX = -0.5f * (cropMax.x + cropMin.x) * scaleX;
offsetY = -0.5f * (cropMax.y + cropMin.y) * scaleY;
//Shadow map stabilization approximation from shaderX 7
//from Practical Cascaded Shadow maps adapted to PSSM
//offset stabilization
if (halfTextureSize != 0) {
offsetX = FastMath.ceil(offsetX * halfTextureSize) / halfTextureSize;
offsetY = FastMath.ceil(offsetY * halfTextureSize) / halfTextureSize;
}
scaleZ = 1.0f / (cropMax.z - cropMin.z);
offsetZ = -cropMin.z * scaleZ;
Matrix4f cropMatrix = vars.tempMat4;
cropMatrix.set(scaleX, 0f, 0f, offsetX,
0f, scaleY, 0f, offsetY,
0f, 0f, scaleZ, offsetZ,
0f, 0f, 0f, 1f);
Matrix4f result = new Matrix4f();
result.set(cropMatrix);
result.multLocal(projMatrix);
vars.release();
shadowCam.setProjectionMatrix(result);
}
/**
@ -514,7 +535,7 @@ public class ShadowUtil {
}
camera.setPlaneState(planeState);
}
}
/**
@ -545,6 +566,6 @@ public class ShadowUtil {
outputGeometryList.add(g);
}
}
}
}

@ -32,6 +32,7 @@
package jme3test.light;
import com.jme3.app.SimpleApplication;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
@ -59,6 +60,7 @@ import com.jme3.util.SkyFactory;
import com.jme3.util.TangentBinormalGenerator;
public class TestDirectionalLightShadow extends SimpleApplication implements ActionListener, AnalogListener {
public static final int SHADOWMAP_SIZE = 1024;
private Spatial[] obj;
private Material[] mat;
@ -135,7 +137,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
rootNode.attachChild(ground);
l = new DirectionalLight();
// l.setDirection(new Vector3f(0.5973172f, -0.16583486f, 0.7846725f).normalizeLocal());
//l.setDirection(new Vector3f(0.5973172f, -0.16583486f, 0.7846725f).normalizeLocal());
l.setDirection(new Vector3f(-1, -1, -1));
rootNode.addLight(l);
@ -161,7 +163,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
loadScene();
dlsr = new DirectionalLightShadowRenderer(assetManager, 1024, 3);
dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 3);
dlsr.setLight(l);
dlsr.setLambda(0.55f);
dlsr.setShadowIntensity(0.6f);
@ -169,7 +171,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
dlsr.displayDebug();
viewPort.addProcessor(dlsr);
dlsf = new DirectionalLightShadowFilter(assetManager, 1024, 3);
dlsf = new DirectionalLightShadowFilter(assetManager, SHADOWMAP_SIZE, 3);
dlsf.setLight(l);
dlsf.setLambda(0.55f);
dlsf.setShadowIntensity(0.6f);
@ -192,6 +194,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
inputManager.addMapping("lambdaDown", new KeyTrigger(KeyInput.KEY_J));
inputManager.addMapping("switchGroundMat", new KeyTrigger(KeyInput.KEY_M));
inputManager.addMapping("debug", new KeyTrigger(KeyInput.KEY_X));
inputManager.addMapping("stabilize", new KeyTrigger(KeyInput.KEY_B));
inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_NUMPAD8));
@ -204,14 +207,21 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
inputManager.addListener(this, "lambdaUp", "lambdaDown", "ThicknessUp", "ThicknessDown",
"switchGroundMat", "debug", "up", "down", "right", "left", "fwd", "back","pp");
"switchGroundMat", "debug", "up", "down", "right", "left", "fwd", "back", "pp","stabilize");
ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, dlsr, dlsf, guiNode, inputManager, viewPort);
inputManager.addListener(this, "Size+", "Size-");
inputManager.addMapping("Size+", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("Size-", new KeyTrigger(KeyInput.KEY_S));
inputManager.addMapping("Size+", new KeyTrigger(KeyInput.KEY_W));
inputManager.addMapping("Size-", new KeyTrigger(KeyInput.KEY_S));
shadowStabilizationText = new BitmapText(guiFont, false);
shadowStabilizationText.setSize(guiFont.getCharSet().getRenderedSize() * 0.75f);
shadowStabilizationText.setText("(b:on/off) Shadow stabilization : " + dlsr.isEnabledStabilization());
shadowStabilizationText.setLocalTranslation(10, viewPort.getCamera().getHeight() - 100, 0);
guiNode.attachChild(shadowStabilizationText);
}
private BitmapText shadowStabilizationText ;
public void onAction(String name, boolean keyPressed, float tpf) {
@ -223,7 +233,7 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
cam.setParallelProjection(true);
float aspect = (float) cam.getWidth() / cam.getHeight();
cam.setFrustum(-1000, 1000, -aspect * frustumSize, aspect * frustumSize, frustumSize, -frustumSize);
}
}
@ -242,6 +252,11 @@ public class TestDirectionalLightShadow extends SimpleApplication implements Act
dlsr.displayFrustum();
}
if (name.equals("stabilize") && keyPressed) {
dlsr.setEnabledStabilization(!dlsr.isEnabledStabilization());
dlsf.setEnabledStabilization(!dlsf.isEnabledStabilization());
shadowStabilizationText.setText("(b:on/off) Shadow stabilization : " + dlsr.isEnabledStabilization());
}
if (name.equals("switchGroundMat") && keyPressed) {
if (ground.getMaterial() == matGroundL) {

@ -46,6 +46,7 @@ import com.jme3.shadow.PointLightShadowFilter;
import com.jme3.shadow.PointLightShadowRenderer;
public class TestPointLightShadows extends SimpleApplication {
public static final int SHADOWMAP_SIZE = 512;
public static void main(String[] args) {
TestPointLightShadows app = new TestPointLightShadows();
@ -83,12 +84,12 @@ public class TestPointLightShadows extends SimpleApplication {
box.setLocalTranslation(-1f, 0.5f, -2);
plsr = new PointLightShadowRenderer(assetManager, 512);
plsr = new PointLightShadowRenderer(assetManager, SHADOWMAP_SIZE);
plsr.setLight((PointLight) scene.getLocalLightList().get(0));
plsr.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
// plsr.setFlushQueues(false);
// plsr.displayDebug();
plsr.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
// plsr.setFlushQueues(false);
//plsr.displayFrustum();
plsr.displayDebug();
viewPort.addProcessor(plsr);
@ -96,7 +97,7 @@ public class TestPointLightShadows extends SimpleApplication {
// pl.setPosition(new Vector3f(0, 0.5f, 0));
// pl.setRadius(5);
// rootNode.addLight(pl);
//
// Geometry lightMdl2 = new Geometry("Light2", new Sphere(10, 10, 0.1f));
// //Geometry lightMdl = new Geometry("Light", new Box(.1f,.1f,.1f));
// lightMdl2.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));
@ -104,26 +105,27 @@ public class TestPointLightShadows extends SimpleApplication {
// rootNode.attachChild(lightMdl2);
// lightMdl2.setLocalTranslation(pl.getPosition());
// PointLightShadowRenderer plsr2 = new PointLightShadowRenderer(assetManager, 512);
// plsr2.setShadowIntensity(0.3f);
// plsr2.setLight(pl);
// plsr2.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
// plsr2.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
// // plsr.displayDebug();
// viewPort.addProcessor(plsr2);
plsf = new PointLightShadowFilter(assetManager, 512);
plsf.setLight((PointLight) scene.getLocalLightList().get(0));
plsf.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
plsf = new PointLightShadowFilter(assetManager, SHADOWMAP_SIZE);
plsf.setLight((PointLight) scene.getLocalLightList().get(0));
plsf.setEdgeFilteringMode(EdgeFilteringMode.PCF4);
plsf.setEnabled(false);
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
fpp.addFilter(plsf);
viewPort.addProcessor(fpp);
ShadowTestUIManager uiMan = new ShadowTestUIManager(assetManager, plsr, plsf, guiNode, inputManager, viewPort);
}
@Override
public void simpleUpdate(float tpf) {
// lightNode.move(FastMath.cos(tpf) * 0.4f, 0, FastMath.sin(tpf) * 0.4f);
// lightNode.move(FastMath.cos(tpf) * 0.4f, 0, FastMath.sin(tpf) * 0.4f);
}
}

@ -29,12 +29,14 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jme3test.light;
import com.jme3.app.SimpleApplication;
import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
@ -45,9 +47,9 @@ import com.jme3.scene.Geometry;
import com.jme3.scene.Spatial;
import com.jme3.scene.shape.Quad;
import com.jme3.scene.shape.Sphere;
import com.jme3.shadow.PssmShadowRenderer;
import com.jme3.shadow.PssmShadowRenderer.CompareMode;
import com.jme3.shadow.PssmShadowRenderer.FilterMode;
import com.jme3.shadow.CompareMode;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import com.jme3.shadow.EdgeFilteringMode;
public class TestTransparentShadow extends SimpleApplication {
@ -69,7 +71,7 @@ public class TestTransparentShadow extends SimpleApplication {
Material mat = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
mat.setFloat("Shininess", 0);
geom.setMaterial(mat);
geom.rotate(-FastMath.HALF_PI, 0, 0);
geom.center();
geom.setShadowMode(ShadowMode.CastAndReceive);
@ -80,7 +82,7 @@ public class TestTransparentShadow extends SimpleApplication {
tree.setQueueBucket(Bucket.Transparent);
tree.setShadowMode(ShadowMode.CastAndReceive);
AmbientLight al = new AmbientLight();
al.setColor(ColorRGBA.White.mult(0.7f));
rootNode.addLight(al);
@ -90,8 +92,8 @@ public class TestTransparentShadow extends SimpleApplication {
dl1.setColor(ColorRGBA.White.mult(1.5f));
rootNode.addLight(dl1);
rootNode.attachChild(tree);
rootNode.attachChild(tree);
/** Uses Texture from jme3-test-data library! */
ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30);
Material mat_red = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
@ -99,39 +101,51 @@ public class TestTransparentShadow extends SimpleApplication {
//mat_red.getAdditionalRenderState().setDepthTest(true);
//mat_red.getAdditionalRenderState().setDepthWrite(true);
fire.setMaterial(mat_red);
fire.setImagesX(2); fire.setImagesY(2); // 2x2 texture animation
fire.setEndColor( new ColorRGBA(1f, 0f, 0f, 1f)); // red
fire.setImagesX(2);
fire.setImagesY(2); // 2x2 texture animation
fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f)); // red
fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow
fire.setInitialVelocity(new Vector3f(0, 2, 0));
fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0));
fire.setStartSize(0.6f);
fire.setEndSize(0.1f);
fire.setGravity(0, 0, 0);
fire.setLowLife(0.5f);
fire.setHighLife(1.5f);
fire.setVelocityVariation(0.3f);
fire.getParticleInfluencer().setVelocityVariation(0.3f);
fire.setLocalTranslation(1.0f, 0, 1.0f);
fire.setLocalScale(0.3f);
fire.setQueueBucket(Bucket.Translucent);
// rootNode.attachChild(fire);
// rootNode.attachChild(fire);
Material mat2 = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
Material mat2 = assetManager.loadMaterial("Common/Materials/RedColor.j3m");
Geometry ball = new Geometry("sphere", new Sphere(16, 16, 0.5f));
ball.setMaterial(mat2);
ball.setShadowMode(ShadowMode.CastAndReceive);
rootNode.attachChild(ball);
ball.setLocalTranslation(-1.0f, 1.5f, 1.0f);
PssmShadowRenderer pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 1);
pssmRenderer.setDirection(dl1.getDirection());
pssmRenderer.setLambda(0.55f);
pssmRenderer.setShadowIntensity(0.8f);
pssmRenderer.setCompareMode(CompareMode.Software);
pssmRenderer.setFilterMode(FilterMode.PCF4);
//pssmRenderer.displayDebug();
viewPort.addProcessor(pssmRenderer);
}
final DirectionalLightShadowRenderer dlsRenderer = new DirectionalLightShadowRenderer(assetManager, 1024, 1);
dlsRenderer.setLight(dl1);
dlsRenderer.setLambda(0.55f);
dlsRenderer.setShadowIntensity(0.8f);
dlsRenderer.setShadowCompareMode(CompareMode.Software);
dlsRenderer.setEdgeFilteringMode(EdgeFilteringMode.Nearest);
dlsRenderer.displayDebug();
viewPort.addProcessor(dlsRenderer);
inputManager.addMapping("stabilize", new KeyTrigger(KeyInput.KEY_B));
inputManager.addListener(new ActionListener() {
@Override
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("stabilize") && isPressed) {
dlsRenderer.setEnabledStabilization(!dlsRenderer.isEnabledStabilization()) ;
}
}
}, "stabilize");
}
}

Loading…
Cancel
Save