Compare commits
56 Commits
master
...
in-pass-sh
Author | SHA1 | Date | |
---|---|---|---|
|
dd2626c560 | ||
|
d444c28183 | ||
|
54ef6ec280 | ||
|
cbf6ffaad8 | ||
|
251511ee00 | ||
|
2e9996d498 | ||
|
5f66eeacb4 | ||
|
5b800952f0 | ||
|
caad16626e | ||
|
6fb2d029d2 | ||
|
5108f52ebf | ||
|
42432ed4ea | ||
|
6487def9d3 | ||
|
e4536808ca | ||
|
fe158e7b31 | ||
|
628fa23059 | ||
|
fca6d4a8b2 | ||
|
8d125a30ba | ||
|
d50fb09efb | ||
|
59c85d58c8 | ||
|
4b4bf24127 | ||
|
0fae3839d3 | ||
|
c3cfab65c6 | ||
|
c136a4212e | ||
|
ec0fcd24d2 | ||
|
47b34c6de5 | ||
|
1e861fd2fa | ||
|
b52d0e3743 | ||
|
3889cb47b7 | ||
|
2c385914c6 | ||
|
0a4a439745 | ||
|
a3145885d9 | ||
|
5aa2c722fe | ||
|
77e552f551 | ||
|
9c4fcac876 | ||
|
d159e1746c | ||
|
8a747276d7 | ||
|
ce28e35393 | ||
|
42051b045b | ||
|
cfcec44b9a | ||
|
55e9fd067a | ||
|
f5ad0274b3 | ||
|
2ce2995956 | ||
|
4d60b2df70 | ||
|
16e472678a | ||
|
bc50b09bf4 | ||
|
134c3651c8 | ||
|
7441865307 | ||
|
88aaa079e3 | ||
|
b0316e419c | ||
|
af3a0c70ce | ||
|
7a22f8c940 | ||
|
23700d5140 | ||
|
69139a1e95 | ||
|
259694605e | ||
|
406c3144d8 |
@ -59,6 +59,7 @@ public final class DefaultLightFilter implements LightFilter {
|
||||
for (Light light : processedLights) {
|
||||
light.frustumCheckNeeded = true;
|
||||
}
|
||||
processedLights.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -37,6 +37,7 @@ import com.jme3.export.*;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.shadow.next.ShadowMap;
|
||||
import com.jme3.util.TempVars;
|
||||
import java.io.IOException;
|
||||
|
||||
@ -120,6 +121,8 @@ public abstract class Light implements Savable, Cloneable {
|
||||
boolean frustumCheckNeeded = true;
|
||||
boolean intersectsFrustum = false;
|
||||
|
||||
protected ShadowMap shadowMap;
|
||||
|
||||
protected Light() {
|
||||
}
|
||||
|
||||
@ -164,6 +167,22 @@ public abstract class Light implements Savable, Cloneable {
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return the light's shadow map, or null if none was assigned.
|
||||
*/
|
||||
public ShadowMap getShadowMap() {
|
||||
return shadowMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used internally to associate the light with a shadow map
|
||||
*
|
||||
* @param shadowMap the light's shadow map
|
||||
*/
|
||||
public void setShadowMap(ShadowMap shadowMap) {
|
||||
this.shadowMap = shadowMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the light color.
|
||||
*
|
||||
|
@ -219,6 +219,18 @@ public final class LightList implements Iterable<Light>, Savable, Cloneable, Jme
|
||||
}
|
||||
}
|
||||
|
||||
public void sort(Comparator<Light> comparator) {
|
||||
if (listSize > 1) {
|
||||
if (tlist == null || tlist.length != list.length) {
|
||||
tlist = list.clone();
|
||||
} else {
|
||||
System.arraycopy(list, 0, tlist, 0, list.length);
|
||||
}
|
||||
|
||||
SortUtil.msort(tlist, list, 0, listSize - 1, comparator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a "world-space" light list, using the spatial's local-space
|
||||
* light list and its parent's world-space light list.
|
||||
|
@ -78,9 +78,9 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
private AssetKey key;
|
||||
private String name;
|
||||
private MaterialDef def;
|
||||
private ListMap<String, MatParam> paramValues = new ListMap<String, MatParam>();
|
||||
private ListMap<String, MatParam> paramValues = new ListMap<>();
|
||||
private Technique technique;
|
||||
private HashMap<String, Technique> techniques = new HashMap<String, Technique>();
|
||||
private HashMap<String, Technique> techniques = new HashMap<>();
|
||||
private RenderState additionalState = null;
|
||||
private RenderState mergedRenderState = new RenderState();
|
||||
private boolean transparent = false;
|
||||
@ -140,10 +140,12 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setKey(AssetKey key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssetKey getKey() {
|
||||
return key;
|
||||
}
|
||||
@ -197,9 +199,9 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
mat.additionalState = additionalState.clone();
|
||||
}
|
||||
mat.technique = null;
|
||||
mat.techniques = new HashMap<String, Technique>();
|
||||
mat.techniques = new HashMap<>();
|
||||
|
||||
mat.paramValues = new ListMap<String, MatParam>();
|
||||
mat.paramValues = new ListMap<>();
|
||||
for (int i = 0; i < paramValues.size(); i++) {
|
||||
Map.Entry<String, MatParam> entry = paramValues.getEntry(i);
|
||||
mat.paramValues.put(entry.getKey(), entry.getValue().clone());
|
||||
@ -866,7 +868,14 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
|
||||
private void updateRenderState(RenderManager renderManager, Renderer renderer, TechniqueDef techniqueDef) {
|
||||
if (renderManager.getForcedRenderState() != null) {
|
||||
if (techniqueDef.getForcedRenderState() != null) {
|
||||
renderer.applyRenderState(
|
||||
techniqueDef.getForcedRenderState().copyMergedTo(
|
||||
renderManager.getForcedRenderState(),
|
||||
mergedRenderState));
|
||||
} else {
|
||||
renderer.applyRenderState(renderManager.getForcedRenderState());
|
||||
}
|
||||
} else {
|
||||
if (techniqueDef.getRenderState() != null) {
|
||||
renderer.applyRenderState(techniqueDef.getRenderState().copyMergedTo(additionalState, mergedRenderState));
|
||||
@ -899,8 +908,8 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
// Get world overrides
|
||||
SafeArrayList<MatParamOverride> overrides = geometry.getWorldMatParamOverrides();
|
||||
|
||||
Shader shader = technique.makeCurrent(renderManager, overrides, null, null, rendererCaps);
|
||||
updateShaderMaterialParameters(renderer, shader, overrides, null);
|
||||
Shader shader = technique.makeCurrent(renderManager, geometry, overrides, renderManager.getForcedMatParams(), rendererCaps);
|
||||
updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams());
|
||||
renderManager.getRenderer().setShader(shader);
|
||||
}
|
||||
|
||||
@ -984,10 +993,9 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
* </ul>
|
||||
*
|
||||
* @param geometry The geometry to render
|
||||
* @param lights Presorted and filtered light list to use for rendering
|
||||
* @param renderManager The render manager requesting the rendering
|
||||
*/
|
||||
public void render(Geometry geometry, LightList lights, RenderManager renderManager) {
|
||||
public void render(Geometry geometry, RenderManager renderManager) {
|
||||
if (technique == null) {
|
||||
selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager);
|
||||
}
|
||||
@ -1007,7 +1015,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
SafeArrayList<MatParamOverride> overrides = geometry.getWorldMatParamOverrides();
|
||||
|
||||
// Select shader to use
|
||||
Shader shader = technique.makeCurrent(renderManager, overrides, renderManager.getForcedMatParams(), lights, rendererCaps);
|
||||
Shader shader = technique.makeCurrent(renderManager, geometry, overrides, renderManager.getForcedMatParams(), rendererCaps);
|
||||
|
||||
// Begin tracking which uniforms were changed by material.
|
||||
clearUniformsSetByCurrent(shader);
|
||||
@ -1016,36 +1024,13 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
renderManager.updateUniformBindings(shader);
|
||||
|
||||
// Set material parameters
|
||||
int unit = updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams());
|
||||
int nextTextureUnit = updateShaderMaterialParameters(renderer, shader, overrides, renderManager.getForcedMatParams());
|
||||
|
||||
// Clear any uniforms not changed by material.
|
||||
resetUniformsNotSetByCurrent(shader);
|
||||
|
||||
// Delegate rendering to the technique
|
||||
technique.render(renderManager, shader, geometry, lights, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@link RenderManager} to render the geometry by
|
||||
* using this material.
|
||||
*
|
||||
* Note that this version of the render method
|
||||
* does not perform light filtering.
|
||||
*
|
||||
* @param geom The geometry to render
|
||||
* @param rm The render manager requesting the rendering
|
||||
*/
|
||||
public void render(Geometry geom, RenderManager rm) {
|
||||
render(geom, geom.getWorldLightList(), rm);
|
||||
}
|
||||
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(def.getAssetName(), "material_def", null);
|
||||
oc.write(additionalState, "render_state", null);
|
||||
oc.write(transparent, "is_transparent", false);
|
||||
oc.write(name, "name", null);
|
||||
oc.writeStringSavableMap(paramValues, "parameters", null);
|
||||
technique.render(renderManager, shader, geometry, nextTextureUnit);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1056,6 +1041,17 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
"]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(JmeExporter ex) throws IOException {
|
||||
OutputCapsule oc = ex.getCapsule(this);
|
||||
oc.write(def.getAssetName(), "material_def", null);
|
||||
oc.write(additionalState, "render_state", null);
|
||||
oc.write(transparent, "is_transparent", false);
|
||||
oc.write(name, "name", null);
|
||||
oc.writeStringSavableMap(paramValues, "parameters", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(JmeImporter im) throws IOException {
|
||||
InputCapsule ic = im.getCapsule(this);
|
||||
|
||||
@ -1105,7 +1101,7 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
|
||||
}
|
||||
|
||||
def = (MaterialDef) im.getAssetManager().loadAsset(new AssetKey(defName));
|
||||
paramValues = new ListMap<String, MatParam>();
|
||||
paramValues = new ListMap<>();
|
||||
|
||||
// load the textures and update nextTexUnit
|
||||
for (Map.Entry<String, MatParam> entry : params.entrySet()) {
|
||||
|
@ -435,6 +435,9 @@ public class RenderState implements Cloneable, Savable {
|
||||
ADDITIONAL.applyColorWrite = false;
|
||||
ADDITIONAL.applyBlendMode = false;
|
||||
ADDITIONAL.applyPolyOffset = false;
|
||||
ADDITIONAL.applyStencilTest = false;
|
||||
ADDITIONAL.applyLineWidth = false;
|
||||
ADDITIONAL.applyDepthFunc = false;
|
||||
}
|
||||
boolean wireframe = false;
|
||||
boolean applyWireFrame = true;
|
||||
|
@ -133,9 +133,10 @@ public final class Technique {
|
||||
* @param rendererCaps The renderer capabilities which the shader should support.
|
||||
* @return A compatible shader.
|
||||
*/
|
||||
Shader makeCurrent(RenderManager renderManager, SafeArrayList<MatParamOverride> worldOverrides,
|
||||
Shader makeCurrent(RenderManager renderManager, Geometry geometry,
|
||||
SafeArrayList<MatParamOverride> worldOverrides,
|
||||
SafeArrayList<MatParamOverride> forcedOverrides,
|
||||
LightList lights, EnumSet<Caps> rendererCaps) {
|
||||
EnumSet<Caps> rendererCaps) {
|
||||
TechniqueDefLogic logic = def.getLogic();
|
||||
AssetManager assetManager = owner.getMaterialDef().getAssetManager();
|
||||
|
||||
@ -149,7 +150,7 @@ public final class Technique {
|
||||
applyOverrides(dynamicDefines, forcedOverrides);
|
||||
}
|
||||
|
||||
return logic.makeCurrent(assetManager, renderManager, rendererCaps, lights, dynamicDefines);
|
||||
return logic.makeCurrent(assetManager, renderManager, rendererCaps, geometry, dynamicDefines);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,9 +162,9 @@ public final class Technique {
|
||||
* @param geometry The geometry to render
|
||||
* @param lights Lights which influence the geometry.
|
||||
*/
|
||||
void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
|
||||
void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTextureUnit) {
|
||||
TechniqueDefLogic logic = def.getLogic();
|
||||
logic.render(renderManager, shader, geometry, lights, lastTexUnit);
|
||||
logic.render(renderManager, shader, geometry, lastTextureUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,17 +105,6 @@ public class TechniqueDef implements Savable, Cloneable {
|
||||
*/
|
||||
@Deprecated
|
||||
FixedPipeline,
|
||||
/**
|
||||
* Similar to {@link #SinglePass} except the type of each light is known
|
||||
* at shader compile time.
|
||||
* <p>
|
||||
* The advantage is that the shader can be much more efficient, i.e. not
|
||||
* do operations required for spot and point lights if it knows the
|
||||
* light is a directional light. The disadvantage is that the number of
|
||||
* shaders used balloons because of the variations in the number of
|
||||
* lights used by objects.
|
||||
*/
|
||||
StaticPass
|
||||
}
|
||||
|
||||
public enum ShadowMode {
|
||||
|
@ -43,11 +43,13 @@ import com.jme3.scene.Mesh;
|
||||
import com.jme3.scene.instancing.InstancedGeometry;
|
||||
import com.jme3.shader.DefineList;
|
||||
import com.jme3.shader.Shader;
|
||||
import com.jme3.shadow.next.array.ArrayShadowMap;
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class DefaultTechniqueDefLogic implements TechniqueDefLogic {
|
||||
|
||||
protected final TechniqueDef techniqueDef;
|
||||
protected final LightList filteredLightList = new LightList(null);
|
||||
|
||||
public DefaultTechniqueDefLogic(TechniqueDef techniqueDef) {
|
||||
this.techniqueDef = techniqueDef;
|
||||
@ -55,7 +57,7 @@ public class DefaultTechniqueDefLogic implements TechniqueDefLogic {
|
||||
|
||||
@Override
|
||||
public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
|
||||
EnumSet<Caps> rendererCaps, LightList lights, DefineList defines) {
|
||||
EnumSet<Caps> rendererCaps, Geometry geometry, DefineList defines) {
|
||||
return techniqueDef.getShader(assetManager, rendererCaps, defines);
|
||||
}
|
||||
|
||||
@ -71,6 +73,41 @@ public class DefaultTechniqueDefLogic implements TechniqueDefLogic {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTexUnit) {
|
||||
Renderer renderer = renderManager.getRenderer();
|
||||
renderer.setShader(shader);
|
||||
renderMeshFromGeometry(renderer, geometry);
|
||||
}
|
||||
|
||||
protected LightList getFilteredLightList(RenderManager renderManager, Geometry geom) {
|
||||
filteredLightList.clear();
|
||||
renderManager.getLightFilter().filterLights(geom, filteredLightList);
|
||||
return filteredLightList;
|
||||
}
|
||||
|
||||
protected float encodeLightType(Light light) {
|
||||
switch (light.getType()) {
|
||||
case Directional:
|
||||
return 0.125f;
|
||||
case Point:
|
||||
return 0.25f;
|
||||
case Spot:
|
||||
return 0.5f;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Invalid light type: " + light.getType());
|
||||
}
|
||||
}
|
||||
|
||||
protected float encodeLightTypeAndShadowMapIndex(Light light) {
|
||||
if (light.getShadowMap() == null) {
|
||||
return encodeLightType(light);
|
||||
} else {
|
||||
ArrayShadowMap map = (ArrayShadowMap) light.getShadowMap();
|
||||
return -(encodeLightType(light) + map.getFirstArraySlice());
|
||||
}
|
||||
}
|
||||
|
||||
protected static ColorRGBA getAmbientColor(LightList lightList, boolean removeLights, ColorRGBA ambientLightColor) {
|
||||
ambientLightColor.set(0, 0, 0, 1);
|
||||
for (int j = 0; j < lightList.size(); j++) {
|
||||
@ -85,13 +122,4 @@ public class DefaultTechniqueDefLogic implements TechniqueDefLogic {
|
||||
ambientLightColor.a = 1.0f;
|
||||
return ambientLightColor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
|
||||
Renderer renderer = renderManager.getRenderer();
|
||||
renderer.setShader(shader);
|
||||
renderMeshFromGeometry(renderer, geometry);
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
*/
|
||||
package com.jme3.material.logic;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.light.AmbientLight;
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.light.Light;
|
||||
@ -41,20 +40,16 @@ import com.jme3.light.SpotLight;
|
||||
import com.jme3.material.RenderState;
|
||||
import com.jme3.material.TechniqueDef;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.math.Vector4f;
|
||||
import com.jme3.renderer.Caps;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.shader.DefineList;
|
||||
import com.jme3.shader.Shader;
|
||||
import com.jme3.shader.Uniform;
|
||||
import com.jme3.shader.VarType;
|
||||
import com.jme3.util.TempVars;
|
||||
import java.util.EnumSet;
|
||||
|
||||
public final class MultiPassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
|
||||
@ -73,7 +68,7 @@ public final class MultiPassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTexUnit) {
|
||||
Renderer r = renderManager.getRenderer();
|
||||
Uniform lightDir = shader.getUniform("g_LightDirection");
|
||||
Uniform lightColor = shader.getUniform("g_LightColor");
|
||||
@ -82,6 +77,7 @@ public final class MultiPassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
boolean isFirstLight = true;
|
||||
boolean isSecondLight = false;
|
||||
|
||||
LightList lights = getFilteredLightList(renderManager, geometry);
|
||||
getAmbientColor(lights, false, ambientLightColor);
|
||||
|
||||
for (int i = 0; i < lights.size(); i++) {
|
||||
|
@ -34,13 +34,19 @@ package com.jme3.material.logic;
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.bounding.BoundingSphere;
|
||||
import com.jme3.light.*;
|
||||
import static com.jme3.light.Light.Type.Directional;
|
||||
import static com.jme3.light.Light.Type.Spot;
|
||||
import com.jme3.material.*;
|
||||
import com.jme3.material.RenderState.BlendMode;
|
||||
import com.jme3.math.*;
|
||||
import com.jme3.renderer.*;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.shader.*;
|
||||
import com.jme3.util.TempVars;
|
||||
import com.jme3.shadow.next.array.ArrayShadowMap;
|
||||
import com.jme3.shadow.next.array.ArrayShadowMapSlice;
|
||||
import com.jme3.shadow.next.array.DirectionalArrayShadowMap;
|
||||
import com.jme3.texture.TextureArray;
|
||||
import java.util.Comparator;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -48,10 +54,16 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
||||
|
||||
private static final String DEFINE_SINGLE_PASS_LIGHTING = "SINGLE_PASS_LIGHTING";
|
||||
private static final String DEFINE_NB_LIGHTS = "NB_LIGHTS";
|
||||
private static final String DEFINE_NB_PROBES = "NB_PROBES";
|
||||
private static final String DEFINE_INDIRECT_LIGHTING = "INDIRECT_LIGHTING";
|
||||
private static final String DEFINE_IN_PASS_SHADOWS = "IN_PASS_SHADOWS";
|
||||
private static final String DEFINE_NUM_PSSM_SPLITS = "NUM_PSSM_SPLITS";
|
||||
private static final RenderState ADDITIVE_LIGHT = new RenderState();
|
||||
|
||||
private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
|
||||
private TextureArray shadowMapArray;
|
||||
private Vector3f pssmSplitsPositions;
|
||||
private int numPssmSplits;
|
||||
private static final String DEFINE_NB_PROBES = "NB_PROBES";
|
||||
private List<LightProbe> lightProbes = new ArrayList<>(3);
|
||||
|
||||
static {
|
||||
@ -60,33 +72,79 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
||||
}
|
||||
|
||||
private final int singlePassLightingDefineId;
|
||||
private final int inPassShadowsDefineId;
|
||||
private final int nbLightsDefineId;
|
||||
private final int numPssmSplitsDefineId;
|
||||
private final int nbProbesDefineId;
|
||||
|
||||
public SinglePassAndImageBasedLightingLogic(TechniqueDef techniqueDef) {
|
||||
super(techniqueDef);
|
||||
numPssmSplitsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_PSSM_SPLITS, VarType.Int);
|
||||
singlePassLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_SINGLE_PASS_LIGHTING, VarType.Boolean);
|
||||
nbLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_LIGHTS, VarType.Int);
|
||||
inPassShadowsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_IN_PASS_SHADOWS, VarType.Boolean);
|
||||
nbProbesDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NB_PROBES, VarType.Int);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
|
||||
EnumSet<Caps> rendererCaps, LightList lights, DefineList defines) {
|
||||
defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
|
||||
EnumSet<Caps> rendererCaps, Geometry geometry, DefineList defines) {
|
||||
|
||||
defines.set(singlePassLightingDefineId, true);
|
||||
|
||||
// TODO: here we have a problem, this is called once before render,
|
||||
// so the define will be set for all passes (in case we have more than NB_LIGHTS lights)
|
||||
// Though the second pass should not render IBL as it is taken care of on
|
||||
// first pass like ambient light in phong lighting.
|
||||
// We cannot change the define between passes and the old technique, and
|
||||
// for some reason the code fails on mac (renders nothing).
|
||||
getFilteredLightList(renderManager, geometry);
|
||||
|
||||
//TODO here we have a problem, this is called once before render, so the define will be set for all passes (in case we have more than NB_LIGHTS lights)
|
||||
//Though the second pass should not render IBL as it is taken care of on first pass like ambient light in phong lighting.
|
||||
//We cannot change the define between passes and the old technique, and for some reason the code fails on mac (renders nothing).
|
||||
if(lights != null) {
|
||||
ambientLightColor.set(0, 0, 0, 1);
|
||||
lightProbes.clear();
|
||||
extractIndirectLights(lights, false);
|
||||
defines.set(nbProbesDefineId, lightProbes.size());
|
||||
}
|
||||
pssmSplitsPositions = null;
|
||||
numPssmSplits = 0;
|
||||
|
||||
return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
|
||||
for (int i = 0; i < filteredLightList.size(); i++) {
|
||||
Light light = filteredLightList.get(i);
|
||||
if (light instanceof AmbientLight) {
|
||||
ambientLightColor.addLocal(light.getColor());
|
||||
filteredLightList.remove(i--);
|
||||
} else if (light instanceof LightProbe) {
|
||||
lightProbes.add((LightProbe) light);
|
||||
filteredLightList.remove(i--);
|
||||
} else if (light.getShadowMap() != null) {
|
||||
ArrayShadowMap shadowMap = (ArrayShadowMap) light.getShadowMap();
|
||||
shadowMapArray = shadowMap.getArray();
|
||||
if (light.getType() == Light.Type.Directional) {
|
||||
numPssmSplits = shadowMap.getNumSlices();
|
||||
pssmSplitsPositions = ((DirectionalArrayShadowMap) shadowMap).getProjectionSplitPositions();
|
||||
}
|
||||
}
|
||||
}
|
||||
defines.set(nbProbesDefineId, lightProbes.size());
|
||||
ambientLightColor.a = 1.0f;
|
||||
|
||||
filteredLightList.sort(new Comparator<Light>() {
|
||||
@Override
|
||||
public int compare(Light a, Light b) {
|
||||
boolean shadA = a.getShadowMap() != null;
|
||||
boolean shadB = b.getShadowMap() != null;
|
||||
if (shadA != shadB) {
|
||||
return shadA ? -1 : 1;
|
||||
} else {
|
||||
int ordA = a.getType().ordinal();
|
||||
int ordB = b.getType().ordinal();
|
||||
return ordB - ordA;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
|
||||
defines.set(inPassShadowsDefineId, shadowMapArray != null);
|
||||
defines.set(numPssmSplitsDefineId, numPssmSplits);
|
||||
|
||||
return super.makeCurrent(assetManager, renderManager, rendererCaps, geometry, defines);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -123,13 +181,11 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
||||
Uniform shCoeffs3 = shader.getUniform("g_ShCoeffs3");
|
||||
Uniform lightProbePemMap3 = shader.getUniform("g_PrefEnvMap3");
|
||||
|
||||
lightProbes.clear();
|
||||
if (startIndex != 0) {
|
||||
// apply additive blending for 2nd and future passes
|
||||
rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
|
||||
ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
|
||||
}else{
|
||||
extractIndirectLights(lightList,true);
|
||||
} else {
|
||||
ambientColor.setValue(VarType.Vector4, ambientLightColor);
|
||||
}
|
||||
|
||||
@ -150,88 +206,103 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
||||
lightProbeData.setValue(VarType.Matrix4, LightProbe.FALLBACK_MATRIX);
|
||||
}
|
||||
|
||||
Uniform shadowMatricesUniform = shader.getUniform("g_ShadowMatrices");
|
||||
shadowMatricesUniform.setMatrix4Length(numLights + numPssmSplits);
|
||||
int shadowMatrixIndex = numPssmSplits;
|
||||
int lightDataIndex = 0;
|
||||
TempVars vars = TempVars.get();
|
||||
Vector4f tmpVec = vars.vect4f1;
|
||||
int curIndex;
|
||||
int endIndex = numLights + startIndex;
|
||||
for (curIndex = startIndex; curIndex < endIndex && curIndex < lightList.size(); curIndex++) {
|
||||
int endIndex = Math.min(startIndex + numLights, lightList.size());
|
||||
|
||||
ArrayShadowMap directionalShadowMap = null;
|
||||
|
||||
Light l = lightList.get(curIndex);
|
||||
if(l.getType() == Light.Type.Ambient){
|
||||
endIndex++;
|
||||
continue;
|
||||
for (curIndex = startIndex; curIndex < endIndex; curIndex++) {
|
||||
Light light = lightList.get(curIndex);
|
||||
|
||||
if (light.getType() == Light.Type.Ambient || light.getType() == Light.Type.Probe) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
ColorRGBA color = l.getColor();
|
||||
//Color
|
||||
|
||||
if(l.getType() != Light.Type.Probe){
|
||||
lightData.setVector4InArray(color.getRed(),
|
||||
if (light.getShadowMap() != null) {
|
||||
ArrayShadowMap shadowMap = (ArrayShadowMap) light.getShadowMap();
|
||||
if (light.getType() == Directional) {
|
||||
directionalShadowMap = shadowMap;
|
||||
} else if (light.getType() == Spot) {
|
||||
for (int j = 0; j < shadowMap.getNumSlices(); j++) {
|
||||
ArrayShadowMapSlice slice = (ArrayShadowMapSlice) shadowMap.getSlice(j);
|
||||
shadowMatricesUniform.setMatrix4InArray(
|
||||
slice.getBiasedViewProjectionMatrix(),
|
||||
shadowMatrixIndex);
|
||||
shadowMatrixIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColorRGBA color = light.getColor();
|
||||
lightData.setVector4InArray(
|
||||
color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(),
|
||||
l.getType().getId(),
|
||||
lightDataIndex);
|
||||
lightDataIndex++;
|
||||
}
|
||||
encodeLightTypeAndShadowMapIndex(light),
|
||||
lightDataIndex++);
|
||||
|
||||
switch (l.getType()) {
|
||||
case Directional:
|
||||
DirectionalLight dl = (DirectionalLight) l;
|
||||
switch (light.getType()) {
|
||||
case Directional: {
|
||||
DirectionalLight dl = (DirectionalLight) light;
|
||||
Vector3f dir = dl.getDirection();
|
||||
//Data directly sent in view space to avoid a matrix mult for each pixel
|
||||
tmpVec.set(dir.getX(), dir.getY(), dir.getZ(), 0.0f);
|
||||
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), -1, lightDataIndex);
|
||||
lightDataIndex++;
|
||||
//PADDING
|
||||
lightData.setVector4InArray(0,0,0,0, lightDataIndex);
|
||||
lightDataIndex++;
|
||||
lightData.setVector4InArray(dir.getX(), dir.getY(), dir.getZ(), -1, lightDataIndex++);
|
||||
lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex++);
|
||||
break;
|
||||
case Point:
|
||||
PointLight pl = (PointLight) l;
|
||||
}
|
||||
case Point: {
|
||||
PointLight pl = (PointLight) light;
|
||||
Vector3f pos = pl.getPosition();
|
||||
float invRadius = pl.getInvRadius();
|
||||
tmpVec.set(pos.getX(), pos.getY(), pos.getZ(), 1.0f);
|
||||
|
||||
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRadius, lightDataIndex);
|
||||
lightDataIndex++;
|
||||
//PADDING
|
||||
lightData.setVector4InArray(0,0,0,0, lightDataIndex);
|
||||
lightDataIndex++;
|
||||
lightData.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRadius, lightDataIndex++);
|
||||
lightData.setVector4InArray(0, 0, 0, 0, lightDataIndex++);
|
||||
break;
|
||||
case Spot:
|
||||
SpotLight sl = (SpotLight) l;
|
||||
Vector3f pos2 = sl.getPosition();
|
||||
Vector3f dir2 = sl.getDirection();
|
||||
}
|
||||
case Spot: {
|
||||
SpotLight sl = (SpotLight) light;
|
||||
Vector3f pos = sl.getPosition();
|
||||
Vector3f dir = sl.getDirection();
|
||||
float invRange = sl.getInvSpotRange();
|
||||
float spotAngleCos = sl.getPackedAngleCos();
|
||||
tmpVec.set(pos2.getX(), pos2.getY(), pos2.getZ(), 1.0f);
|
||||
|
||||
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), invRange, lightDataIndex);
|
||||
lightDataIndex++;
|
||||
|
||||
tmpVec.set(dir2.getX(), dir2.getY(), dir2.getZ(), 0.0f);
|
||||
lightData.setVector4InArray(tmpVec.getX(), tmpVec.getY(), tmpVec.getZ(), spotAngleCos, lightDataIndex);
|
||||
lightDataIndex++;
|
||||
lightData.setVector4InArray(pos.getX(), pos.getY(), pos.getZ(), invRange, lightDataIndex++);
|
||||
lightData.setVector4InArray(dir.getX(), dir.getY(), dir.getZ(), spotAngleCos, lightDataIndex++);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unknown type of light: " + l.getType());
|
||||
throw new UnsupportedOperationException("Unknown type of light: " + light.getType());
|
||||
}
|
||||
}
|
||||
vars.release();
|
||||
|
||||
//Padding of unsued buffer space
|
||||
while(lightDataIndex < numLights * 3) {
|
||||
lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex);
|
||||
lightDataIndex++;
|
||||
// Padding of unsued buffer space
|
||||
while (lightDataIndex < numLights * 3) {
|
||||
lightData.setVector4InArray(0f, 0f, 0f, 0f, lightDataIndex++);
|
||||
}
|
||||
|
||||
if (directionalShadowMap != null) {
|
||||
for (int i = 0; i < numPssmSplits; i++) {
|
||||
ArrayShadowMapSlice slice = (ArrayShadowMapSlice) directionalShadowMap.getSlice(i);
|
||||
shadowMatricesUniform.setMatrix4InArray(slice.getBiasedViewProjectionMatrix(), i);
|
||||
}
|
||||
}
|
||||
|
||||
if (shadowMapArray != null) {
|
||||
rm.getRenderer().setTexture(lastTexUnit, shadowMapArray);
|
||||
shader.getUniform("g_ShadowMapArray").setValue(VarType.Int, lastTexUnit);
|
||||
}
|
||||
|
||||
if (pssmSplitsPositions != null) {
|
||||
shader.getUniform("g_PssmSplits").setValue(VarType.Vector3, pssmSplitsPositions);
|
||||
}
|
||||
|
||||
return curIndex;
|
||||
}
|
||||
|
||||
private int setProbeData(RenderManager rm, int lastTexUnit, Uniform lightProbeData, Uniform shCoeffs, Uniform lightProbePemMap, LightProbe lightProbe) {
|
||||
|
||||
lightProbeData.setValue(VarType.Matrix4, lightProbe.getUniformMatrix());
|
||||
//setVector4InArray(lightProbe.getPosition().x, lightProbe.getPosition().y, lightProbe.getPosition().z, 1f / area.getRadius() + lightProbe.getNbMipMaps(), 0);
|
||||
shCoeffs.setValue(VarType.Vector3Array, lightProbe.getShCoeffs());
|
||||
//assigning new texture indexes
|
||||
int pemUnit = lastTexUnit++;
|
||||
@ -241,43 +312,20 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTexUnit) {
|
||||
int nbRenderedLights = 0;
|
||||
Renderer renderer = renderManager.getRenderer();
|
||||
int batchSize = renderManager.getSinglePassLightBatchSize();
|
||||
if (lights.size() == 0) {
|
||||
updateLightListUniforms(shader, geometry, lights,batchSize, renderManager, 0, lastTexUnit);
|
||||
if (filteredLightList.size() == 0) {
|
||||
updateLightListUniforms(shader, geometry, filteredLightList,batchSize, renderManager, 0, lastTexUnit);
|
||||
renderer.setShader(shader);
|
||||
renderMeshFromGeometry(renderer, geometry);
|
||||
} else {
|
||||
while (nbRenderedLights < lights.size()) {
|
||||
nbRenderedLights = updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, nbRenderedLights, lastTexUnit);
|
||||
while (nbRenderedLights < filteredLightList.size()) {
|
||||
nbRenderedLights = updateLightListUniforms(shader, geometry, filteredLightList, batchSize, renderManager, nbRenderedLights, lastTexUnit);
|
||||
renderer.setShader(shader);
|
||||
renderMeshFromGeometry(renderer, geometry);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
protected void extractIndirectLights(LightList lightList, boolean removeLights) {
|
||||
ambientLightColor.set(0, 0, 0, 1);
|
||||
for (int j = 0; j < lightList.size(); j++) {
|
||||
Light l = lightList.get(j);
|
||||
if (l instanceof AmbientLight) {
|
||||
ambientLightColor.addLocal(l.getColor());
|
||||
if(removeLights){
|
||||
lightList.remove(l);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
if (l instanceof LightProbe) {
|
||||
lightProbes.add((LightProbe) l);
|
||||
if(removeLights){
|
||||
lightList.remove(l);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
ambientLightColor.a = 1.0f;
|
||||
}
|
||||
}
|
||||
|
@ -77,25 +77,31 @@ public final class SinglePassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
|
||||
EnumSet<Caps> rendererCaps, LightList lights, DefineList defines) {
|
||||
public Shader makeCurrent(
|
||||
AssetManager assetManager,
|
||||
RenderManager renderManager,
|
||||
EnumSet<Caps> rendererCaps,
|
||||
Geometry geometry,
|
||||
DefineList defines) {
|
||||
defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
|
||||
defines.set(singlePassLightingDefineId, true);
|
||||
return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
|
||||
return super.makeCurrent(assetManager, renderManager, rendererCaps, geometry, defines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the lights in the light list as two uniform arrays.<br/><br/> *
|
||||
* Uploads the lights in the light list as two uniform arrays.<br><br>
|
||||
*
|
||||
* <p>
|
||||
* <code>uniform vec4 g_LightColor[numLights];</code><br/> //
|
||||
* g_LightColor.rgb is the diffuse/specular color of the light.<br/> //
|
||||
* g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point, <br/> //
|
||||
* 2 = Spot. <br/> <br/>
|
||||
* <code>uniform vec4 g_LightPosition[numLights];</code><br/> //
|
||||
* g_LightPosition.xyz is the position of the light (for point lights)<br/>
|
||||
* // or the direction of the light (for directional lights).<br/> //
|
||||
* <code>uniform vec4 g_LightColor[numLights];</code><br>
|
||||
* g_LightColor.rgb is the diffuse/specular color of the light.<br>
|
||||
* g_Lightcolor.a is the type of light, 0 = Directional, 1 = Point, <br>
|
||||
* 2 = Spot. <br> <br>
|
||||
* <code>uniform vec4 g_LightPosition[numLights];</code><br>
|
||||
* g_LightPosition.xyz is the position of the light (for point lights)<br>
|
||||
* // or the direction of the light (for directional lights).<br>
|
||||
* g_LightPosition.w is the inverse radius (1/r) of the light (for
|
||||
* attenuation) <br/> </p>
|
||||
* attenuation) <br>
|
||||
* </p>
|
||||
*/
|
||||
protected int updateLightListUniforms(Shader shader, Geometry g, LightList lightList, int numLights, RenderManager rm, int startIndex) {
|
||||
if (numLights == 0) { // this shader does not do lighting, ignore.
|
||||
@ -131,7 +137,7 @@ public final class SinglePassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
lightData.setVector4InArray(color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(),
|
||||
l.getType().getId(),
|
||||
encodeLightType(l),
|
||||
lightDataIndex);
|
||||
lightDataIndex++;
|
||||
|
||||
@ -198,10 +204,11 @@ public final class SinglePassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTexUnit) {
|
||||
int nbRenderedLights = 0;
|
||||
Renderer renderer = renderManager.getRenderer();
|
||||
int batchSize = renderManager.getSinglePassLightBatchSize();
|
||||
LightList lights = getFilteredLightList(renderManager, geometry);
|
||||
if (lights.size() == 0) {
|
||||
updateLightListUniforms(shader, geometry, lights, batchSize, renderManager, 0);
|
||||
renderer.setShader(shader);
|
||||
|
@ -1,182 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2015 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.material.logic;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.light.LightList;
|
||||
import com.jme3.light.PointLight;
|
||||
import com.jme3.light.SpotLight;
|
||||
import com.jme3.material.TechniqueDef;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Matrix4f;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.Caps;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.shader.DefineList;
|
||||
import com.jme3.shader.Shader;
|
||||
import com.jme3.shader.Uniform;
|
||||
import com.jme3.shader.VarType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Rendering logic for static pass.
|
||||
*
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public final class StaticPassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
|
||||
private static final String DEFINE_NUM_DIR_LIGHTS = "NUM_DIR_LIGHTS";
|
||||
private static final String DEFINE_NUM_POINT_LIGHTS = "NUM_POINT_LIGHTS";
|
||||
private static final String DEFINE_NUM_SPOT_LIGHTS = "NUM_SPOT_LIGHTS";
|
||||
|
||||
private final int numDirLightsDefineId;
|
||||
private final int numPointLightsDefineId;
|
||||
private final int numSpotLightsDefineId;
|
||||
|
||||
private final ArrayList<DirectionalLight> tempDirLights = new ArrayList<DirectionalLight>();
|
||||
private final ArrayList<PointLight> tempPointLights = new ArrayList<PointLight>();
|
||||
private final ArrayList<SpotLight> tempSpotLights = new ArrayList<SpotLight>();
|
||||
|
||||
private final ColorRGBA ambientLightColor = new ColorRGBA(0, 0, 0, 1);
|
||||
private final Vector3f tempPosition = new Vector3f();
|
||||
private final Vector3f tempDirection = new Vector3f();
|
||||
|
||||
public StaticPassLightingLogic(TechniqueDef techniqueDef) {
|
||||
super(techniqueDef);
|
||||
|
||||
numDirLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_DIR_LIGHTS, VarType.Int);
|
||||
numPointLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_POINT_LIGHTS, VarType.Int);
|
||||
numSpotLightsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_NUM_SPOT_LIGHTS, VarType.Int);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
|
||||
EnumSet<Caps> rendererCaps, LightList lights, DefineList defines) {
|
||||
|
||||
// TODO: if it ever changes that render isn't called
|
||||
// right away with the same geometry after makeCurrent, it would be
|
||||
// a problem.
|
||||
// Do a radix sort.
|
||||
tempDirLights.clear();
|
||||
tempPointLights.clear();
|
||||
tempSpotLights.clear();
|
||||
for (Light light : lights) {
|
||||
switch (light.getType()) {
|
||||
case Directional:
|
||||
tempDirLights.add((DirectionalLight) light);
|
||||
break;
|
||||
case Point:
|
||||
tempPointLights.add((PointLight) light);
|
||||
break;
|
||||
case Spot:
|
||||
tempSpotLights.add((SpotLight) light);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
defines.set(numDirLightsDefineId, tempDirLights.size());
|
||||
defines.set(numPointLightsDefineId, tempPointLights.size());
|
||||
defines.set(numSpotLightsDefineId, tempSpotLights.size());
|
||||
|
||||
return techniqueDef.getShader(assetManager, rendererCaps, defines);
|
||||
}
|
||||
|
||||
private void transformDirection(Matrix4f viewMatrix, Vector3f direction) {
|
||||
viewMatrix.multNormal(direction, direction);
|
||||
}
|
||||
|
||||
private void transformPosition(Matrix4f viewMatrix, Vector3f location) {
|
||||
viewMatrix.mult(location, location);
|
||||
}
|
||||
|
||||
private void updateLightListUniforms(Matrix4f viewMatrix, Shader shader, LightList lights) {
|
||||
Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
|
||||
ambientColor.setValue(VarType.Vector4, getAmbientColor(lights, true, ambientLightColor));
|
||||
|
||||
Uniform lightData = shader.getUniform("g_LightData");
|
||||
|
||||
int totalSize = tempDirLights.size() * 2
|
||||
+ tempPointLights.size() * 2
|
||||
+ tempSpotLights.size() * 3;
|
||||
lightData.setVector4Length(totalSize);
|
||||
|
||||
int index = 0;
|
||||
for (DirectionalLight light : tempDirLights) {
|
||||
ColorRGBA color = light.getColor();
|
||||
tempDirection.set(light.getDirection());
|
||||
transformDirection(viewMatrix, tempDirection);
|
||||
lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++);
|
||||
lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, 1f, index++);
|
||||
}
|
||||
|
||||
for (PointLight light : tempPointLights) {
|
||||
ColorRGBA color = light.getColor();
|
||||
tempPosition.set(light.getPosition());
|
||||
float invRadius = light.getInvRadius();
|
||||
transformPosition(viewMatrix, tempPosition);
|
||||
lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++);
|
||||
lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRadius, index++);
|
||||
}
|
||||
|
||||
for (SpotLight light : tempSpotLights) {
|
||||
ColorRGBA color = light.getColor();
|
||||
Vector3f pos = light.getPosition();
|
||||
Vector3f dir = light.getDirection();
|
||||
|
||||
tempPosition.set(light.getPosition());
|
||||
tempDirection.set(light.getDirection());
|
||||
transformPosition(viewMatrix, tempPosition);
|
||||
transformDirection(viewMatrix, tempDirection);
|
||||
|
||||
float invRange = light.getInvSpotRange();
|
||||
float spotAngleCos = light.getPackedAngleCos();
|
||||
lightData.setVector4InArray(color.r, color.g, color.b, 1f, index++);
|
||||
lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRange, index++);
|
||||
lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, spotAngleCos, index++);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit) {
|
||||
Renderer renderer = renderManager.getRenderer();
|
||||
Matrix4f viewMatrix = renderManager.getCurrentCamera().getViewMatrix();
|
||||
updateLightListUniforms(viewMatrix, shader, lights);
|
||||
renderer.setShader(shader);
|
||||
renderMeshFromGeometry(renderer, geometry);
|
||||
}
|
||||
|
||||
}
|
@ -32,7 +32,9 @@
|
||||
package com.jme3.material.logic;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.light.LightList;
|
||||
import com.jme3.material.MatParam;
|
||||
import com.jme3.material.RenderState;
|
||||
import com.jme3.material.TechniqueDef;
|
||||
import com.jme3.material.TechniqueDef.LightMode;
|
||||
import com.jme3.renderer.Caps;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
@ -63,11 +65,10 @@ public interface TechniqueDefLogic {
|
||||
*
|
||||
* @param assetManager The asset manager to use for loading shader source code,
|
||||
* shader nodes, and and lookup textures.
|
||||
* @param geometry The geometry being rendered
|
||||
* @param renderManager The render manager for which rendering is to be performed.
|
||||
* @param rendererCaps Renderer capabilities. The returned shader must
|
||||
* support these capabilities.
|
||||
* @param lights The lights with which the geometry shall be rendered. This
|
||||
* list must not include culled lights.
|
||||
* @param defines The define list used by the technique, any
|
||||
* {@link TechniqueDef#addShaderUnmappedDefine(java.lang.String) unmapped defines}
|
||||
* should be set here to change shader behavior.
|
||||
@ -75,7 +76,7 @@ public interface TechniqueDefLogic {
|
||||
* @return The shader to use for rendering.
|
||||
*/
|
||||
public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
|
||||
EnumSet<Caps> rendererCaps, LightList lights, DefineList defines);
|
||||
EnumSet<Caps> rendererCaps, Geometry geometry, DefineList defines);
|
||||
|
||||
/**
|
||||
* Requests that the <code>TechniqueDefLogic</code> renders the given geometry.
|
||||
@ -88,10 +89,10 @@ public interface TechniqueDefLogic {
|
||||
* can still be overriden.
|
||||
*
|
||||
* @param renderManager The render manager to perform the rendering against.
|
||||
* * @param shader The shader that was selected by this logic in
|
||||
* @param shader The shader that was selected by this logic in
|
||||
* {@link #makeCurrent(com.jme3.asset.AssetManager, com.jme3.renderer.RenderManager, java.util.EnumSet, com.jme3.shader.DefineList)}.
|
||||
* @param geometry The geometry to render
|
||||
* @param lights Lights which influence the geometry.
|
||||
* @param lastTextureUnit The last unused texture unit
|
||||
*/
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, LightList lights, int lastTexUnit);
|
||||
public void render(RenderManager renderManager, Shader shader, Geometry geometry, int lastTextureUnit);
|
||||
}
|
||||
|
@ -753,7 +753,6 @@ public final class Matrix4f implements Savable, Cloneable, java.io.Serializable
|
||||
|
||||
TempVars vars = TempVars.get();
|
||||
|
||||
|
||||
fillFloatArray(vars.matrixWrite, columnMajor);
|
||||
fb.put(vars.matrixWrite, 0, 16);
|
||||
|
||||
|
@ -60,7 +60,7 @@ public class PreDepthProcessor implements SceneProcessor {
|
||||
preDepth.getAdditionalRenderState().setPolyOffset(0, 0);
|
||||
preDepth.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Back);
|
||||
|
||||
forcedRS = new RenderState();
|
||||
forcedRS = RenderState.ADDITIONAL.clone();
|
||||
forcedRS.setDepthTest(true);
|
||||
forcedRS.setDepthWrite(false);
|
||||
}
|
||||
|
@ -84,7 +84,6 @@ public class RenderManager {
|
||||
private final SafeArrayList<MatParamOverride> forcedOverrides = new SafeArrayList<>(MatParamOverride.class);
|
||||
private int viewX, viewY, viewWidth, viewHeight;
|
||||
private final Matrix4f orthoMatrix = new Matrix4f();
|
||||
private final LightList filteredLightList = new LightList(null);
|
||||
private boolean handleTranlucentBucket = true;
|
||||
private AppProfiler prof;
|
||||
private LightFilter lightFilter = new DefaultLightFilter();
|
||||
@ -563,15 +562,6 @@ public class RenderManager {
|
||||
setWorldMatrix(geom.getWorldMatrix());
|
||||
}
|
||||
|
||||
// Perform light filtering if we have a light filter.
|
||||
LightList lightList = geom.getWorldLightList();
|
||||
|
||||
if (lightFilter != null) {
|
||||
filteredLightList.clear();
|
||||
lightFilter.filterLights(geom, filteredLightList);
|
||||
lightList = filteredLightList;
|
||||
}
|
||||
|
||||
Material material = geom.getMaterial();
|
||||
|
||||
//if forcedTechnique we try to force it for render,
|
||||
@ -588,30 +578,22 @@ public class RenderManager {
|
||||
: TechniqueDef.DEFAULT_TECHNIQUE_NAME;
|
||||
|
||||
geom.getMaterial().selectTechnique(forcedTechnique, this);
|
||||
//saving forcedRenderState for future calls
|
||||
RenderState tmpRs = forcedRenderState;
|
||||
if (geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState() != null) {
|
||||
//forcing forced technique renderState
|
||||
forcedRenderState = geom.getMaterial().getActiveTechnique().getDef().getForcedRenderState();
|
||||
}
|
||||
// use geometry's material
|
||||
material.render(geom, lightList, this);
|
||||
material.selectTechnique(previousTechniqueName, this);
|
||||
|
||||
//restoring forcedRenderState
|
||||
forcedRenderState = tmpRs;
|
||||
// use geometry's material
|
||||
material.render(geom, this);
|
||||
material.selectTechnique(previousTechniqueName, this);
|
||||
|
||||
//Reverted this part from revision 6197
|
||||
//If forcedTechnique does not exists, and forcedMaterial is not set, the geom MUST NOT be rendered
|
||||
} else if (forcedMaterial != null) {
|
||||
// use forced material
|
||||
forcedMaterial.render(geom, lightList, this);
|
||||
forcedMaterial.render(geom, this);
|
||||
}
|
||||
} else if (forcedMaterial != null) {
|
||||
// use forced material
|
||||
forcedMaterial.render(geom, lightList, this);
|
||||
forcedMaterial.render(geom, this);
|
||||
} else {
|
||||
material.render(geom, lightList, this);
|
||||
material.render(geom, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ public class GLDebugES extends GLDebug implements GL, GLFbo, GLExt {
|
||||
|
||||
@Override
|
||||
public void glGenQueries(int num, IntBuffer ids) {
|
||||
glGenQueries(num, ids);
|
||||
gl.glGenQueries(num, ids);
|
||||
checkError();
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,7 @@ public final class GLTracer implements InvocationHandler {
|
||||
noEnumArgs("glTexImage3D", 1, 3, 4, 5, 6);
|
||||
noEnumArgs("glTexSubImage2D", 1, 2, 3, 4, 5);
|
||||
noEnumArgs("glTexSubImage3D", 1, 2, 3, 4, 5, 6, 7);
|
||||
noEnumArgs("glTexImage2DMultisample", 1, 3, 4);
|
||||
noEnumArgs("glCompressedTexImage2D", 1, 3, 4, 5);
|
||||
noEnumArgs("glCompressedTexSubImage3D", 1, 2, 3, 4, 5, 6, 7);
|
||||
noEnumArgs("glDeleteTextures", 0);
|
||||
@ -101,6 +102,7 @@ public final class GLTracer implements InvocationHandler {
|
||||
noEnumArgs("glVertexAttribPointer", 0, 1, 4, 5);
|
||||
noEnumArgs("glVertexAttribDivisorARB", 0, 1);
|
||||
noEnumArgs("glDrawRangeElements", 1, 2, 3, 5);
|
||||
noEnumArgs("glDrawElementsInstancedARB", 1, 3, 4);
|
||||
noEnumArgs("glDrawArrays", 1, 2);
|
||||
noEnumArgs("glDeleteBuffers", 0);
|
||||
noEnumArgs("glBindVertexArray", 0);
|
||||
|
@ -199,10 +199,12 @@ final class TextureUtil {
|
||||
format.format,
|
||||
format.dataType,
|
||||
data);
|
||||
} else {
|
||||
} else if (data != null) {
|
||||
// For texture arrays, only upload 1 slice at a time.
|
||||
// zoffset specifies slice index, and depth is 1 to indicate
|
||||
// a single texture in the array.
|
||||
// We don't need to do this for NULL data because the
|
||||
// main texture storage was already allocated with slice == -1
|
||||
gl2.glTexSubImage3D(target,
|
||||
level, // level
|
||||
0, // xoffset
|
||||
|
@ -197,7 +197,7 @@ public class Uniform extends ShaderVariable {
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(VarType type, Object value){
|
||||
public void setValue(VarType type, Object value) {
|
||||
if (location == LOC_NOT_DEFINED) {
|
||||
return;
|
||||
}
|
||||
@ -402,8 +402,36 @@ public class Uniform extends ShaderVariable {
|
||||
updateNeeded = true;
|
||||
}
|
||||
|
||||
public void setVector4Length(int length){
|
||||
if (location == -1) {
|
||||
public void setMatrix4Length(int length) {
|
||||
if (location == LOC_NOT_DEFINED) {
|
||||
return;
|
||||
}
|
||||
|
||||
multiData = BufferUtils.ensureLargeEnough(multiData, length * 4 * 4);
|
||||
value = multiData;
|
||||
varType = VarType.Matrix4Array;
|
||||
updateNeeded = true;
|
||||
setByCurrentMaterial = true;
|
||||
}
|
||||
|
||||
public void setMatrix4InArray(Matrix4f matrix, int index) {
|
||||
if (location == LOC_NOT_DEFINED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (varType != null && varType != VarType.Matrix4Array) {
|
||||
throw new IllegalArgumentException("Expected a " + varType.name() + " value!");
|
||||
}
|
||||
|
||||
multiData.position(index * 4 * 4);
|
||||
matrix.fillFloatBuffer(multiData, true);
|
||||
multiData.rewind();
|
||||
updateNeeded = true;
|
||||
setByCurrentMaterial = true;
|
||||
}
|
||||
|
||||
public void setVector4Length(int length) {
|
||||
if (location == LOC_NOT_DEFINED) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -414,8 +442,8 @@ public class Uniform extends ShaderVariable {
|
||||
setByCurrentMaterial = true;
|
||||
}
|
||||
|
||||
public void setVector4InArray(float x, float y, float z, float w, int index){
|
||||
if (location == -1) {
|
||||
public void setVector4InArray(float x, float y, float z, float w, int index) {
|
||||
if (location == LOC_NOT_DEFINED) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ public abstract class AbstractShadowRenderer implements SceneProcessor, Savable,
|
||||
protected EdgeFilteringMode edgeFilteringMode = EdgeFilteringMode.Bilinear;
|
||||
protected CompareMode shadowCompareMode = CompareMode.Hardware;
|
||||
protected Picture[] dispPic;
|
||||
protected RenderState forcedRenderState = new RenderState();
|
||||
protected RenderState forcedRenderState = RenderState.ADDITIONAL.clone();
|
||||
protected boolean renderBackFacesShadows = true;
|
||||
protected AppProfiler prof;
|
||||
|
||||
|
@ -158,7 +158,6 @@ public class BasicShadowRenderer implements SceneProcessor {
|
||||
ShadowUtil.updateFrustumPoints(viewCam,
|
||||
viewCam.getFrustumNear(),
|
||||
viewCam.getFrustumFar(),
|
||||
1.0f,
|
||||
points);
|
||||
|
||||
Vector3f frustaCenter = new Vector3f();
|
||||
|
@ -148,7 +148,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
|
||||
|
||||
//We prevent computing the frustum points and splits with zeroed or negative near clip value
|
||||
float frustumNear = Math.max(viewCam.getFrustumNear(), 0.001f);
|
||||
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, 1.0f, points);
|
||||
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, points);
|
||||
|
||||
shadowCam.setFrustumFar(zFar);
|
||||
shadowCam.getRotation().lookAt(light.getDirection(), shadowCam.getUp());
|
||||
@ -183,7 +183,7 @@ public class DirectionalLightShadowRenderer extends AbstractShadowRenderer {
|
||||
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) {
|
||||
|
||||
// update frustum points based on current camera and split
|
||||
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], 1.0f, points);
|
||||
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], points);
|
||||
|
||||
//Updating shadow cam with current split frusta
|
||||
if (lightReceivers.size()==0) {
|
||||
|
@ -398,7 +398,7 @@ public class PssmShadowRenderer implements SceneProcessor {
|
||||
|
||||
//We prevent computing the frustum points and splits with zeroed or negative near clip value
|
||||
float frustumNear = Math.max(viewCam.getFrustumNear(), 0.001f);
|
||||
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, 1.0f, points);
|
||||
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, points);
|
||||
|
||||
//shadowCam.setDirection(direction);
|
||||
shadowCam.getRotation().lookAt(direction, shadowCam.getUp());
|
||||
@ -428,7 +428,7 @@ public class PssmShadowRenderer implements SceneProcessor {
|
||||
for (int i = 0; i < nbSplits; i++) {
|
||||
|
||||
// update frustum points based on current camera and split
|
||||
ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], 1.0f, points);
|
||||
ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], points);
|
||||
|
||||
//Updating shadow cam with current split frusta
|
||||
ShadowUtil.updateShadowCamera(viewPort, lightReceivers, shadowCam, points, splitOccluders, shadowMapSize);
|
||||
|
@ -67,15 +67,4 @@ public final class PssmShadowUtil {
|
||||
splits[0] = near;
|
||||
splits[splits.length - 1] = far;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the Zfar in the model vieuw to adjust the Zfar distance for the splits calculation
|
||||
*/
|
||||
public static float computeZFar(GeometryList occ, GeometryList recv, Camera cam) {
|
||||
Matrix4f mat = cam.getViewMatrix();
|
||||
BoundingBox bbOcc = ShadowUtil.computeUnionBound(occ, mat);
|
||||
BoundingBox bbRecv = ShadowUtil.computeUnionBound(recv, mat);
|
||||
|
||||
return min(max(bbOcc.getZExtent() - bbOcc.getCenter().z, bbRecv.getZExtent() - bbRecv.getCenter().z), cam.getFrustumFar());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -96,7 +99,6 @@ public class ShadowUtil {
|
||||
public static void updateFrustumPoints(Camera viewCam,
|
||||
float nearOverride,
|
||||
float farOverride,
|
||||
float scale,
|
||||
Vector3f[] points) {
|
||||
|
||||
Vector3f pos = viewCam.getLocation();
|
||||
@ -149,22 +151,6 @@ public class ShadowUtil {
|
||||
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();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
center.addLocal(points[i]);
|
||||
}
|
||||
center.divideLocal(8f);
|
||||
|
||||
Vector3f cDir = new Vector3f();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
cDir.set(points[i]).subtractLocal(center);
|
||||
cDir.multLocal(scale - 1.0f);
|
||||
points[i].addLocal(cDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -270,65 +256,8 @@ public class ShadowUtil {
|
||||
max.maxLocal(temp);
|
||||
}
|
||||
vars.release();
|
||||
Vector3f center = min.add(max).multLocal(0.5f);
|
||||
Vector3f extent = max.subtract(min).multLocal(0.5f);
|
||||
//Nehon 08/18/2010 : Added an offset to the extend to avoid banding artifacts when the frustum are aligned
|
||||
return new BoundingBox(center, extent.x + 2.0f, extent.y + 2.0f, extent.z + 2.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the shadow camera to properly contain the given points (which
|
||||
* contain the eye camera frustum corners)
|
||||
*
|
||||
* @param shadowCam
|
||||
* @param points
|
||||
*/
|
||||
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);
|
||||
|
||||
// splitMin.z = 0;
|
||||
|
||||
// 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);
|
||||
return new BoundingBox(min, max);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -342,7 +271,6 @@ public class ShadowUtil {
|
||||
{
|
||||
// global variables set in order not to have recursive process method with too many parameters
|
||||
Matrix4f viewProjMatrix;
|
||||
public Integer casterCount;
|
||||
BoundingBox splitBB, casterBB;
|
||||
GeometryList splitOccluders;
|
||||
TempVars vars;
|
||||
@ -350,9 +278,8 @@ public class ShadowUtil {
|
||||
public OccludersExtractor() {}
|
||||
|
||||
// initialize the global OccludersExtractor variables
|
||||
public OccludersExtractor(Matrix4f vpm, int cc, BoundingBox sBB, BoundingBox cBB, GeometryList sOCC, TempVars v) {
|
||||
public OccludersExtractor(Matrix4f vpm, BoundingBox sBB, BoundingBox cBB, GeometryList sOCC, TempVars v) {
|
||||
viewProjMatrix = vpm;
|
||||
casterCount = cc;
|
||||
splitBB = sBB;
|
||||
casterBB = cBB;
|
||||
splitOccluders = sOCC;
|
||||
@ -364,82 +291,78 @@ public class ShadowUtil {
|
||||
* The global OccludersExtractor variables need to be initialized first.
|
||||
* Variables are updated and used in {@link ShadowUtil#updateShadowCamera} at last.
|
||||
*/
|
||||
public int addOccluders(Spatial scene) {
|
||||
public void addOccluders(Spatial scene) {
|
||||
if ( scene != null ) process(scene);
|
||||
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 disappearing 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));
|
||||
if (intersectsIgnoreNearZ(splitBB, occBox)) {
|
||||
casterBB.mergeLocal(occBox);
|
||||
casterCount++;
|
||||
}
|
||||
if (splitOccluders != null) {
|
||||
splitOccluders.add(occluder);
|
||||
}
|
||||
}
|
||||
} else if (intersects) {
|
||||
casterBB.mergeLocal(occBox);
|
||||
casterCount++;
|
||||
if (splitOccluders != null) {
|
||||
splitOccluders.add(occluder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 disappearing 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);
|
||||
}
|
||||
@ -457,7 +380,7 @@ public class ShadowUtil {
|
||||
GeometryList receivers,
|
||||
Camera shadowCam,
|
||||
Vector3f[] points,
|
||||
GeometryList splitOccluders,
|
||||
GeometryList shadowCasters,
|
||||
float shadowMapSize) {
|
||||
|
||||
boolean ortho = shadowCam.isParallelProjection();
|
||||
@ -465,7 +388,7 @@ public class ShadowUtil {
|
||||
shadowCam.setProjectionMatrix(null);
|
||||
|
||||
if (ortho) {
|
||||
shadowCam.setFrustum(-shadowCam.getFrustumFar(), shadowCam.getFrustumFar(), -1, 1, 1, -1);
|
||||
shadowCam.setFrustum(-1, 1, -1, 1, 1, -1);
|
||||
}
|
||||
|
||||
// create transform to rotate points to viewspace
|
||||
@ -478,8 +401,7 @@ public class ShadowUtil {
|
||||
BoundingBox casterBB = new BoundingBox();
|
||||
BoundingBox receiverBB = new BoundingBox();
|
||||
|
||||
int casterCount = 0, receiverCount = 0;
|
||||
|
||||
if (receivers != null && receivers.size() != 0) {
|
||||
for (int i = 0; i < receivers.size(); i++) {
|
||||
// convert bounding box to light's viewproj space
|
||||
Geometry receiver = receivers.get(i);
|
||||
@ -490,24 +412,20 @@ public class ShadowUtil {
|
||||
//Nehon : prevent NaN and infinity values to screw the final bounding box
|
||||
if (!Float.isNaN(recvBox.getCenter().x) && !Float.isInfinite(recvBox.getCenter().x)) {
|
||||
receiverBB.mergeLocal(recvBox);
|
||||
receiverCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
receiverBB.setXExtent(Float.POSITIVE_INFINITY);
|
||||
receiverBB.setYExtent(Float.POSITIVE_INFINITY);
|
||||
receiverBB.setZExtent(Float.POSITIVE_INFINITY);
|
||||
}
|
||||
|
||||
// collect splitOccluders through scene recursive traverse
|
||||
OccludersExtractor occExt = new OccludersExtractor(viewProjMatrix, casterCount, splitBB, casterBB, splitOccluders, vars);
|
||||
OccludersExtractor occExt = new OccludersExtractor(viewProjMatrix, splitBB, casterBB, shadowCasters, vars);
|
||||
for (Spatial scene : viewPort.getScenes()) {
|
||||
occExt.addOccluders(scene);
|
||||
}
|
||||
casterCount = occExt.casterCount;
|
||||
|
||||
//Nehon 08/18/2010 this is to avoid shadow bleeding when the ground is set to only receive shadows
|
||||
if (casterCount != receiverCount) {
|
||||
casterBB.setXExtent(casterBB.getXExtent() + 2.0f);
|
||||
casterBB.setYExtent(casterBB.getYExtent() + 2.0f);
|
||||
casterBB.setZExtent(casterBB.getZExtent() + 2.0f);
|
||||
}
|
||||
|
||||
Vector3f casterMin = casterBB.getMin(vars.vect1);
|
||||
Vector3f casterMax = casterBB.getMax(vars.vect2);
|
||||
@ -518,27 +436,26 @@ public class ShadowUtil {
|
||||
Vector3f splitMin = splitBB.getMin(vars.vect5);
|
||||
Vector3f splitMax = splitBB.getMax(vars.vect6);
|
||||
|
||||
splitMin.z = 0;
|
||||
|
||||
// if (!ortho) {
|
||||
// shadowCam.setFrustumPerspective(45, 1, 1, splitMax.z);
|
||||
// }
|
||||
|
||||
Matrix4f projMatrix = shadowCam.getProjectionMatrix();
|
||||
|
||||
Vector3f cropMin = vars.vect7;
|
||||
Vector3f cropMax = vars.vect8;
|
||||
|
||||
if (shadowCasters.size() > 0) {
|
||||
// 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);
|
||||
|
||||
} else {
|
||||
// Set crop = split so that everything in the scene has a depth < 1.0 in light space.
|
||||
// This avoids shadowing everything when there are no casters.
|
||||
cropMin.set(splitMin);
|
||||
cropMax.set(splitMax);
|
||||
}
|
||||
|
||||
// Create the crop matrix.
|
||||
float scaleX, scaleY, scaleZ;
|
||||
|
@ -137,7 +137,7 @@ public class SpotLightShadowRenderer extends AbstractShadowRenderer {
|
||||
|
||||
//We prevent computing the frustum points and splits with zeroed or negative near clip value
|
||||
float frustumNear = Math.max(viewCam.getFrustumNear(), 0.001f);
|
||||
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, 1.0f, points);
|
||||
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, points);
|
||||
//shadowCam.setDirection(direction);
|
||||
|
||||
shadowCam.setFrustumPerspective(light.getSpotOuterAngle() * FastMath.RAD_TO_DEG * 2.0f, 1, 1f, light.getSpotRange());
|
||||
|
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.shadow.next.pssm.DirectionalShadowParameters;
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.light.Light.Type;
|
||||
import com.jme3.light.PointLight;
|
||||
import com.jme3.light.SpotLight;
|
||||
import com.jme3.material.MatParamOverride;
|
||||
import com.jme3.material.RenderState;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.post.SceneProcessor;
|
||||
import com.jme3.profile.AppProfiler;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.renderer.queue.OpaqueComparator;
|
||||
import com.jme3.renderer.queue.RenderQueue;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.shader.VarType;
|
||||
import com.jme3.shadow.next.array.DirectionalArrayShadowMap;
|
||||
import com.jme3.shadow.next.array.PointArrayShadowMap;
|
||||
import com.jme3.shadow.next.array.SpotArrayShadowMap;
|
||||
import com.jme3.texture.FrameBuffer;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.Image.Format;
|
||||
import com.jme3.texture.Texture.MagFilter;
|
||||
import com.jme3.texture.Texture.MinFilter;
|
||||
import com.jme3.texture.Texture.ShadowCompareMode;
|
||||
import com.jme3.texture.TextureArray;
|
||||
import com.jme3.texture.image.ColorSpace;
|
||||
import com.jme3.util.ListMap;
|
||||
import com.jme3.util.TempVars;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* The 4th generation of shadow mapping in jME3.
|
||||
* <p>
|
||||
* This version is primarily focused on rendering in-pass shadows, so pre-pass
|
||||
* and subsequent stages are separated.
|
||||
*
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class InPassShadowRenderer implements SceneProcessor {
|
||||
|
||||
private static final String PRE_SHADOW_TECHNIQUE_NAME = "PreShadow";
|
||||
|
||||
private RenderManager renderManager;
|
||||
private ViewPort viewPort;
|
||||
private final Vector3f[] points = new Vector3f[8];
|
||||
private final GeometryList shadowCasters = new GeometryList(new OpaqueComparator());
|
||||
private final ListMap<Light, ShadowMap> shadowedLights = new ListMap<>();
|
||||
private final RenderState prePassRenderState = RenderState.ADDITIONAL.clone();
|
||||
private final MatParamOverride pointLightOverride = new MatParamOverride(VarType.Boolean, "IsPointLight", true);
|
||||
private final TextureArray array = new TextureArray();
|
||||
|
||||
private int textureSize = 1024;
|
||||
private int nextArraySlice = 0;
|
||||
|
||||
// parameters for directional lights
|
||||
private final DirectionalShadowParameters directionalParams = new DirectionalShadowParameters();
|
||||
|
||||
public InPassShadowRenderer() {
|
||||
for (int i = 0; i < points.length; i++) {
|
||||
points[i] = new Vector3f();
|
||||
}
|
||||
|
||||
prePassRenderState.setFaceCullMode(RenderState.FaceCullMode.Back);
|
||||
prePassRenderState.setColorWrite(false);
|
||||
prePassRenderState.setDepthWrite(true);
|
||||
prePassRenderState.setDepthTest(true);
|
||||
prePassRenderState.setPolyOffset(0, 0);
|
||||
|
||||
array.setAnisotropicFilter(1);
|
||||
array.setShadowCompareMode(ShadowCompareMode.LessOrEqual);
|
||||
|
||||
array.setMagFilter(MagFilter.Bilinear);
|
||||
array.setMinFilter(MinFilter.BilinearNoMipMaps);
|
||||
}
|
||||
|
||||
public void displayDebug(AssetManager assetManager, Node guiRoot) {
|
||||
guiRoot.addControl(new ShadowDebugControl(assetManager, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(RenderManager rm, ViewPort vp) {
|
||||
this.renderManager = rm;
|
||||
this.viewPort = vp;
|
||||
}
|
||||
|
||||
public DirectionalShadowParameters directional() {
|
||||
return directionalParams;
|
||||
}
|
||||
|
||||
public void setPolyOffset(float factor, float units) {
|
||||
prePassRenderState.setPolyOffset(factor, units);
|
||||
}
|
||||
|
||||
public int getTextureSize() {
|
||||
return textureSize;
|
||||
}
|
||||
|
||||
public void setTextureSize(int textureSize) {
|
||||
// TODO: support changing texture size after shadow maps are created
|
||||
this.textureSize = textureSize;
|
||||
}
|
||||
|
||||
public TextureArray getShadowMapTexture() {
|
||||
return array;
|
||||
}
|
||||
|
||||
public void addLight(Light light) {
|
||||
if (array.getImage() == null) {
|
||||
array.setImage(new Image(
|
||||
Format.Depth32F,
|
||||
textureSize,
|
||||
textureSize,
|
||||
0,
|
||||
new ArrayList<ByteBuffer>(),
|
||||
ColorSpace.Linear));
|
||||
}
|
||||
|
||||
ShadowMap shadowMap;
|
||||
switch (light.getType()) {
|
||||
case Directional:
|
||||
shadowMap = new DirectionalArrayShadowMap(
|
||||
(DirectionalLight) light,
|
||||
array,
|
||||
nextArraySlice,
|
||||
textureSize,
|
||||
directionalParams.getNumSplits());
|
||||
break;
|
||||
case Point:
|
||||
shadowMap = new PointArrayShadowMap(
|
||||
(PointLight) light,
|
||||
array,
|
||||
nextArraySlice,
|
||||
textureSize);
|
||||
break;
|
||||
case Spot:
|
||||
shadowMap = new SpotArrayShadowMap(
|
||||
(SpotLight) light,
|
||||
array,
|
||||
nextArraySlice,
|
||||
textureSize);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
shadowedLights.put(light, shadowMap);
|
||||
nextArraySlice += shadowMap.getNumSlices();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reshape(ViewPort vp, int w, int h) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return this.viewPort != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preFrame(float tpf) {
|
||||
}
|
||||
|
||||
private void renderShadowMaps(ViewPort viewPort) {
|
||||
renderManager.setForcedRenderState(prePassRenderState);
|
||||
renderManager.setForcedTechnique(PRE_SHADOW_TECHNIQUE_NAME);
|
||||
renderManager.addForcedMatParam(pointLightOverride);
|
||||
|
||||
for (int i = 0; i < shadowedLights.size(); i++) {
|
||||
Light light = shadowedLights.getKey(i);
|
||||
ShadowMap shadowMap = shadowedLights.getValue(i);
|
||||
|
||||
TempVars vars = TempVars.get();
|
||||
try {
|
||||
light.setFrustumCheckNeeded(false);
|
||||
light.setIntersectsFrustum(light.intersectsFrustum(viewPort.getCamera(), vars));
|
||||
if (!light.isIntersectsFrustum()) {
|
||||
continue;
|
||||
}
|
||||
} finally {
|
||||
vars.release();
|
||||
}
|
||||
|
||||
pointLightOverride.setEnabled(shadowMap.getLightType() == Type.Point);
|
||||
|
||||
switch (shadowMap.getLightType()) {
|
||||
case Directional:
|
||||
DirectionalArrayShadowMap directionalShadow = (DirectionalArrayShadowMap) shadowMap;
|
||||
directionalShadow.renderShadowMap(renderManager, viewPort, directionalParams, shadowCasters, points);
|
||||
break;
|
||||
case Point:
|
||||
PointArrayShadowMap pointShadow = (PointArrayShadowMap) shadowMap;
|
||||
pointShadow.renderShadowMap(renderManager, viewPort, shadowCasters);
|
||||
break;
|
||||
case Spot:
|
||||
SpotArrayShadowMap spotShadow = (SpotArrayShadowMap) shadowMap;
|
||||
spotShadow.renderShadowMap(renderManager, viewPort, shadowCasters);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
light.setShadowMap(shadowMap);
|
||||
}
|
||||
|
||||
Renderer renderer = renderManager.getRenderer();
|
||||
renderer.setFrameBuffer(viewPort.getOutputFrameBuffer());
|
||||
renderManager.removeForcedMatParam(pointLightOverride);
|
||||
renderManager.setForcedRenderState(null);
|
||||
renderManager.setForcedTechnique(null);
|
||||
renderManager.setCamera(viewPort.getCamera(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postQueue(RenderQueue rq) {
|
||||
directionalParams.updateSplitPositions(viewPort.getCamera());
|
||||
renderShadowMaps(viewPort);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postFrame(FrameBuffer out) {
|
||||
// TODO: call discard contents on all the framebuffers.
|
||||
for (int i = 0; i < shadowedLights.size(); i++) {
|
||||
Light light = shadowedLights.getKey(i);
|
||||
light.setShadowMap(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfiler(AppProfiler profiler) {
|
||||
}
|
||||
|
||||
}
|
183
jme3-core/src/main/java/com/jme3/shadow/next/PreShadowRenderer.java
Executable file
183
jme3-core/src/main/java/com/jme3/shadow/next/PreShadowRenderer.java
Executable file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next;
|
||||
|
||||
import com.jme3.shadow.next.pssm.DirectionalShadowParameters;
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.material.RenderState;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.post.SceneProcessor;
|
||||
import com.jme3.profile.AppProfiler;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.renderer.queue.OpaqueComparator;
|
||||
import com.jme3.renderer.queue.RenderQueue;
|
||||
import com.jme3.shadow.next.pssm.DirectionalShadowMap;
|
||||
import com.jme3.texture.FrameBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The 4th generation of shadow mapping in jME3.
|
||||
* <p>
|
||||
* This version is primarily focused on rendering in-pass shadows, so pre-pass
|
||||
* and subsequent stages are separated.
|
||||
*
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class PreShadowRenderer implements SceneProcessor {
|
||||
|
||||
private static final String PRE_SHADOW_TECHNIQUE_NAME = "PreShadow";
|
||||
|
||||
private RenderManager renderManager;
|
||||
private ViewPort viewPort;
|
||||
private final Vector3f[] points = new Vector3f[8];
|
||||
private final GeometryList shadowCasters = new GeometryList(new OpaqueComparator());
|
||||
private final List<ShadowMap> shadowMaps = new ArrayList<>();
|
||||
private final RenderState prePassRenderState = RenderState.ADDITIONAL.clone();
|
||||
|
||||
private int textureSize = 1024;
|
||||
|
||||
// parameters for directional lights
|
||||
private final DirectionalShadowParameters directionalParams = new DirectionalShadowParameters();
|
||||
|
||||
public PreShadowRenderer() {
|
||||
for (int i = 0; i < points.length; i++) {
|
||||
points[i] = new Vector3f();
|
||||
}
|
||||
|
||||
prePassRenderState.setFaceCullMode(RenderState.FaceCullMode.Off);
|
||||
prePassRenderState.setColorWrite(false);
|
||||
prePassRenderState.setDepthWrite(true);
|
||||
prePassRenderState.setDepthTest(true);
|
||||
prePassRenderState.setPolyOffset(1.2f, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(RenderManager rm, ViewPort vp) {
|
||||
this.renderManager = rm;
|
||||
this.viewPort = vp;
|
||||
}
|
||||
|
||||
public DirectionalShadowParameters directional() {
|
||||
return directionalParams;
|
||||
}
|
||||
|
||||
public void setPolyOffset(float factor, float units) {
|
||||
// TODO: might want to set this separately per model
|
||||
prePassRenderState.setPolyOffset(factor, units);
|
||||
}
|
||||
|
||||
public int getTextureSize() {
|
||||
return textureSize;
|
||||
}
|
||||
|
||||
public void setTextureSize(int textureSize) {
|
||||
// TODO: support changing texture size after shadow maps are created
|
||||
this.textureSize = textureSize;
|
||||
}
|
||||
|
||||
public void addLight(Light light) {
|
||||
ShadowMap shadowMap;
|
||||
switch (light.getType()) {
|
||||
case Directional:
|
||||
shadowMap = new DirectionalShadowMap(
|
||||
(DirectionalLight) light,
|
||||
textureSize,
|
||||
directionalParams.getNumSplits(),
|
||||
points);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
light.setShadowMap(shadowMap);
|
||||
shadowMaps.add(shadowMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reshape(ViewPort vp, int w, int h) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
return this.viewPort != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preFrame(float tpf) {
|
||||
}
|
||||
|
||||
private void renderShadowMaps() {
|
||||
renderManager.setForcedRenderState(prePassRenderState);
|
||||
renderManager.setForcedTechnique(PRE_SHADOW_TECHNIQUE_NAME);
|
||||
|
||||
for (ShadowMap shadowMap : shadowMaps) {
|
||||
switch (shadowMap.getLightType()) {
|
||||
case Directional:
|
||||
DirectionalShadowMap directionalShadow = (DirectionalShadowMap) shadowMap;
|
||||
directionalShadow.renderShadowMap(renderManager, viewPort, directionalParams, shadowCasters);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
Renderer renderer = renderManager.getRenderer();
|
||||
renderer.setFrameBuffer(viewPort.getOutputFrameBuffer());
|
||||
renderManager.setForcedRenderState(null);
|
||||
renderManager.setForcedTechnique(null);
|
||||
renderManager.setCamera(viewPort.getCamera(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postQueue(RenderQueue rq) {
|
||||
directionalParams.updateSplitPositions(viewPort.getCamera());
|
||||
renderShadowMaps();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postFrame(FrameBuffer out) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfiler(AppProfiler profiler) {
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2017 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next;
|
||||
|
||||
import com.jme3.asset.AssetManager;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.scene.Node;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.scene.control.AbstractControl;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.TextureArray;
|
||||
import com.jme3.ui.Picture;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Shows the shadow maps on the screen
|
||||
*
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
final class ShadowDebugControl extends AbstractControl {
|
||||
|
||||
private final List<Picture> pictures = new ArrayList<>();
|
||||
|
||||
public ShadowDebugControl(AssetManager assetManager, InPassShadowRenderer shadowRenderer) {
|
||||
TextureArray shadowMapArray = shadowRenderer.getShadowMapTexture();
|
||||
Image shadowMap = shadowMapArray.getImage();
|
||||
for (int i = 0; i < shadowMap.getDepth(); i++) {
|
||||
Picture picture = new Picture("Shadow Map " + i);
|
||||
picture.setPosition(20, i * 128 + 20);
|
||||
picture.setWidth(128);
|
||||
picture.setHeight(128);
|
||||
|
||||
Material material = new Material(assetManager, "Common/MatDefs/Shadow/ShowShadowArray.j3md");
|
||||
material.setTexture("ShadowMapArray", shadowMapArray);
|
||||
material.setFloat("ShadowMapSlice", i);
|
||||
picture.setMaterial(material);
|
||||
|
||||
pictures.add(picture);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSpatial(Spatial spatial) {
|
||||
if (spatial != null) {
|
||||
for (Picture picture : pictures) {
|
||||
((Node) spatial).detachChild(picture);
|
||||
}
|
||||
}
|
||||
super.setSpatial(spatial);
|
||||
if (spatial != null) {
|
||||
for (Picture picture : pictures) {
|
||||
((Node) spatial).attachChild(picture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void controlUpdate(float tpf) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void controlRender(RenderManager rm, ViewPort vp) {
|
||||
}
|
||||
|
||||
}
|
50
jme3-core/src/main/java/com/jme3/shadow/next/ShadowMap.java
Executable file
50
jme3-core/src/main/java/com/jme3/shadow/next/ShadowMap.java
Executable file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next;
|
||||
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.light.Light.Type;
|
||||
|
||||
/**
|
||||
* Represents shadow information for a light.
|
||||
* @param <T> Type of light
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public interface ShadowMap<T extends Light> {
|
||||
|
||||
public Type getLightType();
|
||||
|
||||
public int getNumSlices();
|
||||
|
||||
public ShadowMapSlice<T> getSlice(int index);
|
||||
|
||||
}
|
58
jme3-core/src/main/java/com/jme3/shadow/next/ShadowMapSlice.java
Executable file
58
jme3-core/src/main/java/com/jme3/shadow/next/ShadowMapSlice.java
Executable file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next;
|
||||
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.math.Matrix4f;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
|
||||
/**
|
||||
* Represents a single slice of a shadow map.
|
||||
*
|
||||
* @param <T> Type of light
|
||||
*
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public interface ShadowMapSlice<T extends Light> {
|
||||
|
||||
public static final Matrix4f BIAS_MATRIX = new Matrix4f(
|
||||
0.5f, 0.0f, 0.0f, 0.5f,
|
||||
0.0f, 0.5f, 0.0f, 0.5f,
|
||||
0.0f, 0.0f, 0.5f, 0.5f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
public Matrix4f getBiasedViewProjectionMatrix();
|
||||
|
||||
public void renderShadowMap(RenderManager renderManager, T light, ViewPort viewPort, GeometryList shadowCasters);
|
||||
}
|
47
jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMap.java
Executable file
47
jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMap.java
Executable file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.shadow.next.ShadowMap;
|
||||
import com.jme3.texture.TextureArray;
|
||||
|
||||
/**
|
||||
* Represents shadow information for a light, uses texture arrays.
|
||||
*
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public interface ArrayShadowMap extends ShadowMap {
|
||||
|
||||
public TextureArray getArray();
|
||||
|
||||
public int getFirstArraySlice();
|
||||
}
|
41
jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMapSlice.java
Executable file
41
jme3-core/src/main/java/com/jme3/shadow/next/array/ArrayShadowMapSlice.java
Executable file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.shadow.next.ShadowMapSlice;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public interface ArrayShadowMapSlice<T extends Light> extends ShadowMapSlice<T> {
|
||||
}
|
75
jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMap.java
Executable file
75
jme3-core/src/main/java/com/jme3/shadow/next/array/BaseArrayShadowMap.java
Executable file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.texture.TextureArray;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public abstract class BaseArrayShadowMap<T extends ArrayShadowMapSlice> implements ArrayShadowMap {
|
||||
|
||||
protected final TextureArray array;
|
||||
protected final int firstArraySlice;
|
||||
protected T[] slices;
|
||||
|
||||
public BaseArrayShadowMap(TextureArray array, int firstArraySlice) {
|
||||
this.array = array;
|
||||
this.firstArraySlice = firstArraySlice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureArray getArray() {
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstArraySlice() {
|
||||
return firstArraySlice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Light.Type getLightType();
|
||||
|
||||
@Override
|
||||
public int getNumSlices() {
|
||||
return slices.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getSlice(int index) {
|
||||
return slices[index];
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.math.Matrix4f;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.texture.FrameBuffer;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.TextureArray;
|
||||
|
||||
/**
|
||||
* @param <T>
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class BaseArrayShadowMapSlice<T extends Light> implements ArrayShadowMapSlice<T> {
|
||||
|
||||
protected final FrameBuffer frameBuffer;
|
||||
protected final Camera shadowCamera;
|
||||
protected final Matrix4f biasedViewProjectionMatrix = new Matrix4f();
|
||||
|
||||
protected boolean fbNeedClear = true;
|
||||
|
||||
public BaseArrayShadowMapSlice(TextureArray array, int layer, int textureSize, boolean useBorder) {
|
||||
this.shadowCamera = new Camera(textureSize, textureSize);
|
||||
|
||||
if (useBorder) {
|
||||
float onePx = 1f / textureSize;
|
||||
this.shadowCamera.setViewPort(onePx, 1f - onePx, onePx, 1f - onePx);
|
||||
}
|
||||
|
||||
this.frameBuffer = new FrameBuffer(textureSize, textureSize, 1);
|
||||
|
||||
Image image = array.getImage();
|
||||
image.setDepth(image.getDepth() + 1);
|
||||
image.addData(null);
|
||||
|
||||
this.frameBuffer.setDepthTexture(array, layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix4f getBiasedViewProjectionMatrix() {
|
||||
return biasedViewProjectionMatrix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderShadowMap(RenderManager renderManager, Light light, ViewPort viewPort, GeometryList shadowCasters) {
|
||||
Renderer renderer = renderManager.getRenderer();
|
||||
|
||||
if (fbNeedClear) {
|
||||
renderer.setFrameBuffer(frameBuffer);
|
||||
renderer.clearClipRect();
|
||||
renderer.clearBuffers(false, true, false);
|
||||
fbNeedClear = false;
|
||||
}
|
||||
|
||||
if (shadowCasters.size() > 0) {
|
||||
renderManager.setCamera(shadowCamera, false);
|
||||
viewPort.getQueue().renderShadowQueue(shadowCasters, renderManager, shadowCamera, true);
|
||||
fbNeedClear = true;
|
||||
}
|
||||
|
||||
BIAS_MATRIX.mult(shadowCamera.getViewProjectionMatrix(), biasedViewProjectionMatrix);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.shadow.next.pssm.DirectionalShadowParameters;
|
||||
import com.jme3.texture.TextureArray;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class DirectionalArrayShadowMap extends BaseArrayShadowMap<DirectionalArrayShadowMapSlice> {
|
||||
|
||||
private final DirectionalLight light;
|
||||
private final Vector3f projectionSplitPositions = new Vector3f();
|
||||
|
||||
public DirectionalArrayShadowMap(DirectionalLight light, TextureArray array, int firstArraySlice, int textureSize, int numSplits) {
|
||||
super(array, firstArraySlice);
|
||||
this.light = light;
|
||||
this.slices = new DirectionalArrayShadowMapSlice[numSplits];
|
||||
for (int i = 0; i < numSplits; i++) {
|
||||
this.slices[i] = new DirectionalArrayShadowMapSlice(array, firstArraySlice + i, textureSize);
|
||||
}
|
||||
}
|
||||
|
||||
public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, DirectionalShadowParameters params, GeometryList shadowCasters, Vector3f[] points) {
|
||||
projectionSplitPositions.set(params.getProjectionSplitPositions());
|
||||
float[] splitPositionsViewSpace = params.getSplitPositions();
|
||||
for (int i = 0; i < slices.length; i++) {
|
||||
float near = splitPositionsViewSpace[i];
|
||||
float far = splitPositionsViewSpace[i + 1];
|
||||
shadowCasters.clear();
|
||||
slices[i].updateShadowCamera(viewPort, light, shadowCasters, near, far, points);
|
||||
slices[i].renderShadowMap(renderManager, light, viewPort, shadowCasters);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3f getProjectionSplitPositions() {
|
||||
return projectionSplitPositions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Light.Type getLightType() {
|
||||
return Light.Type.Directional;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.shadow.ShadowUtil;
|
||||
import com.jme3.texture.TextureArray;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class DirectionalArrayShadowMapSlice extends BaseArrayShadowMapSlice<DirectionalLight> {
|
||||
|
||||
public DirectionalArrayShadowMapSlice(TextureArray array, int layer, int textureSize) {
|
||||
super(array, layer, textureSize, true);
|
||||
this.shadowCamera.setParallelProjection(true);
|
||||
}
|
||||
|
||||
private static boolean isParallelToYUp(Vector3f direction) {
|
||||
return direction.x == 0 && direction.z == 0
|
||||
&& (direction.y == -1 || direction.y == 1);
|
||||
}
|
||||
|
||||
public void updateShadowCamera(
|
||||
ViewPort viewPort,
|
||||
DirectionalLight light,
|
||||
GeometryList shadowCasters,
|
||||
float near,
|
||||
float far,
|
||||
Vector3f[] points) {
|
||||
if (isParallelToYUp(light.getDirection())) {
|
||||
// direction and up cannot be parallel
|
||||
shadowCamera.lookAtDirection(light.getDirection(), Vector3f.UNIT_Z);
|
||||
} else {
|
||||
shadowCamera.lookAtDirection(light.getDirection(), Vector3f.UNIT_Y);
|
||||
}
|
||||
|
||||
int textureSize = frameBuffer.getWidth();
|
||||
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), near, far, points);
|
||||
ShadowUtil.updateShadowCamera(viewPort, null, shadowCamera, points, shadowCasters, textureSize);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2017 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.light.Light.Type;
|
||||
import com.jme3.light.PointLight;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.texture.TextureArray;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class PointArrayShadowMap extends BaseArrayShadowMap<PointArrayShadowMapSlice> {
|
||||
|
||||
private final PointLight light;
|
||||
|
||||
private static final Quaternion[] ROTATIONS = new Quaternion[6];
|
||||
|
||||
static {
|
||||
for (int i = 0; i < ROTATIONS.length; i++) {
|
||||
ROTATIONS[i] = new Quaternion();
|
||||
}
|
||||
|
||||
// left
|
||||
ROTATIONS[0].fromAxes(Vector3f.UNIT_Z, Vector3f.UNIT_Y, Vector3f.UNIT_X.mult(-1f));
|
||||
|
||||
// right
|
||||
ROTATIONS[1].fromAxes(Vector3f.UNIT_Z.mult(-1f), Vector3f.UNIT_Y, Vector3f.UNIT_X);
|
||||
|
||||
// bottom
|
||||
ROTATIONS[2].fromAxes(Vector3f.UNIT_X.mult(-1f), Vector3f.UNIT_Z.mult(-1f), Vector3f.UNIT_Y.mult(-1f));
|
||||
|
||||
// top
|
||||
ROTATIONS[3].fromAxes(Vector3f.UNIT_X.mult(-1f), Vector3f.UNIT_Z, Vector3f.UNIT_Y);
|
||||
|
||||
// forward
|
||||
ROTATIONS[4].fromAxes(Vector3f.UNIT_X.mult(-1f), Vector3f.UNIT_Y, Vector3f.UNIT_Z.mult(-1f));
|
||||
|
||||
// backward
|
||||
ROTATIONS[5].fromAxes(Vector3f.UNIT_X, Vector3f.UNIT_Y, Vector3f.UNIT_Z);
|
||||
}
|
||||
|
||||
public PointArrayShadowMap(PointLight light, TextureArray array, int firstArraySlice, int textureSize) {
|
||||
super(array, firstArraySlice);
|
||||
this.light = light;
|
||||
this.slices = new PointArrayShadowMapSlice[6];
|
||||
for (int i = 0; i < slices.length; i++) {
|
||||
this.slices[i] = new PointArrayShadowMapSlice(array, firstArraySlice + i, textureSize, ROTATIONS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, GeometryList shadowCasters) {
|
||||
for (int i = 0; i < slices.length; i++) {
|
||||
shadowCasters.clear();
|
||||
slices[i].updateShadowCamera(viewPort, light, shadowCasters);
|
||||
slices[i].renderShadowMap(renderManager, light, viewPort, shadowCasters);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Light.Type getLightType() {
|
||||
return Type.Point;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2017 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.light.PointLight;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.shadow.ShadowUtil;
|
||||
import com.jme3.texture.TextureArray;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class PointArrayShadowMapSlice extends BaseArrayShadowMapSlice<PointLight> {
|
||||
|
||||
public PointArrayShadowMapSlice(TextureArray array, int layer, int textureSize, Quaternion axes) {
|
||||
super(array, layer, textureSize, false);
|
||||
shadowCamera.setAxes(axes);
|
||||
}
|
||||
|
||||
public void updateShadowCamera(ViewPort viewPort, PointLight light, GeometryList shadowCasters) {
|
||||
shadowCamera.setFrustumPerspective(90f, 1f, 0.5f, light.getRadius());
|
||||
shadowCamera.setLocation(light.getPosition());
|
||||
for (Spatial scene : viewPort.getScenes()) {
|
||||
ShadowUtil.getGeometriesInCamFrustum(scene, shadowCamera, ShadowMode.Cast, shadowCasters);
|
||||
}
|
||||
}
|
||||
}
|
66
jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
Executable file
66
jme3-core/src/main/java/com/jme3/shadow/next/array/SpotArrayShadowMap.java
Executable file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.light.SpotLight;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.texture.TextureArray;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class SpotArrayShadowMap extends BaseArrayShadowMap<SpotArrayShadowMapSlice> {
|
||||
|
||||
private final SpotLight light;
|
||||
|
||||
public SpotArrayShadowMap(SpotLight light, TextureArray array, int firstArraySlice, int textureSize) {
|
||||
super(array, firstArraySlice);
|
||||
this.light = light;
|
||||
slices = new SpotArrayShadowMapSlice[]{
|
||||
new SpotArrayShadowMapSlice(array, firstArraySlice, textureSize)
|
||||
};
|
||||
}
|
||||
|
||||
public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, GeometryList shadowCasters) {
|
||||
shadowCasters.clear();
|
||||
slices[0].updateShadowCamera(viewPort, light, shadowCasters);
|
||||
slices[0].renderShadowMap(renderManager, light, viewPort, shadowCasters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Light.Type getLightType() {
|
||||
return Light.Type.Spot;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.array;
|
||||
|
||||
import com.jme3.light.SpotLight;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.renderer.queue.RenderQueue;
|
||||
import com.jme3.scene.Spatial;
|
||||
import com.jme3.shadow.ShadowUtil;
|
||||
import com.jme3.texture.TextureArray;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class SpotArrayShadowMapSlice extends BaseArrayShadowMapSlice<SpotLight> {
|
||||
|
||||
public SpotArrayShadowMapSlice(TextureArray array, int layer, int textureSize) {
|
||||
super(array, layer, textureSize, true);
|
||||
}
|
||||
|
||||
private static boolean isParallelToYUp(Vector3f direction) {
|
||||
return direction.x == 0 && direction.z == 0
|
||||
&& (direction.y == -1 || direction.y == 1);
|
||||
}
|
||||
|
||||
public void updateShadowCamera(ViewPort viewPort, SpotLight light, GeometryList shadowCasters) {
|
||||
shadowCamera.setLocation(light.getPosition());
|
||||
if (isParallelToYUp(light.getDirection())) {
|
||||
// direction and up cannot be parallel
|
||||
shadowCamera.lookAtDirection(light.getDirection(), Vector3f.UNIT_Z);
|
||||
} else {
|
||||
shadowCamera.lookAtDirection(light.getDirection(), Vector3f.UNIT_Y);
|
||||
}
|
||||
shadowCamera.setFrustumPerspective(light.getSpotOuterAngle() * FastMath.RAD_TO_DEG * 2.0f, 1, 1, light.getSpotRange());
|
||||
for (Spatial scene : viewPort.getScenes()) {
|
||||
ShadowUtil.getGeometriesInCamFrustum(scene, shadowCamera, RenderQueue.ShadowMode.Cast, shadowCasters);
|
||||
}
|
||||
}
|
||||
}
|
87
jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java
Executable file
87
jme3-core/src/main/java/com/jme3/shadow/next/pssm/BaseShadowMapSlice.java
Executable file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.pssm;
|
||||
|
||||
import com.jme3.light.Light;
|
||||
import com.jme3.math.Matrix4f;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.Renderer;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.texture.FrameBuffer;
|
||||
import com.jme3.texture.Image;
|
||||
import com.jme3.texture.Texture.MagFilter;
|
||||
import com.jme3.texture.Texture.MinFilter;
|
||||
import com.jme3.texture.Texture.ShadowCompareMode;
|
||||
import com.jme3.texture.Texture2D;
|
||||
import com.jme3.shadow.next.ShadowMapSlice;
|
||||
|
||||
public abstract class BaseShadowMapSlice<T extends Light> implements ShadowMapSlice<T> {
|
||||
|
||||
protected final FrameBuffer frameBuffer;
|
||||
protected final Texture2D depthTexture;
|
||||
protected final Camera shadowCamera;
|
||||
protected final Vector3f[] points;
|
||||
protected final Matrix4f biasedViewProjectionMatrix = new Matrix4f();
|
||||
|
||||
public BaseShadowMapSlice(int size, Vector3f[] points) {
|
||||
this.depthTexture = new Texture2D(size, size, Image.Format.Depth16);
|
||||
this.depthTexture.setAnisotropicFilter(1);
|
||||
this.depthTexture.setShadowCompareMode(ShadowCompareMode.LessOrEqual);
|
||||
this.depthTexture.setMagFilter(MagFilter.Bilinear);
|
||||
this.depthTexture.setMinFilter(MinFilter.BilinearNoMipMaps);
|
||||
this.shadowCamera = new Camera(size, size);
|
||||
this.frameBuffer = new FrameBuffer(size, size, 1);
|
||||
this.frameBuffer.setDepthTexture(depthTexture);
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderShadowMap(RenderManager renderManager, T light, ViewPort viewPort, GeometryList shadowCasters) {
|
||||
Renderer renderer = renderManager.getRenderer();
|
||||
|
||||
renderer.setFrameBuffer(frameBuffer);
|
||||
renderer.clearBuffers(false, true, false);
|
||||
|
||||
if (shadowCasters.size() > 0) {
|
||||
renderManager.setCamera(shadowCamera, false);
|
||||
viewPort.getQueue().renderShadowQueue(shadowCasters, renderManager, shadowCamera, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Matrix4f getBiasedViewProjectionMatrix() {
|
||||
return BIAS_MATRIX.mult(shadowCamera.getViewProjectionMatrix(), biasedViewProjectionMatrix);
|
||||
}
|
||||
}
|
92
jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMap.java
Executable file
92
jme3-core/src/main/java/com/jme3/shadow/next/pssm/DirectionalShadowMap.java
Executable file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.pssm;
|
||||
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.light.Light.Type;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.math.Vector4f;
|
||||
import com.jme3.renderer.RenderManager;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.shadow.next.ShadowMapSlice;
|
||||
import com.jme3.shadow.next.ShadowMap;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class DirectionalShadowMap implements ShadowMap<DirectionalLight> {
|
||||
|
||||
private final DirectionalLight light;
|
||||
private final DirectionalShadowMapSlice[] splits;
|
||||
private final Vector3f projectionSplitPositions = new Vector3f();
|
||||
|
||||
public DirectionalShadowMap(DirectionalLight light, int textureSize, int numSplits, Vector3f[] points) {
|
||||
this.light = light;
|
||||
this.splits = new DirectionalShadowMapSlice[numSplits];
|
||||
for (int i = 0; i < splits.length; i++) {
|
||||
this.splits[i] = new DirectionalShadowMapSlice(textureSize, points);
|
||||
}
|
||||
}
|
||||
|
||||
public void renderShadowMap(RenderManager renderManager, ViewPort viewPort, DirectionalShadowParameters params, GeometryList shadowCasters) {
|
||||
projectionSplitPositions.set(params.getProjectionSplitPositions());
|
||||
float[] splitPositionsViewSpace = params.getSplitPositions();
|
||||
for (int i = 0; i < splits.length; i++) {
|
||||
float near = splitPositionsViewSpace[i];
|
||||
float far = splitPositionsViewSpace[i + 1];
|
||||
shadowCasters.clear();
|
||||
splits[i].updateShadowCamera(viewPort, light, shadowCasters, near, far);
|
||||
splits[i].renderShadowMap(renderManager, light, viewPort, shadowCasters);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3f getProjectionSplitPositions() {
|
||||
return projectionSplitPositions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumSlices() {
|
||||
return splits.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShadowMapSlice getSlice(int index) {
|
||||
return splits[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getLightType() {
|
||||
return Type.Directional;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.pssm;
|
||||
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.ViewPort;
|
||||
import com.jme3.renderer.queue.GeometryList;
|
||||
import com.jme3.shadow.ShadowUtil;
|
||||
import com.jme3.texture.Texture2D;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public class DirectionalShadowMapSlice extends BaseShadowMapSlice<DirectionalLight> {
|
||||
|
||||
public DirectionalShadowMapSlice(int size, Vector3f[] points) {
|
||||
super(size, points);
|
||||
this.shadowCamera.setParallelProjection(true);
|
||||
}
|
||||
|
||||
public void updateShadowCamera(
|
||||
ViewPort viewPort,
|
||||
DirectionalLight light,
|
||||
GeometryList shadowCasters,
|
||||
float near,
|
||||
float far) {
|
||||
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), near, far, points);
|
||||
shadowCamera.lookAtDirection(light.getDirection(), shadowCamera.getUp());
|
||||
|
||||
int textureSize = frameBuffer.getWidth();
|
||||
ShadowUtil.updateShadowCamera(viewPort, null, shadowCamera, points, shadowCasters, textureSize);
|
||||
}
|
||||
|
||||
public Texture2D getTexture() {
|
||||
return depthTexture;
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2016 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package com.jme3.shadow.next.pssm;
|
||||
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.renderer.Camera;
|
||||
import com.jme3.shadow.PssmShadowUtil;
|
||||
|
||||
/**
|
||||
* @author Kirill Vainer
|
||||
*/
|
||||
public final class DirectionalShadowParameters {
|
||||
|
||||
private float lambda = 0.65f;
|
||||
private int numSplits = 4;
|
||||
protected float zFarOverride = 0;
|
||||
private float[] splitPositions = new float[numSplits + 1];
|
||||
private final Vector3f projectionSplitPositions = new Vector3f();
|
||||
|
||||
public float getLambda() {
|
||||
return lambda;
|
||||
}
|
||||
|
||||
public void setLambda(float lambda) {
|
||||
this.lambda = lambda;
|
||||
}
|
||||
|
||||
public int getNumSplits() {
|
||||
return numSplits;
|
||||
}
|
||||
|
||||
public void setNumSplits(int numSplits) {
|
||||
if (numSplits < 1 || numSplits > 4) {
|
||||
throw new IllegalArgumentException("Number of splits must be between 1 and 4");
|
||||
}
|
||||
this.numSplits = numSplits;
|
||||
this.splitPositions = new float[numSplits + 1];
|
||||
}
|
||||
|
||||
public float[] getSplitPositions() {
|
||||
return splitPositions;
|
||||
}
|
||||
|
||||
public Vector3f getProjectionSplitPositions() {
|
||||
return projectionSplitPositions;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* The default value is dynamically computed based on 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;
|
||||
|
||||
// TODO: Fade length not supported yet
|
||||
// if (zFarOverride == 0) {
|
||||
// fadeInfo = null;
|
||||
// frustumCam = null;
|
||||
// } else {
|
||||
// if (fadeInfo != null) {
|
||||
// fadeInfo.set(zFarOverride - fadeLength, 1f / fadeLength);
|
||||
// }
|
||||
// if (frustumCam == null && viewPort != null) {
|
||||
// initFrustumCam();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public void updateSplitPositions(Camera viewCamera) {
|
||||
float near = viewCamera.getFrustumNear();
|
||||
float far = zFarOverride == 0f ? viewCamera.getFrustumFar() : zFarOverride;
|
||||
|
||||
PssmShadowUtil.updateFrustumSplits(splitPositions, near, far, lambda);
|
||||
|
||||
// TODO: Parallel projection can have negative near value, so split
|
||||
// positions must be adjusted.
|
||||
// if (viewCamera.isParallelProjection()) {
|
||||
// for (int i = 0; i < splitPositions.length; i++) {
|
||||
// splitPositions[i] = splitPositions[i] / (far - near);
|
||||
// }
|
||||
// }
|
||||
|
||||
switch (splitPositions.length) {
|
||||
case 5:
|
||||
// projectionSplitPositions.w = 1.0f;
|
||||
case 4:
|
||||
projectionSplitPositions.z = viewCamera.getViewToProjectionZ(splitPositions[3]);
|
||||
case 3:
|
||||
projectionSplitPositions.y = viewCamera.getViewToProjectionZ(splitPositions[2]);
|
||||
case 2:
|
||||
case 1:
|
||||
projectionSplitPositions.x = viewCamera.getViewToProjectionZ(splitPositions[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -173,7 +173,7 @@ void main(){
|
||||
// allow use of control flow
|
||||
if(g_LightDirection.w != 0.0){
|
||||
#endif
|
||||
spotFallOff = computeSpotFalloff(g_LightDirection, lightVec);
|
||||
spotFallOff = computeSpotFalloff(g_LightDirection, lightDir.xyz);
|
||||
#if __VERSION__ >= 110
|
||||
if(spotFallOff <= 0.0){
|
||||
gl_FragColor.rgb = AmbientSum * diffuseColor.rgb;
|
||||
|
@ -27,6 +27,9 @@ MaterialDef Phong Lighting {
|
||||
// Specular power/shininess
|
||||
Float Shininess : 1
|
||||
|
||||
// Ambient map
|
||||
Texture2D AmbientMap
|
||||
|
||||
// Diffuse map
|
||||
Texture2D DiffuseMap
|
||||
|
||||
@ -120,6 +123,9 @@ MaterialDef Phong Lighting {
|
||||
Boolean UseInstancing
|
||||
|
||||
Boolean BackfaceShadows : false
|
||||
|
||||
// PreShadow: use point light mode for depth
|
||||
Boolean IsPointLight
|
||||
}
|
||||
|
||||
Technique {
|
||||
@ -213,12 +219,16 @@ MaterialDef Phong Lighting {
|
||||
WorldViewMatrix
|
||||
ViewProjectionMatrix
|
||||
ViewMatrix
|
||||
WorldMatrix
|
||||
CameraPosition
|
||||
FrustumNearFar
|
||||
}
|
||||
|
||||
Defines {
|
||||
DISCARD_ALPHA : AlphaDiscardThreshold
|
||||
NUM_BONES : NumberOfBones
|
||||
INSTANCING : UseInstancing
|
||||
POINT_LIGHT : IsPointLight
|
||||
NUM_MORPH_TARGETS: NumberOfMorphTargets
|
||||
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ void main(){
|
||||
// allow use of control flow
|
||||
if(lightColor.w > 1.0){
|
||||
#endif
|
||||
spotFallOff = computeSpotFalloff(g_LightDirection, lightVec);
|
||||
spotFallOff = computeSpotFalloff(g_LightDirection, vLightDir.xyz);
|
||||
#if __VERSION__ >= 110
|
||||
}
|
||||
#endif
|
||||
|
@ -2,6 +2,7 @@
|
||||
#import "Common/ShaderLib/PBR.glsllib"
|
||||
#import "Common/ShaderLib/Parallax.glsllib"
|
||||
#import "Common/ShaderLib/Lighting.glsllib"
|
||||
#import "Common/ShaderLib/InPassShadows.glsllib"
|
||||
|
||||
varying vec2 texCoord;
|
||||
#ifdef SEPARATE_TEXCOORD
|
||||
@ -35,6 +36,8 @@ varying vec3 wPosition;
|
||||
uniform mat4 g_LightProbeData3;
|
||||
#endif
|
||||
|
||||
uniform vec4 g_AmbientLightColor;
|
||||
|
||||
#ifdef BASECOLORMAP
|
||||
uniform sampler2D m_BaseColorMap;
|
||||
#endif
|
||||
@ -94,7 +97,7 @@ varying vec3 wNormal;
|
||||
uniform float m_AlphaDiscardThreshold;
|
||||
#endif
|
||||
|
||||
void main(){
|
||||
void main() {
|
||||
vec2 newTexCoord;
|
||||
vec3 viewDir = normalize(g_CameraPosition - wPosition);
|
||||
|
||||
@ -223,10 +226,19 @@ void main(){
|
||||
specularColor.rgb *= lightMapColor;
|
||||
#endif
|
||||
|
||||
Shadow_ProcessPssmSlice();
|
||||
|
||||
|
||||
float ndotv = max( dot( normal, viewDir ),0.0);
|
||||
for( int i = 0;i < NB_LIGHTS; i+=3){
|
||||
vec4 lightColor = g_LightData[i];
|
||||
|
||||
float shadowMapIndex = -1.0;
|
||||
if (lightColor.w < 0.0) {
|
||||
shadowMapIndex = floor(-lightColor.w);
|
||||
lightColor.w = fract(-lightColor.w);
|
||||
}
|
||||
|
||||
vec4 lightData1 = g_LightData[i+1];
|
||||
vec4 lightDir;
|
||||
vec3 lightVec;
|
||||
@ -235,16 +247,19 @@ void main(){
|
||||
float fallOff = 1.0;
|
||||
#if __VERSION__ >= 110
|
||||
// allow use of control flow
|
||||
if(lightColor.w > 1.0){
|
||||
if(lightColor.w > 0.4){
|
||||
#endif
|
||||
fallOff = computeSpotFalloff(g_LightData[i+2], lightVec);
|
||||
fallOff = computeSpotFalloff(g_LightData[i+2], lightDir.xyz);
|
||||
#if __VERSION__ >= 110
|
||||
}
|
||||
#endif
|
||||
//point light attenuation
|
||||
fallOff *= lightDir.w;
|
||||
|
||||
lightDir.xyz = normalize(lightDir.xyz);
|
||||
if (shadowMapIndex >= 0.0) {
|
||||
fallOff *= Shadow_Process(i / 3, lightColor.w, shadowMapIndex, lightVec, lightDir.xyz, wPosition, lightData1.w);
|
||||
}
|
||||
|
||||
vec3 directDiffuse;
|
||||
vec3 directSpecular;
|
||||
|
||||
@ -257,6 +272,8 @@ void main(){
|
||||
gl_FragColor.rgb += directLighting * fallOff;
|
||||
}
|
||||
|
||||
|
||||
gl_FragColor.rgb += g_AmbientLightColor.rgb * diffuseColor.rgb;
|
||||
#if NB_PROBES >= 1
|
||||
vec3 color1 = vec3(0.0);
|
||||
vec3 color2 = vec3(0.0);
|
||||
@ -295,7 +312,6 @@ void main(){
|
||||
weight3 /= weightSum;
|
||||
#endif
|
||||
gl_FragColor.rgb += color1 * clamp(weight1,0.0,1.0) + color2 * clamp(weight2,0.0,1.0) + color3 * clamp(weight3,0.0,1.0);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(EMISSIVE) || defined (EMISSIVEMAP)
|
||||
|
@ -118,6 +118,9 @@ MaterialDef PBR Lighting {
|
||||
Boolean UseVertexColor
|
||||
|
||||
Boolean BackfaceShadows : false
|
||||
|
||||
// PreShadow: use point light mode for depth
|
||||
Boolean IsPointLight
|
||||
}
|
||||
|
||||
Technique {
|
||||
@ -175,12 +178,16 @@ MaterialDef PBR Lighting {
|
||||
WorldViewMatrix
|
||||
ViewProjectionMatrix
|
||||
ViewMatrix
|
||||
WorldMatrix
|
||||
CameraPosition
|
||||
FrustumNearFar
|
||||
}
|
||||
|
||||
Defines {
|
||||
DISCARD_ALPHA : AlphaDiscardThreshold
|
||||
NUM_BONES : NumberOfBones
|
||||
INSTANCING : UseInstancing
|
||||
POINT_LIGHT : IsPointLight
|
||||
NUM_MORPH_TARGETS: NumberOfMorphTargets
|
||||
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#import "Common/ShaderLib/GLSLCompat.glsllib"
|
||||
#import "Common/ShaderLib/Instancing.glsllib"
|
||||
#import "Common/ShaderLib/Skinning.glsllib"
|
||||
#import "Common/ShaderLib/InPassShadows.glsllib"
|
||||
#import "Common/ShaderLib/MorphAnim.glsllib"
|
||||
|
||||
uniform vec4 m_BaseColor;
|
||||
@ -59,7 +60,11 @@ void main(){
|
||||
texCoord2 = inTexCoord2;
|
||||
#endif
|
||||
|
||||
wPosition = TransformWorld(modelSpacePos).xyz;
|
||||
vec3 worldPos = TransformWorld(modelSpacePos).xyz;
|
||||
|
||||
Shadow_ProcessProjCoord(worldPos);
|
||||
|
||||
wPosition = worldPos;
|
||||
wNormal = TransformWorldNormal(modelSpaceNorm);
|
||||
|
||||
#if defined(NORMALMAP) || defined(PARALLAXMAP)
|
||||
|
@ -188,7 +188,7 @@ void main(){
|
||||
// allow use of control flow
|
||||
if(lightColor.w > 1.0){
|
||||
#endif
|
||||
spotFallOff = computeSpotFalloff(g_LightData[i+2], lightVec);
|
||||
spotFallOff = computeSpotFalloff(g_LightData[i+2], lightDir.xyz);
|
||||
#if __VERSION__ >= 110
|
||||
}
|
||||
#endif
|
||||
|
@ -165,7 +165,7 @@ void main(){
|
||||
if(lightColor.w > 1.0){
|
||||
#endif
|
||||
vec4 lightDirection = g_LightData[i+2];
|
||||
spotFallOff = computeSpotFalloff(lightDirection, lightVec);
|
||||
spotFallOff = computeSpotFalloff(lightDirection, lightDir.xyz);
|
||||
#if __VERSION__ >= 110
|
||||
}
|
||||
#endif
|
||||
|
@ -14,6 +14,9 @@ MaterialDef Point Sprite {
|
||||
Texture2D GlowMap
|
||||
// The glow color of the object
|
||||
Color GlowColor
|
||||
|
||||
// PreShadow: use point light mode for depth
|
||||
Boolean IsPointLight
|
||||
}
|
||||
|
||||
Technique {
|
||||
@ -56,10 +59,14 @@ MaterialDef Point Sprite {
|
||||
WorldViewMatrix
|
||||
ViewProjectionMatrix
|
||||
ViewMatrix
|
||||
WorldMatrix
|
||||
CameraPosition
|
||||
FrustumNearFar
|
||||
}
|
||||
|
||||
Defines {
|
||||
COLOR_MAP : Texture
|
||||
POINT_LIGHT : IsPointLight
|
||||
}
|
||||
|
||||
ForcedRenderState {
|
||||
|
@ -59,6 +59,9 @@ MaterialDef Unshaded {
|
||||
Float ShadowMapSize
|
||||
|
||||
Boolean BackfaceShadows: true
|
||||
|
||||
// PreShadow: use point light mode for depth
|
||||
Boolean IsPointLight
|
||||
}
|
||||
|
||||
Technique {
|
||||
@ -117,6 +120,9 @@ MaterialDef Unshaded {
|
||||
WorldViewMatrix
|
||||
ViewProjectionMatrix
|
||||
ViewMatrix
|
||||
WorldMatrix
|
||||
CameraPosition
|
||||
FrustumNearFar
|
||||
}
|
||||
|
||||
Defines {
|
||||
@ -124,6 +130,7 @@ MaterialDef Unshaded {
|
||||
DISCARD_ALPHA : AlphaDiscardThreshold
|
||||
NUM_BONES : NumberOfBones
|
||||
INSTANCING : UseInstancing
|
||||
POINT_LIGHT : IsPointLight
|
||||
NUM_MORPH_TARGETS: NumberOfMorphTargets
|
||||
NUM_TARGETS_BUFFERS: NumberOfTargetsBuffers
|
||||
}
|
||||
|
@ -1,11 +1,24 @@
|
||||
MaterialDef Pre Shadow {
|
||||
|
||||
MaterialParameters {
|
||||
// PreShadow: use point light mode for depth
|
||||
Boolean IsPointLight
|
||||
}
|
||||
|
||||
Technique {
|
||||
VertexShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.vert
|
||||
FragmentShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.frag
|
||||
|
||||
Defines {
|
||||
POINT_LIGHT : IsPointLight
|
||||
}
|
||||
|
||||
WorldParameters {
|
||||
WorldViewProjectionMatrix
|
||||
WorldViewMatrix
|
||||
WorldMatrix
|
||||
CameraPosition
|
||||
FrustumNearFar
|
||||
}
|
||||
|
||||
RenderState {
|
||||
|
@ -4,11 +4,17 @@
|
||||
#import "Common/ShaderLib/MorphAnim.glsllib"
|
||||
|
||||
attribute vec3 inPosition;
|
||||
#ifdef DISCARD_ALPHA
|
||||
attribute vec2 inTexCoord;
|
||||
|
||||
varying vec2 texCoord;
|
||||
#endif
|
||||
|
||||
void main(){
|
||||
#ifdef POINT_LIGHT
|
||||
uniform vec3 g_CameraPosition;
|
||||
uniform vec2 g_FrustumNearFar;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
vec4 modelSpacePos = vec4(inPosition, 1.0);
|
||||
|
||||
#ifdef NUM_MORPH_TARGETS
|
||||
@ -18,6 +24,20 @@ void main(){
|
||||
#ifdef NUM_BONES
|
||||
Skinning_Compute(modelSpacePos);
|
||||
#endif
|
||||
gl_Position = TransformWorldViewProjection(modelSpacePos);
|
||||
|
||||
#ifdef DISCARD_ALPHA
|
||||
texCoord = inTexCoord;
|
||||
#endif
|
||||
|
||||
gl_Position = TransformWorldViewProjection(modelSpacePos);
|
||||
|
||||
#ifdef POINT_LIGHT
|
||||
vec3 lightDir = g_CameraPosition - TransformWorld(modelSpacePos).xyz;
|
||||
|
||||
// The Z value to write into the depth map, should be [0.0, 1.0]
|
||||
float z = sqrt(length(lightDir) / g_FrustumNearFar.y);
|
||||
|
||||
// Remap [0.0, 1.0] into [-1.0, 1.0]
|
||||
gl_Position.z = (clamp(z, 0.0, 1.0) * 2.0 - 1.0) * gl_Position.w;
|
||||
#endif
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#import "Common/ShaderLib/GLSLCompat.glsllib"
|
||||
|
||||
uniform float m_ShadowMapSlice;
|
||||
uniform sampler2DArray m_ShadowMapArray;
|
||||
varying vec2 texCoord1;
|
||||
|
||||
void main() {
|
||||
float shadow = texture2D(m_ShadowMapArray, vec3(texCoord1, m_ShadowMapSlice)).r;
|
||||
|
||||
shadow = sqrt(shadow);
|
||||
|
||||
// TODO: make it betterer
|
||||
gl_FragColor.rgb = vec3(shadow);
|
||||
gl_FragColor.a = 1.0;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
MaterialDef Pre Shadow {
|
||||
|
||||
MaterialParameters {
|
||||
TextureArray ShadowMapArray
|
||||
Float ShadowMapSlice
|
||||
}
|
||||
|
||||
Technique {
|
||||
VertexShader GLSL150 : Common/MatDefs/Misc/Unshaded.vert
|
||||
FragmentShader GLSL150 : Common/MatDefs/Shadow/ShowShadowArray.frag
|
||||
|
||||
WorldParameters {
|
||||
WorldViewProjectionMatrix
|
||||
ViewProjectionMatrix
|
||||
}
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ out vec4 outFragColor;
|
||||
# define texture3D texture
|
||||
# define textureCube texture
|
||||
# define texture2DLod textureLod
|
||||
# define shadow2D(a,b) vec4(texture(a,b))
|
||||
# define textureCubeLod textureLod
|
||||
# if defined VERTEX_SHADER
|
||||
# define varying out
|
||||
|
165
jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsllib
Executable file
165
jme3-core/src/main/resources/Common/ShaderLib/InPassShadows.glsllib
Executable file
@ -0,0 +1,165 @@
|
||||
#import "Common/ShaderLib/GLSLCompat.glsllib"
|
||||
|
||||
#extension GL_EXT_texture_array : enable
|
||||
|
||||
#ifndef NUM_PSSM_SPLITS
|
||||
#define NUM_PSSM_SPLITS 0
|
||||
#endif
|
||||
|
||||
#ifdef IN_PASS_SHADOWS
|
||||
|
||||
uniform mat4 g_ShadowMatrices[(NB_LIGHTS/3) + NUM_PSSM_SPLITS];
|
||||
|
||||
#if NUM_PSSM_SPLITS > 0
|
||||
varying vec3 dirProjCoord[NUM_PSSM_SPLITS];
|
||||
#else
|
||||
varying vec3 dirProjCoord[1];
|
||||
#endif
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
void Shadow_ProcessProjCoord(vec3 worldPos) {
|
||||
#if NUM_PSSM_SPLITS > 0
|
||||
for (int i = 0; i < NUM_PSSM_SPLITS; i++) {
|
||||
#if __VERSION__ >= 150
|
||||
dirProjCoord[i] = mat4x3(g_ShadowMatrices[i]) * vec4(worldPos, 1.0);
|
||||
#else
|
||||
dirProjCoord[i] = (g_ShadowMatrices[i] * vec4(worldPos, 1.0)).xyz;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
uniform sampler2DArrayShadow g_ShadowMapArray;
|
||||
uniform vec3 g_PssmSplits;
|
||||
|
||||
float pssmSliceOffset;
|
||||
|
||||
void Shadow_ProcessPssmSlice() {
|
||||
#if NUM_PSSM_SPLITS > 1
|
||||
pssmSliceOffset = dot(step(g_PssmSplits.xyz, gl_FragCoord.zzz), vec3(1.0));
|
||||
#else
|
||||
pssmSliceOffset = 0.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
vec3 Shadow_GetCubeMapTC(in vec3 direction) {
|
||||
vec3 axis = abs(direction);
|
||||
float largest = max(axis.x, max(axis.y, axis.z));
|
||||
vec3 tc;
|
||||
if (largest == axis.x) {
|
||||
if (direction.x > 0.0) {
|
||||
tc = vec3( direction.z, -direction.y, 0.0);
|
||||
} else {
|
||||
tc = vec3(-direction.z, -direction.y, 1.0);
|
||||
}
|
||||
} else if (largest == axis.y) {
|
||||
if (direction.y > 0.0) {
|
||||
tc = vec3(-direction.x, direction.z, 2.0);
|
||||
} else {
|
||||
tc = vec3(-direction.x, -direction.z, 3.0);
|
||||
}
|
||||
} else {
|
||||
if (direction.z > 0.0) {
|
||||
tc = vec3(-direction.x, -direction.y, 4.0);
|
||||
} else {
|
||||
tc = vec3(direction.x, -direction.y, 5.0);
|
||||
}
|
||||
}
|
||||
largest = 1.0 / largest;
|
||||
tc.xy = 0.5 * (tc.xy * vec2(largest) + 1.0);
|
||||
return tc;
|
||||
}
|
||||
|
||||
float Shadow_Process(int lightIndex, float lightType, float shadowMapIndex,
|
||||
vec3 lightVec, vec3 lightDir,
|
||||
vec3 worldPos, float invRadius) {
|
||||
vec4 tc;
|
||||
|
||||
if (lightType <= 0.2) {
|
||||
vec3 projCoord = dirProjCoord[int(pssmSliceOffset)];
|
||||
tc = vec4(projCoord.xy, shadowMapIndex + pssmSliceOffset, projCoord.z);
|
||||
} else if (lightType <= 0.3) {
|
||||
vec3 projCoord = Shadow_GetCubeMapTC(lightVec.xyz);
|
||||
float dist = sqrt(length(lightVec) * invRadius);
|
||||
tc = vec4(projCoord.xy, shadowMapIndex + projCoord.z, dist);
|
||||
} else {
|
||||
tc = g_ShadowMatrices[NUM_PSSM_SPLITS + lightIndex] * vec4(worldPos, 1.0);
|
||||
tc.xyz /= tc.w;
|
||||
tc = vec4(tc.xy, shadowMapIndex, tc.z);
|
||||
}
|
||||
|
||||
#if __VERSION__ >= 150
|
||||
return texture(g_ShadowMapArray, tc);
|
||||
#else
|
||||
return shadow2DArray(g_ShadowMapArray, tc).x;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif NUM_PSSM_SPLITS > 0
|
||||
|
||||
// A lightweight version of in-pass lighting that only handles directional lights
|
||||
// Control flow and loop iteration count are static
|
||||
|
||||
varying vec4 vProjCoord[NUM_PSSM_SPLITS];
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
uniform mat4 g_DirectionalShadowMatrix[NUM_PSSM_SPLITS];
|
||||
void Shadow_ProcessProjCoord(vec3 worldPos) {
|
||||
for (int i = 0; i < NUM_PSSM_SPLITS; i++) {
|
||||
vProjCoord[i] = g_DirectionalShadowMatrix[i] * vec4(worldPos, 1.0);
|
||||
}
|
||||
}
|
||||
#else
|
||||
uniform sampler2DShadow g_DirectionalShadowMap[NUM_PSSM_SPLITS];
|
||||
uniform vec4 g_PssmSplits;
|
||||
|
||||
const vec2 invTexSize = vec2(1.0 / 1024.0);
|
||||
|
||||
float Shadow_SampleOffset(sampler2DShadow shadowMap, vec4 projCoord, vec2 offset) {
|
||||
return shadow2D(shadowMap, vec3(projCoord.xy + offset * invTexSize, projCoord.z)).r;
|
||||
}
|
||||
|
||||
float Shadow_Sample(sampler2DShadow shadowMap, vec4 projCoord) {
|
||||
return shadow2D(shadowMap, projCoord.xyz).r;
|
||||
}
|
||||
|
||||
#define GET_SHADOW(i) if (z < g_PssmSplits[i]) return Shadow_Sample(g_DirectionalShadowMap[i], vProjCoord[i]);
|
||||
|
||||
void Shadow_ProcessPssmSlice() {
|
||||
}
|
||||
|
||||
float Shadow_ProcessDirectional() {
|
||||
float z = gl_FragCoord.z;
|
||||
|
||||
GET_SHADOW(0);
|
||||
#if NUM_PSSM_SPLITS > 1
|
||||
GET_SHADOW(1)
|
||||
#if NUM_PSSM_SPLITS > 2
|
||||
GET_SHADOW(2)
|
||||
#if NUM_PSSM_SPLITS > 3
|
||||
GET_SHADOW(3)
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return 1.0;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#define NUM_PSSM_SPLITS 0
|
||||
|
||||
const int pssmSliceOffset = 0;
|
||||
|
||||
void Shadow_ProcessProjCoord(vec3 worldPos) {
|
||||
}
|
||||
|
||||
void Shadow_ProcessPssmSlice() {
|
||||
}
|
||||
|
||||
float Shadow_Process(int lightIndex, float lightType, float shadowMapIndex,
|
||||
vec3 lightVec, vec3 lightDir,
|
||||
vec3 worldPos, float invRadius) {
|
||||
return 1.0;
|
||||
}
|
||||
#endif
|
@ -7,7 +7,7 @@
|
||||
* Outputs the light direction and the light half vector.
|
||||
*/
|
||||
void lightComputeDir(in vec3 worldPos, in float lightType, in vec4 position, out vec4 lightDir, out vec3 lightVec){
|
||||
float posLight = step(0.5, lightType);
|
||||
float posLight = step(0.2, lightType);
|
||||
vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight);
|
||||
lightVec = tempVec;
|
||||
float dist = length(tempVec);
|
||||
@ -23,9 +23,9 @@ void lightComputeDir(in vec3 worldPos, in float lightType, in vec4 position, out
|
||||
/*
|
||||
* Computes the spot falloff for a spotlight
|
||||
*/
|
||||
float computeSpotFalloff(in vec4 lightDirection, in vec3 lightVector){
|
||||
vec3 L=normalize(lightVector);
|
||||
vec3 spotdir = normalize(lightDirection.xyz);
|
||||
float computeSpotFalloff(in vec4 lightDirection, in vec3 lightVector) {
|
||||
vec3 L = lightVector;
|
||||
vec3 spotdir = lightDirection.xyz;
|
||||
float curAngleCos = dot(-L, spotdir);
|
||||
float innerAngleCos = floor(lightDirection.w) * 0.001;
|
||||
float outerAngleCos = fract(lightDirection.w);
|
||||
|
@ -39,7 +39,6 @@ import com.jme3.material.RenderState.BlendMode;
|
||||
import com.jme3.material.RenderState.FaceCullMode;
|
||||
import com.jme3.material.TechniqueDef.LightMode;
|
||||
import com.jme3.material.TechniqueDef.ShadowMode;
|
||||
import com.jme3.material.logic.StaticPassLightingLogic;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.Vector2f;
|
||||
import com.jme3.math.Vector3f;
|
||||
@ -645,9 +644,6 @@ public class J3MLoader implements AssetLoader {
|
||||
case SinglePass:
|
||||
technique.setLogic(new SinglePassLightingLogic(technique));
|
||||
break;
|
||||
case StaticPass:
|
||||
technique.setLogic(new StaticPassLightingLogic(technique));
|
||||
break;
|
||||
case SinglePassAndImageBased:
|
||||
technique.setLogic(new SinglePassAndImageBasedLightingLogic(technique));
|
||||
break;
|
||||
|
@ -430,7 +430,6 @@ public class MaterialMatParamTest {
|
||||
|
||||
private final Geometry geometry = new Geometry("Geometry", new Box(1, 1, 1));
|
||||
private final Node root = new Node("Root Node");
|
||||
private final LightList lightList = new LightList(geometry);
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@ -526,7 +525,7 @@ public class MaterialMatParamTest {
|
||||
private void evaluateTechniqueDef() {
|
||||
Assert.assertFalse(evaluated);
|
||||
Material mat = geometry.getMaterial();
|
||||
mat.render(geometry, lightList, renderManager);
|
||||
mat.render(geometry, renderManager);
|
||||
Assert.assertTrue(evaluated);
|
||||
}
|
||||
|
||||
|
206
jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
Executable file
206
jme3-examples/src/main/java/jme3test/light/TestInPassShadows.java
Executable file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2018 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* 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.input.KeyInput;
|
||||
import com.jme3.input.controls.ActionListener;
|
||||
import com.jme3.input.controls.AnalogListener;
|
||||
import com.jme3.input.controls.KeyTrigger;
|
||||
import com.jme3.light.AmbientLight;
|
||||
import com.jme3.light.DirectionalLight;
|
||||
import com.jme3.light.PointLight;
|
||||
import com.jme3.light.SpotLight;
|
||||
import com.jme3.material.Material;
|
||||
import com.jme3.material.TechniqueDef.LightMode;
|
||||
import com.jme3.math.ColorRGBA;
|
||||
import com.jme3.math.FastMath;
|
||||
import com.jme3.math.Quaternion;
|
||||
import com.jme3.math.Vector3f;
|
||||
import com.jme3.post.FilterPostProcessor;
|
||||
import com.jme3.post.filters.ToneMapFilter;
|
||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||
import com.jme3.scene.Geometry;
|
||||
import com.jme3.scene.shape.Box;
|
||||
import com.jme3.scene.shape.Quad;
|
||||
import com.jme3.shadow.next.InPassShadowRenderer;
|
||||
import com.jme3.system.AppSettings;
|
||||
|
||||
public class TestInPassShadows extends SimpleApplication {
|
||||
|
||||
private DirectionalLight dl;
|
||||
private SpotLight sl;
|
||||
private PointLight pl;
|
||||
private InPassShadowRenderer ipsr;
|
||||
private ToneMapFilter tmf;
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestInPassShadows app = new TestInPassShadows();
|
||||
AppSettings settings = new AppSettings(true);
|
||||
settings.setGammaCorrection(true);
|
||||
app.setSettings(settings);
|
||||
app.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simpleInitApp() {
|
||||
renderManager.setPreferredLightMode(LightMode.SinglePassAndImageBased);
|
||||
renderManager.setSinglePassLightBatchSize(3);
|
||||
|
||||
cam.setLocation(new Vector3f(8.079489f, 10.792628f, -6.714233f));
|
||||
cam.setRotation(new Quaternion(0.38442945f, -0.35025623f, 0.16050051f, 0.8389125f));
|
||||
flyCam.setMoveSpeed(5);
|
||||
|
||||
tmf = new ToneMapFilter(new Vector3f(50, 50, 50));
|
||||
FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
|
||||
fpp.addFilter(tmf);
|
||||
viewPort.addProcessor(fpp);
|
||||
|
||||
loadLights();
|
||||
loadScene();
|
||||
loadInputs();
|
||||
}
|
||||
|
||||
private void loadLights() {
|
||||
AmbientLight al = new AmbientLight(new ColorRGBA(0.2f, 0.2f, 0.3f, 1.0f).mult(2f));
|
||||
rootNode.addLight(al);
|
||||
|
||||
dl = new DirectionalLight();
|
||||
dl.setDirection(new Vector3f(-1, -0.5f, -1).normalizeLocal());
|
||||
dl.setColor(new ColorRGBA(1, 0.9f, 0.8f, 1).mult(2.5f));
|
||||
rootNode.addLight(dl);
|
||||
|
||||
sl = new SpotLight();
|
||||
sl.setSpotRange(15);
|
||||
sl.setSpotInnerAngle(20 * FastMath.DEG_TO_RAD);
|
||||
sl.setSpotOuterAngle(25 * FastMath.DEG_TO_RAD);
|
||||
sl.setPosition(new Vector3f(-5.2193f, -0.5851393f, 4.831882f));
|
||||
sl.setDirection(new Vector3f(0.8429418f, -0.42458484f, -0.33041906f));
|
||||
sl.setColor(new ColorRGBA(0.5f, 0.7f, 1.0f, 1.0f).mult(50));
|
||||
rootNode.addLight(sl);
|
||||
|
||||
pl = new PointLight(
|
||||
new Vector3f(-0.10135013f, 1.9986207f, -2.0745828f),
|
||||
new ColorRGBA(0.5f, 0.3f, 0.1f, 1f).mult(20),
|
||||
30);
|
||||
rootNode.addLight(pl);
|
||||
|
||||
ipsr = new InPassShadowRenderer();
|
||||
ipsr.setTextureSize(512);
|
||||
ipsr.setPolyOffset(5, 0);
|
||||
ipsr.directional().setNumSplits(1);
|
||||
ipsr.addLight(dl);
|
||||
ipsr.addLight(sl);
|
||||
ipsr.addLight(pl);
|
||||
viewPort.addProcessor(ipsr);
|
||||
}
|
||||
|
||||
private void loadScene() {
|
||||
Geometry box = new Geometry("Box", new Box(1, 1, 1));
|
||||
box.setShadowMode(ShadowMode.CastAndReceive);
|
||||
Material boxMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||
boxMat.setFloat("Roughness", 0.5f);
|
||||
boxMat.setFloat("Metallic", 0f);
|
||||
box.setMaterial(boxMat);
|
||||
rootNode.attachChild(box);
|
||||
|
||||
Geometry box2 = box.clone(true);
|
||||
box2.move(3, 0, 0);
|
||||
rootNode.attachChild(box2);
|
||||
|
||||
Geometry box3 = box.clone(true);
|
||||
box3.move(-3, 0, 0);
|
||||
rootNode.attachChild(box3);
|
||||
|
||||
Geometry floor = new Geometry("floor", new Quad(100, 100));
|
||||
floor.rotate(-FastMath.HALF_PI, 0, 0);
|
||||
floor.center();
|
||||
floor.move(0, -1, 0);
|
||||
floor.setShadowMode(ShadowMode.Receive);
|
||||
Material floorMat = new Material(assetManager, "Common/MatDefs/Light/PBRLighting.j3md");
|
||||
floorMat.setFloat("Roughness", 0.5f);
|
||||
floorMat.setFloat("Metallic", 0f);
|
||||
floor.setMaterial(floorMat);
|
||||
rootNode.attachChild(floor);
|
||||
}
|
||||
|
||||
private boolean moveLight = false;
|
||||
|
||||
private void loadInputs() {
|
||||
inputManager.addMapping("MoveLight", new KeyTrigger(KeyInput.KEY_SPACE));
|
||||
inputManager.addListener(new ActionListener() {
|
||||
@Override
|
||||
public void onAction(String name, boolean isPressed, float tpf) {
|
||||
moveLight = isPressed;
|
||||
}
|
||||
}, "MoveLight");
|
||||
|
||||
inputManager.addMapping("OffsetFactorUp", new KeyTrigger(KeyInput.KEY_U));
|
||||
inputManager.addMapping("OffsetFactorDown", new KeyTrigger(KeyInput.KEY_J));
|
||||
inputManager.addMapping("OffsetUnitsUp", new KeyTrigger(KeyInput.KEY_I));
|
||||
inputManager.addMapping("OffsetUnitsDown", new KeyTrigger(KeyInput.KEY_K));
|
||||
inputManager.addListener(new AnalogListener() {
|
||||
private float factor, units;
|
||||
@Override
|
||||
public void onAnalog(String name, float value, float tpf) {
|
||||
switch (name) {
|
||||
case "OffsetFactorUp":
|
||||
factor += tpf * 5f;
|
||||
break;
|
||||
case "OffsetFactorDown":
|
||||
factor -= tpf * 5f;
|
||||
break;
|
||||
case "OffsetUnitsUp":
|
||||
units += tpf * 50f;
|
||||
break;
|
||||
case "OffsetUnitsDown":
|
||||
units -= tpf * 50f;
|
||||
break;
|
||||
}
|
||||
ipsr.setPolyOffset(factor, units);
|
||||
System.out.println("PolyOffset(" + factor + ", " + units + ")");
|
||||
}
|
||||
|
||||
}, "OffsetFactorUp", "OffsetFactorDown", "OffsetUnitsUp", "OffsetUnitsDown");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simpleUpdate(float tpf) {
|
||||
if (moveLight) {
|
||||
sl.setPosition(cam.getLocation());
|
||||
sl.setDirection(cam.getDirection());
|
||||
System.out.println(sl.getPosition());
|
||||
System.out.println(sl.getDirection());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -453,7 +453,7 @@ public class JmeBatchRenderBackend implements BatchRenderBackend {
|
||||
|
||||
private final Mesh mesh = new Mesh();
|
||||
private final Geometry meshGeometry = new Geometry("nifty-quad", mesh);
|
||||
private final RenderState renderState = new RenderState();
|
||||
private final RenderState renderState = RenderState.ADDITIONAL.clone();
|
||||
|
||||
private FloatBuffer vertexPosBuffer;
|
||||
private FloatBuffer vertexTexCoordBuffer;
|
||||
|
@ -73,7 +73,7 @@ public class RenderDeviceJme implements RenderDevice {
|
||||
private VertexBuffer quadColor;
|
||||
private Matrix4f tempMat = new Matrix4f();
|
||||
private ColorRGBA tempColor = new ColorRGBA();
|
||||
private RenderState renderState = new RenderState();
|
||||
private RenderState renderState = RenderState.ADDITIONAL.clone();
|
||||
|
||||
private Material colorMaterial;
|
||||
private Material textureColorMaterial;
|
||||
|
@ -145,7 +145,7 @@ public class DirectionalLightShadowRendererVR extends AbstractShadowRendererVR {
|
||||
|
||||
//We prevent computing the frustum points and splits with zeroed or negative near clip value
|
||||
float frustumNear = Math.max(viewCam.getFrustumNear(), 0.001f);
|
||||
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, 1.0f, points);
|
||||
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, points);
|
||||
|
||||
//shadowCam.setDirection(direction);
|
||||
shadowCam.getRotation().lookAt(light.getDirection(), shadowCam.getUp());
|
||||
@ -180,7 +180,7 @@ public class DirectionalLightShadowRendererVR extends AbstractShadowRendererVR {
|
||||
protected GeometryList getOccludersToRender(int shadowMapIndex, GeometryList shadowMapOccluders) {
|
||||
|
||||
// update frustum points based on current camera and split
|
||||
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], 1.0f, points);
|
||||
ShadowUtil.updateFrustumPoints(viewPort.getCamera(), splitsArray[shadowMapIndex], splitsArray[shadowMapIndex + 1], points);
|
||||
|
||||
//Updating shadow cam with current split frusta
|
||||
if (lightReceivers.size()==0) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user