Cascaded shadows

This commit is contained in:
Lubos Lenco 2017-11-15 13:34:51 +01:00
parent 402a710eb7
commit 900f2b77c7
16 changed files with 384 additions and 138 deletions

View file

@ -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

View file

@ -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

View file

@ -63,7 +63,13 @@
},
{
"name": "LWVP",
"link": "_biasLampWorldViewProjectionMatrix"
"link": "_biasLampWorldViewProjectionMatrix",
"ifndef": ["_CSM"]
},
{
"name": "casData",
"link": "_cascadeData",
"ifdef": ["_CSM"]
},
{
"name": "snoise",

View file

@ -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

167
Shaders/std/shadows_csm.glsl Executable file
View file

@ -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

View file

@ -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;

View file

@ -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);
}

View file

@ -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() {

View file

@ -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()

View file

@ -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'

View file

@ -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')

View file

@ -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);')

View file

@ -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')

View file

@ -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'),

View file

@ -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")

View file

@ -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