From 900f2b77c70aa1a5a66d01ccae8c8afb46bc0c97 Mon Sep 17 00:00:00 2001 From: Lubos Lenco Date: Wed, 15 Nov 2017 13:34:51 +0100 Subject: [PATCH] Cascaded shadows --- .../deferred_light/deferred_light.frag.glsl | 32 ++-- .../deferred_light_quad.frag.glsl | 44 ++--- .../deferred_light_quad.json | 8 +- Shaders/std/shadows.glsl | 122 +++++++++++-- Shaders/std/shadows_csm.glsl | 167 ++++++++++++++++++ Shaders/std/skinning.glsl | 44 ++--- Shaders/std/skinning_mat.glsl | 19 +- Sources/armory/trait/internal/DebugConsole.hx | 3 + blender/arm/exporter.py | 2 +- blender/arm/make_renderer.py | 18 +- blender/arm/make_world.py | 19 +- blender/arm/material/make_mesh.py | 21 ++- blender/arm/material/make_voxel.py | 9 +- blender/arm/props_renderpath.py | 6 +- blender/arm/props_ui.py | 2 +- blender/arm/write_data.py | 6 + 16 files changed, 384 insertions(+), 138 deletions(-) create mode 100755 Shaders/std/shadows_csm.glsl diff --git a/Shaders/deferred_light/deferred_light.frag.glsl b/Shaders/deferred_light/deferred_light.frag.glsl index 8add6140..64eed316 100644 --- a/Shaders/deferred_light/deferred_light.frag.glsl +++ b/Shaders/deferred_light/deferred_light.frag.glsl @@ -91,23 +91,6 @@ uniform vec3 eye; in vec4 wvpposition; out vec4 fragColor; -#ifndef _NoShadows -float shadowTest(const vec3 lPos) { - - // Out of bounds - if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return 1.0; - - #ifdef _PCSS - return PCSS(lPos.xy, lPos.z - shadowsBias); - #else - return PCF(lPos.xy, lPos.z - shadowsBias); - #endif -} -float shadowTestCube(const vec3 lp, const vec3 l) { - return PCFCube(lp, -l, shadowsBias, lightPlane); -} -#endif - void main() { vec2 texCoord = wvpposition.xy / wvpposition.w; texCoord = texCoord * 0.5 + 0.5; @@ -151,13 +134,18 @@ void main() { // float cosAngle = max(1.0 - dotNL, 0.0); // vec3 noff = n * shadowsBias * cosAngle; if (lightShadow == 1) { - // vec4 lampPos = LWVP * vec4(p + noff, 1.0); - vec4 lampPos = LWVP * vec4(p, 1.0); - if (lampPos.w > 0.0) visibility = shadowTest(lampPos.xyz / lampPos.w); + // vec4 lPos = LWVP * vec4(p + noff, 1.0); + vec4 lPos = LWVP * vec4(p, 1.0); + if (lPos.w > 0.0) { + #ifdef _PCSS + visibility = PCSS(lPos.xy, lPos.z - shadowsBias); + #else + visibility = shadowTest(lPos.xyz / lPos.w, shadowsBias); + #endif + } } else if (lightShadow == 2) { // Cube - // visibility = shadowTestCube(lp + noff, l); - visibility = shadowTestCube(lp, l); + visibility = PCFCube(lp, -l, shadowsBias, lightPlane); } #endif diff --git a/Shaders/deferred_light_quad/deferred_light_quad.frag.glsl b/Shaders/deferred_light_quad/deferred_light_quad.frag.glsl index dd4de85e..504e93eb 100644 --- a/Shaders/deferred_light_quad/deferred_light_quad.frag.glsl +++ b/Shaders/deferred_light_quad/deferred_light_quad.frag.glsl @@ -11,11 +11,11 @@ precision mediump float; #include "../std/conetrace.glsl" #endif #ifndef _NoShadows - #ifdef _PCSS - #include "../std/shadows_pcss.glsl" - #else - #include "../std/shadows.glsl" - #endif + // #ifdef _PCSS + // #include "../std/shadows_pcss.glsl" + // #else + #include "../std/shadows_csm.glsl" + // #endif #endif #ifdef _SSS #include "../std/sss.glsl" @@ -38,9 +38,14 @@ uniform sampler2D gbuffer1; #ifndef _NoShadows //!uniform sampler2D shadowMap; - #ifdef _PCSS - //!uniform sampler2D snoise; - //!uniform float lampSizeUV; + // #ifdef _PCSS + //-!uniform sampler2D snoise; + //-!uniform float lampSizeUV; + // #endif + #ifdef _CSM + //!uniform vec4 casData[shadowmapCascades * 4 + 4]; + #else + uniform mat4 LWVP; #endif #endif #ifdef _LampClouds @@ -48,7 +53,6 @@ uniform sampler2D gbuffer1; uniform float time; #endif -uniform mat4 LWVP; uniform vec3 lightColor; uniform vec3 l; // lightDir uniform int lightShadow; @@ -69,17 +73,6 @@ in vec2 texCoord; in vec3 viewRay; out vec4 fragColor; -#ifndef _NoShadows -float shadowTest(const vec3 lPos) { - - #ifdef _PCSS - return PCSS(lPos.xy, lPos.z - shadowsBias); - #else - return PCF(lPos.xy, lPos.z - shadowsBias); - #endif -} -#endif - void main() { vec4 g0 = texture(gbuffer0, texCoord); // Normal.xy, metallic/roughness, occlusion vec4 g1 = texture(gbuffer1, texCoord); // Basecolor.rgb, @@ -105,11 +98,12 @@ void main() { float visibility = 1.0; #ifndef _NoShadows if (lightShadow == 1) { - // float cosAngle = max(1.0 - dotNL, 0.0); - // vec3 noff = n * shadowsBias * cosAngle; - // vec4 lampPos = LWVP * vec4(p + noff, 1.0); - vec4 lampPos = LWVP * vec4(p, 1.0); - if (lampPos.w > 0.0) visibility = shadowTest(lampPos.xyz / lampPos.w); + #ifdef _CSM + visibility = shadowTestCascade(eye, p, shadowsBias); + #else + vec4 lPos = LWVP * vec4(p, 1.0); + if (lPos.w > 0.0) visibility = shadowTest(lPos.xyz / lPos.w, shadowsBias); + #endif } #endif diff --git a/Shaders/deferred_light_quad/deferred_light_quad.json b/Shaders/deferred_light_quad/deferred_light_quad.json index c5670be7..5d20f165 100755 --- a/Shaders/deferred_light_quad/deferred_light_quad.json +++ b/Shaders/deferred_light_quad/deferred_light_quad.json @@ -63,7 +63,13 @@ }, { "name": "LWVP", - "link": "_biasLampWorldViewProjectionMatrix" + "link": "_biasLampWorldViewProjectionMatrix", + "ifndef": ["_CSM"] + }, + { + "name": "casData", + "link": "_cascadeData", + "ifdef": ["_CSM"] }, { "name": "snoise", diff --git a/Shaders/std/shadows.glsl b/Shaders/std/shadows.glsl index 32566615..b7ce983e 100755 --- a/Shaders/std/shadows.glsl +++ b/Shaders/std/shadows.glsl @@ -3,15 +3,25 @@ uniform sampler2D shadowMap; uniform samplerCube shadowMapCube; +#ifdef _CSM +uniform vec4 casData[shadowmapCascades * 4 + 4]; +#endif + +// #ifdef _CSM +// const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0); +// #else +const vec2 smSize = shadowmapSize; +// #endif + float shadowCompare(const vec2 uv, const float compare){ float depth = texture(shadowMap, uv).r; return step(compare, depth); } float shadowLerp(const vec2 uv, const float compare){ - const vec2 texelSize = vec2(1.0) / shadowmapSize; - vec2 f = fract(uv * shadowmapSize + 0.5); - vec2 centroidUV = floor(uv * shadowmapSize + 0.5) / shadowmapSize; + const vec2 texelSize = vec2(1.0) / smSize; + vec2 f = fract(uv * smSize + 0.5); + vec2 centroidUV = floor(uv * smSize + 0.5) / smSize; float lb = shadowCompare(centroidUV, compare); float lt = shadowCompare(centroidUV + texelSize * vec2(0.0, 1.0), compare); float rb = shadowCompare(centroidUV + texelSize * vec2(1.0, 0.0), compare); @@ -26,17 +36,17 @@ float PCF(const vec2 uv, const float compare) { // float result = 0.0; // for (int x = -1; x <= 1; x++){ // for(int y = -1; y <= 1; y++){ - // vec2 off = vec2(x, y) / shadowmapSize; - // result += shadowLerp(shadowmapSize, uv + off, compare); - float result = shadowLerp(uv + (vec2(-1.0, -1.0) / shadowmapSize), compare); - result += shadowLerp(uv + (vec2(-1.0, 0.0) / shadowmapSize), compare); - result += shadowLerp(uv + (vec2(-1.0, 1.0) / shadowmapSize), compare); - result += shadowLerp(uv + (vec2(0.0, -1.0) / shadowmapSize), compare); + // vec2 off = vec2(x, y) / smSize; + // result += shadowLerp(smSize, uv + off, compare); + float result = shadowLerp(uv + (vec2(-1.0, -1.0) / smSize), compare); + result += shadowLerp(uv + (vec2(-1.0, 0.0) / smSize), compare); + result += shadowLerp(uv + (vec2(-1.0, 1.0) / smSize), compare); + result += shadowLerp(uv + (vec2(0.0, -1.0) / smSize), compare); result += shadowLerp(uv, compare); - result += shadowLerp(uv + (vec2(0.0, 1.0) / shadowmapSize), compare); - result += shadowLerp(uv + (vec2(1.0, -1.0) / shadowmapSize), compare); - result += shadowLerp(uv + (vec2(1.0, 0.0) / shadowmapSize), compare); - result += shadowLerp(uv + (vec2(1.0, 1.0) / shadowmapSize), compare); + result += shadowLerp(uv + (vec2(0.0, 1.0) / smSize), compare); + result += shadowLerp(uv + (vec2(1.0, -1.0) / smSize), compare); + result += shadowLerp(uv + (vec2(1.0, 0.0) / smSize), compare); + result += shadowLerp(uv + (vec2(1.0, 1.0) / smSize), compare); // } // } return result / 9.0; @@ -69,3 +79,89 @@ float PCFCube(const vec3 lp, const vec3 ml, const float bias, const vec2 lightPl result /= 9.0; return result; } + + + +float shadowTest(const vec3 lPos, const float shadowsBias) { + + // float cosAngle = max(1.0 - dotNL, 0.0); + // vec3 noff = n * shadowsBias * cosAngle; + // vec4 lPos = LWVP * vec4(p + noff, 1.0); + + // Out of bounds + if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return 1.0; + + return PCF(lPos.xy, lPos.z - shadowsBias); +} + +#ifdef _CSM +mat4 getCascadeMat(const float d, out int casi, out int casIndex) { + const int c = shadowmapCascades; + + // Get cascade index + // TODO: use bounding box slice selection instead of sphere + const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3)); + // int ci; + // if (d < casData[c * 4].x) ci = 0; + // else if (d < casData[c * 4].y) ci = 1 * 4; + // else if (d < casData[c * 4].z) ci = 2 * 4; + // else ci = 3 * 4; + // Splits + vec4 comp = vec4( + float(d > casData[c * 4].x), + float(d > casData[c * 4].y), + float(d > casData[c * 4].z), + float(d > casData[c * 4].w)); + casi = int(min(dot(ci, comp), c)); + + // Get cascade mat + casIndex = casi * 4; + return mat4( + casData[casIndex + 0], + casData[casIndex + 1], + casData[casIndex + 2], + casData[casIndex + 3]); +} + +float shadowTestCascade(const vec3 eye, const vec3 p, const float shadowsBias) { + const int c = shadowmapCascades; + float d = distance(eye, p); + + int casi; + int casIndex; + mat4 LWVP = getCascadeMat(d, casi, casIndex); + + vec4 lPos = LWVP * vec4(p, 1.0); + float visibility = 1.0; + if (lPos.w > 0.0) visibility = shadowTest(lPos.xyz / lPos.w, shadowsBias); + + // Blend cascade + // https://github.com/TheRealMJP/Shadows + const float blendThres = 0.15; + float nextSplit = casData[c * 4][casi]; + float splitSize = casi == 0 ? nextSplit : nextSplit - casData[c * 4][casi - 1]; + float splitDist = (nextSplit - d) / splitSize; + if (splitDist <= blendThres && casi != c - 1) { + int casIndex2 = casIndex + 4; + mat4 LWVP2 = mat4( + casData[casIndex2 + 0], + casData[casIndex2 + 1], + casData[casIndex2 + 2], + casData[casIndex2 + 3]); + + vec4 lPos2 = LWVP2 * vec4(p, 1.0); + float visibility2 = 1.0; + if (lPos2.w > 0.0) visibility2 = shadowTest(lPos2.xyz / lPos2.w, shadowsBias); + + float lerpAmt = smoothstep(0.0, blendThres, splitDist); + return mix(visibility2, visibility, lerpAmt); + } + return visibility; + + // Visualize cascades + // if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0); + // if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0); + // if (ci == 8) albedo.rgb = vec3(0.0, 0.0, 1.0); + // if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0); +} +#endif diff --git a/Shaders/std/shadows_csm.glsl b/Shaders/std/shadows_csm.glsl new file mode 100755 index 00000000..b0cda838 --- /dev/null +++ b/Shaders/std/shadows_csm.glsl @@ -0,0 +1,167 @@ +#include "../compiled.glsl" + +uniform sampler2D shadowMap; +uniform samplerCube shadowMapCube; + +#ifdef _CSM +uniform vec4 casData[shadowmapCascades * 4 + 4]; +#endif + +#ifdef _CSM +const vec2 smSize = shadowmapSize * vec2(shadowmapCascades, 1.0); +#else +const vec2 smSize = shadowmapSize; +#endif + +float shadowCompare(const vec2 uv, const float compare){ + float depth = texture(shadowMap, uv).r; + return step(compare, depth); +} + +float shadowLerp(const vec2 uv, const float compare){ + const vec2 texelSize = vec2(1.0) / smSize; + vec2 f = fract(uv * smSize + 0.5); + vec2 centroidUV = floor(uv * smSize + 0.5) / smSize; + float lb = shadowCompare(centroidUV, compare); + float lt = shadowCompare(centroidUV + texelSize * vec2(0.0, 1.0), compare); + float rb = shadowCompare(centroidUV + texelSize * vec2(1.0, 0.0), compare); + float rt = shadowCompare(centroidUV + texelSize, compare); + float a = mix(lb, lt, f.y); + float b = mix(rb, rt, f.y); + float c = mix(a, b, f.x); + return c; +} + +float PCF(const vec2 uv, const float compare) { + // float result = 0.0; + // for (int x = -1; x <= 1; x++){ + // for(int y = -1; y <= 1; y++){ + // vec2 off = vec2(x, y) / smSize; + // result += shadowLerp(smSize, uv + off, compare); + float result = shadowLerp(uv + (vec2(-1.0, -1.0) / smSize), compare); + result += shadowLerp(uv + (vec2(-1.0, 0.0) / smSize), compare); + result += shadowLerp(uv + (vec2(-1.0, 1.0) / smSize), compare); + result += shadowLerp(uv + (vec2(0.0, -1.0) / smSize), compare); + result += shadowLerp(uv, compare); + result += shadowLerp(uv + (vec2(0.0, 1.0) / smSize), compare); + result += shadowLerp(uv + (vec2(1.0, -1.0) / smSize), compare); + result += shadowLerp(uv + (vec2(1.0, 0.0) / smSize), compare); + result += shadowLerp(uv + (vec2(1.0, 1.0) / smSize), compare); + // } + // } + return result / 9.0; +} + +float lpToDepth(vec3 lp, const vec2 lightPlane) { + // TODO: pass uniforms + float a = lightPlane.y + lightPlane.x; + float b = lightPlane.y - lightPlane.x; + float c = 2.0 * lightPlane.y * lightPlane.x; + lp = abs(lp); + float zcomp = max(lp.x, max(lp.y, lp.z)); + zcomp = a / b - c / b / zcomp; + return zcomp * 0.5 + 0.5; +} + +float PCFCube(const vec3 lp, const vec3 ml, const float bias, const vec2 lightPlane) { + // return float(texture(shadowMapCube, ml).r + bias > lpToDepth(lp, lightPlane)); + float compare = lpToDepth(lp, lightPlane) - bias; + float result = step(compare, texture(shadowMapCube, ml).r); + const float s = shadowmapCubePcfSize; // 0.001 TODO: incorrect... + result += step(compare, texture(shadowMapCube, ml + vec3(s, s, s)).r); + result += step(compare, texture(shadowMapCube, ml + vec3(-s, s, s)).r); + result += step(compare, texture(shadowMapCube, ml + vec3(s, -s, s)).r); + result += step(compare, texture(shadowMapCube, ml + vec3(s, s, -s)).r); + result += step(compare, texture(shadowMapCube, ml + vec3(-s, -s, s)).r); + result += step(compare, texture(shadowMapCube, ml + vec3(s, -s, -s)).r); + result += step(compare, texture(shadowMapCube, ml + vec3(-s, s, -s)).r); + result += step(compare, texture(shadowMapCube, ml + vec3(-s, -s, -s)).r); + result /= 9.0; + return result; +} + + + +float shadowTest(const vec3 lPos, const float shadowsBias) { + + // float cosAngle = max(1.0 - dotNL, 0.0); + // vec3 noff = n * shadowsBias * cosAngle; + // vec4 lPos = LWVP * vec4(p + noff, 1.0); + + // Out of bounds + if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return 1.0; + + return PCF(lPos.xy, lPos.z - shadowsBias); +} + +#ifdef _CSM +mat4 getCascadeMat(const float d, out int casi, out int casIndex) { + const int c = shadowmapCascades; + + // Get cascade index + // TODO: use bounding box slice selection instead of sphere + const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3)); + // int ci; + // if (d < casData[c * 4].x) ci = 0; + // else if (d < casData[c * 4].y) ci = 1 * 4; + // else if (d < casData[c * 4].z) ci = 2 * 4; + // else ci = 3 * 4; + // Splits + vec4 comp = vec4( + float(d > casData[c * 4].x), + float(d > casData[c * 4].y), + float(d > casData[c * 4].z), + float(d > casData[c * 4].w)); + casi = int(min(dot(ci, comp), c)); + + // Get cascade mat + casIndex = casi * 4; + return mat4( + casData[casIndex + 0], + casData[casIndex + 1], + casData[casIndex + 2], + casData[casIndex + 3]); +} + +float shadowTestCascade(const vec3 eye, const vec3 p, const float shadowsBias) { + const int c = shadowmapCascades; + float d = distance(eye, p); + + int casi; + int casIndex; + mat4 LWVP = getCascadeMat(d, casi, casIndex); + + vec4 lPos = LWVP * vec4(p, 1.0); + float visibility = 1.0; + if (lPos.w > 0.0) visibility = shadowTest(lPos.xyz / lPos.w, shadowsBias); + + // Blend cascade + // https://github.com/TheRealMJP/Shadows + const float blendThres = 0.15; + float nextSplit = casData[c * 4][casi]; + float splitSize = casi == 0 ? nextSplit : nextSplit - casData[c * 4][casi - 1]; + float splitDist = (nextSplit - d) / splitSize; + if (splitDist <= blendThres && casi != c - 1) { + int casIndex2 = casIndex + 4; + mat4 LWVP2 = mat4( + casData[casIndex2 + 0], + casData[casIndex2 + 1], + casData[casIndex2 + 2], + casData[casIndex2 + 3]); + + vec4 lPos2 = LWVP2 * vec4(p, 1.0); + float visibility2 = 1.0; + if (lPos2.w > 0.0) visibility2 = shadowTest(lPos2.xyz / lPos2.w, shadowsBias); + + float lerpAmt = smoothstep(0.0, blendThres, splitDist); + return mix(visibility2, visibility, lerpAmt); + } + return visibility; + + // Visualize cascades + // if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0); + // if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0); + // if (ci == 8) albedo.rgb = vec3(0.0, 0.0, 1.0); + // if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0); +} +#endif diff --git a/Shaders/std/skinning.glsl b/Shaders/std/skinning.glsl index 5fae2cdd..0b9133a6 100755 --- a/Shaders/std/skinning.glsl +++ b/Shaders/std/skinning.glsl @@ -4,39 +4,17 @@ uniform vec4 skinBones[skinMaxBones * 2]; void getSkinningDualQuat(const ivec4 bone, vec4 weight, out vec4 A, inout vec4 B) { // Retrieve the real and dual part of the dual-quaternions - mat4 matA, matB; - matA[0][0] = skinBones[bone.x * 2].x; - matA[0][1] = skinBones[bone.x * 2].y; - matA[0][2] = skinBones[bone.x * 2].z; - matA[0][3] = skinBones[bone.x * 2].w; - matB[0][0] = skinBones[bone.x * 2 + 1].x; - matB[0][1] = skinBones[bone.x * 2 + 1].y; - matB[0][2] = skinBones[bone.x * 2 + 1].z; - matB[0][3] = skinBones[bone.x * 2 + 1].w; - matA[1][0] = skinBones[bone.y * 2].x; - matA[1][1] = skinBones[bone.y * 2].y; - matA[1][2] = skinBones[bone.y * 2].z; - matA[1][3] = skinBones[bone.y * 2].w; - matB[1][0] = skinBones[bone.y * 2 + 1].x; - matB[1][1] = skinBones[bone.y * 2 + 1].y; - matB[1][2] = skinBones[bone.y * 2 + 1].z; - matB[1][3] = skinBones[bone.y * 2 + 1].w; - matA[2][0] = skinBones[bone.z * 2].x; - matA[2][1] = skinBones[bone.z * 2].y; - matA[2][2] = skinBones[bone.z * 2].z; - matA[2][3] = skinBones[bone.z * 2].w; - matB[2][0] = skinBones[bone.z * 2 + 1].x; - matB[2][1] = skinBones[bone.z * 2 + 1].y; - matB[2][2] = skinBones[bone.z * 2 + 1].z; - matB[2][3] = skinBones[bone.z * 2 + 1].w; - matA[3][0] = skinBones[bone.w * 2].x; - matA[3][1] = skinBones[bone.w * 2].y; - matA[3][2] = skinBones[bone.w * 2].z; - matA[3][3] = skinBones[bone.w * 2].w; - matB[3][0] = skinBones[bone.w * 2 + 1].x; - matB[3][1] = skinBones[bone.w * 2 + 1].y; - matB[3][2] = skinBones[bone.w * 2 + 1].z; - matB[3][3] = skinBones[bone.w * 2 + 1].w; + ivec4 bonei = bone * 2; + mat4 matA = mat4( + skinBones[bonei.x], + skinBones[bonei.y], + skinBones[bonei.z], + skinBones[bonei.w]); + mat4 matB = mat4( + skinBones[bonei.x + 1], + skinBones[bonei.y + 1], + skinBones[bonei.z + 1], + skinBones[bonei.w + 1]); // Handles antipodality by sticking joints in the same neighbourhood // weight.xyz *= sign(matA[3] * mat3x4(matA)).xyz; weight.xyz *= sign(matA[3] * matA).xyz; diff --git a/Shaders/std/skinning_mat.glsl b/Shaders/std/skinning_mat.glsl index 9a43aa56..7c1b7ffa 100755 --- a/Shaders/std/skinning_mat.glsl +++ b/Shaders/std/skinning_mat.glsl @@ -1,21 +1,10 @@ uniform vec4 skinBones[skinMaxBones * 3]; mat4 getBoneMat(const int boneIndex) { - vec4 v0 = vec4(skinBones[boneIndex * 3].x, - skinBones[boneIndex * 3].y, - skinBones[boneIndex * 3].z, - skinBones[boneIndex * 3].w); - vec4 v1 = vec4(skinBones[boneIndex * 3 + 1].x, - skinBones[boneIndex * 3 + 1].y, - skinBones[boneIndex * 3 + 1].z, - skinBones[boneIndex * 3 + 1].w); - vec4 v2 = vec4(skinBones[boneIndex * 3 + 2].x, - skinBones[boneIndex * 3 + 2].y, - skinBones[boneIndex * 3 + 2].z, - skinBones[boneIndex * 3 + 2].w); - return mat4(v0.x, v0.y, v0.z, v0.w, - v1.x, v1.y, v1.z, v1.w, - v2.x, v2.y, v2.z, v2.w, + int bonei = boneIndex * 3; + return mat4(skinBones[bonei], + skinBones[bonei + 1], + skinBones[bonei + 2], 0.0, 0.0, 0.0, 1.0); } diff --git a/Sources/armory/trait/internal/DebugConsole.hx b/Sources/armory/trait/internal/DebugConsole.hx index 171d9cbb..15449ddb 100755 --- a/Sources/armory/trait/internal/DebugConsole.hx +++ b/Sources/armory/trait/internal/DebugConsole.hx @@ -165,6 +165,9 @@ class DebugConsole extends Trait { } frameTime = Scheduler.realTime() - lastTime; lastTime = Scheduler.realTime(); + + // var rp = pathdata.renderTargets.get("shadowMap"); + // g.drawScaledImage(rp.image, 0, 0, 256, 256); } function update() { diff --git a/blender/arm/exporter.py b/blender/arm/exporter.py index bd503a9f..dd6fa665 100755 --- a/blender/arm/exporter.py +++ b/blender/arm/exporter.py @@ -2202,7 +2202,7 @@ class ArmoryExporter: else: o['shadowmap_size'] = int(rpdat.rp_shadowmap) if o['type'] == 'sun': # Scale bias for ortho light matrix - o['shadows_bias'] *= 10.0 + o['shadows_bias'] *= 25.0 if (objtype == 'POINT' or objtype == 'SPOT') and objref.shadow_soft_size > 0.1: o['lamp_size'] = objref.shadow_soft_size * 10 # Match to Cycles gapi = arm.utils.get_gapi() diff --git a/blender/arm/make_renderer.py b/blender/arm/make_renderer.py index b1c077b5..a7c5f811 100644 --- a/blender/arm/make_renderer.py +++ b/blender/arm/make_renderer.py @@ -63,8 +63,8 @@ def set_preset(self, context, preset): rpdat.rp_renderer = 'Forward' rpdat.rp_depthprepass = True rpdat.arm_material_model = 'Full' - rpdat.rp_shadowmap = '2048' - rpdat.rp_shadowmap_cascades = '3' + rpdat.rp_shadowmap = '1024' + rpdat.rp_shadowmap_cascades = '4' rpdat.rp_translucency_state = 'Auto' rpdat.rp_overlays_state = 'Auto' rpdat.rp_decals_state = 'Auto' @@ -95,8 +95,8 @@ def set_preset(self, context, preset): elif preset == 'Deferred': rpdat.rp_renderer = 'Deferred' rpdat.arm_material_model = 'Full' - rpdat.rp_shadowmap = '2048' - rpdat.rp_shadowmap_cascades = '3' + rpdat.rp_shadowmap = '1024' + rpdat.rp_shadowmap_cascades = '4' rpdat.rp_translucency_state = 'Auto' rpdat.rp_overlays_state = 'Auto' rpdat.rp_decals_state = 'Auto' @@ -126,8 +126,8 @@ def set_preset(self, context, preset): rpdat.arm_diffuse_model = 'Lambert' elif preset == 'Render Capture': rpdat.rp_renderer = 'Deferred' - rpdat.rp_shadowmap = '8192' - rpdat.rp_shadowmap_cascades = '3' + rpdat.rp_shadowmap = '4096' + rpdat.rp_shadowmap_cascades = '4' rpdat.rp_translucency_state = 'Auto' rpdat.rp_overlays_state = 'Auto' rpdat.rp_decals_state = 'Auto' @@ -162,7 +162,7 @@ def set_preset(self, context, preset): elif preset == 'Deferred Plus': rpdat.rp_renderer = 'Deferred Plus' rpdat.arm_material_model = 'Full' - rpdat.rp_shadowmap = '4096' + rpdat.rp_shadowmap = '1024' rpdat.rp_shadowmap_cascades = '1' rpdat.rp_translucency_state = 'Auto' rpdat.rp_overlays_state = 'Auto' @@ -290,8 +290,8 @@ def set_preset(self, context, preset): rpdat.arm_diffuse_model = 'Lambert' elif preset == 'Max': rpdat.rp_renderer = 'Deferred' - rpdat.rp_shadowmap = '8192' - rpdat.rp_shadowmap_cascades = '3' + rpdat.rp_shadowmap = '4096' + rpdat.rp_shadowmap_cascades = '4' rpdat.rp_translucency_state = 'Auto' rpdat.rp_overlays_state = 'Auto' rpdat.rp_decals_state = 'Auto' diff --git a/blender/arm/make_world.py b/blender/arm/make_world.py index 418d66d0..1eb9404f 100755 --- a/blender/arm/make_world.py +++ b/blender/arm/make_world.py @@ -78,11 +78,11 @@ def build_node_tree(world): wrd.world_defs += '_EnvClouds' # Percentage closer soft shadows - if rpdat.arm_pcss_state == 'On': - wrd.world_defs += '_PCSS' - sdk_path = arm.utils.get_sdk_path() - assets.add(sdk_path + 'armory/Assets/noise64.png') - assets.add_embedded_data('noise64.png') + # if rpdat.arm_pcss_state == 'On': + # wrd.world_defs += '_PCSS' + # sdk_path = arm.utils.get_sdk_path() + # assets.add(sdk_path + 'armory/Assets/noise64.png') + # assets.add_embedded_data('noise64.png') # Screen-space ray-traced shadows if rpdat.arm_ssrs: @@ -115,16 +115,19 @@ def build_node_tree(world): voxelao = False if rpdat.rp_renderer == 'Deferred': assets.add_khafile_def('arm_deferred') + # Shadows + if rpdat.rp_shadowmap_cascades != '1' and rpdat.rp_gi == 'Off': + wrd.world_defs += '_CSM' + assets.add_khafile_def('arm_csm') if rpdat.rp_shadowmap == 'None': wrd.world_defs += '_NoShadows' assets.add_khafile_def('arm_no_shadows') - if rpdat.rp_shadowmap_cascades != '1': - wrd.world_defs += '_CSM' - assets.add_khafile_def('arm_csm') + # GI if rpdat.rp_gi == 'Voxel GI': voxelgi = True elif rpdat.rp_gi == 'Voxel AO': voxelao = True + # SS if rpdat.rp_dfrs: wrd.world_defs += '_DFRS' assets.add_khafile_def('arm_sdf') diff --git a/blender/arm/material/make_mesh.py b/blender/arm/material/make_mesh.py index a76d9f20..f06a6d0c 100644 --- a/blender/arm/material/make_mesh.py +++ b/blender/arm/material/make_mesh.py @@ -428,6 +428,7 @@ def make_forward_mobile(con_mesh): # frag.write(' visibility *= PCF(lpos.xy, lpos.z - shadowsBias);') frag.write(' const float texelSize = 1.0 / shadowmapSize.x;') frag.write(' visibility = 0.0;') + # TODO: CSM frag.write(' visibility += float(texture(shadowMap, lpos.xy).r + shadowsBias > lpos.z);') frag.write(' visibility += float(texture(shadowMap, lpos.xy + vec2(texelSize, 0.0)).r + shadowsBias > lpos.z) * 0.5;') frag.write(' visibility += float(texture(shadowMap, lpos.xy + vec2(-texelSize, 0.0)).r + shadowsBias > lpos.z) * 0.25;') @@ -585,10 +586,11 @@ def make_forward_base(con_mesh, parse_opacity=False): tese.add_uniform('int lightShadow', '_lampCastShadow') tese.write('if (lightShadow == 1) lampPos = LVP * vec4(wposition, 1.0);') else: - vert.add_out('vec4 lampPos') - vert.add_uniform('mat4 LWVP', '_biasLampWorldViewProjectionMatrix') - vert.add_uniform('int lightShadow', '_lampCastShadow') - vert.write('if (lightShadow == 1) lampPos = LWVP * spos;') + if not '_CSM' in wrd.world_defs: + vert.add_out('vec4 lampPos') + vert.add_uniform('int lightShadow', '_lampCastShadow') + vert.add_uniform('mat4 LWVP', '_biasLampWorldViewProjectionMatrix') + vert.write('if (lightShadow == 1) lampPos = LWVP * spos;') if is_pcss: frag.add_include('../../Shaders/std/shadows_pcss.glsl') @@ -604,7 +606,15 @@ def make_forward_base(con_mesh, parse_opacity=False): frag.add_uniform('vec2 lightPlane', '_lampPlane') frag.write('if (receiveShadow) {') - frag.write(' if (lightShadow == 1 && lampPos.w > 0.0) {') + frag.write(' if (lightShadow == 1) {') + if '_CSM' in wrd.world_defs: + frag.add_include('../../Shaders/compiled.glsl') + frag.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True) + frag.add_uniform('vec3 eye', '_cameraPosition') + frag.write(' int casi;') + frag.write(' int casindex;') + frag.write(' mat4 LWVP = getCascadeMat(distance(eye, wposition), casi, casindex);') + frag.write(' vec4 lampPos = LWVP * vec4(wposition, 1.0);') frag.write(' vec3 lpos = lampPos.xyz / lampPos.w;') # frag.write('float bias = clamp(shadowsBias * 1.0 * tan(acos(clamp(dotNL, 0.0, 1.0))), 0.0, 0.01);') if is_pcss: @@ -696,4 +706,3 @@ def make_forward_base(con_mesh, parse_opacity=False): frag.write('vec3 indirectSpecular = traceSpecular(voxpos, n, vVec, roughness);') frag.write('indirectSpecular *= f0 * envBRDF.x + envBRDF.y;') frag.write('indirect = indirect * voxelgiEnv + vec3(indirectDiffuse.rgb * voxelgiDiff * basecol + indirectSpecular * voxelgiSpec);') - diff --git a/blender/arm/material/make_voxel.py b/blender/arm/material/make_voxel.py index 050c8125..45929ce4 100644 --- a/blender/arm/material/make_voxel.py +++ b/blender/arm/material/make_voxel.py @@ -166,7 +166,14 @@ def make_gi(context_id): if is_shadows: vert.add_out('vec4 lampPosGeom') - vert.add_uniform('mat4 LWVP', '_biasLampWorldViewProjectionMatrix') + if '_CSM' in wrd.world_defs: + vert.add_include('../../Shaders/compiled.glsl') + vert.add_include('../../Shaders/std/shadows.glsl') + vert.add_uniform('vec4 casData[shadowmapCascades * 4 + 4]', '_cascadeData', included=True) + # TODO: Using second cascade + vert.write('mat4 LWVP = mat4(casData[4 + 0], casData[4 + 1], casData[4 + 2], casData[4 + 3]);') + else: + vert.add_uniform('mat4 LWVP', '_biasLampWorldViewProjectionMatrix') vert.write('lampPosGeom = LWVP * vec4(pos, 1.0);') geom.add_out('vec3 voxposition') diff --git a/blender/arm/props_renderpath.py b/blender/arm/props_renderpath.py index 0b04c53b..71898d1b 100644 --- a/blender/arm/props_renderpath.py +++ b/blender/arm/props_renderpath.py @@ -86,13 +86,13 @@ class ArmRPListItem(bpy.types.PropertyGroup): ('4096', '4096', '4096'), ('8192', '8192', '8192'), ('16384', '16384', '16384'),], - name="Shadow Map", description="Shadow map resolution", default='2048', update=update_renderpath) + name="Shadow Map", description="Shadow map resolution", default='1024', update=update_renderpath) rp_shadowmap_cascades = EnumProperty( items=[('1', '1', '1'), ('2', '2', '2'), - ('3', '3', '3'), + # ('3', '3', '3'), ('4', '4', '4')], - name="Cascades", description="Shadow map cascades", default='3', update=udpate_shadowmap_cascades) + name="Cascades", description="Shadow map cascades", default='4', update=udpate_shadowmap_cascades) rp_supersampling = EnumProperty( items=[('1', '1X', '1X'), ('2', '2X', '2X'), diff --git a/blender/arm/props_ui.py b/blender/arm/props_ui.py index 05df4cb4..19f0a8b9 100644 --- a/blender/arm/props_ui.py +++ b/blender/arm/props_ui.py @@ -1018,7 +1018,7 @@ class ArmRenderPathPanel(bpy.types.Panel): layout.prop(rpdat, 'arm_rp_resolution') layout.separator() - layout.prop(rpdat, 'arm_pcss_state') + # layout.prop(rpdat, 'arm_pcss_state') layout.prop(rpdat, 'arm_samples_per_pixel') layout.prop(rpdat, 'arm_texture_filter') layout.prop(rpdat, "arm_diffuse_model") diff --git a/blender/arm/write_data.py b/blender/arm/write_data.py index 7c3ab2e0..42f7cc11 100755 --- a/blender/arm/write_data.py +++ b/blender/arm/write_data.py @@ -272,6 +272,12 @@ class Main { f.write(""" public static function main() { iron.object.BoneAnimation.skinMaxBones = """ + str(wrd.arm_skin_max_bones) + """; +""") + if rpdat.rp_shadowmap_cascades != '1': + f.write(""" + iron.object.LampObject.shadowmapCascades = """ + str(rpdat.rp_shadowmap_cascades) + """; +""") + f.write(""" state = 1; #if (js && arm_bullet) state++; loadLibAmmo("ammo.js"); #end #if (js && arm_navigation) state++; loadLib("recast.js"); #end