in-pass-shadows: add spot / point light support
This commit is contained in:
parent
6fb2d029d2
commit
caad16626e
@ -43,6 +43,7 @@ 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 {
|
||||
@ -84,6 +85,28 @@ public class DefaultTechniqueDefLogic implements TechniqueDefLogic {
|
||||
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);
|
||||
|
||||
@ -138,15 +138,6 @@ public class ShadowStaticPassLightingLogic extends StaticPassLightingLogic {
|
||||
defines.set(numPssmSplitsDefineId, pssmSplits);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getShadowMapIndex(Light light) {
|
||||
if (light.getShadowMap() == null) {
|
||||
return -1.0f;
|
||||
}
|
||||
ArrayShadowMap map = (ArrayShadowMap) light.getShadowMap();
|
||||
return (float) map.getFirstArraySlice();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTextureUnit) {
|
||||
TextureArray array = null;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ public final class SinglePassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
lightData.setVector4InArray(color.getRed(),
|
||||
color.getGreen(),
|
||||
color.getBlue(),
|
||||
l.getType().getId(),
|
||||
encodeLightType(l),
|
||||
lightDataIndex);
|
||||
lightDataIndex++;
|
||||
|
||||
|
||||
@ -126,10 +126,6 @@ public class StaticPassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
return techniqueDef.getShader(assetManager, rendererCaps, defines);
|
||||
}
|
||||
|
||||
protected float getShadowMapIndex(Light light) {
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
protected void updateLightListUniforms(Matrix4f viewMatrix, Shader shader) {
|
||||
Uniform ambientColor = shader.getUniform("g_AmbientLightColor");
|
||||
ambientColor.setValue(VarType.Vector4, ambientLightColor);
|
||||
@ -142,36 +138,41 @@ public class StaticPassLightingLogic extends DefaultTechniqueDefLogic {
|
||||
lightData.setVector4Length(totalSize);
|
||||
|
||||
int index = 0;
|
||||
|
||||
for (SpotLight light : tempSpotLights) {
|
||||
ColorRGBA color = light.getColor();
|
||||
float lightTypeAndShadowMap = encodeLightTypeAndShadowMapIndex(light);
|
||||
lightData.setVector4InArray(color.r, color.g, color.b, lightTypeAndShadowMap, index++);
|
||||
|
||||
tempPosition.set(light.getPosition());
|
||||
float invRange = light.getInvSpotRange();
|
||||
lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRange, index++);
|
||||
|
||||
tempDirection.set(light.getDirection());
|
||||
float spotAngleCos = light.getPackedAngleCos();
|
||||
lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, spotAngleCos, index++);
|
||||
}
|
||||
|
||||
for (DirectionalLight light : tempDirLights) {
|
||||
ColorRGBA color = light.getColor();
|
||||
float shadowMapIndex = getShadowMapIndex(light);
|
||||
float lightTypeAndShadowMap = encodeLightTypeAndShadowMapIndex(light);
|
||||
lightData.setVector4InArray(color.r, color.g, color.b, lightTypeAndShadowMap, index++);
|
||||
|
||||
tempDirection.set(light.getDirection());
|
||||
lightData.setVector4InArray(color.r, color.g, color.b, shadowMapIndex, index++);
|
||||
lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, 1f, index++);
|
||||
}
|
||||
|
||||
for (PointLight light : tempPointLights) {
|
||||
ColorRGBA color = light.getColor();
|
||||
float shadowMapIndex = getShadowMapIndex(light);
|
||||
float lightTypeAndShadowMap = encodeLightTypeAndShadowMapIndex(light);
|
||||
lightData.setVector4InArray(color.r, color.g, color.b, lightTypeAndShadowMap, index++);
|
||||
|
||||
tempPosition.set(light.getPosition());
|
||||
float invRadius = light.getInvRadius();
|
||||
lightData.setVector4InArray(color.r, color.g, color.b, shadowMapIndex, index++);
|
||||
lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRadius, index++);
|
||||
}
|
||||
|
||||
for (SpotLight light : tempSpotLights) {
|
||||
ColorRGBA color = light.getColor();
|
||||
float shadowMapIndex = getShadowMapIndex(light);
|
||||
|
||||
tempPosition.set(light.getPosition());
|
||||
tempDirection.set(light.getDirection());
|
||||
|
||||
float invRange = light.getInvSpotRange();
|
||||
float spotAngleCos = light.getPackedAngleCos();
|
||||
lightData.setVector4InArray(color.r, color.g, color.b, shadowMapIndex, index++);
|
||||
lightData.setVector4InArray(tempPosition.x, tempPosition.y, tempPosition.z, invRange, index++);
|
||||
lightData.setVector4InArray(tempDirection.x, tempDirection.y, tempDirection.z, spotAngleCos, index++);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void updateShadowUniforms(Renderer renderer, Shader shader, int nextTextureUnit) {
|
||||
|
||||
@ -31,6 +31,7 @@
|
||||
*/
|
||||
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;
|
||||
@ -48,6 +49,7 @@ 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;
|
||||
@ -105,12 +107,14 @@ public class PreShadowArrayRenderer implements SceneProcessor {
|
||||
|
||||
array.setAnisotropicFilter(1);
|
||||
array.setShadowCompareMode(ShadowCompareMode.LessOrEqual);
|
||||
array.setMagFilter(MagFilter.Nearest);
|
||||
array.setMinFilter(MinFilter.NearestNoMipMaps);
|
||||
|
||||
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) {
|
||||
@ -135,10 +139,14 @@ public class PreShadowArrayRenderer implements SceneProcessor {
|
||||
this.textureSize = textureSize;
|
||||
}
|
||||
|
||||
public TextureArray getShadowMapTexture() {
|
||||
return array;
|
||||
}
|
||||
|
||||
public void addLight(Light light) {
|
||||
if (array.getImage() == null) {
|
||||
array.setImage(new Image(
|
||||
Format.Depth16,
|
||||
Format.Depth32F,
|
||||
textureSize,
|
||||
textureSize,
|
||||
0,
|
||||
|
||||
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,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;
|
||||
|
||||
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.shader.VarType;
|
||||
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, PreShadowArrayRenderer 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) {
|
||||
}
|
||||
|
||||
}
|
||||
@ -82,6 +82,7 @@ public class BaseArrayShadowMapSlice<T extends Light> implements ArrayShadowMapS
|
||||
|
||||
if (fbNeedClear) {
|
||||
renderer.setFrameBuffer(frameBuffer);
|
||||
renderer.clearClipRect();
|
||||
renderer.clearBuffers(false, true, false);
|
||||
fbNeedClear = false;
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ public class PointArrayShadowMapSlice extends BaseArrayShadowMapSlice<PointLight
|
||||
}
|
||||
|
||||
public void updateShadowCamera(ViewPort viewPort, PointLight light, GeometryList shadowCasters) {
|
||||
shadowCamera.setFrustumPerspective(90f, 1f, 0.1f, light.getRadius());
|
||||
shadowCamera.setFrustumPerspective(90f, 1f, 0.5f, light.getRadius());
|
||||
shadowCamera.setLocation(light.getPosition());
|
||||
for (Spatial scene : viewPort.getScenes()) {
|
||||
ShadowUtil.getGeometriesInCamFrustum(scene, shadowCamera, ShadowMode.Cast, shadowCasters);
|
||||
|
||||
@ -49,10 +49,20 @@ 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());
|
||||
shadowCamera.lookAtDirection(light.getDirection(), Vector3f.UNIT_Y);
|
||||
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;
|
||||
|
||||
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 shadowCamera.getViewProjectionMatrix();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
#import "Common/ShaderLib/PBR.glsllib"
|
||||
#import "Common/ShaderLib/Parallax.glsllib"
|
||||
#import "Common/ShaderLib/Lighting.glsllib"
|
||||
|
||||
#import "Common/ShaderLib/InPassShadows.glsl"
|
||||
|
||||
varying vec2 texCoord;
|
||||
#ifdef SEPARATE_TEXCOORD
|
||||
@ -28,6 +28,8 @@ varying vec3 wPosition;
|
||||
uniform vec4 g_LightProbeData;
|
||||
#endif
|
||||
|
||||
uniform vec4 g_AmbientLightColor;
|
||||
|
||||
#ifdef BASECOLORMAP
|
||||
uniform sampler2D m_BaseColorMap;
|
||||
#endif
|
||||
@ -87,7 +89,7 @@ varying vec3 wNormal;
|
||||
uniform float m_AlphaDiscardThreshold;
|
||||
#endif
|
||||
|
||||
void main(){
|
||||
void main() {
|
||||
vec2 newTexCoord;
|
||||
vec3 viewDir = normalize(g_CameraPosition - wPosition);
|
||||
|
||||
@ -216,11 +218,20 @@ 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];
|
||||
vec4 lightData1 = g_LightData[i+1];
|
||||
|
||||
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;
|
||||
lightComputeDir(wPosition, lightColor.w, lightData1, lightDir, lightVec);
|
||||
@ -228,7 +239,7 @@ 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], lightDir.xyz);
|
||||
#if __VERSION__ >= 110
|
||||
@ -237,6 +248,10 @@ void main(){
|
||||
//point light attenuation
|
||||
fallOff *= lightDir.w;
|
||||
|
||||
if (shadowMapIndex >= 0.0) {
|
||||
fallOff *= Shadow_Process(i / 3, lightColor.w, shadowMapIndex, lightVec, lightDir.xyz, wPosition, lightData1.w);
|
||||
}
|
||||
|
||||
vec3 directDiffuse;
|
||||
vec3 directSpecular;
|
||||
|
||||
@ -249,6 +264,8 @@ void main(){
|
||||
gl_FragColor.rgb += directLighting * fallOff;
|
||||
}
|
||||
|
||||
gl_FragColor.rgb += g_AmbientLightColor.rgb * diffuseColor.rgb;
|
||||
|
||||
#ifdef INDIRECT_LIGHTING
|
||||
vec3 rv = reflect(-viewDir.xyz, normal.xyz);
|
||||
//prallax fix for spherical bounds from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#import "Common/ShaderLib/GLSLCompat.glsllib"
|
||||
#import "Common/ShaderLib/Instancing.glsllib"
|
||||
#import "Common/ShaderLib/Skinning.glsllib"
|
||||
#import "Common/ShaderLib/InPassShadows.glsl"
|
||||
|
||||
|
||||
uniform vec4 m_BaseColor;
|
||||
@ -52,7 +53,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)
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
#import "Common/ShaderLib/GLSLCompat.glsllib"
|
||||
#import "Common/ShaderLib/BlinnPhongLighting.glsllib"
|
||||
#import "Common/ShaderLib/Lighting.glsllib"
|
||||
#import "Common/ShaderLib/InPassShadows.glsl"
|
||||
#import "Common/ShaderLib/PBR.glsllib"
|
||||
@ -34,7 +33,7 @@
|
||||
#define SPOT_LIGHT_START (SPOT_SHADOW_LIGHT_END)
|
||||
#define SPOT_LIGHT_END (SPOT_LIGHT_START + NUM_SPOT_LIGHTS * 3)
|
||||
|
||||
#define LIGHT_DATA_SIZE (SPOT_LIGHT_END)
|
||||
#define LIGHT_DATA_SIZE (NUM_SHADOW_DIR_LIGHTS * 2 )
|
||||
|
||||
uniform vec3 g_CameraPosition;
|
||||
|
||||
@ -64,74 +63,36 @@ struct surface_t {
|
||||
float ndotv;
|
||||
};
|
||||
|
||||
float Lighting_ProcessAttenuation(float invRadius, float dist) {
|
||||
#ifdef SRGB
|
||||
float invRadTimesDist = invRadius * dist;
|
||||
float atten = (1.0 - invRadTimesDist) / (1.0 + invRadTimesDist * dist);
|
||||
return clamp(atten, 0.0, 1.0);
|
||||
#else
|
||||
return max(0.0, 1.0 - invRadius * dist);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Lighting_ProcessDirectional(int lightIndex, surface_t surface, out vec3 outDiffuse, out vec3 outSpecular) {
|
||||
void Lighting_Process(in int lightIndex, in surface_t surface, out vec3 outDiffuse, out vec3 outSpecular, inout int startProjIndex) {
|
||||
vec4 lightColor = g_LightData[lightIndex];
|
||||
vec3 lightDirection = g_LightData[lightIndex + 1].xyz;
|
||||
vec4 lightData1 = g_LightData[lightIndex + 1];
|
||||
float shadowMapIndex = -1.0;
|
||||
|
||||
PBR_ComputeDirectLightSpecWF(surface.normal, -lightDirection, surface.viewDir,
|
||||
if (lightColor.w < 0.0) {
|
||||
lightColor.w = -lightColor.w;
|
||||
shadowMapIndex = floor(lightColor.w);
|
||||
lightColor.w = lightColor.w - shadowMapIndex;
|
||||
}
|
||||
|
||||
vec4 lightDir;
|
||||
vec3 lightVec;
|
||||
lightComputeDir(surface.position, lightColor.w, lightData1, lightDir, lightVec);
|
||||
|
||||
if (shadowMapIndex >= 0.0) {
|
||||
lightDir.w *= Shadow_Process(lightColor.w, lightDir.xyz, shadowMapIndex, startProjIndex);
|
||||
}
|
||||
|
||||
if (lightColor.w >= 0.5) {
|
||||
lightDir.w *= computeSpotFalloff(g_LightData[lightIndex + 2], lightDir.xyz);
|
||||
}
|
||||
|
||||
lightColor.rgb *= lightDir.w;
|
||||
|
||||
PBR_ComputeDirectLightSpecWF(surface.normal, lightDir.xyz, surface.viewDir,
|
||||
lightColor.rgb, surface.specular.rgb, surface.roughness, surface.ndotv,
|
||||
outDiffuse, outSpecular);
|
||||
}
|
||||
|
||||
vec3 Lighting_ProcessPoint(in int lightIndex, in surface_t surface, out vec3 outDiffuse, out vec3 outSpecular) {
|
||||
vec4 lightColor = g_LightData[lightIndex];
|
||||
vec4 lightPosition = g_LightData[lightIndex + 1];
|
||||
vec3 lightDirection = lightPosition.xyz - surface.position;
|
||||
float dist = length(lightDirection);
|
||||
lightDirection /= vec3(dist);
|
||||
float atten = Lighting_ProcessAttenuation(lightPosition.w, dist);
|
||||
if (atten == 0.0) {
|
||||
outDiffuse = vec3(0.0);
|
||||
outSpecular = vec3(0.0);
|
||||
return lightDirection;
|
||||
}
|
||||
PBR_ComputeDirectLightSpecWF(surface.normal, lightDirection, surface.viewDir,
|
||||
lightColor.rgb, surface.specular.rgb, surface.roughness, surface.ndotv,
|
||||
outDiffuse, outSpecular);
|
||||
|
||||
outDiffuse *= atten;
|
||||
outSpecular *= atten;
|
||||
|
||||
return lightDirection;
|
||||
}
|
||||
|
||||
void Lighting_ProcessSpot(in int lightIndex, in surface_t surface, out vec3 outDiffuse, out vec3 outSpecular) {
|
||||
vec4 lightColor = g_LightData[lightIndex];
|
||||
vec4 lightPosition = g_LightData[lightIndex + 1];
|
||||
vec4 lightDirection = g_LightData[lightIndex + 2];
|
||||
vec3 lightVector = lightPosition.xyz - surface.position;
|
||||
float dist = length(lightVector);
|
||||
lightVector /= vec3(dist);
|
||||
float atten = computeSpotFalloff(lightDirection, lightVector);
|
||||
if (atten == 0.0) {
|
||||
outDiffuse = vec3(0.0);
|
||||
outSpecular = vec3(0.0);
|
||||
return;
|
||||
}
|
||||
atten *= Lighting_ProcessAttenuation(lightPosition.w, dist);
|
||||
if (atten == 0.0) {
|
||||
outDiffuse = vec3(0.0);
|
||||
outSpecular = vec3(0.0);
|
||||
return;
|
||||
}
|
||||
PBR_ComputeDirectLightSpecWF(surface.normal, lightVector, surface.viewDir,
|
||||
lightColor.rgb, surface.specular.rgb, surface.roughness, surface.ndotv,
|
||||
outDiffuse, outSpecular);
|
||||
|
||||
outDiffuse *= atten;
|
||||
outSpecular *= atten;
|
||||
}
|
||||
|
||||
void Lighting_ProcessAll(surface_t surface, out vec3 ambient, out vec3 diffuse, out vec3 specular) {
|
||||
|
||||
ambient = g_AmbientLightColor.rgb;
|
||||
@ -143,62 +104,50 @@ void Lighting_ProcessAll(surface_t surface, out vec3 ambient, out vec3 diffuse,
|
||||
#if LIGHT_DATA_SIZE > 0
|
||||
int projIndex = 0;
|
||||
|
||||
for (int i = DIR_SHADOW_LIGHT_START; i < DIR_SHADOW_LIGHT_END; i += 2) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
Lighting_ProcessDirectional(i, surface, outDiffuse, outSpecular);
|
||||
|
||||
float shadow = Shadow_Process(0, vec3(0.0), g_LightData[i].w, projIndex);
|
||||
outDiffuse *= shadow;
|
||||
outSpecular *= shadow;
|
||||
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
|
||||
for (int i = DIR_LIGHT_START; i < DIR_LIGHT_END; i += 2) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
Lighting_ProcessDirectional(i, surface, outDiffuse, outSpecular);
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
|
||||
for (int i = POINT_SHADOW_LIGHT_START; i < POINT_SHADOW_LIGHT_END; i += 2) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
vec3 lightDir = Lighting_ProcessPoint(i, surface, outDiffuse, outSpecular);
|
||||
|
||||
float shadow = Shadow_Process(1, lightDir, g_LightData[i].w, projIndex);
|
||||
outDiffuse *= shadow;
|
||||
outSpecular *= shadow;
|
||||
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
for (int i = POINT_LIGHT_START; i < POINT_LIGHT_END; i += 2) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
Lighting_ProcessPoint(i, surface, outDiffuse, outSpecular);
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
|
||||
for (int i = SPOT_SHADOW_LIGHT_START; i < SPOT_SHADOW_LIGHT_END; i += 3) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
Lighting_ProcessSpot(i, surface, outDiffuse, outSpecular);
|
||||
|
||||
float shadow = Shadow_Process(2, vec3(0.0), g_LightData[i].w, projIndex);
|
||||
outDiffuse *= shadow;
|
||||
outSpecular *= shadow;
|
||||
|
||||
Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
|
||||
for (int i = SPOT_LIGHT_START; i < SPOT_LIGHT_END; i += 3) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
Lighting_ProcessSpot(i, surface, outDiffuse, outSpecular);
|
||||
Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
|
||||
for (int i = DIR_SHADOW_LIGHT_START; i < DIR_SHADOW_LIGHT_END; i += 2) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
|
||||
for (int i = DIR_LIGHT_START; i < DIR_LIGHT_END; i += 2) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
|
||||
for (int i = POINT_SHADOW_LIGHT_START; i < POINT_SHADOW_LIGHT_END; i += 2) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
|
||||
for (int i = POINT_LIGHT_START; i < POINT_LIGHT_END; i += 2) {
|
||||
vec3 outDiffuse, outSpecular;
|
||||
Lighting_Process(i, surface, outDiffuse, outSpecular, projIndex);
|
||||
diffuse += outDiffuse;
|
||||
specular += outSpecular;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ void main() {
|
||||
vec3 lightDir = g_CameraPosition - TransformWorld(modelSpacePos).xyz;
|
||||
|
||||
// The Z value to write into the depth map, should be [0.0, 1.0]
|
||||
float z = length(lightDir) / g_FrustumNearFar.y;
|
||||
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;
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,100 +1,98 @@
|
||||
#ifndef NUM_SHADOW_DIR_LIGHTS
|
||||
#define NUM_SHADOW_DIR_LIGHTS 0
|
||||
#endif
|
||||
#ifndef NUM_SHADOW_POINT_LIGHTS
|
||||
#define NUM_SHADOW_POINT_LIGHTS 0
|
||||
#endif
|
||||
#ifndef NUM_SHADOW_SPOT_LIGHTS
|
||||
#define NUM_SHADOW_SPOT_LIGHTS 0
|
||||
#endif
|
||||
#import "Common/ShaderLib/GLSLCompat.glsllib"
|
||||
|
||||
#extension GL_EXT_texture_array : enable
|
||||
|
||||
#ifndef NUM_PSSM_SPLITS
|
||||
#define NUM_PSSM_SPLITS 0
|
||||
#endif
|
||||
|
||||
#define SHADOW_DATA_SIZE (NUM_SHADOW_DIR_LIGHTS * NUM_PSSM_SPLITS + NUM_SHADOW_POINT_LIGHTS * 6 + NUM_SHADOW_SPOT_LIGHTS)
|
||||
#ifdef IN_PASS_SHADOWS
|
||||
|
||||
#if SHADOW_DATA_SIZE > 0
|
||||
uniform mat4 g_ShadowMatrices[(NB_LIGHTS/3) + NUM_PSSM_SPLITS];
|
||||
|
||||
varying vec4 vProjCoord[SHADOW_DATA_SIZE];
|
||||
#if NUM_PSSM_SPLITS > 0
|
||||
varying vec3 dirProjCoord[NUM_PSSM_SPLITS];
|
||||
#else
|
||||
varying vec3 dirProjCoord[1];
|
||||
#endif
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
uniform mat4 g_ShadowMatrices[SHADOW_DATA_SIZE];
|
||||
|
||||
void Shadow_ProcessProjCoord(vec3 worldPos) {
|
||||
for (int i = 0; i < SHADOW_DATA_SIZE; i++) {
|
||||
vProjCoord[i] = g_ShadowMatrices[i] * vec4(worldPos, 1.0);
|
||||
#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;
|
||||
|
||||
int pssmSliceOffset;
|
||||
float pssmSliceOffset;
|
||||
|
||||
void Shadow_ProcessPssmSlice() {
|
||||
#if defined(NUM_PSSM_SPLITS) && NUM_PSSM_SPLITS > 1
|
||||
pssmSliceOffset = int(dot(step(g_PssmSplits.xyz, gl_FragCoord.zzz), vec3(1.0)));
|
||||
#if NUM_PSSM_SPLITS > 1
|
||||
pssmSliceOffset = dot(step(g_PssmSplits.xyz, gl_FragCoord.zzz), vec3(1.0));
|
||||
#else
|
||||
pssmSliceOffset = 0;
|
||||
pssmSliceOffset = 0.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a float from 0.0 - 5.0 containing the index
|
||||
* of the cubemap face to fetch for the given direction
|
||||
*/
|
||||
float Shadow_GetCubeMapFace(in vec3 direction) {
|
||||
vec3 mag = abs(direction);
|
||||
|
||||
// Compare each component against the other two
|
||||
// Largest component is set to 1.0, the rest are 0.0
|
||||
vec3 largestComp = step(mag.yzx, mag) * step(mag.zxy, mag);
|
||||
|
||||
// Negative components are set to 1.0, the positive are 0.0
|
||||
vec3 negComp = step(direction, vec3(0.0));
|
||||
|
||||
// Each component contains the face index to use
|
||||
vec3 faceIndices = vec3(0.0, 2.0, 4.0) + negComp;
|
||||
|
||||
// Pick the face index with the largest component
|
||||
return dot(largestComp, faceIndices);
|
||||
}
|
||||
|
||||
float Shadow_ProcessDirectional(in int lightType, in vec3 lightDir, in float startArrayLayer, inout int startProjIndex) {
|
||||
float arraySlice = startArrayLayer + float(pssmSliceOffset);
|
||||
vec3 projCoord = vProjCoord[startProjIndex + pssmSliceOffset].xyz;
|
||||
startProjIndex += NUM_PSSM_SPLITS;
|
||||
return texture(g_ShadowMapArray, vec4(projCoord.xy, arraySlice, projCoord.z));
|
||||
}
|
||||
|
||||
float Shadow_ProcessSpot(in int lightType, in vec3 lightDir, in float startArrayLayer, inout int startProjIndex) {
|
||||
vec4 projCoord = vProjCoord[startProjIndex];
|
||||
projCoord.xyz /= projCoord.w;
|
||||
startProjIndex ++;
|
||||
return texture(g_ShadowMapArray, vec4(projCoord.xy, startArrayLayer, projCoord.z));
|
||||
}
|
||||
|
||||
float Shadow_Process(in int lightType, in vec3 lightDir, in float startArrayLayer, inout int startProjIndex) {
|
||||
float arraySlice = startArrayLayer;
|
||||
vec4 projCoord;
|
||||
|
||||
if (lightType == 0) {
|
||||
arraySlice += float(pssmSliceOffset);
|
||||
projCoord = vProjCoord[startProjIndex + pssmSliceOffset];
|
||||
startProjIndex += NUM_PSSM_SPLITS;
|
||||
} else if (lightType == 1) {
|
||||
float face = Shadow_GetCubeMapFace(lightDir);
|
||||
arraySlice += face;
|
||||
projCoord = vProjCoord[startProjIndex + int(face)];
|
||||
projCoord.xyz /= projCoord.w;
|
||||
startProjIndex += 6;
|
||||
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 {
|
||||
projCoord = vProjCoord[startProjIndex];
|
||||
projCoord.xyz /= projCoord.w;
|
||||
startProjIndex += 1;
|
||||
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);
|
||||
}
|
||||
|
||||
return texture(g_ShadowMapArray, vec4(projCoord.xy, arraySlice, projCoord.z));
|
||||
#if __VERSION__ >= 150
|
||||
return texture(g_ShadowMapArray, tc);
|
||||
#else
|
||||
return shadow2DArray(g_ShadowMapArray, tc).x;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -149,10 +147,9 @@
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#define NUM_SHADOW_DIR_LIGHTS 0
|
||||
#define NUM_SHADOW_POINT_LIGHTS 0
|
||||
#define NUM_SHADOW_SPOT_LIGHTS 0
|
||||
#define NUM_PSSM_SPLITS 0
|
||||
|
||||
const int pssmSliceOffset = 0;
|
||||
|
||||
void Shadow_ProcessProjCoord(vec3 worldPos) {
|
||||
}
|
||||
@ -160,15 +157,9 @@
|
||||
void Shadow_ProcessPssmSlice() {
|
||||
}
|
||||
|
||||
float Shadow_ProcessDirectional(int startLightIndex, float startArrayLayer) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
float Shadow_ProcessSpot(int startLightIndex, float startArrayLayer) {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
float Shadow_Process(in int lightType, in vec3 lightDir, in float startArrayLayer, inout int startProjIndex) {
|
||||
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);
|
||||
@ -15,7 +15,7 @@ void lightComputeDir(in vec3 worldPos, in float lightType, in vec4 position, out
|
||||
lightDir.w = (1.0 - position.w * dist) / (1.0 + position.w * dist * dist);
|
||||
lightDir.w = clamp(lightDir.w, 1.0 - posLight, 1.0);
|
||||
#else
|
||||
lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
|
||||
lightDir.w = 1.0; // clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
|
||||
#endif
|
||||
lightDir.xyz = tempVec / vec3(dist);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user