mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-18 03:35:07 +02:00
POM Relief Mapping
This commit is contained in:
@@ -2643,7 +2643,7 @@ struct Light
|
||||
// The scalar radius above is still kept as a max/fallback range for point lights,
|
||||
// as the influence range for rect lights, and as the far clip distance for spot lights.
|
||||
float3 pointRadius;
|
||||
float pointRadiusPad; // non-zero disables specular for this light
|
||||
float pointRadiusPad;
|
||||
|
||||
uint iesTextureIndex; // 0 = none, 1..8 = gIesTextures index + 1
|
||||
float iesStrength;
|
||||
@@ -3745,7 +3745,7 @@ float EstimateSpecularRoughness(float3 specularAlbedo)
|
||||
// get tighter highlights, but keep a floor high enough that POM/normal-map
|
||||
// detail cannot collapse into one-pixel GGX fireflies.
|
||||
float peak = SpecularPeak3(saturate(specularAlbedo));
|
||||
return clamp(lerp(0.70, 0.42, peak), 0.38, 0.74);
|
||||
return clamp(lerp(0.66, 0.40, peak), 0.36, 0.72);
|
||||
}
|
||||
|
||||
float3 LimitSpecularPeak(float3 c, float peakLimit)
|
||||
@@ -3757,7 +3757,7 @@ float3 LimitSpecularPeak(float3 c, float peakLimit)
|
||||
return c;
|
||||
}
|
||||
|
||||
float3 ComputeSpecular(
|
||||
float3 ComputeSpecularShaped(
|
||||
float3 N,
|
||||
float3 V,
|
||||
float3 L,
|
||||
@@ -3765,7 +3765,13 @@ float3 ComputeSpecular(
|
||||
float lightIntensity,
|
||||
float atten,
|
||||
float shadow,
|
||||
float3 specularAlbedo)
|
||||
float3 specularAlbedo,
|
||||
float roughnessBias,
|
||||
float specularWrap,
|
||||
float f0Blend,
|
||||
float fresnelToWhiteScale,
|
||||
float energyScale,
|
||||
float peakLimit)
|
||||
{
|
||||
if (gEnableSpecular == 0)
|
||||
return 0.0;
|
||||
@@ -3777,7 +3783,10 @@ float3 ComputeSpecular(
|
||||
V = normalize(V);
|
||||
L = normalize(L);
|
||||
|
||||
float NoL = saturate(dot(N, L));
|
||||
float rawNoL = dot(N, L);
|
||||
float NoL = (specularWrap > 0.0)
|
||||
? saturate((rawNoL + specularWrap) / (1.0 + specularWrap))
|
||||
: saturate(rawNoL);
|
||||
float NoV = saturate(dot(N, V));
|
||||
|
||||
if (NoL <= 1.0e-4 || NoV <= 1.0e-4)
|
||||
@@ -3795,7 +3804,7 @@ float3 ComputeSpecular(
|
||||
if (specPeak <= 0.001)
|
||||
return 0.0;
|
||||
|
||||
float roughness = EstimateSpecularRoughness(specMask);
|
||||
float roughness = clamp(EstimateSpecularRoughness(specMask) + roughnessBias, 0.38, 0.90);
|
||||
float a = roughness * roughness;
|
||||
float a2 = max(a * a, 1.0e-4);
|
||||
|
||||
@@ -3813,11 +3822,11 @@ float3 ComputeSpecular(
|
||||
float Gl = NoL / max(NoL * (1.0 - k) + k, 1.0e-4);
|
||||
float G = Gv * Gl;
|
||||
|
||||
float3 F0 = saturate(lerp(float3(0.025, 0.025, 0.025), specMask, 0.58));
|
||||
float3 F = F0 + (1.0 - F0) * pow(1.0 - VoH, 5.0);
|
||||
float3 F0 = saturate(lerp(float3(0.025, 0.025, 0.025), specMask, saturate(f0Blend)));
|
||||
float3 F = F0 + (1.0 - F0) * (pow(1.0 - VoH, 5.0) * saturate(fresnelToWhiteScale));
|
||||
|
||||
float specTerm = (D * G) / max(4.0 * NoL * NoV, 1.0e-4);
|
||||
specTerm = min(specTerm, 3.0);
|
||||
specTerm = min(specTerm, 3.6);
|
||||
|
||||
const float SPECULAR_ENERGY_SCALE = 2.35;
|
||||
|
||||
@@ -3829,9 +3838,155 @@ float3 ComputeSpecular(
|
||||
NoL *
|
||||
F *
|
||||
specTerm *
|
||||
SPECULAR_ENERGY_SCALE;
|
||||
(SPECULAR_ENERGY_SCALE * max(energyScale, 0.0));
|
||||
|
||||
return LimitSpecularPeak(specular, 4.0);
|
||||
return LimitSpecularPeak(specular, peakLimit);
|
||||
}
|
||||
|
||||
float3 ComputeSpecular(
|
||||
float3 N,
|
||||
float3 V,
|
||||
float3 L,
|
||||
float3 lightColor,
|
||||
float lightIntensity,
|
||||
float atten,
|
||||
float shadow,
|
||||
float3 specularAlbedo)
|
||||
{
|
||||
return ComputeSpecularShaped(
|
||||
N,
|
||||
V,
|
||||
L,
|
||||
lightColor,
|
||||
lightIntensity,
|
||||
atten,
|
||||
shadow,
|
||||
specularAlbedo,
|
||||
-0.04,
|
||||
0.12,
|
||||
0.82,
|
||||
1.0,
|
||||
1.42,
|
||||
4.8);
|
||||
}
|
||||
|
||||
float EstimateSkeletalSubsurfaceMask(float3 baseAlbedo, float3 specularAlbedo)
|
||||
{
|
||||
// Doom 3 characters have no authored SSS/thickness maps. Use a conservative
|
||||
// skin/flesh proxy from the visible albedo and damp it on shiny/metal-like
|
||||
// pieces so armor and gear do not glow like wax.
|
||||
baseAlbedo = saturate(baseAlbedo);
|
||||
|
||||
float luma = dot(baseAlbedo, float3(0.299, 0.587, 0.114));
|
||||
float warm = saturate((baseAlbedo.r - baseAlbedo.b * 0.55) * 2.35);
|
||||
float redBias = saturate((baseAlbedo.r - max(baseAlbedo.g, baseAlbedo.b)) * 3.25 + 0.18);
|
||||
float fleshRange = smoothstep(0.035, 0.18, luma) * (1.0 - smoothstep(0.82, 1.0, luma));
|
||||
float matte = 1.0 - saturate(SpecularPeak3(specularAlbedo) * 0.85);
|
||||
|
||||
return saturate((0.08 + warm * 0.42 + redBias * 0.38) * fleshRange * lerp(0.55, 1.0, matte));
|
||||
}
|
||||
|
||||
float3 ComputeSkeletalSpecularAlbedo(float3 baseAlbedo, float3 specularAlbedo)
|
||||
{
|
||||
float subsurfaceMask = EstimateSkeletalSubsurfaceMask(baseAlbedo, specularAlbedo);
|
||||
|
||||
// Old character spec maps were authored for Doom 3's stylized interaction
|
||||
// lights. In the path tracer they behave like wet plastic unless we make the
|
||||
// BRDF much softer and cap the F0 on skin/flesh-like areas.
|
||||
float3 spec = saturate(specularAlbedo);
|
||||
float3 softSpec = spec * lerp(0.48, 0.24, subsurfaceMask);
|
||||
float cap = lerp(0.16, 0.075, subsurfaceMask);
|
||||
return min(softSpec, float3(cap, cap, cap));
|
||||
}
|
||||
|
||||
float3 ComputeSkeletalSpecular(
|
||||
float3 N,
|
||||
float3 V,
|
||||
float3 L,
|
||||
float3 baseAlbedo,
|
||||
float3 lightColor,
|
||||
float lightIntensity,
|
||||
float atten,
|
||||
float shadow,
|
||||
float3 specularAlbedo)
|
||||
{
|
||||
float subsurfaceMask = EstimateSkeletalSubsurfaceMask(baseAlbedo, specularAlbedo);
|
||||
float3 characterSpec = ComputeSkeletalSpecularAlbedo(baseAlbedo, specularAlbedo);
|
||||
|
||||
// Character MD5 specular maps often encode art-directed shine, not material
|
||||
// F0. Shape the whole BRDF, including grazing Fresnel, so faces and bodies
|
||||
// keep a soft oily skin response instead of reflecting like sealed plastic.
|
||||
return ComputeSpecularShaped(
|
||||
N,
|
||||
V,
|
||||
L,
|
||||
lightColor,
|
||||
lightIntensity,
|
||||
atten,
|
||||
shadow,
|
||||
characterSpec,
|
||||
lerp(0.10, 0.20, subsurfaceMask),
|
||||
0.0,
|
||||
0.58,
|
||||
lerp(0.32, 0.14, subsurfaceMask),
|
||||
lerp(0.40, 0.24, subsurfaceMask),
|
||||
lerp(0.55, 0.18, subsurfaceMask));
|
||||
}
|
||||
|
||||
float ComputeSubsurfaceShape(float3 N, float3 V, float3 L)
|
||||
{
|
||||
N = normalize(N);
|
||||
V = normalize(V);
|
||||
L = normalize(L);
|
||||
|
||||
float NoL = dot(N, L);
|
||||
float wrap = saturate((NoL + 0.58) / 1.58);
|
||||
wrap = wrap * wrap;
|
||||
|
||||
// Transmission becomes visible around the terminator and when the light is
|
||||
// behind the viewed surface, which is the bit missing most painfully on MD5s.
|
||||
float back = saturate((-NoL + 0.22) / 1.22);
|
||||
float forward = pow(saturate(dot(-L, V)), 2.25);
|
||||
float rim = pow(saturate(1.0 - abs(dot(N, V))), 1.60);
|
||||
|
||||
return saturate(wrap * 0.42 + back * (0.55 + forward * 0.85) + rim * wrap * 0.18);
|
||||
}
|
||||
|
||||
float3 ComputeSkeletalSubsurfaceRadiance(
|
||||
float3 N,
|
||||
float3 V,
|
||||
float3 L,
|
||||
float3 baseAlbedo,
|
||||
float3 lightColor,
|
||||
float lightIntensity,
|
||||
float atten,
|
||||
float shadow,
|
||||
float subsurfaceMask)
|
||||
{
|
||||
if (subsurfaceMask <= 0.001 || atten <= 0.0 || lightIntensity <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
float shape = ComputeSubsurfaceShape(N, V, L);
|
||||
if (shape <= 0.001)
|
||||
return 0.0;
|
||||
|
||||
float softShadow = lerp(shadow, 1.0, 0.18 * subsurfaceMask);
|
||||
float3 scatterTint = saturate(lerp(
|
||||
float3(1.0, 0.30, 0.18),
|
||||
saturate(baseAlbedo) * float3(1.22, 0.68, 0.52) + float3(0.10, 0.03, 0.02),
|
||||
0.58));
|
||||
|
||||
const float SUBSURFACE_DIRECT_SCALE = 0.34;
|
||||
return clamp(
|
||||
lightColor *
|
||||
lightIntensity *
|
||||
atten *
|
||||
softShadow *
|
||||
scatterTint *
|
||||
shape *
|
||||
(subsurfaceMask * SUBSURFACE_DIRECT_SCALE),
|
||||
0.0,
|
||||
2.25);
|
||||
}
|
||||
)"
|
||||
R"(
|
||||
@@ -4255,10 +4410,12 @@ float3 EstimatePathTracedSky(float3 worldPos, float3 N, inout uint rng)
|
||||
accum /= (float)bounceSamples;
|
||||
return accum * 0.55;
|
||||
}
|
||||
|
||||
float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
|
||||
)"
|
||||
R"(
|
||||
float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, bool isSkeletal, float subsurfaceMask, Light Lgt, inout uint rng, out float3 specularOut, out float3 subsurfaceOut)
|
||||
{
|
||||
specularOut = 0.0;
|
||||
subsurfaceOut = 0.0;
|
||||
|
||||
float3 toCenter = Lgt.position - worldPos;
|
||||
float centerDist = length(toCenter);
|
||||
@@ -4284,6 +4441,7 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
|
||||
|
||||
float3 diffuseAccum = 0.0;
|
||||
float3 specAccum = 0.0;
|
||||
float3 sssAccum = 0.0;
|
||||
|
||||
[loop]
|
||||
for (uint s = 0u; s < sampleCount; ++s)
|
||||
@@ -4303,24 +4461,28 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
|
||||
float diffuseNoL = ComputeDiffuseLightingTerm(N, L);
|
||||
|
||||
float shadow = 1.0;
|
||||
if (Lgt.samples != 0u && diffuseNoL > 0.0001)
|
||||
if (Lgt.samples != 0u && (diffuseNoL > 0.0001 || subsurfaceMask > 0.001))
|
||||
shadow = TraceVisibilityBiased(worldPos, N, L, dist);
|
||||
|
||||
if (Lgt.pointRadiusPad <= 0.5)
|
||||
specAccum += ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo);
|
||||
specAccum += isSkeletal
|
||||
? ComputeSkeletalSpecular(N, V, L, baseAlbedo, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo)
|
||||
: ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo);
|
||||
|
||||
sssAccum += ComputeSkeletalSubsurfaceRadiance(N, V, L, baseAlbedo, Lgt.color, Lgt.intensity, atten, shadow, subsurfaceMask);
|
||||
diffuseAccum += Lgt.color * (Lgt.intensity * atten * diffuseNoL * shadow);
|
||||
}
|
||||
|
||||
float invSamples = 1.0 / (float)sampleCount;
|
||||
specularOut = specAccum * invSamples;
|
||||
subsurfaceOut = sssAccum * invSamples;
|
||||
return diffuseAccum * invSamples;
|
||||
}
|
||||
)"
|
||||
R"(
|
||||
float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
|
||||
float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, bool isSkeletal, float subsurfaceMask, Light Lgt, inout uint rng, out float3 specularOut, out float3 subsurfaceOut)
|
||||
{
|
||||
specularOut = 0.0;
|
||||
subsurfaceOut = 0.0;
|
||||
|
||||
float3 toLight = Lgt.position - worldPos;
|
||||
float dist = length(toLight);
|
||||
@@ -4333,19 +4495,22 @@ float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 base
|
||||
float diffuseNoL = ComputeDiffuseLightingTerm(N, L);
|
||||
|
||||
float shadow = 1.0;
|
||||
if (Lgt.samples != 0u && diffuseNoL > 0.0001 && atten > 0.0)
|
||||
if (Lgt.samples != 0u && (diffuseNoL > 0.0001 || subsurfaceMask > 0.001) && atten > 0.0)
|
||||
shadow = TraceVisibilityBiased(worldPos, N, L, dist);
|
||||
|
||||
if (Lgt.pointRadiusPad <= 0.5)
|
||||
specularOut = ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo);
|
||||
specularOut = isSkeletal
|
||||
? ComputeSkeletalSpecular(N, V, L, baseAlbedo, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo)
|
||||
: ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo);
|
||||
|
||||
subsurfaceOut = ComputeSkeletalSubsurfaceRadiance(N, V, L, baseAlbedo, Lgt.color, Lgt.intensity, atten, shadow, subsurfaceMask);
|
||||
return Lgt.color * (Lgt.intensity * atten * diffuseNoL * shadow);
|
||||
}
|
||||
)"
|
||||
R"(
|
||||
float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
|
||||
float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, bool isSkeletal, float subsurfaceMask, Light Lgt, inout uint rng, out float3 specularOut, out float3 subsurfaceOut)
|
||||
{
|
||||
specularOut = 0.0;
|
||||
subsurfaceOut = 0.0;
|
||||
|
||||
float3 toCenter = Lgt.position - worldPos;
|
||||
float centerDist = length(toCenter);
|
||||
@@ -4365,6 +4530,7 @@ float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V
|
||||
|
||||
float3 diffuseAccum = 0.0;
|
||||
float3 specAccum = 0.0;
|
||||
float3 sssAccum = 0.0;
|
||||
|
||||
[loop]
|
||||
for (uint s = 0u; s < sampleCount; ++s)
|
||||
@@ -4385,7 +4551,8 @@ float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V
|
||||
|
||||
float3 L = sampleVec / sampleDist;
|
||||
float NdotL = ComputeDiffuseLightingTerm(N, L);
|
||||
if (NdotL <= 0.0)
|
||||
float sssShape = (subsurfaceMask > 0.001) ? ComputeSubsurfaceShape(N, V, L) : 0.0;
|
||||
if (NdotL <= 0.0 && sssShape <= 0.001)
|
||||
continue;
|
||||
|
||||
float faceTerm = (Lgt.twoSided != 0)
|
||||
@@ -4399,9 +4566,18 @@ float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V
|
||||
if (Lgt.samples != 0u)
|
||||
shadow = TraceVisibilityBiased(worldPos, N, L, sampleDist);
|
||||
|
||||
if (Lgt.pointRadiusPad <= 0.5)
|
||||
{
|
||||
specAccum += ComputeSpecular(
|
||||
specAccum += (isSkeletal
|
||||
? ComputeSkeletalSpecular(
|
||||
N,
|
||||
V,
|
||||
L,
|
||||
baseAlbedo,
|
||||
Lgt.color,
|
||||
Lgt.intensity * faceTerm,
|
||||
1.0,
|
||||
shadow,
|
||||
specularAlbedo)
|
||||
: ComputeSpecular(
|
||||
N,
|
||||
V,
|
||||
L,
|
||||
@@ -4409,14 +4585,25 @@ float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V
|
||||
Lgt.intensity * faceTerm,
|
||||
1.0,
|
||||
shadow,
|
||||
specularAlbedo) * atten;
|
||||
}
|
||||
specularAlbedo)) * atten;
|
||||
|
||||
sssAccum += ComputeSkeletalSubsurfaceRadiance(
|
||||
N,
|
||||
V,
|
||||
L,
|
||||
baseAlbedo,
|
||||
Lgt.color,
|
||||
Lgt.intensity * faceTerm,
|
||||
atten,
|
||||
shadow,
|
||||
subsurfaceMask);
|
||||
|
||||
diffuseAccum += clamp(Lgt.color * (Lgt.intensity * NdotL * faceTerm * atten * shadow), 0.0, 4.0);
|
||||
}
|
||||
|
||||
float invSamples = 1.0 / (float)sampleCount;
|
||||
specularOut = specAccum * invSamples;
|
||||
subsurfaceOut = sssAccum * invSamples;
|
||||
return diffuseAccum * invSamples;
|
||||
}
|
||||
|
||||
@@ -4618,29 +4805,31 @@ float3 EstimateUnresolvedBounceRadiance(float3 hitPos, float3 hitN, float3 albed
|
||||
return clamp(albedo * max(lighting, 0.0), 0.0, 6.0);
|
||||
}
|
||||
|
||||
float3 EstimateShadowedBounceLight(uint2 hitPixel, float3 hitPos, float3 hitN, float3 hitV, float3 hitAlbedo, Light Lgt, inout uint rng)
|
||||
float3 EstimateShadowedBounceLight(uint2 hitPixel, float3 hitPos, float3 hitN, float3 hitV, float3 hitAlbedo, bool hitIsSkeletal, Light Lgt, inout uint rng)
|
||||
{
|
||||
float3 spec = 0.0;
|
||||
float3 sss = 0.0;
|
||||
float3 diffuse = 0.0;
|
||||
float3 hitSpecularAlbedo = LoadSceneSpecularAlbedo(hitPixel, hitAlbedo);
|
||||
float subsurfaceMask = hitIsSkeletal ? EstimateSkeletalSubsurfaceMask(hitAlbedo, hitSpecularAlbedo) * 0.45 : 0.0;
|
||||
|
||||
// Use the same visibility-capable direct-light samplers as the primary hit.
|
||||
// This supplies proper next-event estimation at secondary hits instead of the
|
||||
// old unoccluded light-list approximation.
|
||||
if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
|
||||
{
|
||||
diffuse = PathTraceDirectPointLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, Lgt, rng, spec);
|
||||
diffuse = PathTraceDirectPointLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, hitIsSkeletal, subsurfaceMask, Lgt, rng, spec, sss);
|
||||
}
|
||||
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_SPOT)
|
||||
{
|
||||
diffuse = PathTraceDirectSpotLight(hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, Lgt, rng, spec);
|
||||
diffuse = PathTraceDirectSpotLight(hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, hitIsSkeletal, subsurfaceMask, Lgt, rng, spec, sss);
|
||||
}
|
||||
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
|
||||
{
|
||||
diffuse = PathTraceDirectRectLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, Lgt, rng, spec);
|
||||
diffuse = PathTraceDirectRectLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, hitIsSkeletal, subsurfaceMask, Lgt, rng, spec, sss);
|
||||
}
|
||||
|
||||
return clamp(diffuse, 0.0, 12.0);
|
||||
return clamp(diffuse + sss * 0.35, 0.0, 12.0);
|
||||
}
|
||||
|
||||
float3 EstimateBounceSkyLighting(float3 hitPos, float3 hitN, inout uint rng)
|
||||
@@ -4731,7 +4920,7 @@ float3 EstimateDirectLightingForBounceHit(uint2 hitPixel, float3 hitPos, float3
|
||||
uint lightIndex = (start + c * stride) % gLightCount;
|
||||
Light Lgt = gLights[lightIndex];
|
||||
float3 fast = EstimateFastBounceLight(hitPos, hitN, Lgt);
|
||||
float3 shadowed = EstimateShadowedBounceLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, Lgt, lightingRng);
|
||||
float3 shadowed = EstimateShadowedBounceLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitIsSkeletal, Lgt, lightingRng);
|
||||
lighting += shadowed - fast;
|
||||
}
|
||||
}
|
||||
@@ -5056,7 +5245,10 @@ float3 ApplyPrimarySpecularPost(float3 specularAccum, float ao, bool isSkeletal)
|
||||
// surfaces. Keep a mild occlusion tint, but let direct-light specular read.
|
||||
float specAo = lerp(0.58, 1.0, saturate(ao));
|
||||
if (isSkeletal)
|
||||
{
|
||||
specAo = lerp(specAo, 1.0, 0.50);
|
||||
specularAccum *= 0.42;
|
||||
}
|
||||
specularAccum *= specAo;
|
||||
|
||||
//if (isSkeletal)
|
||||
@@ -5077,9 +5269,11 @@ float3 PathTraceDeterministicLighting(
|
||||
float ao,
|
||||
float skyVis,
|
||||
float ambientSkyVis,
|
||||
out float3 specularAccum)
|
||||
out float3 specularAccum,
|
||||
out float3 subsurfaceAccum)
|
||||
{
|
||||
specularAccum = 0.0;
|
||||
subsurfaceAccum = 0.0;
|
||||
|
||||
float microShadow = lerp(0.75, 1.0, cavity);
|
||||
|
||||
@@ -5104,32 +5298,37 @@ float3 PathTraceDeterministicLighting(
|
||||
// argument only because the functions share the same signature as stochastic
|
||||
// helpers; it is not consumed by PathTraceDirect* in the current shader.
|
||||
uint directRng = InitRng(pixel, 0u, 0xD17EC7u);
|
||||
float subsurfaceMask = isSkeletal ? EstimateSkeletalSubsurfaceMask(baseAlbedo, specularAlbedo) : 0.0;
|
||||
|
||||
[loop]
|
||||
for (uint i = 0; i < gLightCount; ++i)
|
||||
{
|
||||
Light Lgt = gLights[i];
|
||||
float3 spec = 0.0;
|
||||
float3 sss = 0.0;
|
||||
float3 diffuse = 0.0;
|
||||
|
||||
if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
|
||||
{
|
||||
diffuse = PathTraceDirectPointLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, Lgt, directRng, spec);
|
||||
diffuse = PathTraceDirectPointLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, isSkeletal, subsurfaceMask, Lgt, directRng, spec, sss);
|
||||
}
|
||||
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_SPOT)
|
||||
{
|
||||
diffuse = PathTraceDirectSpotLight(worldPos, N, V, baseAlbedo, specularAlbedo, Lgt, directRng, spec);
|
||||
diffuse = PathTraceDirectSpotLight(worldPos, N, V, baseAlbedo, specularAlbedo, isSkeletal, subsurfaceMask, Lgt, directRng, spec, sss);
|
||||
}
|
||||
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
|
||||
{
|
||||
diffuse = PathTraceDirectRectLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, Lgt, directRng, spec);
|
||||
diffuse = PathTraceDirectRectLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, isSkeletal, subsurfaceMask, Lgt, directRng, spec, sss);
|
||||
}
|
||||
|
||||
lightingAccum += diffuse;
|
||||
specularAccum += spec;
|
||||
subsurfaceAccum += sss;
|
||||
}
|
||||
|
||||
specularAccum = ApplyPrimarySpecularPost(specularAccum, ao, isSkeletal);
|
||||
if (isSkeletal)
|
||||
subsurfaceAccum *= lerp(0.72, 1.0, saturate(ao));
|
||||
return ApplyPrimaryDiffusePost(lightingAccum, ao, microShadow, isSkeletal);
|
||||
}
|
||||
|
||||
@@ -5193,7 +5392,7 @@ float ComputeSpecularReflectionLocalEnergy(float3 worldPos, float3 N)
|
||||
continue;
|
||||
|
||||
float3 toLight = SafeNormalizeOr(Lgt.position - worldPos, N);
|
||||
float facing = saturate(dot(N, toLight));
|
||||
float facing = saturate((dot(N, toLight) + 0.18) / 1.18);
|
||||
float lightPeak = max(max(Lgt.color.r, Lgt.color.g), Lgt.color.b);
|
||||
|
||||
energy += atten * facing * Lgt.intensity * lightPeak;
|
||||
@@ -5201,7 +5400,7 @@ float ComputeSpecularReflectionLocalEnergy(float3 worldPos, float3 N)
|
||||
|
||||
// Keep reflections tied to nearby light contribution instead of becoming
|
||||
// a global mirror pass.
|
||||
return saturate(energy * 0.08);
|
||||
return saturate(energy * 0.12);
|
||||
}
|
||||
|
||||
float ComputeSpecularReflectionMaxDistance(float3 worldPos)
|
||||
@@ -5264,11 +5463,18 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
float3 baseAlbedo,
|
||||
float3 specularAlbedo,
|
||||
float cavity,
|
||||
bool isSkeletal,
|
||||
inout uint rng)
|
||||
{
|
||||
if (gEnableSpecular == 0u || gMaxBounces <= 1u)
|
||||
return 0.0;
|
||||
|
||||
// Character materials should get soft direct specular, not mirror-like local
|
||||
// reflections. The G-buffer material model has no skeletal roughness map, so
|
||||
// reflected TLAS hits make skin/armor read much wetter than intended.
|
||||
if (isSkeletal)
|
||||
return 0.0;
|
||||
|
||||
N = SafeNormalizeOr(N, float3(0.0, 0.0, 1.0));
|
||||
V = SafeNormalizeOr(V, -N);
|
||||
|
||||
@@ -5280,7 +5486,7 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
bool hasSpecularMap = LooksLikeAuthoredSpecularSample(rawSpecular, baseAlbedo);
|
||||
|
||||
float specPeak = SpecularPeak3(specularAlbedo);
|
||||
if (specPeak <= 0.015)
|
||||
if (specPeak <= 0.006)
|
||||
return 0.0;
|
||||
|
||||
float NoV = saturate(dot(N, V));
|
||||
@@ -5319,8 +5525,8 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
{
|
||||
// Do not reflect sky forever. A missed finite reflection ray contributes
|
||||
// only a tiny local glossy sheen.
|
||||
reflectedRadiance = GetSkyRadiance(R) * 0.035;
|
||||
distanceFade = 0.20;
|
||||
reflectedRadiance = GetSkyRadiance(R) * 0.055;
|
||||
distanceFade = 0.28;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5373,13 +5579,13 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
}
|
||||
|
||||
reflectedRadiance *= reflectedSurfaceAverageColor;
|
||||
reflectedRadiance = CompressEmissiveRadiance(reflectedRadiance, hasSpecularMap ? 5.0 : 3.5);
|
||||
reflectedRadiance = CompressEmissiveRadiance(reflectedRadiance, hasSpecularMap ? 3.5 : 2.5);
|
||||
|
||||
float cavityFade = lerp(0.42, 1.0, saturate(cavity));
|
||||
float reflectionStrength = hasSpecularMap
|
||||
? saturate(specPeak * 1.35)
|
||||
: saturate((specPeak - 0.10) * 0.65);
|
||||
float reflectionScale = hasSpecularMap ? 0.90 : 0.55;
|
||||
? saturate(specPeak * 1.30)
|
||||
: saturate((specPeak - 0.08) * 0.70);
|
||||
float reflectionScale = hasSpecularMap ? 0.85 : 0.52;
|
||||
|
||||
if (reflectionStrength <= 0.001)
|
||||
return 0.0;
|
||||
@@ -5393,7 +5599,7 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
localReflectionEnergy *
|
||||
distanceFade,
|
||||
0.0,
|
||||
3.5);
|
||||
2.6);
|
||||
}
|
||||
)"
|
||||
R"(
|
||||
@@ -5488,6 +5694,7 @@ void RayGen()
|
||||
}
|
||||
|
||||
float3 specularAccum = 0.0;
|
||||
float3 subsurfaceAccum = 0.0;
|
||||
float3 lightingAccum = PathTraceDeterministicLighting(
|
||||
pixel,
|
||||
worldPos,
|
||||
@@ -5500,7 +5707,8 @@ void RayGen()
|
||||
ao,
|
||||
skyVis,
|
||||
ambientSkyVis,
|
||||
specularAccum);
|
||||
specularAccum,
|
||||
subsurfaceAccum);
|
||||
lightingAccum += EstimateScreenSpaceEmissiveParticleLighting(pixel, worldPos, N);
|
||||
|
||||
// Only the indirect bounce path uses per-SPP randomness now. Direct lights,
|
||||
@@ -5540,6 +5748,7 @@ void RayGen()
|
||||
baseAlbedo,
|
||||
specularAlbedo,
|
||||
cavity,
|
||||
isSkeletal,
|
||||
reflectionRng);
|
||||
|
||||
float3 albedo = baseAlbedo * cavity;
|
||||
@@ -5554,6 +5763,7 @@ void RayGen()
|
||||
|
||||
float outputAo = isSkeletal ? lerp(ao, 1.0, 0.55) : ao;
|
||||
finalColor *= clamp(outputAo + 0.3, 0.0, 1.0);
|
||||
finalColor += subsurfaceAccum;
|
||||
|
||||
// Volumetric light scattering is radiance in the camera ray, not surface
|
||||
// reflectance, so add it after surface albedo/specular composition. Because
|
||||
|
||||
Reference in New Issue
Block a user