Merge pull request #2102 from N8n5h/light-fix-2
Add support for shadow map atlasing
This commit is contained in:
commit
49a599dc66
|
@ -2,7 +2,6 @@
|
|||
|
||||
#include "compiled.inc"
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/light.glsl"
|
||||
#ifdef _Clusters
|
||||
#include "std/clusters.glsl"
|
||||
#endif
|
||||
|
@ -80,14 +79,11 @@ uniform mat4 invVP;
|
|||
#ifdef _ShadowMap
|
||||
#ifdef _SinglePoint
|
||||
//!uniform sampler2DShadow shadowMapSpot[1];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot1;
|
||||
//!uniform mat4 LWVPSpot2;
|
||||
//!uniform mat4 LWVPSpot3;
|
||||
//!uniform mat4 LWVPSpotArray[4];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -109,21 +105,36 @@ uniform vec2 cameraPlane;
|
|||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
//!uniform sampler2DShadow shadowMapSpot[1];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot[1];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[1];
|
||||
//!uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
//!uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifdef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#endif
|
||||
//!uniform vec4 pointLightDataArray[4];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#endif
|
||||
//!uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot1;
|
||||
//!uniform mat4 LWVPSpot2;
|
||||
//!uniform mat4 LWVPSpot3;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#endif
|
||||
#else
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
#endif
|
||||
//!uniform mat4 LWVPSpotArray[4];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -132,7 +143,13 @@ uniform vec2 cameraPlane;
|
|||
uniform vec3 sunDir;
|
||||
uniform vec3 sunCol;
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSun;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMap;
|
||||
#endif
|
||||
uniform float shadowsBias;
|
||||
#ifdef _CSM
|
||||
//!uniform vec4 casData[shadowmapCascades * 4 + 4];
|
||||
|
@ -159,6 +176,8 @@ uniform sampler2D texClouds;
|
|||
uniform float time;
|
||||
#endif
|
||||
|
||||
#include "std/light.glsl"
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec3 viewRay;
|
||||
out vec4 fragColor;
|
||||
|
@ -289,10 +308,32 @@ void main() {
|
|||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _CSM
|
||||
svisibility = shadowTestCascade(shadowMap, eye, p + n * shadowsBias * 10, shadowsBias);
|
||||
svisibility = shadowTestCascade(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, eye, p + n * shadowsBias * 10, shadowsBias
|
||||
);
|
||||
#else
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) svisibility = shadowTest(shadowMap, lPos.xyz / lPos.w, shadowsBias);
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) svisibility = shadowTest(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, shadowsBias
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -335,7 +376,18 @@ void main() {
|
|||
int casi, casindex;
|
||||
mat4 LWVP = getCascadeMat(distance(eye, p), casi, casindex);
|
||||
#endif
|
||||
fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVP, p, n, sunDir, lightPlane.y, shadowMap);
|
||||
fragColor.rgb += fragColor.rgb * SSSSTransmittance(
|
||||
LWVP, p, n, sunDir, lightPlane.y,
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -199,43 +199,37 @@
|
|||
"ifdef": ["_SinglePoint", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot0",
|
||||
"name": "LWVPSpotArray",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpotArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "pointLightDataArray",
|
||||
"link": "_pointLightsAtlasArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_ShadowMapAtlas"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[0]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot0",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot1",
|
||||
"name": "LWVPSpot[1]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot1",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot2",
|
||||
"name": "LWVPSpot[2]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot2",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot3",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot0",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot0",
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot1",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot1",
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot2",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot2",
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot3",
|
||||
"name": "LWVPSpot[3]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
}
|
||||
],
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "compiled.inc"
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/math.glsl"
|
||||
#include "std/light_mobile.glsl"
|
||||
#ifdef _Clusters
|
||||
#include "std/clusters.glsl"
|
||||
#endif
|
||||
|
@ -47,21 +46,36 @@ uniform vec2 cameraPlane;
|
|||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
//!uniform sampler2DShadow shadowMapSpot[1];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot[1];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[1];
|
||||
//!uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
//!uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifdef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#endif
|
||||
//!uniform vec4 pointLightDataArray[4];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#endif
|
||||
//!uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
//!uniform mat4 LWVPSpot0;
|
||||
//!uniform mat4 LWVPSpot1;
|
||||
//!uniform mat4 LWVPSpot2;
|
||||
//!uniform mat4 LWVPSpot3;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#endif
|
||||
#else
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
#endif
|
||||
//!uniform mat4 LWVPSpotArray[4];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -70,7 +84,13 @@ uniform vec2 cameraPlane;
|
|||
uniform vec3 sunDir;
|
||||
uniform vec3 sunCol;
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSun;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMap;
|
||||
#endif
|
||||
uniform float shadowsBias;
|
||||
#ifdef _CSM
|
||||
//!uniform vec4 casData[shadowmapCascades * 4 + 4];
|
||||
|
@ -90,6 +110,8 @@ uniform float pointBias;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include "std/light_mobile.glsl"
|
||||
|
||||
in vec2 texCoord;
|
||||
in vec3 viewRay;
|
||||
out vec4 fragColor;
|
||||
|
@ -168,10 +190,32 @@ void main() {
|
|||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _CSM
|
||||
svisibility = shadowTestCascade(shadowMap, eye, p + n * shadowsBias * 10, shadowsBias, shadowmapSize * vec2(shadowmapCascades, 1.0));
|
||||
svisibility = shadowTestCascade(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, eye, p + n * shadowsBias * 10, shadowsBias
|
||||
);
|
||||
#else
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) svisibility = shadowTest(shadowMap, lPos.xyz / lPos.w, shadowsBias, shadowmapSize);
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) svisibility = shadowTest(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, shadowsBias
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -138,24 +138,38 @@
|
|||
"ifdef": ["_SinglePoint", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot0",
|
||||
"name": "LWVPSpotArray",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpotArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "pointLightDataArray",
|
||||
"link": "_pointLightsAtlasArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_ShadowMapAtlas"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[0]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot0",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot1",
|
||||
"name": "LWVPSpot[1]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot1",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot2",
|
||||
"name": "LWVPSpot[2]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot2",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot3",
|
||||
"name": "LWVPSpot[3]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
}
|
||||
],
|
||||
"vertex_shader": "../include/pass_viewray.vert.glsl",
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
|
||||
const int maxLights = 16;
|
||||
const int maxLightsCluster = 4; // Ensure fast loop unroll before going higher
|
||||
const float clusterNear = 3.0;
|
||||
const vec3 clusterSlices = vec3(16, 16, 16);
|
||||
|
||||
int getClusterI(vec2 tc, float viewz, vec2 cameraPlane) {
|
||||
|
|
|
@ -21,27 +21,41 @@
|
|||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot0;
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
#ifndef _LTC
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot1;
|
||||
uniform mat4 LWVPSpot2;
|
||||
uniform mat4 LWVPSpot3;
|
||||
#ifdef _Clusters
|
||||
#ifdef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _LTC
|
||||
uniform vec3 lightArea0;
|
||||
|
@ -51,17 +65,14 @@ uniform vec3 lightArea3;
|
|||
uniform sampler2D sltcMat;
|
||||
uniform sampler2D sltcMag;
|
||||
#ifdef _ShadowMap
|
||||
#ifndef _Spot
|
||||
#ifndef _Spot
|
||||
#ifdef _SinglePoint
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot1;
|
||||
uniform mat4 LWVPSpot2;
|
||||
uniform mat4 LWVPSpot3;
|
||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -132,24 +143,24 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) {
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 1) {
|
||||
vec4 lPos = LWVPSpot1 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[1] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 2) {
|
||||
vec4 lPos = LWVPSpot2 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[2] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 3) {
|
||||
vec4 lPos = LWVPSpot3 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[3] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
#endif
|
||||
|
@ -168,26 +179,30 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) {
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 1) {
|
||||
vec4 lPos = LWVPSpot1 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 2) {
|
||||
vec4 lPos = LWVPSpot2 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 3) {
|
||||
vec4 lPos = LWVPSpot3 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
#ifdef _ShadowMapAtlas
|
||||
vec3 uv = lPos.xyz / lPos.w;
|
||||
#ifdef _InvY
|
||||
uv.y = 1.0 - uv.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
direct *= shadowTest(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
, uv, bias
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -207,10 +222,21 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n);
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= PCFFakeCube(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
, ld, -l, bias, lightProj, n, index
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -11,21 +11,33 @@
|
|||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#ifdef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlas;
|
||||
#endif
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot1;
|
||||
uniform mat4 LWVPSpot2;
|
||||
uniform mat4 LWVPSpot3;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -62,26 +74,30 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) {
|
||||
vec4 lPos = LWVPSpot0 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 1) {
|
||||
vec4 lPos = LWVPSpot1 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 2) {
|
||||
vec4 lPos = LWVPSpot2 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
else if (index == 3) {
|
||||
vec4 lPos = LWVPSpot3 * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
}
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
#ifdef _ShadowMapAtlas
|
||||
vec3 uv = lPos.xyz / lPos.w;
|
||||
#ifdef _InvY
|
||||
uv.y = 1.0 - uv.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
direct *= shadowTest(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
, uv, bias
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], lPos.xyz / lPos.w, bias);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], lPos.xyz / lPos.w, bias);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -96,10 +112,21 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co
|
|||
direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n);
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= PCFFakeCube(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
, ld, -l, bias, lightProj, n, index
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0], ld, -l, bias, lightProj, n);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], ld, -l, bias, lightProj, n);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], ld, -l, bias, lightProj, n);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], ld, -l, bias, lightProj, n);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,41 @@ uniform vec4 casData[shadowmapCascades * 4 + 4];
|
|||
uniform vec2 smSizeUniform;
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _Clusters
|
||||
#ifdef _ShadowMapAtlas
|
||||
uniform vec4 pointLightDataArray[maxLightsCluster * 6];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMapAtlas
|
||||
// https://www.khronos.org/registry/OpenGL/specs/gl/glspec20.pdf // p:168
|
||||
// https://www.gamedev.net/forums/topic/687535-implementing-a-cube-map-lookup-function/5337472/
|
||||
vec2 sampleCube(vec3 dir, out int faceIndex) {
|
||||
vec3 dirAbs = abs(dir);
|
||||
float ma;
|
||||
vec2 uv;
|
||||
if(dirAbs.z >= dirAbs.x && dirAbs.z >= dirAbs.y) {
|
||||
faceIndex = dir.z < 0.0 ? 5 : 4;
|
||||
ma = 0.5 / dirAbs.z;
|
||||
uv = vec2(dir.z < 0.0 ? -dir.x : dir.x, -dir.y);
|
||||
}
|
||||
else if(dirAbs.y >= dirAbs.x) {
|
||||
faceIndex = dir.y < 0.0 ? 3 : 2;
|
||||
ma = 0.5 / dirAbs.y;
|
||||
uv = vec2(dir.x, dir.y < 0.0 ? -dir.z : dir.z);
|
||||
}
|
||||
else {
|
||||
faceIndex = dir.x < 0.0 ? 1 : 0;
|
||||
ma = 0.5 / dirAbs.x;
|
||||
uv = vec2(dir.x < 0.0 ? dir.z : -dir.z, -dir.y);
|
||||
}
|
||||
// downscale uv a little to hide seams
|
||||
return uv * 0.9976 * ma + 0.5;
|
||||
}
|
||||
#endif
|
||||
|
||||
float PCF(sampler2DShadow shadowMap, const vec2 uv, const float compare, const vec2 smSize) {
|
||||
float result = texture(shadowMap, vec3(uv + (vec2(-1.0, -1.0) / smSize), compare));
|
||||
result += texture(shadowMap, vec3(uv + (vec2(-1.0, 0.0) / smSize), compare));
|
||||
|
@ -50,6 +85,185 @@ float PCFCube(samplerCubeShadow shadowMapCube, const vec3 lp, vec3 ml, const flo
|
|||
return result / 9.0;
|
||||
}
|
||||
|
||||
#ifdef _ShadowMapAtlas
|
||||
// transform "out-of-bounds" coordinates to the correct face/coordinate system
|
||||
vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) {
|
||||
if (uv.x < 0.0) {
|
||||
if (faceIndex == 0) { // X+
|
||||
newFaceIndex = 4; // Z+
|
||||
}
|
||||
else if (faceIndex == 1) { // X-
|
||||
newFaceIndex = 5; // Z-
|
||||
}
|
||||
else if (faceIndex == 2) { // Y+
|
||||
newFaceIndex = 1; // X-
|
||||
}
|
||||
else if (faceIndex == 3) { // Y-
|
||||
newFaceIndex = 1; // X-
|
||||
}
|
||||
else if (faceIndex == 4) { // Z+
|
||||
newFaceIndex = 1; // X-
|
||||
}
|
||||
else { // Z-
|
||||
newFaceIndex = 0; // X+
|
||||
}
|
||||
uv = vec2(1.0 + uv.x, uv.y);
|
||||
}
|
||||
else if (uv.x > 1.0) {
|
||||
if (faceIndex == 0) { // X+
|
||||
newFaceIndex = 5; // Z-
|
||||
}
|
||||
else if (faceIndex == 1) { // X-
|
||||
newFaceIndex = 4; // Z+
|
||||
}
|
||||
else if (faceIndex == 2) { // Y+
|
||||
newFaceIndex = 0; // X+
|
||||
}
|
||||
else if (faceIndex == 3) { // Y-
|
||||
newFaceIndex = 0; // X+
|
||||
}
|
||||
else if (faceIndex == 4) { // Z+
|
||||
newFaceIndex = 0; // X+
|
||||
}
|
||||
else { // Z-
|
||||
newFaceIndex = 1; // X-
|
||||
}
|
||||
uv = vec2(1.0 - uv.x, uv.y);
|
||||
}
|
||||
else if (uv.y < 0.0) {
|
||||
if (faceIndex == 0) { // X+
|
||||
newFaceIndex = 2; // Y+
|
||||
}
|
||||
else if (faceIndex == 1) { // X-
|
||||
newFaceIndex = 2; // Y+
|
||||
}
|
||||
else if (faceIndex == 2) { // Y+
|
||||
newFaceIndex = 5; // Z-
|
||||
}
|
||||
else if (faceIndex == 3) { // Y-
|
||||
newFaceIndex = 4; // Z+
|
||||
}
|
||||
else if (faceIndex == 4) { // Z+
|
||||
newFaceIndex = 2; // Y+
|
||||
}
|
||||
else { // Z-
|
||||
newFaceIndex = 2; // Y+
|
||||
}
|
||||
uv = vec2(uv.x, 1.0 + uv.y);
|
||||
}
|
||||
else if (uv.y > 1.0) {
|
||||
if (faceIndex == 0) { // X+
|
||||
newFaceIndex = 3; // Y-
|
||||
}
|
||||
else if (faceIndex == 1) { // X-
|
||||
newFaceIndex = 3; // Y-
|
||||
}
|
||||
else if (faceIndex == 2) { // Y+
|
||||
newFaceIndex = 4; // Z+
|
||||
}
|
||||
else if (faceIndex == 3) { // Y-
|
||||
newFaceIndex = 5; // Z-
|
||||
}
|
||||
else if (faceIndex == 4) { // Z+
|
||||
newFaceIndex = 3; // Y-
|
||||
}
|
||||
else { // Z-
|
||||
newFaceIndex = 3; // Y-
|
||||
}
|
||||
uv = vec2(uv.x, 1.0 - uv.y);
|
||||
} else {
|
||||
newFaceIndex = faceIndex;
|
||||
}
|
||||
// cover corner cases too
|
||||
return uv;
|
||||
}
|
||||
|
||||
float PCFFakeCube(sampler2DShadow shadowMap, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index) {
|
||||
const vec2 smSize = smSizeUniform; // TODO: incorrect...
|
||||
const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
||||
ml = ml + n * bias * 20;
|
||||
|
||||
int faceIndex = 0;
|
||||
const int lightIndex = index * 6;
|
||||
const vec2 uv = sampleCube(ml, faceIndex);
|
||||
|
||||
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
|
||||
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
|
||||
#ifdef _InvY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
|
||||
float result = texture(shadowMap, vec3(uvtiled, compare));
|
||||
// soft shadowing
|
||||
int newFaceIndex = 0;
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, 0.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _InvY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result += texture(shadowMap, vec3(pointLightTile.z * uvtiled + pointLightTile.xy, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, 1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _InvY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, -1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _InvY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, -1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _InvY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, 1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _InvY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, -1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _InvY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, 0.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _InvY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, 1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _InvY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
return result / 9.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
float shadowTest(sampler2DShadow shadowMap, const vec3 lPos, const float shadowsBias) {
|
||||
#ifdef _SMSizeUniform
|
||||
vec2 smSize = smSizeUniform;
|
||||
|
@ -95,7 +309,7 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
|
|||
|
||||
float shadowTestCascade(sampler2DShadow shadowMap, const vec3 eye, const vec3 p, const float shadowsBias) {
|
||||
#ifdef _SMSizeUniform
|
||||
vec2 smSize = smSizeUniform * vec2(shadowmapCascades, 1.0);
|
||||
vec2 smSize = smSizeUniform;
|
||||
#else
|
||||
const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0);
|
||||
#endif
|
||||
|
|
|
@ -24,7 +24,7 @@ uniform vec2 cameraPlane;
|
|||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform vec2 lightProj;
|
||||
|
@ -35,10 +35,7 @@ uniform vec2 cameraPlane;
|
|||
uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform mat4 LWVPSpot0;
|
||||
uniform mat4 LWVPSpot1;
|
||||
uniform mat4 LWVPSpot2;
|
||||
uniform mat4 LWVPSpot3;
|
||||
uniform mat4 LWVPSpot[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -103,7 +100,7 @@ void rayStep(inout vec3 curPos, inout float curOpticalDepth, inout float scatter
|
|||
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
vec4 lPos = LWVPSpot0 * vec4(curPos, 1.0);
|
||||
vec4 lPos = LWVPSpot[0] * vec4(curPos, 1.0);
|
||||
visibility = shadowTest(shadowMapSpot[0], lPos.xyz / lPos.w, pointBias);
|
||||
float spotEffect = dot(spotDir, normalize(pointPos - curPos)); // lightDir
|
||||
if (spotEffect < spotData.x) { // x - cutoff, y - cutoff - exponent
|
||||
|
|
|
@ -108,23 +108,32 @@
|
|||
"ifdef": ["_SinglePoint", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot0",
|
||||
"name": "LWVPSpotArray",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpotArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[0]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot0",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot1",
|
||||
"name": "LWVPSpot[1]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot1",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot2",
|
||||
"name": "LWVPSpot[2]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot2",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot3",
|
||||
"name": "LWVPSpot[3]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_Spot", "_ShadowMap"]
|
||||
}
|
||||
],
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package armory.renderpath;
|
||||
|
||||
import iron.RenderPath;
|
||||
import iron.object.LightObject;
|
||||
|
||||
class Inc {
|
||||
|
||||
|
@ -39,6 +40,171 @@ class Inc {
|
|||
#end
|
||||
}
|
||||
|
||||
#if arm_shadowmap_atlas
|
||||
public static function updatePointLightAtlasData(): Void {
|
||||
var atlas = ShadowMapAtlas.shadowMapAtlases.get(ShadowMapAtlas.shadowMapAtlasName("point"));
|
||||
if (atlas != null) {
|
||||
if(LightObject.pointLightsData == null) {
|
||||
LightObject.pointLightsData = new kha.arrays.Float32Array(
|
||||
LightObject.maxLightsCluster * ShadowMapTile.tilesLightType("point") * 4 ); // max possible visible lights * 6 or 2 (faces) * 4 (xyzw)
|
||||
}
|
||||
|
||||
var n = iron.Scene.active.lights.length > LightObject.maxLightsCluster ? LightObject.maxLightsCluster : iron.Scene.active.lights.length;
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
for (light in iron.Scene.active.lights) {
|
||||
if (i >= n)
|
||||
break;
|
||||
if (LightObject.discardLightCulled(light)) continue;
|
||||
if (light.data.raw.type == "point") {
|
||||
for(k in 0...light.tileOffsetX.length) {
|
||||
LightObject.pointLightsData[j ] = light.tileOffsetX[k]; // posx
|
||||
LightObject.pointLightsData[j + 1] = light.tileOffsetY[k]; // posy
|
||||
LightObject.pointLightsData[j + 2] = light.tileScale[k]; // tile scale factor relative to atlas
|
||||
LightObject.pointLightsData[j + 3] = 0; // padding
|
||||
j += 4;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function bindShadowMapAtlas() {
|
||||
for (atlas in ShadowMapAtlas.shadowMapAtlases) {
|
||||
path.bindTarget(atlas.target, atlas.target);
|
||||
}
|
||||
}
|
||||
|
||||
static function getShadowMapAtlas(atlas:ShadowMapAtlas):String {
|
||||
inline function createDepthTarget(name: String, size: Int) {
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = name;
|
||||
t.width = t.height = size;
|
||||
t.format = "DEPTH16";
|
||||
return path.createRenderTarget(t);
|
||||
}
|
||||
|
||||
var rt = path.renderTargets.get(atlas.target);
|
||||
// Create shadowmap atlas texture on the fly and replace existing on size change
|
||||
if (rt == null) {
|
||||
rt = createDepthTarget(atlas.target, atlas.sizew);
|
||||
}
|
||||
else if (atlas.updateRenderTarget) {
|
||||
atlas.updateRenderTarget = false;
|
||||
// Resize shadow map
|
||||
rt.unload();
|
||||
rt = createDepthTarget(atlas.target, atlas.sizew);
|
||||
}
|
||||
return atlas.target;
|
||||
}
|
||||
|
||||
public static function drawShadowMapAtlas() {
|
||||
#if rp_shadowmap
|
||||
#if rp_probes
|
||||
// Share shadow map with probe
|
||||
if (lastFrame == RenderPath.active.frame)
|
||||
return;
|
||||
lastFrame = RenderPath.active.frame;
|
||||
#end
|
||||
// add new lights to the atlases
|
||||
for (light in iron.Scene.active.lights) {
|
||||
if (!light.lightInAtlas && !light.culledLight && light.visible && light.shadowMapScale > 0.0
|
||||
&& light.data.raw.strength > 0.0 && light.data.raw.cast_shadow) {
|
||||
light.lightInAtlas = ShadowMapAtlas.addLight(light);
|
||||
}
|
||||
}
|
||||
// update point light data before rendering
|
||||
updatePointLightAtlasData();
|
||||
|
||||
for (atlas in ShadowMapAtlas.shadowMapAtlases) {
|
||||
var tilesToRemove = [];
|
||||
#if arm_shadowmap_atlas_lod
|
||||
var tilesToChangeSize = [];
|
||||
#end
|
||||
|
||||
var shadowmap = getShadowMapAtlas(atlas);
|
||||
path.setTargetStream(shadowmap);
|
||||
path.clearTarget(null, 1.0);
|
||||
|
||||
for (tile in atlas.activeTiles) {
|
||||
if (tile.light == null || !tile.light.visible || tile.light.culledLight
|
||||
|| !tile.light.data.raw.cast_shadow || tile.light.data.raw.strength == 0) {
|
||||
tile.unlockLight = true;
|
||||
tilesToRemove.push(tile);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if arm_shadowmap_atlas_lod
|
||||
var newTileSize = atlas.getTileSize(tile.light.shadowMapScale);
|
||||
if (newTileSize != tile.size) {
|
||||
if (newTileSize == 0) {
|
||||
tile.unlockLight = true;
|
||||
tilesToRemove.push(tile);
|
||||
continue;
|
||||
}
|
||||
// queue for size change
|
||||
tile.newTileSize = newTileSize;
|
||||
tilesToChangeSize.push(tile);
|
||||
}
|
||||
#end
|
||||
// set the tile offset for this tile and every linked tile to this one
|
||||
var j = 0;
|
||||
tile.forEachTileLinked(function (lTile) {
|
||||
tile.light.tileOffsetX[j] = (lTile.coordsX == 0) ? 0.0 : lTile.coordsX / atlas.sizew;
|
||||
tile.light.tileOffsetY[j] = (lTile.coordsY == 0) ? 0.0 : lTile.coordsY / atlas.sizew;
|
||||
tile.light.tileScale[j] = lTile.size / atlas.sizew;
|
||||
j++;
|
||||
});
|
||||
// set shadowmap size for uniform
|
||||
tile.light.data.raw.shadowmap_size = atlas.sizew;
|
||||
|
||||
path.light = tile.light;
|
||||
|
||||
var face = 0;
|
||||
var faces = ShadowMapTile.tilesLightType(tile.light.data.raw.type);
|
||||
|
||||
tile.forEachTileLinked(function (lTile) {
|
||||
if (faces > 1) {
|
||||
#if arm_csm
|
||||
switch (tile.light.data.raw.type) {
|
||||
case "sun": tile.light.setCascade(iron.Scene.active.camera, face);
|
||||
case "point": path.currentFace = face;
|
||||
}
|
||||
#else
|
||||
path.currentFace = face;
|
||||
#end
|
||||
face++;
|
||||
}
|
||||
path.setCurrentViewportWithOffset(lTile.size, lTile.size, lTile.coordsX, lTile.coordsY);
|
||||
|
||||
path.drawMeshesStream("shadowmap");
|
||||
});
|
||||
|
||||
path.currentFace = -1;
|
||||
}
|
||||
path.endStream();
|
||||
|
||||
#if arm_shadowmap_atlas_lod
|
||||
for (tile in tilesToChangeSize) {
|
||||
tilesToRemove.push(tile);
|
||||
|
||||
var newTile = ShadowMapTile.assignTiles(tile.light, atlas, tile);
|
||||
if (newTile != null)
|
||||
atlas.activeTiles.push(newTile);
|
||||
}
|
||||
// update point light data after changing size of tiles to avoid render issues
|
||||
updatePointLightAtlasData();
|
||||
#end
|
||||
|
||||
for (tile in tilesToRemove) {
|
||||
atlas.activeTiles.remove(tile);
|
||||
tile.freeTile();
|
||||
}
|
||||
}
|
||||
#end // rp_shadowmap
|
||||
}
|
||||
#else
|
||||
public static function bindShadowMap() {
|
||||
for (l in iron.Scene.active.lights) {
|
||||
if (!l.visible || l.data.raw.type != "sun") continue;
|
||||
|
@ -56,10 +222,15 @@ class Inc {
|
|||
}
|
||||
}
|
||||
|
||||
static function shadowMapName(l: iron.object.LightObject): String {
|
||||
if (l.data.raw.type == "sun") return "shadowMap";
|
||||
if (l.data.raw.type == "point") return "shadowMapPoint[" + pointIndex + "]";
|
||||
else return "shadowMapSpot[" + spotIndex + "]";
|
||||
static function shadowMapName(light: LightObject): String {
|
||||
switch (light.data.raw.type) {
|
||||
case "sun":
|
||||
return "shadowMap";
|
||||
case "point":
|
||||
return "shadowMapPoint[" + pointIndex + "]";
|
||||
default:
|
||||
return "shadowMapSpot[" + spotIndex + "]";
|
||||
}
|
||||
}
|
||||
|
||||
static function getShadowMap(l: iron.object.LightObject): String {
|
||||
|
@ -130,6 +301,7 @@ class Inc {
|
|||
|
||||
#end // rp_shadowmap
|
||||
}
|
||||
#end
|
||||
|
||||
public static function applyConfig() {
|
||||
#if arm_config
|
||||
|
@ -203,7 +375,11 @@ class Inc {
|
|||
path.setTarget("accum", ["revealage"]);
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if arm_shadowmap_atlas
|
||||
bindShadowMapAtlas();
|
||||
#else
|
||||
bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
path.drawMeshes("translucent");
|
||||
|
@ -342,3 +518,490 @@ class Inc {
|
|||
#end
|
||||
}
|
||||
}
|
||||
|
||||
#if arm_shadowmap_atlas
|
||||
class ShadowMapAtlas {
|
||||
|
||||
public var target: String;
|
||||
public var baseTileSizeConst: Int;
|
||||
public var maxAtlasSizeConst: Int;
|
||||
|
||||
public var sizew: Int;
|
||||
public var sizeh: Int;
|
||||
|
||||
public var currTileOffset = 0;
|
||||
public var tiles: Array<ShadowMapTile> = [];
|
||||
public var activeTiles: Array<ShadowMapTile> = [];
|
||||
public var depth = 1;
|
||||
#if arm_shadowmap_atlas_lod
|
||||
static var tileSizes: Array<Int> = [];
|
||||
static var tileSizeFactor: Array<Float> = [];
|
||||
#end
|
||||
public var updateRenderTarget = false;
|
||||
public static var shadowMapAtlases:Map<String, ShadowMapAtlas> = new Map(); // map a shadowmap atlas to their light type
|
||||
|
||||
function new(light: LightObject) {
|
||||
|
||||
var maxTileSize = shadowMapAtlasSize(light);
|
||||
this.target = shadowMapAtlasName(light.data.raw.type);
|
||||
this.sizew = this.sizeh = this.baseTileSizeConst = maxTileSize;
|
||||
this.depth = getSubdivisions();
|
||||
this.maxAtlasSizeConst = getMaxAtlasSize(light.data.raw.type);
|
||||
|
||||
#if arm_shadowmap_atlas_lod
|
||||
if (tileSizes.length == 0)
|
||||
computeTileSizes(maxTileSize, depth);
|
||||
#end
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a light to an atlas. The atlas is decided based on the type of the light
|
||||
* @param light of type LightObject to be added to an yatlas
|
||||
* @return if the light was added succesfully
|
||||
*/
|
||||
public static function addLight(light: LightObject): Bool {
|
||||
// check if light can be added based on culling
|
||||
if (light.culledLight || light.shadowMapScale == 0.0)
|
||||
return false;
|
||||
|
||||
var atlasName = shadowMapAtlasName(light.data.raw.type);
|
||||
var atlas = shadowMapAtlases.get(atlasName);
|
||||
if (atlas == null) {
|
||||
// create a new atlas
|
||||
atlas = new ShadowMapAtlas(light);
|
||||
shadowMapAtlases.set(atlasName, atlas);
|
||||
}
|
||||
|
||||
// find a free tile for this light
|
||||
var mainTile = ShadowMapTile.assignTiles(light, atlas, null);
|
||||
if (mainTile == null)
|
||||
return false;
|
||||
// push main tile to active tiles
|
||||
atlas.activeTiles.push(mainTile);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline function shadowMapAtlasSize(light:LightObject):Int {
|
||||
// TODO: this can break because we are changing shadowmap_size elsewhere.
|
||||
return light.data.raw.shadowmap_size;
|
||||
}
|
||||
|
||||
public function getTileSize(shadowMapScale: Float): Int {
|
||||
#if arm_shadowmap_atlas_lod
|
||||
// find the first scale factor that is smaller to the shadowmap scale, and then return the previous one.
|
||||
var i = 0;
|
||||
for (sizeFactor in tileSizeFactor) {
|
||||
if (sizeFactor < shadowMapScale) break;
|
||||
i++;
|
||||
}
|
||||
return tileSizes[i - 1];
|
||||
#else
|
||||
return this.baseTileSizeConst;
|
||||
#end
|
||||
}
|
||||
|
||||
#if arm_shadowmap_atlas_lod
|
||||
static function computeTileSizes(maxTileSize: Int, depth: Int): Void {
|
||||
// find the highest value based on the calculation done in the cluster code
|
||||
var base = LightObject.zToShadowMapScale(0, 16);
|
||||
var subdiv = base / depth;
|
||||
for(i in 0...depth){
|
||||
tileSizes.push(Std.int(maxTileSize / Math.pow(2, i)));
|
||||
tileSizeFactor.push(base);
|
||||
base -= subdiv;
|
||||
}
|
||||
tileSizes.push(0);
|
||||
tileSizeFactor.push(0.0);
|
||||
}
|
||||
#end
|
||||
|
||||
public inline function atlasLimitReached() {
|
||||
// asume square atlas
|
||||
return (currTileOffset + 1) * baseTileSizeConst > maxAtlasSizeConst;
|
||||
}
|
||||
|
||||
public static inline function shadowMapAtlasName(type: String): String {
|
||||
#if arm_shadowmap_atlas_single_map
|
||||
return "shadowMapAtlas";
|
||||
#else
|
||||
switch (type) {
|
||||
case "point":
|
||||
return "shadowMapAtlasPoint";
|
||||
case "sun":
|
||||
return "shadowMapAtlasSun";
|
||||
default:
|
||||
return "shadowMapAtlasSpot";
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function getSubdivisions(): Int {
|
||||
#if (rp_shadowmap_atlas_lod_subdivisions == 2)
|
||||
return 2;
|
||||
#elseif (rp_shadowmap_atlas_lod_subdivisions == 3)
|
||||
return 3;
|
||||
#elseif (rp_shadowmap_atlas_lod_subdivisions == 4)
|
||||
return 4;
|
||||
#elseif (rp_shadowmap_atlas_lod_subdivisions == 5)
|
||||
return 5;
|
||||
#elseif (rp_shadowmap_atlas_lod_subdivisions == 6)
|
||||
return 6;
|
||||
#elseif (rp_shadowmap_atlas_lod_subdivisions == 7)
|
||||
return 7;
|
||||
#elseif (rp_shadowmap_atlas_lod_subdivisions == 8)
|
||||
return 8;
|
||||
#elseif (!arm_shadowmap_atlas_lod)
|
||||
return 1;
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function getMaxAtlasSize(type: String): Int {
|
||||
#if arm_shadowmap_atlas_single_map
|
||||
#if (rp_shadowmap_atlas_max_size == 1024)
|
||||
return 1024;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 2048)
|
||||
return 2048;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 4096)
|
||||
return 4096;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 8192)
|
||||
return 8192;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 16384)
|
||||
return 16384;
|
||||
#end
|
||||
#else
|
||||
switch (type) {
|
||||
case "point": {
|
||||
#if (rp_shadowmap_atlas_max_size_point == 1024)
|
||||
return 1024;
|
||||
#elseif (rp_shadowmap_atlas_max_size_point == 2048)
|
||||
return 2048;
|
||||
#elseif (rp_shadowmap_atlas_max_size_point == 4096)
|
||||
return 4096;
|
||||
#elseif (rp_shadowmap_atlas_max_size_point == 8192)
|
||||
return 8192;
|
||||
#elseif (rp_shadowmap_atlas_max_size_point == 16384)
|
||||
return 16384;
|
||||
#end
|
||||
}
|
||||
case "spot": {
|
||||
#if (rp_shadowmap_atlas_max_size_spot == 1024)
|
||||
return 1024;
|
||||
#elseif (rp_shadowmap_atlas_max_size_spot == 2048)
|
||||
return 2048;
|
||||
#elseif (rp_shadowmap_atlas_max_size_spot == 4096)
|
||||
return 4096;
|
||||
#elseif (rp_shadowmap_atlas_max_size_spot == 8192)
|
||||
return 8192;
|
||||
#elseif (rp_shadowmap_atlas_max_size_spot == 16384)
|
||||
return 16384;
|
||||
#end
|
||||
}
|
||||
case "sun": {
|
||||
#if (rp_shadowmap_atlas_max_size_sun == 1024)
|
||||
return 1024;
|
||||
#elseif (rp_shadowmap_atlas_max_size_sun == 2048)
|
||||
return 2048;
|
||||
#elseif (rp_shadowmap_atlas_max_size_sun == 4096)
|
||||
return 4096;
|
||||
#elseif (rp_shadowmap_atlas_max_size_sun == 8192)
|
||||
return 8192;
|
||||
#elseif (rp_shadowmap_atlas_max_size_sun == 16384)
|
||||
return 16384;
|
||||
#end
|
||||
}
|
||||
default: {
|
||||
#if (rp_shadowmap_atlas_max_size == 1024)
|
||||
return 1024;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 2048)
|
||||
return 2048;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 4096)
|
||||
return 4096;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 8192)
|
||||
return 8192;
|
||||
#elseif (rp_shadowmap_atlas_max_size == 16384)
|
||||
return 16384;
|
||||
#end
|
||||
}
|
||||
|
||||
}
|
||||
#end
|
||||
}
|
||||
}
|
||||
|
||||
class ShadowMapTile {
|
||||
|
||||
public var light:Null<LightObject> = null;
|
||||
public var coordsX:Int;
|
||||
public var coordsY:Int;
|
||||
public var size:Int;
|
||||
public var tiles:Array<ShadowMapTile> = [];
|
||||
public var linkedTile:ShadowMapTile = null;
|
||||
|
||||
#if arm_shadowmap_atlas_lod
|
||||
public var parentTile: ShadowMapTile = null;
|
||||
public var activeSubTiles: Int = 0;
|
||||
public var newTileSize: Int = -1;
|
||||
|
||||
static var tilePattern = [[0, 0], [1, 0], [0, 1], [1, 1]];
|
||||
#end
|
||||
|
||||
function new(coordsX: Int, coordsY: Int, size: Int) {
|
||||
this.coordsX = coordsX;
|
||||
this.coordsY = coordsY;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public static function assignTiles(light: LightObject, atlas: ShadowMapAtlas, oldTile: ShadowMapTile): ShadowMapTile {
|
||||
var tileSize = 0;
|
||||
|
||||
#if arm_shadowmap_atlas_lod
|
||||
if (oldTile != null && oldTile.newTileSize != -1) {
|
||||
// reuse tilesize instead of computing it again
|
||||
tileSize = oldTile.newTileSize;
|
||||
oldTile.newTileSize = -1;
|
||||
}
|
||||
else
|
||||
#end
|
||||
tileSize = atlas.getTileSize(light.shadowMapScale);
|
||||
|
||||
if (tileSize == 0)
|
||||
return null;
|
||||
|
||||
var tiles = [];
|
||||
tiles = findCreateTiles(light, oldTile, atlas, tilesLightType(light.data.raw.type), tileSize);
|
||||
|
||||
// lock new tiles with light
|
||||
for (tile in tiles)
|
||||
tile.lockTile(light);
|
||||
|
||||
return linkTiles(tiles);
|
||||
}
|
||||
|
||||
static inline function linkTiles(tiles: Array<ShadowMapTile>): ShadowMapTile {
|
||||
if (tiles.length > 1) {
|
||||
var linkedTile = tiles[0];
|
||||
for (i in 1...tiles.length) {
|
||||
linkedTile.linkedTile = tiles[i];
|
||||
linkedTile = tiles[i];
|
||||
}
|
||||
}
|
||||
return tiles[0];
|
||||
}
|
||||
|
||||
static inline function findCreateTiles(light: LightObject, oldTile: ShadowMapTile, atlas: ShadowMapAtlas, tilesPerLightType: Int, tileSize: Int): Array<ShadowMapTile> {
|
||||
var tilesFound: Array<ShadowMapTile> = [];
|
||||
|
||||
var updateAtlas = false;
|
||||
while (tilesFound.length < tilesPerLightType) {
|
||||
findTiles(light, oldTile, atlas.tiles, tileSize, tilesPerLightType, tilesFound);
|
||||
|
||||
if (tilesFound.length < tilesPerLightType) {
|
||||
tilesFound = []; // empty tilesFound
|
||||
// skip creating more tiles if limit has been reached
|
||||
if (atlas.atlasLimitReached())
|
||||
break;
|
||||
|
||||
createTiles(atlas.tiles, atlas.baseTileSizeConst, atlas.depth, atlas.currTileOffset, atlas.currTileOffset);
|
||||
atlas.currTileOffset++;
|
||||
// update texture to accomodate new size
|
||||
atlas.updateRenderTarget = true;
|
||||
atlas.sizew = atlas.sizeh = atlas.currTileOffset * atlas.baseTileSizeConst;
|
||||
}
|
||||
}
|
||||
return tilesFound;
|
||||
}
|
||||
|
||||
inline static function findTiles(light:LightObject, oldTile: ShadowMapTile,
|
||||
tiles: Array<ShadowMapTile>, size: Int, tilesCount: Int, tilesFound: Array<ShadowMapTile>): Void {
|
||||
#if arm_shadowmap_atlas_lod
|
||||
if (oldTile != null) {
|
||||
// reuse children tiles
|
||||
if (size < oldTile.size) {
|
||||
oldTile.forEachTileLinked(function(lTile) {
|
||||
var childTile = findFreeChildTile(lTile, size);
|
||||
tilesFound.push(childTile);
|
||||
});
|
||||
}
|
||||
// reuse parent tiles
|
||||
else {
|
||||
oldTile.forEachTileLinked(function(lTile) {
|
||||
// find out if parents tiles are not occupied
|
||||
var parentTile = findFreeParentTile(lTile, size);
|
||||
// if parent is free, add it to found tiles
|
||||
if (parentTile != null)
|
||||
tilesFound.push(parentTile);
|
||||
});
|
||||
if (tilesFound.length < tilesCount) {
|
||||
// find naively the rest of the tiles that couldn't be reused
|
||||
findTilesNaive(light, tiles, size, tilesCount, tilesFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#end
|
||||
findTilesNaive(light, tiles, size, tilesCount, tilesFound);
|
||||
}
|
||||
|
||||
#if arm_shadowmap_atlas_lod
|
||||
static inline function findFreeChildTile(tile: ShadowMapTile, size: Int): ShadowMapTile {
|
||||
var childrenTile = tile;
|
||||
while (size < childrenTile.size) {
|
||||
childrenTile = childrenTile.tiles[0];
|
||||
}
|
||||
return childrenTile;
|
||||
}
|
||||
|
||||
static inline function findFreeParentTile(tile: ShadowMapTile, size: Int): ShadowMapTile {
|
||||
var parentTile = tile;
|
||||
while (size > parentTile.size) {
|
||||
parentTile = parentTile.parentTile;
|
||||
// stop if parent tile is occupied
|
||||
if (parentTile.activeSubTiles > 1) {
|
||||
parentTile = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return parentTile;
|
||||
}
|
||||
#end
|
||||
|
||||
static function findTilesNaive(light:LightObject, tiles: Array<ShadowMapTile>, size: Int, tilesCount: Int, tilesFound: Array<ShadowMapTile>): Void {
|
||||
for (tile in tiles) {
|
||||
if (tile.size == size) {
|
||||
if (tile.light == null #if arm_shadowmap_atlas_lod && tile.activeSubTiles == 0 #end) {
|
||||
tilesFound.push(tile);
|
||||
// stop after finding enough tiles
|
||||
if (tilesFound.length == tilesCount)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// skip over if end of the tree or tile is occupied
|
||||
if (tile.tiles.length == 0 || tile.light != null)
|
||||
continue;
|
||||
findTilesNaive(light, tile.tiles, size, tilesCount, tilesFound);
|
||||
// skip iterating over the rest of the tiles if found enough
|
||||
if (tilesFound.length == tilesCount)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create a basic tile and subdivide it if needed
|
||||
public static function createTiles(tiles:Array<ShadowMapTile>, size:Int, depth: Int, baseX:Int, baseY:Int) {
|
||||
var i = baseX;
|
||||
var j = 0;
|
||||
var lastTile = tiles.length;
|
||||
// assume occupied tiles start from 1 line before the base x
|
||||
var occupiedTiles = baseX - 1;
|
||||
|
||||
while (i >= 0) {
|
||||
if (i <= occupiedTiles) { // avoid overriding tiles
|
||||
j = baseY;
|
||||
}
|
||||
while (j <= baseY) {
|
||||
// create base tile of max-size
|
||||
tiles.push(new ShadowMapTile(size * i, size * j, size));
|
||||
#if arm_shadowmap_atlas_lod
|
||||
tiles[lastTile].tiles = subDivTile(tiles[lastTile], size, size * i, size * j, depth - 1);
|
||||
#end
|
||||
lastTile++;
|
||||
j++;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
#if arm_shadowmap_atlas_lod
|
||||
static function subDivTile(parent: ShadowMapTile, size: Int, baseCoordsX: Int, baseCoordsY: Int, depth: Int): Array<ShadowMapTile> {
|
||||
var tileSize = Std.int(size / 2);
|
||||
|
||||
var tiles = [];
|
||||
|
||||
for (i in 0...4) {
|
||||
var coordsX = baseCoordsX + tilePattern[i][0] * tileSize;
|
||||
var coordsY = baseCoordsY + tilePattern[i][1] * tileSize;
|
||||
|
||||
var tile = new ShadowMapTile(coordsX, coordsY, tileSize);
|
||||
tile.parentTile = parent;
|
||||
|
||||
if (depth > 1)
|
||||
tile.tiles = subDivTile(tile, tileSize, coordsX, coordsY, depth - 1);
|
||||
tiles.push(tile);
|
||||
}
|
||||
|
||||
return tiles;
|
||||
}
|
||||
#end
|
||||
|
||||
public static inline function tilesLightType(type: String): Int {
|
||||
switch (type) {
|
||||
case "sun":
|
||||
return LightObject.cascadeCount;
|
||||
case "point":
|
||||
return 6;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
inline function lockTile(light: LightObject): Void {
|
||||
if (this.light != null)
|
||||
return;
|
||||
this.light = light;
|
||||
#if arm_shadowmap_atlas_lod
|
||||
// update the count of used tiles for parents
|
||||
this.forEachParentTile(function (pTile) {
|
||||
pTile.activeSubTiles++;
|
||||
});
|
||||
#end
|
||||
}
|
||||
|
||||
public var unlockLight: Bool = false;
|
||||
|
||||
public function freeTile(): Void {
|
||||
// prevent duplicates
|
||||
if (light != null && unlockLight) {
|
||||
light.lightInAtlas = false;
|
||||
unlockLight = false;
|
||||
}
|
||||
|
||||
var linkedTile = this;
|
||||
var tempTile = this;
|
||||
while (linkedTile != null) {
|
||||
linkedTile.light = null;
|
||||
#if arm_shadowmap_atlas_lod
|
||||
// update the count of used tiles for parents
|
||||
linkedTile.forEachParentTile(function (pTile) {
|
||||
if (pTile.activeSubTiles > 0)
|
||||
pTile.activeSubTiles--;
|
||||
});
|
||||
#end
|
||||
|
||||
linkedTile = linkedTile.linkedTile;
|
||||
// unlink linked tiles
|
||||
tempTile.linkedTile = null;
|
||||
tempTile = linkedTile;
|
||||
}
|
||||
}
|
||||
|
||||
public inline function forEachTileLinked(action: ShadowMapTile->Void): Void {
|
||||
var linkedTile = this;
|
||||
while (linkedTile != null) {
|
||||
action(linkedTile);
|
||||
linkedTile = linkedTile.linkedTile;
|
||||
}
|
||||
}
|
||||
|
||||
#if arm_shadowmap_atlas_lod
|
||||
public inline function forEachParentTile(action: ShadowMapTile->Void): Void {
|
||||
var parentTile = this.parentTile;
|
||||
while (parentTile != null) {
|
||||
action(parentTile);
|
||||
parentTile = parentTile.parentTile;
|
||||
}
|
||||
}
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
|
|
@ -7,6 +7,8 @@ class RenderPathCreator {
|
|||
|
||||
public static var path: RenderPath;
|
||||
|
||||
public static var commands: Void->Void = function() {};
|
||||
|
||||
#if (rp_renderer == "Forward")
|
||||
public static var setTargetMeshes: Void->Void = RenderPathForward.setTargetMeshes;
|
||||
public static var drawMeshes: Void->Void = RenderPathForward.drawMeshes;
|
||||
|
@ -33,13 +35,22 @@ class RenderPathCreator {
|
|||
|
||||
#if (rp_renderer == "Forward")
|
||||
RenderPathForward.init(path);
|
||||
path.commands = RenderPathForward.commands;
|
||||
path.commands = function() {
|
||||
RenderPathForward.commands();
|
||||
commands();
|
||||
}
|
||||
#elseif (rp_renderer == "Deferred")
|
||||
RenderPathDeferred.init(path);
|
||||
path.commands = RenderPathDeferred.commands;
|
||||
path.commands = function() {
|
||||
RenderPathDeferred.commands();
|
||||
commands();
|
||||
}
|
||||
#elseif (rp_renderer == "Raytracer")
|
||||
RenderPathRaytracer.init(path);
|
||||
path.commands = RenderPathRaytracer.commands;
|
||||
path.commands = function() {
|
||||
RenderPathRaytracer.commands();
|
||||
commands();
|
||||
}
|
||||
#end
|
||||
return path;
|
||||
}
|
||||
|
|
|
@ -502,8 +502,13 @@ class RenderPathDeferred {
|
|||
#end
|
||||
|
||||
#if (rp_shadowmap)
|
||||
// atlasing is exclusive for now
|
||||
#if arm_shadowmap_atlas
|
||||
Inc.drawShadowMapAtlas();
|
||||
#else
|
||||
Inc.drawShadowMap();
|
||||
#end
|
||||
#end
|
||||
|
||||
// Voxels
|
||||
#if rp_voxelao
|
||||
|
@ -572,7 +577,11 @@ class RenderPathDeferred {
|
|||
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if arm_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
|
@ -624,7 +633,11 @@ class RenderPathDeferred {
|
|||
{
|
||||
path.setTarget("singlea");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#if arm_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
path.drawShader("shader_datas/volumetric_light/volumetric_light");
|
||||
|
||||
path.setTarget("singleb");
|
||||
|
|
|
@ -300,7 +300,11 @@ class RenderPathForward {
|
|||
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if arm_shadowmap_atlas
|
||||
Inc.drawShadowMapAtlas();
|
||||
#else
|
||||
Inc.drawShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
|
@ -352,7 +356,11 @@ class RenderPathForward {
|
|||
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if arm_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
|
@ -466,7 +474,11 @@ class RenderPathForward {
|
|||
{
|
||||
path.setTarget("singlea");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#if arm_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
path.drawShader("shader_datas/volumetric_light/volumetric_light");
|
||||
|
||||
path.setTarget("singleb");
|
||||
|
|
|
@ -421,6 +421,9 @@ class DebugConsole extends Trait {
|
|||
var lightHandle = Id.handle();
|
||||
lightHandle.value = light.data.raw.strength / 10;
|
||||
light.data.raw.strength = ui.slider(lightHandle, "Strength", 0.0, 5.0, true) * 10;
|
||||
#if arm_shadowmap_atlas
|
||||
ui.text("status: " + (light.culledLight ? "culled" : "rendered"));
|
||||
#end
|
||||
}
|
||||
else if (Std.is(selectedObject, iron.object.CameraObject)) {
|
||||
selectedType = "(Camera)";
|
||||
|
|
|
@ -43,6 +43,22 @@ def add_world_defs():
|
|||
if rpdat.rp_shadowmap_cascades != '1':
|
||||
wrd.world_defs += '_CSM'
|
||||
assets.add_khafile_def('arm_csm')
|
||||
if rpdat.rp_shadowmap_atlas:
|
||||
assets.add_khafile_def('arm_shadowmap_atlas')
|
||||
wrd.world_defs += '_ShadowMapAtlas'
|
||||
if rpdat.rp_shadowmap_atlas_single_map:
|
||||
assets.add_khafile_def('arm_shadowmap_atlas_single_map')
|
||||
wrd.world_defs += '_SingleAtlas'
|
||||
assets.add_khafile_def('rp_shadowmap_atlas_max_size_point={0}'.format(int(rpdat.rp_shadowmap_atlas_max_size_point)))
|
||||
assets.add_khafile_def('rp_shadowmap_atlas_max_size_spot={0}'.format(int(rpdat.rp_shadowmap_atlas_max_size_spot)))
|
||||
assets.add_khafile_def('rp_shadowmap_atlas_max_size_sun={0}'.format(int(rpdat.rp_shadowmap_atlas_max_size_sun)))
|
||||
assets.add_khafile_def('rp_shadowmap_atlas_max_size={0}'.format(int(rpdat.rp_shadowmap_atlas_max_size)))
|
||||
|
||||
assets.add_khafile_def('rp_max_lights_cluster={0}'.format(int(rpdat.rp_max_lights_cluster)))
|
||||
assets.add_khafile_def('rp_max_lights={0}'.format(int(rpdat.rp_max_lights)))
|
||||
if rpdat.rp_shadowmap_atlas_lod:
|
||||
assets.add_khafile_def('arm_shadowmap_atlas_lod')
|
||||
assets.add_khafile_def('rp_shadowmap_atlas_lod_subdivisions={0}'.format(int(rpdat.rp_shadowmap_atlas_lod_subdivisions)))
|
||||
# SS
|
||||
if rpdat.rp_ssgi == 'RTGI' or rpdat.rp_ssgi == 'RTAO':
|
||||
if rpdat.rp_ssgi == 'RTGI':
|
||||
|
@ -89,9 +105,14 @@ def add_world_defs():
|
|||
wrd.world_defs += '_Spot'
|
||||
assets.add_khafile_def('arm_spot')
|
||||
|
||||
if point_lights == 1:
|
||||
wrd.world_defs += '_SinglePoint'
|
||||
elif point_lights > 1:
|
||||
if not rpdat.rp_shadowmap_atlas:
|
||||
if point_lights == 1:
|
||||
wrd.world_defs += '_SinglePoint'
|
||||
elif point_lights > 1:
|
||||
wrd.world_defs += '_Clusters'
|
||||
assets.add_khafile_def('arm_clusters')
|
||||
else:
|
||||
wrd.world_defs += '_SMSizeUniform'
|
||||
wrd.world_defs += '_Clusters'
|
||||
assets.add_khafile_def('arm_clusters')
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@ import bpy
|
|||
def write(vert, frag):
|
||||
wrd = bpy.data.worlds['Arm']
|
||||
is_shadows = '_ShadowMap' in wrd.world_defs
|
||||
is_shadows_atlas = '_ShadowMapAtlas' in wrd.world_defs
|
||||
is_single_atlas = is_shadows_atlas and '_SingleAtlas' in wrd.world_defs
|
||||
|
||||
frag.add_include('std/clusters.glsl')
|
||||
frag.add_include_front('std/clusters.glsl')
|
||||
frag.add_uniform('vec2 cameraProj', link='_cameraPlaneProj')
|
||||
frag.add_uniform('vec2 cameraPlane', link='_cameraPlane')
|
||||
frag.add_uniform('vec4 lightsArray[maxLights * 2]', link='_lightsArray')
|
||||
|
@ -12,7 +14,12 @@ def write(vert, frag):
|
|||
if is_shadows:
|
||||
frag.add_uniform('bool receiveShadow')
|
||||
frag.add_uniform('vec2 lightProj', link='_lightPlaneProj', included=True)
|
||||
frag.add_uniform('samplerCubeShadow shadowMapPoint[4]', included=True)
|
||||
if is_shadows_atlas:
|
||||
if not is_single_atlas:
|
||||
frag.add_uniform('sampler2DShadow shadowMapAtlasPoint', included=True)
|
||||
frag.add_uniform('vec4 pointLightDataArray[maxLightsCluster]', link='_pointLightsAtlasArray', included=True)
|
||||
else:
|
||||
frag.add_uniform('samplerCubeShadow shadowMapPoint[4]', included=True)
|
||||
vert.add_out('vec4 wvpposition')
|
||||
vert.write('wvpposition = gl_Position;')
|
||||
# wvpposition.z / wvpposition.w
|
||||
|
@ -29,11 +36,12 @@ def write(vert, frag):
|
|||
frag.write('int numSpots = int(texelFetch(clustersData, ivec2(clusterI, 1 + maxLightsCluster), 0).r * 255);')
|
||||
frag.write('int numPoints = numLights - numSpots;')
|
||||
if is_shadows:
|
||||
frag.add_uniform('mat4 LWVPSpot0', link='_biasLightWorldViewProjectionMatrixSpot0', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpot1', link='_biasLightWorldViewProjectionMatrixSpot1', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpot2', link='_biasLightWorldViewProjectionMatrixSpot2', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpot3', link='_biasLightWorldViewProjectionMatrixSpot3', included=True)
|
||||
frag.add_uniform('sampler2DShadow shadowMapSpot[4]', included=True)
|
||||
if is_shadows_atlas and not is_single_atlas:
|
||||
frag.add_uniform(f'sampler2DShadow shadowMapAtlasSpot', included=True)
|
||||
elif not is_shadows_atlas:
|
||||
frag.add_uniform('sampler2DShadow shadowMapSpot[4]', included=True)
|
||||
# FIXME: type is actually mat4, but otherwise it will not be set as floats when writing the shaders' json files
|
||||
frag.add_uniform('vec4 LWVPSpotArray[maxLightsCluster]', link='_biasLightWorldViewProjectionMatrixSpotArray', included=True)
|
||||
|
||||
frag.write('for (int i = 0; i < min(numLights, maxLightsCluster); i++) {')
|
||||
frag.write('int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255);')
|
||||
|
@ -52,7 +60,7 @@ def write(vert, frag):
|
|||
if is_shadows:
|
||||
frag.write(' , li, lightsArray[li * 2].w, receiveShadow') # bias
|
||||
if '_Spot' in wrd.world_defs:
|
||||
frag.write(' , li > numPoints - 1')
|
||||
frag.write(' , lightsArray[li * 2 + 1].w != 0.0')
|
||||
frag.write(' , lightsArray[li * 2 + 1].w') # cutoff
|
||||
frag.write(' , lightsArraySpot[li].w') # cutoff - exponent
|
||||
frag.write(' , lightsArraySpot[li].xyz') # spotDir
|
||||
|
|
|
@ -354,6 +354,12 @@ def make_forward_mobile(con_mesh):
|
|||
return
|
||||
|
||||
is_shadows = '_ShadowMap' in wrd.world_defs
|
||||
is_shadows_atlas = '_ShadowMapAtlas' in wrd.world_defs
|
||||
is_single_atlas = is_shadows_atlas and '_SingleAtlas' in wrd.world_defs
|
||||
shadowmap_sun = 'shadowMap'
|
||||
if is_shadows_atlas:
|
||||
shadowmap_sun = 'shadowMapAtlasSun' if not is_single_atlas else 'shadowMapAtlas'
|
||||
frag.add_uniform('vec2 smSizeUniform', '_shadowMapSize', included=True)
|
||||
frag.write('vec3 direct = vec3(0.0);')
|
||||
|
||||
if '_Sun' in wrd.world_defs:
|
||||
|
@ -366,7 +372,7 @@ def make_forward_mobile(con_mesh):
|
|||
vert.add_uniform('mat4 LWVP', '_biasLightWorldViewProjectionMatrix')
|
||||
vert.write('lightPosition = LWVP * spos;')
|
||||
frag.add_uniform('bool receiveShadow')
|
||||
frag.add_uniform('sampler2DShadow shadowMap')
|
||||
frag.add_uniform(f'sampler2DShadow {shadowmap_sun}')
|
||||
frag.add_uniform('float shadowsBias', '_sunShadowsBias')
|
||||
|
||||
frag.write('if (receiveShadow) {')
|
||||
|
@ -374,14 +380,14 @@ def make_forward_mobile(con_mesh):
|
|||
frag.add_include('std/shadows.glsl')
|
||||
frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True)
|
||||
frag.add_uniform('vec3 eye', '_cameraPosition')
|
||||
frag.write('svisibility = shadowTestCascade(shadowMap, eye, wposition + n * shadowsBias * 10, shadowsBias);')
|
||||
frag.write(f'svisibility = shadowTestCascade({shadowmap_sun}, eye, wposition + n * shadowsBias * 10, shadowsBias);')
|
||||
else:
|
||||
frag.write('if (lightPosition.w > 0.0) {')
|
||||
frag.write(' vec3 lPos = lightPosition.xyz / lightPosition.w;')
|
||||
if '_Legacy' in wrd.world_defs:
|
||||
frag.write(' svisibility = float(texture(shadowMap, vec2(lPos.xy)).r > lPos.z - shadowsBias);')
|
||||
frag.write(f' svisibility = float(texture({shadowmap_sun}, vec2(lPos.xy)).r > lPos.z - shadowsBias);')
|
||||
else:
|
||||
frag.write(' svisibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).r;')
|
||||
frag.write(f' svisibility = texture({shadowmap_sun}, vec3(lPos.xy, lPos.z - shadowsBias)).r;')
|
||||
frag.write('}')
|
||||
frag.write('}') # receiveShadow
|
||||
frag.write('direct += basecol * sdotNL * sunCol * svisibility;')
|
||||
|
@ -404,8 +410,8 @@ def make_forward_mobile(con_mesh):
|
|||
frag.write('if (receiveShadow) {')
|
||||
if '_Spot' in wrd.world_defs:
|
||||
vert.add_out('vec4 spotPosition')
|
||||
vert.add_uniform('mat4 LWVPSpot0', link='_biasLightWorldViewProjectionMatrixSpot0')
|
||||
vert.write('spotPosition = LWVPSpot0 * spos;')
|
||||
vert.add_uniform('mat4 LWVPSpotArray[1]', link='_biasLightWorldViewProjectionMatrixSpotArray')
|
||||
vert.write('spotPosition = LWVPSpotArray[0] * spos;')
|
||||
frag.add_uniform('sampler2DShadow shadowMapSpot[1]')
|
||||
frag.write('if (spotPosition.w > 0.0) {')
|
||||
frag.write(' vec3 lPos = spotPosition.xyz / spotPosition.w;')
|
||||
|
@ -532,13 +538,10 @@ def make_forward(con_mesh):
|
|||
frag.add_uniform('sampler2D sltcMag', '_ltcMag', included=True)
|
||||
if '_ShadowMap' in wrd.world_defs:
|
||||
if '_SinglePoint' in wrd.world_defs:
|
||||
frag.add_uniform('mat4 LWVPSpot0', link='_biasLightViewProjectionMatrixSpot0', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpot[0]', link='_biasLightViewProjectionMatrixSpot0', included=True)
|
||||
frag.add_uniform('sampler2DShadow shadowMapSpot[1]', included=True)
|
||||
if '_Clusters' in wrd.world_defs:
|
||||
frag.add_uniform('mat4 LWVPSpot0', link='_biasLightWorldViewProjectionMatrixSpot0', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpot1', link='_biasLightWorldViewProjectionMatrixSpot1', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpot2', link='_biasLightWorldViewProjectionMatrixSpot2', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpot3', link='_biasLightWorldViewProjectionMatrixSpot3', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpotArray[4]', link='_biasLightWorldViewProjectionMatrixSpotArray', included=True)
|
||||
frag.add_uniform('sampler2DShadow shadowMapSpot[4]', included=True)
|
||||
|
||||
if not blend:
|
||||
|
@ -605,6 +608,12 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
|||
|
||||
frag.add_include('std/light.glsl')
|
||||
is_shadows = '_ShadowMap' in wrd.world_defs
|
||||
is_shadows_atlas = '_ShadowMapAtlas' in wrd.world_defs
|
||||
is_single_atlas = is_shadows_atlas and '_SingleAtlas' in wrd.world_defs
|
||||
shadowmap_sun = 'shadowMap'
|
||||
if is_shadows_atlas:
|
||||
shadowmap_sun = 'shadowMapAtlasSun' if not is_single_atlas else 'shadowMapAtlas'
|
||||
frag.add_uniform('vec2 smSizeUniform', '_shadowMapSize', included=True)
|
||||
|
||||
frag.write('vec3 albedo = surfaceAlbedo(basecol, metallic);')
|
||||
frag.write('vec3 f0 = surfaceF0(basecol, metallic);')
|
||||
|
@ -661,14 +670,14 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
|||
frag.write('float sdotVH = dot(vVec, sh);')
|
||||
if is_shadows:
|
||||
frag.add_uniform('bool receiveShadow')
|
||||
frag.add_uniform('sampler2DShadow shadowMap')
|
||||
frag.add_uniform(f'sampler2DShadow {shadowmap_sun}', top=True)
|
||||
frag.add_uniform('float shadowsBias', '_sunShadowsBias')
|
||||
frag.write('if (receiveShadow) {')
|
||||
if '_CSM' in wrd.world_defs:
|
||||
frag.add_include('std/shadows.glsl')
|
||||
frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True)
|
||||
frag.add_uniform('vec3 eye', '_cameraPosition')
|
||||
frag.write('svisibility = shadowTestCascade(shadowMap, eye, wposition + n * shadowsBias * 10, shadowsBias);')
|
||||
frag.write(f'svisibility = shadowTestCascade({shadowmap_sun}, eye, wposition + n * shadowsBias * 10, shadowsBias);')
|
||||
else:
|
||||
if tese is not None:
|
||||
tese.add_out('vec4 lightPosition')
|
||||
|
@ -685,7 +694,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
|||
vert.write('lightPosition = LWVP * spos;')
|
||||
frag.write('vec3 lPos = lightPosition.xyz / lightPosition.w;')
|
||||
frag.write('const vec2 smSize = shadowmapSize;')
|
||||
frag.write('svisibility = PCF(shadowMap, lPos.xy, lPos.z - shadowsBias, smSize);')
|
||||
frag.write(f'svisibility = PCF({shadowmap_sun}, lPos.xy, lPos.z - shadowsBias, smSize);')
|
||||
frag.write('}') # receiveShadow
|
||||
if '_VoxelShadow' in wrd.world_defs and '_VoxelAOvar' in wrd.world_defs:
|
||||
frag.write('svisibility *= 1.0 - traceShadow(voxels, voxpos, sunDir);')
|
||||
|
@ -703,7 +712,7 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False):
|
|||
frag.add_uniform('float pointBias', link='_pointShadowsBias')
|
||||
if '_Spot' in wrd.world_defs:
|
||||
# Skip world matrix, already in world-space
|
||||
frag.add_uniform('mat4 LWVPSpot0', link='_biasLightViewProjectionMatrixSpot0', included=True)
|
||||
frag.add_uniform('mat4 LWVPSpot[1]', link='_biasLightViewProjectionMatrixSpotArray', included=True)
|
||||
frag.add_uniform('sampler2DShadow shadowMapSpot[1]', included=True)
|
||||
else:
|
||||
frag.add_uniform('vec2 lightProj', link='_lightPlaneProj', included=True)
|
||||
|
|
|
@ -179,6 +179,7 @@ class Shader:
|
|||
self.includes = []
|
||||
self.ins = []
|
||||
self.outs = []
|
||||
self.uniforms_top = []
|
||||
self.uniforms = []
|
||||
self.constants = []
|
||||
self.functions = {}
|
||||
|
@ -205,6 +206,10 @@ class Shader:
|
|||
if not self.has_include(s):
|
||||
self.includes.append(s)
|
||||
|
||||
def add_include_front(self, s):
|
||||
if not self.has_include(s):
|
||||
self.includes.insert(0, s)
|
||||
|
||||
def add_in(self, s):
|
||||
if s not in self.ins:
|
||||
self.ins.append(s)
|
||||
|
@ -213,7 +218,7 @@ class Shader:
|
|||
if s not in self.outs:
|
||||
self.outs.append(s)
|
||||
|
||||
def add_uniform(self, s, link=None, included=False):
|
||||
def add_uniform(self, s, link=None, included=False, top=False):
|
||||
ar = s.split(' ')
|
||||
# layout(RGBA8) image3D voxels
|
||||
utype = ar[-2]
|
||||
|
@ -236,8 +241,12 @@ class Shader:
|
|||
ar[0] = 'floats'
|
||||
ar[1] = ar[1].split('[', 1)[0]
|
||||
self.context.add_constant(ar[0], ar[1], link=link)
|
||||
if not included and s not in self.uniforms:
|
||||
self.uniforms.append(s)
|
||||
if top:
|
||||
if not included and s not in self.uniforms_top:
|
||||
self.uniforms_top.append(s)
|
||||
else:
|
||||
if not included and s not in self.uniforms:
|
||||
self.uniforms.append(s)
|
||||
|
||||
def add_const(self, type_str: str, name: str, value_str: str, array_size: int = 0):
|
||||
"""
|
||||
|
@ -375,6 +384,8 @@ class Shader:
|
|||
s += 'layout(triangle_strip) out;\n'
|
||||
s += 'layout(max_vertices=3) out;\n'
|
||||
|
||||
for a in self.uniforms_top:
|
||||
s += 'uniform ' + a + ';\n'
|
||||
for a in self.includes:
|
||||
s += '#include "' + a + '"\n'
|
||||
if self.geom_passthrough:
|
||||
|
|
|
@ -242,6 +242,62 @@ class ArmRPListItem(bpy.types.PropertyGroup):
|
|||
rp_autoexposure: BoolProperty(name="Auto Exposure", description="Adjust exposure based on luminance", default=False, update=update_renderpath)
|
||||
rp_compositornodes: BoolProperty(name="Compositor", description="Draw compositor nodes", default=True, update=update_renderpath)
|
||||
rp_shadows: BoolProperty(name="Shadows", description="Enable shadow casting", default=True, update=update_renderpath)
|
||||
rp_max_lights: EnumProperty(
|
||||
items=[('4', '4', '4'),
|
||||
('8', '8', '8'),
|
||||
('16', '16', '16'),
|
||||
('24', '24', '24'),
|
||||
('32', '32', '32'),
|
||||
('64', '64', '64'),],
|
||||
name="Max Lights", description="Max number of lights that can be visible in the screen", default='16')
|
||||
rp_max_lights_cluster: EnumProperty(
|
||||
items=[('4', '4', '4'),
|
||||
('8', '8', '8'),
|
||||
('16', '16', '16'),
|
||||
('24', '24', '24'),
|
||||
('32', '32', '32'),
|
||||
('64', '64', '64'),],
|
||||
name="Max Lights Shadows", description="Max number of rendered shadow maps that can be visible in the screen. Always equal or lower than Max Lights", default='16')
|
||||
rp_shadowmap_atlas: BoolProperty(name="Shadow Map Atlasing", description="Group shadow maps of lights of the same type in the same texture", default=False, update=update_renderpath)
|
||||
rp_shadowmap_atlas_single_map: BoolProperty(name="Shadow Map Atlas single map", description="Use a single texture for all different light types.", default=False, update=update_renderpath)
|
||||
rp_shadowmap_atlas_lod: BoolProperty(name="Shadow Map Atlas LOD (Experimental)", description="When enabled, the size of the shadow map will be determined on runtime based on the distance of the light to the camera", default=False, update=update_renderpath)
|
||||
rp_shadowmap_atlas_lod_subdivisions: EnumProperty(
|
||||
items=[('2', '2', '2'),
|
||||
('3', '3', '3'),
|
||||
('4', '4', '4'),
|
||||
('5', '5', '5'),
|
||||
('6', '6', '6'),
|
||||
('7', '7', '7'),
|
||||
('8', '8', '8'),],
|
||||
name="LOD Subdivisions", description="Number of subdivisions of the default tile size for LOD", default='2', update=update_renderpath)
|
||||
rp_shadowmap_atlas_max_size_point: EnumProperty(
|
||||
items=[('1024', '1024', '1024'),
|
||||
('2048', '2048', '2048'),
|
||||
('4096', '4096', '4096'),
|
||||
('8192', '8192', '8192'),
|
||||
('16384', '16384', '16384')],
|
||||
name="Max Atlas Texture Size Points", description="Sets the limit of the size of the texture.", default='8192', update=update_renderpath)
|
||||
rp_shadowmap_atlas_max_size_spot: EnumProperty(
|
||||
items=[('1024', '1024', '1024'),
|
||||
('2048', '2048', '2048'),
|
||||
('4096', '4096', '4096'),
|
||||
('8192', '8192', '8192'),
|
||||
('16384', '16384', '16384')],
|
||||
name="Max Atlas Texture Size Spots", description="Sets the limit of the size of the texture.", default='8192', update=update_renderpath)
|
||||
rp_shadowmap_atlas_max_size_sun: EnumProperty(
|
||||
items=[('1024', '1024', '1024'),
|
||||
('2048', '2048', '2048'),
|
||||
('4096', '4096', '4096'),
|
||||
('8192', '8192', '8192'),
|
||||
('16384', '16384', '16384')],
|
||||
name="Max Atlas Texture Size Sun", description="Sets the limit of the size of the texture.", default='8192', update=update_renderpath)
|
||||
rp_shadowmap_atlas_max_size: EnumProperty(
|
||||
items=[('1024', '1024', '1024'),
|
||||
('2048', '2048', '2048'),
|
||||
('4096', '4096', '4096'),
|
||||
('8192', '8192', '8192'),
|
||||
('16384', '16384', '16384')],
|
||||
name="Max Atlas Texture Size", description="Sets the limit of the size of the texture.", default='8192', update=update_renderpath)
|
||||
rp_shadowmap_cube: EnumProperty(
|
||||
items=[('256', '256', '256'),
|
||||
('512', '512', '512'),
|
||||
|
|
|
@ -1268,6 +1268,13 @@ class ARM_PT_RenderPathShadowsPanel(bpy.types.Panel):
|
|||
rpdat = wrd.arm_rplist[wrd.arm_rplist_index]
|
||||
self.layout.prop(rpdat, "rp_shadows", text="")
|
||||
|
||||
def compute_subdivs(self, max, subdivs):
|
||||
l = [max]
|
||||
for i in range(subdivs - 1):
|
||||
l.append(int(max / 2))
|
||||
max = max / 2
|
||||
return l
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
@ -1287,6 +1294,55 @@ class ARM_PT_RenderPathShadowsPanel(bpy.types.Panel):
|
|||
col2.prop(rpdat, 'arm_shadowmap_split')
|
||||
col.prop(rpdat, 'arm_shadowmap_bounds')
|
||||
col.prop(rpdat, 'arm_pcfsize')
|
||||
layout.separator()
|
||||
|
||||
layout.prop(rpdat, 'rp_shadowmap_atlas')
|
||||
colatlas = layout.column()
|
||||
colatlas.enabled = rpdat.rp_shadowmap_atlas
|
||||
colatlas.prop(rpdat, 'rp_max_lights')
|
||||
colatlas.prop(rpdat, 'rp_max_lights_cluster')
|
||||
colatlas.prop(rpdat, 'rp_shadowmap_atlas_lod')
|
||||
|
||||
colatlas_lod = colatlas.column()
|
||||
colatlas_lod.enabled = rpdat.rp_shadowmap_atlas_lod
|
||||
colatlas_lod.prop(rpdat, 'rp_shadowmap_atlas_lod_subdivisions')
|
||||
|
||||
colatlas_lod_info = colatlas_lod.row()
|
||||
colatlas_lod_info.alignment = 'RIGHT'
|
||||
subdivs_list = self.compute_subdivs(int(rpdat.rp_shadowmap_cascade), int(rpdat.rp_shadowmap_atlas_lod_subdivisions))
|
||||
subdiv_text = "Subdivisions: " + ', '.join(map(str, subdivs_list))
|
||||
colatlas_lod_info.label(text=subdiv_text, icon="IMAGE_ZDEPTH")
|
||||
|
||||
colatlas.prop(rpdat, 'rp_shadowmap_atlas_single_map')
|
||||
# show size for single texture
|
||||
if rpdat.rp_shadowmap_atlas_single_map:
|
||||
colatlas_single = colatlas.column()
|
||||
colatlas_single.prop(rpdat, 'rp_shadowmap_atlas_max_size')
|
||||
if int(rpdat.rp_shadowmap_cascade) >= int(rpdat.rp_shadowmap_atlas_max_size):
|
||||
print(rpdat.rp_shadowmap_atlas_max_size)
|
||||
colatlas_warning = colatlas_single.row()
|
||||
colatlas_warning.alignment = 'RIGHT'
|
||||
colatlas_warning.label(text=f'Warning: {rpdat.rp_shadowmap_atlas_max_size} is too small for the shadowmap size: {rpdat.rp_shadowmap_cascade}', icon="ERROR")
|
||||
else:
|
||||
# show size for all types
|
||||
colatlas_mixed = colatlas.column()
|
||||
colatlas_mixed.prop(rpdat, 'rp_shadowmap_atlas_max_size_spot')
|
||||
if int(rpdat.rp_shadowmap_cascade) > int(rpdat.rp_shadowmap_atlas_max_size_spot):
|
||||
colatlas_warning = colatlas_mixed.row()
|
||||
colatlas_warning.alignment = 'RIGHT'
|
||||
colatlas_warning.label(text=f'Warning: {rpdat.rp_shadowmap_atlas_max_size_spot} is too small for the shadowmap size: {rpdat.rp_shadowmap_cascade}', icon="ERROR")
|
||||
|
||||
colatlas_mixed.prop(rpdat, 'rp_shadowmap_atlas_max_size_point')
|
||||
if int(rpdat.rp_shadowmap_cascade) >= int(rpdat.rp_shadowmap_atlas_max_size_point):
|
||||
colatlas_warning = colatlas_mixed.row()
|
||||
colatlas_warning.alignment = 'RIGHT'
|
||||
colatlas_warning.label(text=f'Warning: {rpdat.rp_shadowmap_atlas_max_size_point} is too small for the shadowmap size: {rpdat.rp_shadowmap_cube}', icon="ERROR")
|
||||
|
||||
colatlas_mixed.prop(rpdat, 'rp_shadowmap_atlas_max_size_sun')
|
||||
if int(rpdat.rp_shadowmap_cascade) >= int(rpdat.rp_shadowmap_atlas_max_size_sun):
|
||||
colatlas_warning = colatlas_mixed.row()
|
||||
colatlas_warning.alignment = 'RIGHT'
|
||||
colatlas_warning.label(text=f'Warning: {rpdat.rp_shadowmap_atlas_max_size_sun} is too small for the shadowmap size: {rpdat.rp_shadowmap_cascade}', icon="ERROR")
|
||||
|
||||
class ARM_PT_RenderPathVoxelsPanel(bpy.types.Panel):
|
||||
bl_label = "Voxel AO"
|
||||
|
|
|
@ -517,6 +517,7 @@ def write_indexhtml(w, h, is_publish):
|
|||
add_compiledglsl = ''
|
||||
def write_compiledglsl(defs, make_variants):
|
||||
rpdat = arm.utils.get_rp()
|
||||
wrd = bpy.data.worlds['Arm']
|
||||
shadowmap_size = arm.utils.get_cascade_size(rpdat) if rpdat.rp_shadows else 0
|
||||
with open(arm.utils.build_dir() + '/compiled/Shaders/compiled.inc', 'w') as f:
|
||||
f.write(
|
||||
|
@ -689,6 +690,22 @@ const float voxelgiAperture = """ + str(round(rpdat.arm_voxelgi_aperture * 100)
|
|||
if rpdat.arm_skin == 'On':
|
||||
f.write(
|
||||
"""const int skinMaxBones = """ + str(rpdat.arm_skin_max_bones) + """;
|
||||
""")
|
||||
|
||||
if '_Clusters' in wrd.world_defs:
|
||||
max_lights = "4"
|
||||
max_lights_clusters = "4"
|
||||
if rpdat.rp_shadowmap_atlas:
|
||||
max_lights = str(rpdat.rp_max_lights)
|
||||
max_lights_clusters = str(rpdat.rp_max_lights_cluster)
|
||||
# prevent max lights cluster being higher than max lights
|
||||
if (int(max_lights_clusters) > int(max_lights)):
|
||||
max_lights_clusters = max_lights
|
||||
|
||||
f.write(
|
||||
"""const int maxLights = """ + max_lights + """;
|
||||
const int maxLightsCluster = """ + max_lights_clusters + """;
|
||||
const float clusterNear = 4.0;
|
||||
""")
|
||||
|
||||
f.write(add_compiledglsl + '\n') # External defined constants
|
||||
|
|
Loading…
Reference in a new issue