mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-16 08:10:32 +02:00
Editor: Added ability to hide/unhide utility brushes and target lines.
Tweaked path tracing so lighting is more realistic.
This commit is contained in:
@@ -3374,6 +3374,35 @@ float3 LoadSceneSpecularAlbedo(uint2 pixel, float3 baseAlbedo)
|
||||
return Doom3PseudoSpecularMask(baseAlbedo);
|
||||
}
|
||||
|
||||
|
||||
float ComputeDiffuseLightingTerm(float3 N, float3 L)
|
||||
{
|
||||
// Keep the original light volume/range attenuation exactly where it is, but
|
||||
// make the surface response less gamey. The old 0.28-0.32 Half-Lambert wrap
|
||||
// pushed too much light around silhouettes and into back-facing normal-map
|
||||
// detail. This smaller squared wrap keeps Doom/idTech readability while
|
||||
// giving a more Lambert-like, physically plausible rolloff.
|
||||
float rawNoL = dot(normalize(N), normalize(L));
|
||||
|
||||
if (gEnableHalfLambert != 0u)
|
||||
{
|
||||
const float REALISTIC_WRAP = 0.12;
|
||||
float wrapped = saturate((rawNoL + REALISTIC_WRAP) / (1.0 + REALISTIC_WRAP));
|
||||
return wrapped * wrapped;
|
||||
}
|
||||
|
||||
return saturate(rawNoL);
|
||||
}
|
||||
|
||||
float EstimateSpecularRoughness(float3 specularAlbedo)
|
||||
{
|
||||
// No roughness map is available in this G-buffer path, so infer a stable
|
||||
// perceptual roughness from the specular map strength. Brighter spec maps
|
||||
// get tighter highlights; dark/missing maps stay broad and subdued.
|
||||
float peak = SpecularPeak3(saturate(specularAlbedo));
|
||||
return clamp(lerp(0.68, 0.34, peak), 0.28, 0.72);
|
||||
}
|
||||
|
||||
float3 ComputeSpecular(
|
||||
float3 N,
|
||||
float3 V,
|
||||
@@ -3387,47 +3416,66 @@ float3 ComputeSpecular(
|
||||
if (gEnableSpecular == 0)
|
||||
return 0.0;
|
||||
|
||||
if (atten <= 0.0 || shadow <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
N = normalize(N);
|
||||
V = normalize(V);
|
||||
L = normalize(L);
|
||||
|
||||
float NdotL = dot(N, L);
|
||||
float NdotV = dot(N, V);
|
||||
float NoL = saturate(dot(N, L));
|
||||
float NoV = saturate(dot(N, V));
|
||||
|
||||
if (atten <= 0.0 || shadow <= 0.0)
|
||||
if (NoL <= 1.0e-4 || NoV <= 1.0e-4)
|
||||
return 0.0;
|
||||
|
||||
// Keep Doom/idTech's front-side behavior, but make the gate soft. A hard
|
||||
// NdotL/NdotV cutoff was making normal-mapped and grazing surfaces randomly
|
||||
// lose all specular even when the half-angle lobe should still be visible.
|
||||
float lightFacing = smoothstep(-0.08, 0.18, NdotL);
|
||||
float viewFacing = smoothstep(-0.04, 0.14, NdotV);
|
||||
if (lightFacing <= 0.0 || viewFacing <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
// idTech4/Doom 3 interaction shader uses half-angle style specular,
|
||||
// not the reflect(-L,N) Phong vector used in the old code here.
|
||||
float3 H = Doom3SafeNormalizeOr(L + V, N);
|
||||
float NdotH = saturate(dot(N, H));
|
||||
float NoH = saturate(dot(N, H));
|
||||
float VoH = saturate(dot(V, H));
|
||||
|
||||
float specTerm = Doom3SpecularLookup(NdotH) * lightFacing * viewFacing;
|
||||
if (specTerm <= 1.0e-5)
|
||||
if (NoH <= 1.0e-4 || VoH <= 1.0e-4)
|
||||
return 0.0;
|
||||
|
||||
float3 specMask = saturate(specularAlbedo);
|
||||
float specPeak = SpecularPeak3(specMask);
|
||||
if (specPeak <= 0.001)
|
||||
return 0.0;
|
||||
|
||||
// Doom 3's interaction pass is strongly additive. Keep it punchy,
|
||||
// but clamp enough to avoid fireflies with stochastic light sampling.
|
||||
const float DOOM3_SPECULAR_SCALE = 4.75;
|
||||
float roughness = EstimateSpecularRoughness(specMask);
|
||||
float a = roughness * roughness;
|
||||
float a2 = max(a * a, 1.0e-4);
|
||||
|
||||
const float PI = 3.14159265;
|
||||
|
||||
// GGX/Trowbridge-Reitz distribution with Smith masking and Schlick Fresnel.
|
||||
// This is still intentionally stylized for the existing idTech-style assets,
|
||||
// but it produces more believable view-dependent highlights than the previous
|
||||
// additive lookup lobe and does not alter light attenuation distance.
|
||||
float dDenom = NoH * NoH * (a2 - 1.0) + 1.0;
|
||||
float D = a2 / max(PI * dDenom * dDenom, 1.0e-4);
|
||||
|
||||
float k = ((roughness + 1.0) * (roughness + 1.0)) * 0.125;
|
||||
float Gv = NoV / max(NoV * (1.0 - k) + k, 1.0e-4);
|
||||
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);
|
||||
|
||||
float specTerm = (D * G) / max(4.0 * NoL * NoV, 1.0e-4);
|
||||
specTerm = min(specTerm, 5.0);
|
||||
|
||||
const float SPECULAR_ENERGY_SCALE = 2.35;
|
||||
|
||||
float3 specular =
|
||||
lightColor *
|
||||
lightIntensity *
|
||||
atten *
|
||||
shadow *
|
||||
specMask *
|
||||
NoL *
|
||||
F *
|
||||
specTerm *
|
||||
DOOM3_SPECULAR_SCALE;
|
||||
SPECULAR_ENERGY_SCALE;
|
||||
|
||||
return clamp(specular, 0.0, 8.0);
|
||||
}
|
||||
@@ -3768,17 +3816,16 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
|
||||
|
||||
float3 L = toLight / dist;
|
||||
|
||||
float wrap = 0.28;
|
||||
float NdotLWrap = saturate((dot(N, L) + wrap) / (1.0 + wrap));
|
||||
float diffuseNoL = ComputeDiffuseLightingTerm(N, L);
|
||||
|
||||
float shadow = 1.0;
|
||||
if (Lgt.samples != 0u && NdotLWrap > 0.0001)
|
||||
if (Lgt.samples != 0u && diffuseNoL > 0.0001)
|
||||
shadow = TraceVisibilityBiased(worldPos, N, L, dist);
|
||||
|
||||
if (Lgt.pointRadiusPad <= 0.5)
|
||||
specAccum += ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo);
|
||||
|
||||
diffuseAccum += Lgt.color * (Lgt.intensity * atten * NdotLWrap * shadow);
|
||||
diffuseAccum += Lgt.color * (Lgt.intensity * atten * diffuseNoL * shadow);
|
||||
}
|
||||
|
||||
float invSamples = 1.0 / (float)sampleCount;
|
||||
@@ -3798,17 +3845,16 @@ float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 base
|
||||
float3 L = toLight / dist;
|
||||
float atten = ComputeSpotLightAttenuation(worldPos, Lgt);
|
||||
|
||||
float wrap = 0.28;
|
||||
float NdotLWrap = saturate((dot(N, L) + wrap) / (1.0 + wrap));
|
||||
float diffuseNoL = ComputeDiffuseLightingTerm(N, L);
|
||||
|
||||
float shadow = 1.0;
|
||||
if (Lgt.samples != 0u && NdotLWrap > 0.0001 && atten > 0.0)
|
||||
if (Lgt.samples != 0u && diffuseNoL > 0.0001 && 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);
|
||||
|
||||
return Lgt.color * (Lgt.intensity * atten * NdotLWrap * shadow);
|
||||
return Lgt.color * (Lgt.intensity * atten * diffuseNoL * shadow);
|
||||
}
|
||||
|
||||
float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, Light Lgt, inout uint rng, out float3 specularOut)
|
||||
@@ -3852,7 +3898,7 @@ float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V
|
||||
continue;
|
||||
|
||||
float3 L = sampleVec / sampleDist;
|
||||
float NdotL = saturate(dot(N, L));
|
||||
float NdotL = ComputeDiffuseLightingTerm(N, L);
|
||||
if (NdotL <= 0.0)
|
||||
continue;
|
||||
|
||||
@@ -4019,8 +4065,7 @@ float3 EstimateFastBounceLight(float3 hitPos, float3 hitN, Light Lgt)
|
||||
if (atten <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
float wrap = 0.32;
|
||||
float nDotL = saturate((dot(hitN, L) + wrap) / (1.0 + wrap));
|
||||
float nDotL = ComputeDiffuseLightingTerm(hitN, L);
|
||||
return clamp(Lgt.color * (Lgt.intensity * atten * nDotL), 0.0, 8.0);
|
||||
}
|
||||
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_SPOT)
|
||||
@@ -4035,8 +4080,7 @@ float3 EstimateFastBounceLight(float3 hitPos, float3 hitN, Light Lgt)
|
||||
if (atten <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
float wrap = 0.32;
|
||||
float nDotL = saturate((dot(hitN, L) + wrap) / (1.0 + wrap));
|
||||
float nDotL = ComputeDiffuseLightingTerm(hitN, L);
|
||||
return clamp(Lgt.color * (Lgt.intensity * atten * nDotL), 0.0, 8.0);
|
||||
}
|
||||
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
|
||||
@@ -4053,7 +4097,7 @@ float3 EstimateFastBounceLight(float3 hitPos, float3 hitN, Light Lgt)
|
||||
return 0.0;
|
||||
|
||||
float3 L = toCenter / centerDist;
|
||||
float nDotL = saturate(dot(hitN, L));
|
||||
float nDotL = ComputeDiffuseLightingTerm(hitN, L);
|
||||
if (nDotL <= 0.0)
|
||||
return 0.0;
|
||||
|
||||
@@ -4507,8 +4551,8 @@ float3 PathTraceDeterministicLighting(
|
||||
float3 skyColor = skyColorRGB * (0.35 + 0.65 * upness);
|
||||
|
||||
float3 lightingAccum = gAmbientColor.rgb * (gAmbientColor.a * 0.04);
|
||||
lightingAccum += skyColor * (0.70 * skyVis);
|
||||
lightingAccum += ambientSkyVis * (skyColorRGB * 0.15);
|
||||
lightingAccum += skyColor * (0.42 * skyVis);
|
||||
lightingAccum += ambientSkyVis * (skyColorRGB * 0.12);
|
||||
|
||||
// Glow-map emissive is direct/bloom-only for now. It is added after lighting
|
||||
// in RayGen and is intentionally not injected into lightingAccum.
|
||||
@@ -4805,6 +4849,24 @@ float3 EstimateRayTracedSpecularReflection(
|
||||
}
|
||||
)"
|
||||
R"(
|
||||
float3 ApplyRealisticOutputCurve(float3 color)
|
||||
{
|
||||
// Final photographic shoulder only: it does not change light radius or
|
||||
// attenuation, but it prevents intense local lights/specular/bloom from
|
||||
// clipping into a flat white patch. Values below 1.0 are left untouched.
|
||||
color = max(color, 0.0);
|
||||
|
||||
float peak = max(max(color.r, color.g), color.b);
|
||||
if (peak > 1.0)
|
||||
{
|
||||
float over = peak - 1.0;
|
||||
float shoulderPeak = 1.0 + over / (1.0 + over * 0.38);
|
||||
color *= shoulderPeak / max(peak, 1.0e-5);
|
||||
}
|
||||
|
||||
return max(color, 0.0);
|
||||
}
|
||||
|
||||
[shader("raygeneration")]
|
||||
void RayGen()
|
||||
{
|
||||
@@ -4822,7 +4884,7 @@ void RayGen()
|
||||
|
||||
if (depthSample <= 0.0 || depthSample >= 1.0)
|
||||
{
|
||||
gOutputTex[pixel] = float4(albedoSample.rgb + emissiveSurface + emissiveBloom, albedoSample.a);
|
||||
gOutputTex[pixel] = float4(ApplyRealisticOutputCurve(albedoSample.rgb + emissiveSurface + emissiveBloom), albedoSample.a);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4840,7 +4902,7 @@ void RayGen()
|
||||
|
||||
if (isUnlit)
|
||||
{
|
||||
gOutputTex[pixel] = float4(baseAlbedo + emissiveSurface + emissiveBloom, albedoSample.a);
|
||||
gOutputTex[pixel] = float4(ApplyRealisticOutputCurve(baseAlbedo + emissiveSurface + emissiveBloom), albedoSample.a);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4851,8 +4913,8 @@ void RayGen()
|
||||
// then reuse them for every stochastic GI sample.
|
||||
float cavity = ComputeCavity(pixel, worldPos, N);
|
||||
float ao = ComputeAmbientOcclusion(worldPos, N, pixel);
|
||||
float skyVis = 0; //ComputeSkyVisibility(worldPos, N, pixel); // jmarshall - fix me later
|
||||
float ambientSkyVis = TraceStraightUpToSky(worldPos, N);
|
||||
float skyVis = 0; //ComputeSkyVisibility(worldPos, N, pixel);
|
||||
float ambientSkyVis = 0; //TraceStraightUpToSky(worldPos, N);
|
||||
float microShadow = lerp(0.75, 1.0, cavity);
|
||||
|
||||
float3 reactiveFinalGather = 0.0;
|
||||
@@ -4947,7 +5009,7 @@ void RayGen()
|
||||
// the eventual swap-chain/backbuffer is LDR.
|
||||
finalColor += emissiveSurface + emissiveBloom;
|
||||
|
||||
gOutputTex[pixel] = float4(max(finalColor * ao, 0.0), albedoSample.a);
|
||||
gOutputTex[pixel] = float4(ApplyRealisticOutputCurve(finalColor), albedoSample.a);
|
||||
}
|
||||
)";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user