|
@@ -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.EnumSet;
|
|
|
|
|
@@ -49,10 +55,15 @@ 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_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 LightProbe lightProbe = null;
|
|
|
+ private LightProbe lightProbe;
|
|
|
+ private TextureArray shadowMapArray;
|
|
|
+ private Vector3f pssmSplitsPositions;
|
|
|
+ private int numPssmSplits;
|
|
|
|
|
|
static {
|
|
|
ADDITIVE_LIGHT.setBlendMode(BlendMode.AlphaAdditive);
|
|
@@ -60,20 +71,24 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
|
|
}
|
|
|
|
|
|
private final int singlePassLightingDefineId;
|
|
|
+ private final int inPassShadowsDefineId;
|
|
|
private final int nbLightsDefineId;
|
|
|
private final int indirectLightingDefineId;
|
|
|
+ private final int numPssmSplitsDefineId;
|
|
|
|
|
|
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);
|
|
|
indirectLightingDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_INDIRECT_LIGHTING, VarType.Boolean);
|
|
|
+ inPassShadowsDefineId = techniqueDef.addShaderUnmappedDefine(DEFINE_IN_PASS_SHADOWS, VarType.Boolean);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
|
|
|
EnumSet<Caps> rendererCaps, Geometry geometry, DefineList defines) {
|
|
|
- defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
|
|
|
+
|
|
|
defines.set(singlePassLightingDefineId, true);
|
|
|
|
|
|
// TODO: here we have a problem, this is called once before render,
|
|
@@ -82,16 +97,52 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
|
|
// 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).
|
|
|
- LightList lights = getFilteredLightList(renderManager, geometry);
|
|
|
- if (lights != null) {
|
|
|
- lightProbe = extractIndirectLights(lights, false);
|
|
|
- if (lightProbe == null) {
|
|
|
- defines.set(indirectLightingDefineId, false);
|
|
|
- } else {
|
|
|
- defines.set(indirectLightingDefineId, true);
|
|
|
+ getFilteredLightList(renderManager, geometry);
|
|
|
+
|
|
|
+ ambientLightColor.set(0, 0, 0, 1);
|
|
|
+ lightProbe = null;
|
|
|
+ pssmSplitsPositions = null;
|
|
|
+ numPssmSplits = 0;
|
|
|
+
|
|
|
+ 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) {
|
|
|
+ lightProbe = (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();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+ 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(indirectLightingDefineId, lightProbe != null);
|
|
|
+ defines.set(inPassShadowsDefineId, shadowMapArray != null);
|
|
|
+ defines.set(numPssmSplitsDefineId, numPssmSplits);
|
|
|
+
|
|
|
return super.makeCurrent(assetManager, renderManager, rendererCaps, geometry, defines);
|
|
|
}
|
|
|
|
|
@@ -123,13 +174,11 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
|
|
Uniform shCoeffs = shader.getUniform("g_ShCoeffs");
|
|
|
Uniform lightProbePemMap = shader.getUniform("g_PrefEnvMap");
|
|
|
|
|
|
- lightProbe = null;
|
|
|
if (startIndex != 0) {
|
|
|
// apply additive blending for 2nd and future passes
|
|
|
rm.getRenderer().applyRenderState(ADDITIVE_LIGHT);
|
|
|
ambientColor.setValue(VarType.Vector4, ColorRGBA.Black);
|
|
|
- }else{
|
|
|
- lightProbe = extractIndirectLights(lightList,true);
|
|
|
+ } else {
|
|
|
ambientColor.setValue(VarType.Vector4, ambientLightColor);
|
|
|
}
|
|
|
|
|
@@ -147,81 +196,97 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
|
|
lightProbeData.setVector4InArray(0,0,0,-1, 0);
|
|
|
}
|
|
|
|
|
|
+ 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++) {
|
|
|
-
|
|
|
-
|
|
|
- Light l = lightList.get(curIndex);
|
|
|
- if(l.getType() == Light.Type.Ambient){
|
|
|
- endIndex++;
|
|
|
- continue;
|
|
|
+ int endIndex = Math.min(startIndex + numLights, lightList.size());
|
|
|
+
|
|
|
+ ArrayShadowMap directionalShadowMap = null;
|
|
|
+
|
|
|
+ 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(),
|
|
|
- color.getGreen(),
|
|
|
- color.getBlue(),
|
|
|
- l.getType().getId(),
|
|
|
- lightDataIndex);
|
|
|
- lightDataIndex++;
|
|
|
+
|
|
|
+ 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(),
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
@@ -230,41 +295,16 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique
|
|
|
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, 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);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- protected LightProbe extractIndirectLights(LightList lightList, boolean removeLights) {
|
|
|
- ambientLightColor.set(0, 0, 0, 1);
|
|
|
- LightProbe probe = null;
|
|
|
- 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) {
|
|
|
- probe = (LightProbe)l;
|
|
|
- if(removeLights){
|
|
|
- lightList.remove(l);
|
|
|
- j--;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- ambientLightColor.a = 1.0f;
|
|
|
- return probe;
|
|
|
- }
|
|
|
}
|