Implemented stable shadows for DirectionalLightShadowRenderer
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10515 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
107b3f2b88
commit
b5014c5fbc
@ -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…
x
Reference in New Issue
Block a user