Graphics/Shaders: Move shadow factor to a separate file
This commit is contained in:
parent
c191cb227b
commit
ceedfbabaf
|
|
@ -51,6 +51,10 @@ namespace Nz
|
||||||
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/LightData.nzslb.h>
|
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/LightData.nzslb.h>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const UInt8 r_lightShadowModule[] = {
|
||||||
|
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/LightShadow.nzslb.h>
|
||||||
|
};
|
||||||
|
|
||||||
const UInt8 r_skeletalDataModule[] = {
|
const UInt8 r_skeletalDataModule[] = {
|
||||||
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/SkeletalData.nzslb.h>
|
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/SkeletalData.nzslb.h>
|
||||||
};
|
};
|
||||||
|
|
@ -422,6 +426,7 @@ namespace Nz
|
||||||
RegisterEmbedShaderModule(r_gammaCorrectionPass);
|
RegisterEmbedShaderModule(r_gammaCorrectionPass);
|
||||||
RegisterEmbedShaderModule(r_instanceDataModule);
|
RegisterEmbedShaderModule(r_instanceDataModule);
|
||||||
RegisterEmbedShaderModule(r_lightDataModule);
|
RegisterEmbedShaderModule(r_lightDataModule);
|
||||||
|
RegisterEmbedShaderModule(r_lightShadowModule);
|
||||||
RegisterEmbedShaderModule(r_mathColorModule);
|
RegisterEmbedShaderModule(r_mathColorModule);
|
||||||
RegisterEmbedShaderModule(r_mathConstantsModule);
|
RegisterEmbedShaderModule(r_mathConstantsModule);
|
||||||
RegisterEmbedShaderModule(r_mathCookTorrancePBRModule);
|
RegisterEmbedShaderModule(r_mathCookTorrancePBRModule);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
[nzsl_version("1.0")]
|
||||||
|
module Engine.LightShadow;
|
||||||
|
|
||||||
|
option EnableShadowMapping: bool = true;
|
||||||
|
option MaxLightCascadeCount: u32 = u32(4); //< FIXME: Fix integral value types
|
||||||
|
|
||||||
|
import DirectionalLight, PointLight, SpotLight from Engine.LightData;
|
||||||
|
|
||||||
|
[export]
|
||||||
|
fn ComputeDirectionalLightShadow(light: DirectionalLight, shadowmap: depth_sampler2D_array[f32], worldPos: vec3[f32], lambert: f32, viewMatrix: mat4[f32]) -> f32
|
||||||
|
{
|
||||||
|
let shadowFactor = 1.0;
|
||||||
|
const if (EnableShadowMapping)
|
||||||
|
{
|
||||||
|
if (light.invShadowMapSize.x > 0.0)
|
||||||
|
{
|
||||||
|
let fragPosViewSpace = viewMatrix * vec4[f32](worldPos, 1.0);
|
||||||
|
let depthValue = abs(fragPosViewSpace.z);
|
||||||
|
|
||||||
|
let cascadeIndex = MaxLightCascadeCount;
|
||||||
|
for index in u32(0) -> light.cascadeCount
|
||||||
|
{
|
||||||
|
if (depthValue < light.cascadeDistances[index])
|
||||||
|
{
|
||||||
|
cascadeIndex = index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cascadeIndex >= light.cascadeCount)
|
||||||
|
cascadeIndex = light.cascadeCount - u32(1);
|
||||||
|
|
||||||
|
let lightProjPos = light.viewProjMatrices[cascadeIndex] * vec4[f32](worldPos, 1.0);
|
||||||
|
let shadowCoords = lightProjPos.xyz / lightProjPos.w;
|
||||||
|
|
||||||
|
// calculate bias (based on depth map resolution and slope)
|
||||||
|
let bias = max(0.05 * (1.0 - lambert), 0.005);
|
||||||
|
bias *= 1.0 / (light.cascadeDistances[cascadeIndex] * 0.05);
|
||||||
|
|
||||||
|
shadowFactor = 0.0;
|
||||||
|
[unroll]
|
||||||
|
for x in -1 -> 2
|
||||||
|
{
|
||||||
|
[unroll]
|
||||||
|
for y in -1 -> 2
|
||||||
|
{
|
||||||
|
let coords = shadowCoords.xy + vec2[f32](f32(x), f32(y)) * light.invShadowMapSize;
|
||||||
|
shadowFactor += shadowmap.SampleDepthComp(vec3[f32](coords, f32(cascadeIndex)), shadowCoords.z - bias).r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadowFactor /= 9.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadowFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
[export]
|
||||||
|
fn ComputePointLightShadow(light: PointLight, shadowmap: sampler_cube[f32], dist: f32, lightDir: vec3[f32]) -> f32
|
||||||
|
{
|
||||||
|
let shadowFactor = 1.0;
|
||||||
|
const if (EnableShadowMapping)
|
||||||
|
{
|
||||||
|
if (light.invShadowMapSize.x > 0.0)
|
||||||
|
{
|
||||||
|
shadowFactor = 0.0;
|
||||||
|
|
||||||
|
let sampleDir = vec3[f32](lightDir.x, lightDir.y, -lightDir.z);
|
||||||
|
|
||||||
|
const sampleCount = 4;
|
||||||
|
const offset = 0.005;
|
||||||
|
|
||||||
|
const invSampleCount = 1.0 / f32(sampleCount);
|
||||||
|
const start = vec3[f32](offset * 0.5, offset * 0.5, offset * 0.5);
|
||||||
|
const shadowContribution = 1.0 / f32(sampleCount * sampleCount * sampleCount);
|
||||||
|
|
||||||
|
let bias = 0.05;
|
||||||
|
|
||||||
|
[unroll]
|
||||||
|
for x in 0 -> sampleCount
|
||||||
|
{
|
||||||
|
[unroll]
|
||||||
|
for y in 0 -> sampleCount
|
||||||
|
{
|
||||||
|
[unroll]
|
||||||
|
for z in 0 -> sampleCount
|
||||||
|
{
|
||||||
|
let dirOffset = vec3[f32](f32(x), f32(y), f32(z)) * invSampleCount * offset - start;
|
||||||
|
let sampleDir = sampleDir + dirOffset;
|
||||||
|
|
||||||
|
let closestDepth = shadowmap.Sample(sampleDir).r;
|
||||||
|
closestDepth *= light.radius;
|
||||||
|
|
||||||
|
if (closestDepth > dist - bias)
|
||||||
|
shadowFactor += shadowContribution;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadowFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
[export]
|
||||||
|
fn ComputeSpotLightShadow(light: SpotLight, shadowmap: depth_sampler2D[f32], worldPos: vec3[f32], lambert: f32) -> f32
|
||||||
|
{
|
||||||
|
let shadowFactor = 1.0;
|
||||||
|
const if (EnableShadowMapping)
|
||||||
|
{
|
||||||
|
if (light.invShadowMapSize.x > 0.0)
|
||||||
|
{
|
||||||
|
let bias = 0.0005 * tan(acos(lambert));
|
||||||
|
bias = clamp(bias, 0.0, 0.01);
|
||||||
|
|
||||||
|
let lightProjPos = light.viewProjMatrix * vec4[f32](worldPos, 1.0);
|
||||||
|
let shadowCoords = lightProjPos.xyz / lightProjPos.w;
|
||||||
|
|
||||||
|
shadowFactor = 0.0;
|
||||||
|
[unroll]
|
||||||
|
for x in -1 -> 2
|
||||||
|
{
|
||||||
|
[unroll]
|
||||||
|
for y in -1 -> 2
|
||||||
|
{
|
||||||
|
let coords = shadowCoords.xy + vec2[f32](f32(x), f32(y)) * light.invShadowMapSize;
|
||||||
|
shadowFactor += shadowmap.SampleDepthComp(coords, shadowCoords.z - bias).r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shadowFactor /= 9.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return shadowFactor;
|
||||||
|
}
|
||||||
|
|
@ -48,3 +48,27 @@ fn FresnelSchlick(cosTheta: f32, F0: vec3[f32]) -> vec3[f32]
|
||||||
// TODO: Clamp
|
// TODO: Clamp
|
||||||
return F0 + (vec3[f32](1.0, 1.0, 1.0) - F0) * pow(min(max(1.0 - cosTheta, 0.0), 1.0), 5.0);
|
return F0 + (vec3[f32](1.0, 1.0, 1.0) - F0) * pow(min(max(1.0 - cosTheta, 0.0), 1.0), 5.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[export]
|
||||||
|
fn ComputeLightRadiance(lightColor: vec3[f32], lightDir: vec3[f32], lightAttenuation: f32, albedoFactor: vec3[f32], eyeVec: vec3[f32], F0: vec3[f32], normal: vec3[f32], metallic: f32, roughness: f32) -> vec3[f32]
|
||||||
|
{
|
||||||
|
let radiance = lightColor * lightAttenuation;
|
||||||
|
|
||||||
|
let halfDir = normalize(lightDir + eyeVec);
|
||||||
|
|
||||||
|
// Cook-Torrance BRDF
|
||||||
|
let NDF = DistributionGGX(normal, halfDir, roughness);
|
||||||
|
let G = GeometrySmith(normal, eyeVec, lightDir, roughness);
|
||||||
|
let F = FresnelSchlick(max(dot(halfDir, eyeVec), 0.0), F0);
|
||||||
|
|
||||||
|
let kS = F;
|
||||||
|
let diffuse = vec3[f32](1.0, 1.0, 1.0) - kS;
|
||||||
|
diffuse *= 1.0 - metallic;
|
||||||
|
|
||||||
|
let numerator = NDF * G * F;
|
||||||
|
let denominator = 4.0 * max(dot(normal, eyeVec), 0.0) * max(dot(normal, lightDir), 0.0);
|
||||||
|
let specular = numerator / max(denominator, 0.0001);
|
||||||
|
|
||||||
|
let NdotL = max(dot(normal, lightDir), 0.0);
|
||||||
|
return (diffuse * albedoFactor + specular) * radiance * NdotL;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import LightData from Engine.LightData;
|
||||||
import SkeletalData from Engine.SkeletalData;
|
import SkeletalData from Engine.SkeletalData;
|
||||||
import ViewerData from Engine.ViewerData;
|
import ViewerData from Engine.ViewerData;
|
||||||
|
|
||||||
|
import * from Engine.LightShadow;
|
||||||
import SkinLinearPosition, SkinLinearPositionNormal from Engine.SkinningLinear;
|
import SkinLinearPosition, SkinLinearPositionNormal from Engine.SkinningLinear;
|
||||||
|
|
||||||
// Pass-specific options
|
// Pass-specific options
|
||||||
|
|
@ -18,7 +19,6 @@ option HasAlphaTexture: bool = false;
|
||||||
option AlphaTest: bool = false;
|
option AlphaTest: bool = false;
|
||||||
|
|
||||||
// Phong material options
|
// Phong material options
|
||||||
option EnableShadowMapping: bool = true;
|
|
||||||
option HasEmissiveTexture: bool = false;
|
option HasEmissiveTexture: bool = false;
|
||||||
option HasHeightTexture: bool = false;
|
option HasHeightTexture: bool = false;
|
||||||
option HasNormalTexture: bool = false;
|
option HasNormalTexture: bool = false;
|
||||||
|
|
@ -40,7 +40,6 @@ option VertexUvLoc: i32 = -1;
|
||||||
option VertexJointIndicesLoc: i32 = -1;
|
option VertexJointIndicesLoc: i32 = -1;
|
||||||
option VertexJointWeightsLoc: i32 = -1;
|
option VertexJointWeightsLoc: i32 = -1;
|
||||||
|
|
||||||
option MaxLightCascadeCount: u32 = u32(4); //< FIXME: Fix integral value types
|
|
||||||
option MaxLightCount: u32 = u32(3); //< FIXME: Fix integral value types
|
option MaxLightCount: u32 = u32(3); //< FIXME: Fix integral value types
|
||||||
|
|
||||||
const HasNormal = (VertexNormalLoc >= 0);
|
const HasNormal = (VertexNormalLoc >= 0);
|
||||||
|
|
@ -128,6 +127,15 @@ fn LinearizeDepth(depth: f32, zNear: f32, zFar: f32) -> f32
|
||||||
return zNear * zFar / (zFar + depth * (zNear - zFar));
|
return zNear * zFar / (zFar + depth * (zNear - zFar));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/
|
||||||
|
fn GetSlopeScaledBias(normal: vec3[f32], lightDir: vec3[f32]) -> f32
|
||||||
|
{
|
||||||
|
let cosAlpha = clamp(dot(normal, lightDir), 0.0, 1.0);
|
||||||
|
let sinAlpha = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L*N))
|
||||||
|
let tanAlpha = sinAlpha / cosAlpha; // tan(acos(L*N))
|
||||||
|
return tanAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
fn ComputeColor(input: VertToFrag) -> vec4[f32]
|
fn ComputeColor(input: VertToFrag) -> vec4[f32]
|
||||||
{
|
{
|
||||||
let color = settings.BaseColor;
|
let color = settings.BaseColor;
|
||||||
|
|
@ -188,48 +196,7 @@ fn main(input: VertToFrag) -> FragOut
|
||||||
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
||||||
specFactor = pow(specFactor, settings.Shininess);
|
specFactor = pow(specFactor, settings.Shininess);
|
||||||
|
|
||||||
let shadowFactor = 1.0;
|
let shadowFactor = ComputeDirectionalLightShadow(light, shadowMapsDirectional[lightIndex], input.worldPos, lambert, viewerData.viewMatrix);
|
||||||
const if (EnableShadowMapping)
|
|
||||||
{
|
|
||||||
if (light.invShadowMapSize.x > 0.0)
|
|
||||||
{
|
|
||||||
let fragPosViewSpace = viewerData.viewMatrix * vec4[f32](input.worldPos, 1.0);
|
|
||||||
let depthValue = abs(fragPosViewSpace.z);
|
|
||||||
|
|
||||||
let cascadeIndex = MaxLightCascadeCount;
|
|
||||||
for index in u32(0) -> light.cascadeCount
|
|
||||||
{
|
|
||||||
if (depthValue < light.cascadeDistances[index])
|
|
||||||
{
|
|
||||||
cascadeIndex = index;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cascadeIndex >= light.cascadeCount)
|
|
||||||
cascadeIndex = light.cascadeCount - u32(1);
|
|
||||||
|
|
||||||
let lightProjPos = light.viewProjMatrices[cascadeIndex] * vec4[f32](input.worldPos, 1.0);
|
|
||||||
let shadowCoords = lightProjPos.xyz / lightProjPos.w;
|
|
||||||
|
|
||||||
// calculate bias (based on depth map resolution and slope)
|
|
||||||
let bias = max(0.05 * (1.0 - lambert), 0.005);
|
|
||||||
bias *= 1.0 / (light.cascadeDistances[cascadeIndex] * 0.05);
|
|
||||||
|
|
||||||
shadowFactor = 0.0;
|
|
||||||
[unroll]
|
|
||||||
for x in -1 -> 2
|
|
||||||
{
|
|
||||||
[unroll]
|
|
||||||
for y in -1 -> 2
|
|
||||||
{
|
|
||||||
let coords = shadowCoords.xy + vec2[f32](f32(x), f32(y)) * light.invShadowMapSize;
|
|
||||||
shadowFactor += shadowMapsDirectional[lightIndex].SampleDepthComp(vec3[f32](coords, f32(cascadeIndex)), shadowCoords.z - bias).r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shadowFactor /= 9.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lightAmbient += shadowFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb;
|
lightAmbient += shadowFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb;
|
||||||
lightDiffuse += shadowFactor * lambert * light.color.rgb * light.diffuseFactor;
|
lightDiffuse += shadowFactor * lambert * light.color.rgb * light.diffuseFactor;
|
||||||
|
|
@ -251,46 +218,7 @@ fn main(input: VertToFrag) -> FragOut
|
||||||
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
||||||
specFactor = pow(specFactor, settings.Shininess);
|
specFactor = pow(specFactor, settings.Shininess);
|
||||||
|
|
||||||
let shadowFactor = 1.0;
|
let shadowFactor = ComputePointLightShadow(light, shadowMapsPoint[lightIndex], dist, lightToPosNorm);
|
||||||
const if (EnableShadowMapping)
|
|
||||||
{
|
|
||||||
if (light.invShadowMapSize.x > 0.0)
|
|
||||||
{
|
|
||||||
shadowFactor = 0.0;
|
|
||||||
|
|
||||||
let sampleDir = vec3[f32](lightToPosNorm.x, lightToPosNorm.y, -lightToPosNorm.z);
|
|
||||||
|
|
||||||
const sampleCount = 4;
|
|
||||||
const offset = 0.005;
|
|
||||||
|
|
||||||
const invSampleCount = 1.0 / f32(sampleCount);
|
|
||||||
const start = vec3[f32](offset * 0.5, offset * 0.5, offset * 0.5);
|
|
||||||
const shadowContribution = 1.0 / f32(sampleCount * sampleCount * sampleCount);
|
|
||||||
|
|
||||||
let bias = 0.05;
|
|
||||||
|
|
||||||
[unroll]
|
|
||||||
for x in 0 -> sampleCount
|
|
||||||
{
|
|
||||||
[unroll]
|
|
||||||
for y in 0 -> sampleCount
|
|
||||||
{
|
|
||||||
[unroll]
|
|
||||||
for z in 0 -> sampleCount
|
|
||||||
{
|
|
||||||
let dirOffset = vec3[f32](f32(x), f32(y), f32(z)) * invSampleCount * offset - start;
|
|
||||||
let sampleDir = sampleDir + dirOffset;
|
|
||||||
|
|
||||||
let closestDepth = shadowMapsPoint[lightIndex].Sample(sampleDir).r;
|
|
||||||
closestDepth *= light.radius;
|
|
||||||
|
|
||||||
if (closestDepth > dist - bias)
|
|
||||||
shadowFactor += shadowContribution;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb;
|
lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb;
|
||||||
lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * light.diffuseFactor;
|
lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * light.diffuseFactor;
|
||||||
|
|
@ -317,31 +245,7 @@ fn main(input: VertToFrag) -> FragOut
|
||||||
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
||||||
specFactor = pow(specFactor, settings.Shininess);
|
specFactor = pow(specFactor, settings.Shininess);
|
||||||
|
|
||||||
let shadowFactor = 1.0;
|
let shadowFactor = ComputeSpotLightShadow(light, shadowMapsSpot[lightIndex], input.worldPos, lambert);
|
||||||
const if (EnableShadowMapping)
|
|
||||||
{
|
|
||||||
if (light.invShadowMapSize.x > 0.0)
|
|
||||||
{
|
|
||||||
let bias = 0.0005 * tan(acos(lambert));
|
|
||||||
bias = clamp(bias, 0.0, 0.01);
|
|
||||||
|
|
||||||
let lightProjPos = light.viewProjMatrix * vec4[f32](input.worldPos, 1.0);
|
|
||||||
let shadowCoords = lightProjPos.xyz / lightProjPos.w;
|
|
||||||
|
|
||||||
shadowFactor = 0.0;
|
|
||||||
[unroll]
|
|
||||||
for x in -1 -> 2
|
|
||||||
{
|
|
||||||
[unroll]
|
|
||||||
for y in -1 -> 2
|
|
||||||
{
|
|
||||||
let coords = shadowCoords.xy + vec2[f32](f32(x), f32(y)) * light.invShadowMapSize;
|
|
||||||
shadowFactor += shadowMapsSpot[lightIndex].SampleDepthComp(coords, shadowCoords.z - bias).r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shadowFactor /= 9.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb;
|
lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb;
|
||||||
lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * light.diffuseFactor;
|
lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * light.diffuseFactor;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue