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>
|
||||
};
|
||||
|
||||
const UInt8 r_lightShadowModule[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/LightShadow.nzslb.h>
|
||||
};
|
||||
|
||||
const UInt8 r_skeletalDataModule[] = {
|
||||
#include <Nazara/Graphics/Resources/Shaders/Modules/Engine/SkeletalData.nzslb.h>
|
||||
};
|
||||
|
|
@ -422,6 +426,7 @@ namespace Nz
|
|||
RegisterEmbedShaderModule(r_gammaCorrectionPass);
|
||||
RegisterEmbedShaderModule(r_instanceDataModule);
|
||||
RegisterEmbedShaderModule(r_lightDataModule);
|
||||
RegisterEmbedShaderModule(r_lightShadowModule);
|
||||
RegisterEmbedShaderModule(r_mathColorModule);
|
||||
RegisterEmbedShaderModule(r_mathConstantsModule);
|
||||
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
|
||||
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 ViewerData from Engine.ViewerData;
|
||||
|
||||
import * from Engine.LightShadow;
|
||||
import SkinLinearPosition, SkinLinearPositionNormal from Engine.SkinningLinear;
|
||||
|
||||
// Pass-specific options
|
||||
|
|
@ -18,7 +19,6 @@ option HasAlphaTexture: bool = false;
|
|||
option AlphaTest: bool = false;
|
||||
|
||||
// Phong material options
|
||||
option EnableShadowMapping: bool = true;
|
||||
option HasEmissiveTexture: bool = false;
|
||||
option HasHeightTexture: bool = false;
|
||||
option HasNormalTexture: bool = false;
|
||||
|
|
@ -40,7 +40,6 @@ option VertexUvLoc: i32 = -1;
|
|||
option VertexJointIndicesLoc: 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
|
||||
|
||||
const HasNormal = (VertexNormalLoc >= 0);
|
||||
|
|
@ -126,6 +125,15 @@ struct FragOut
|
|||
fn LinearizeDepth(depth: f32, zNear: f32, zFar: f32) -> f32
|
||||
{
|
||||
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]
|
||||
|
|
@ -188,48 +196,7 @@ fn main(input: VertToFrag) -> FragOut
|
|||
let specFactor = max(dot(reflection, eyeVec), 0.0);
|
||||
specFactor = pow(specFactor, settings.Shininess);
|
||||
|
||||
let shadowFactor = 1.0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
let shadowFactor = ComputeDirectionalLightShadow(light, shadowMapsDirectional[lightIndex], input.worldPos, lambert, viewerData.viewMatrix);
|
||||
|
||||
lightAmbient += shadowFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb;
|
||||
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);
|
||||
specFactor = pow(specFactor, settings.Shininess);
|
||||
|
||||
let shadowFactor = 1.0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let shadowFactor = ComputePointLightShadow(light, shadowMapsPoint[lightIndex], dist, lightToPosNorm);
|
||||
|
||||
lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb;
|
||||
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);
|
||||
specFactor = pow(specFactor, settings.Shininess);
|
||||
|
||||
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](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;
|
||||
}
|
||||
}
|
||||
let shadowFactor = ComputeSpotLightShadow(light, shadowMapsSpot[lightIndex], input.worldPos, lambert);
|
||||
|
||||
lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb;
|
||||
lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * light.diffuseFactor;
|
||||
|
|
|
|||
Loading…
Reference in New Issue