Spec fixes

This commit is contained in:
Justin Marshall
2026-05-28 22:16:09 -07:00
parent f480070f8a
commit c795aba899
4 changed files with 217 additions and 45 deletions
+118 -45
View File
@@ -2983,6 +2983,13 @@ float4 LoadSceneNormal(uint2 pixel)
return nSample;
}
float LoadSceneSurfaceRoughness(float4 normalSample)
{
// The raster G-buffer stores authored/material roughness in normal.w.
// Keep a small floor so glossy materials do not become perfect mirrors.
return clamp(normalSample.w, 0.05, 1.0);
}
float SafeLengthSq(float3 v)
{
return max(dot(v, v), 1e-8);
@@ -3234,7 +3241,8 @@ void BounceClosestHit(inout BouncePayload payload, in BuiltInTriangleIntersectio
payload.meshIndex = InstanceID() & GL_RAYTRACING_INSTANCE_USER_ID_MASK;
DecodeRayMaterialAtHit(payload.meshIndex, attr, payload.hitNormal, payload.hitTexCoord);
}
)"
R"(
[shader("closesthit")]
void ReflectionClosestHit(inout BouncePayload payload, in BuiltInTriangleIntersectionAttributes attr)
{
@@ -4014,6 +4022,17 @@ float EstimateSpecularNormalVariance(uint2 pixel, float3 centerN)
return saturate(v * 1.70);
}
float StabilizeSpecularSurfaceRoughness(uint2 pixel, float3 N, float surfaceRoughness)
{
float normalVariance = EstimateSpecularNormalVariance(pixel, N);
// Doom 3 normal maps can be extremely high contrast. Let clean painted metal
// and wet floors stay glossy, but force rougher lobes on noisy pixels so GGX
// does not turn texel-scale normal detail into broken sparkles.
float varianceFloor = lerp(0.12, 0.46, smoothstep(0.08, 0.42, normalVariance));
return clamp(max(surfaceRoughness, varianceFloor), 0.05, 1.0);
}
float3 Doom3SyntheticSpecularMask(uint2 pixel, float3 baseAlbedo)
{
// Missing Doom 3 specular maps used to get a bright Phong-era fallback. Build
@@ -4034,8 +4053,8 @@ float3 Doom3SyntheticSpecularMask(uint2 pixel, float3 baseAlbedo)
float cavityDamping = lerp(1.0, 0.48, smoothstep(0.03, 0.32, normalVariance));
float roughSurfaceDamping = lerp(1.0, 0.58, smoothstep(0.08, 0.45, normalVariance));
float f0 = 0.04 * cleanDiffuse * cavityDamping * roughSurfaceDamping;
f0 = clamp(f0, 0.010, 0.055);
float f0 = 0.045 * cleanDiffuse * cavityDamping * roughSurfaceDamping;
f0 = clamp(f0, 0.012, 0.070);
float tintAmount = 0.10 * saturate(saturation);
float3 neutralSpec = float3(f0, f0, f0);
@@ -4058,17 +4077,17 @@ float3 ShapeAuthoredDoom3Specular(uint2 pixel, float3 baseAlbedo, float3 authore
// Doom/idTech spec maps were painted for Phong, often as broad intensity masks.
// Treat them as strength/tint hints over a physical dielectric baseline instead
// of feeding their RGB straight into F0.
float authoredStrength = smoothstep(0.025, 0.72, authoredPeak);
float strengthScale = lerp(0.65, 2.85, authoredStrength);
float authoredStrength = smoothstep(0.018, 0.68, authoredPeak);
float strengthScale = lerp(0.85, 4.65, authoredStrength);
float3 shaped = synthetic * strengthScale;
float3 authoredTint = authored / max(authoredPeak, 1.0e-4);
float tintTrust = saturate((authoredPeak - 0.08) * 0.55);
float tintTrust = saturate((authoredPeak - 0.05) * 0.85);
shaped = lerp(shaped, authoredTint * SpecularPeak3(shaped), tintTrust);
float peak = SpecularPeak3(shaped);
if (peak > 0.16 && peak > 1.0e-5)
shaped *= 0.16 / peak;
if (peak > 0.30 && peak > 1.0e-5)
shaped *= 0.30 / peak;
return max(shaped, float3(0.004, 0.004, 0.004));
}
@@ -4108,15 +4127,17 @@ float ComputeDiffuseLightingTerm(float3 N, float3 L)
return saturate(rawNoL);
}
float EstimateSpecularRoughness(float3 specularAlbedo)
float EstimateSpecularRoughness(float3 specularAlbedo, float surfaceRoughness)
{
// 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, but keep a floor high enough that POM/normal-map
// detail cannot collapse into one-pixel GGX fireflies.
// Doom 3 spec maps are art-directed intensity/tint masks, not roughness maps.
// Use the authored/material roughness packed by the raster path, with spec
// strength only nudging the lobe sharper for bright painted highlights.
float peak = SpecularPeak3(saturate(specularAlbedo));
float strength = smoothstep(0.010, 0.145, peak);
return clamp(lerp(0.70, 0.42, strength), 0.38, 0.76);
float specDrivenRoughness = lerp(0.68, 0.22, strength);
float materialRoughness = clamp(surfaceRoughness, 0.05, 1.0);
float roughness = lerp(specDrivenRoughness, min(specDrivenRoughness, materialRoughness), 0.72);
return clamp(roughness, 0.18, 0.86);
}
float3 LimitSpecularPeak(float3 c, float peakLimit)
@@ -4142,7 +4163,8 @@ float3 ComputeSpecularShaped(
float f0Blend,
float fresnelToWhiteScale,
float energyScale,
float peakLimit)
float peakLimit,
float surfaceRoughness)
{
if (gEnableSpecular == 0)
return 0.0;
@@ -4175,7 +4197,7 @@ float3 ComputeSpecularShaped(
if (specPeak <= 0.001)
return 0.0;
float roughness = clamp(EstimateSpecularRoughness(specMask) + roughnessBias, 0.38, 0.90);
float roughness = clamp(EstimateSpecularRoughness(specMask, surfaceRoughness) + roughnessBias, 0.18, 0.92);
float a = roughness * roughness;
float a2 = max(a * a, 1.0e-4);
@@ -4197,9 +4219,9 @@ float3 ComputeSpecularShaped(
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.6);
specTerm = min(specTerm, 2.85);
const float SPECULAR_ENERGY_SCALE = 2.35;
const float SPECULAR_ENERGY_SCALE = 3.15;
float3 specular =
lightColor *
@@ -4211,6 +4233,42 @@ float3 ComputeSpecularShaped(
specTerm *
(SPECULAR_ENERGY_SCALE * max(energyScale, 0.0));
float legacyLobe = Doom3SpecularLookup(NoH) * saturate(1.0 - roughness * 0.55);
specular +=
lightColor *
lightIntensity *
atten *
shadow *
NoL *
specMask *
legacyLobe *
(0.72 * max(energyScale, 0.0));
float clearcoatMask = smoothstep(0.075, 0.22, specPeak) * saturate((0.58 - roughness) / 0.42);
if (clearcoatMask > 0.0)
{
float coatRoughness = clamp(roughness * 0.55, 0.14, 0.36);
float coatA = coatRoughness * coatRoughness;
float coatA2 = max(coatA * coatA, 1.0e-4);
float coatDenom = NoH * NoH * (coatA2 - 1.0) + 1.0;
float coatD = coatA2 / max(PI * coatDenom * coatDenom, 1.0e-4);
float coatK = ((coatRoughness + 1.0) * (coatRoughness + 1.0)) * 0.125;
float coatGv = NoV / max(NoV * (1.0 - coatK) + coatK, 1.0e-4);
float coatGl = NoL / max(NoL * (1.0 - coatK) + coatK, 1.0e-4);
float coatF = 0.04 + 0.96 * pow(1.0 - VoH, 5.0);
float coatTerm = min((coatD * coatGv * coatGl) / max(4.0 * NoL * NoV, 1.0e-4), 2.75);
specular +=
lightColor *
lightIntensity *
atten *
shadow *
NoL *
coatF *
coatTerm *
(0.30 * clearcoatMask * max(energyScale, 0.0));
}
return LimitSpecularPeak(specular, peakLimit);
}
@@ -4222,7 +4280,8 @@ float3 ComputeSpecular(
float lightIntensity,
float atten,
float shadow,
float3 specularAlbedo)
float3 specularAlbedo,
float surfaceRoughness)
{
return ComputeSpecularShaped(
N,
@@ -4237,8 +4296,9 @@ float3 ComputeSpecular(
0.12,
0.82,
1.0,
1.42,
4.8);
1.70,
6.5,
surfaceRoughness);
}
float EstimateSkeletalSubsurfaceMask(float3 baseAlbedo, float3 specularAlbedo)
@@ -4256,7 +4316,8 @@ float EstimateSkeletalSubsurfaceMask(float3 baseAlbedo, float3 specularAlbedo)
return saturate((0.08 + warm * 0.42 + redBias * 0.38) * fleshRange * lerp(0.55, 1.0, matte));
}
)"
R"(
float3 ComputeSkeletalSpecularAlbedo(float3 baseAlbedo, float3 specularAlbedo)
{
float subsurfaceMask = EstimateSkeletalSubsurfaceMask(baseAlbedo, specularAlbedo);
@@ -4269,7 +4330,8 @@ float3 ComputeSkeletalSpecularAlbedo(float3 baseAlbedo, float3 specularAlbedo)
float cap = lerp(0.16, 0.075, subsurfaceMask);
return min(softSpec, float3(cap, cap, cap));
}
)"
R"(
float3 ComputeSkeletalSpecular(
float3 N,
float3 V,
@@ -4279,7 +4341,8 @@ float3 ComputeSkeletalSpecular(
float lightIntensity,
float atten,
float shadow,
float3 specularAlbedo)
float3 specularAlbedo,
float surfaceRoughness)
{
float subsurfaceMask = EstimateSkeletalSubsurfaceMask(baseAlbedo, specularAlbedo);
float3 characterSpec = ComputeSkeletalSpecularAlbedo(baseAlbedo, specularAlbedo);
@@ -4301,7 +4364,8 @@ float3 ComputeSkeletalSpecular(
0.58,
lerp(0.32, 0.14, subsurfaceMask),
lerp(0.40, 0.24, subsurfaceMask),
lerp(0.55, 0.18, subsurfaceMask));
lerp(0.55, 0.18, subsurfaceMask),
max(surfaceRoughness, 0.48));
}
float ComputeSubsurfaceShape(float3 N, float3 V, float3 L)
@@ -4817,7 +4881,7 @@ float3 EstimatePathTracedSky(float3 worldPos, float3 N, inout uint rng)
}
)"
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)
float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, float surfaceRoughness, bool isSkeletal, float subsurfaceMask, Light Lgt, inout uint rng, out float3 specularOut, out float3 subsurfaceOut)
{
specularOut = 0.0;
subsurfaceOut = 0.0;
@@ -4870,8 +4934,8 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
shadow = TraceVisibilityBiased(worldPos, N, L, dist);
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);
? ComputeSkeletalSpecular(N, V, L, baseAlbedo, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo, surfaceRoughness)
: ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo, surfaceRoughness);
sssAccum += ComputeSkeletalSubsurfaceRadiance(N, V, L, baseAlbedo, Lgt.color, Lgt.intensity, atten, shadow, subsurfaceMask);
diffuseAccum += Lgt.color * (Lgt.intensity * atten * diffuseNoL * shadow);
@@ -4884,7 +4948,7 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
}
)"
R"(
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)
float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, float surfaceRoughness, bool isSkeletal, float subsurfaceMask, Light Lgt, inout uint rng, out float3 specularOut, out float3 subsurfaceOut)
{
specularOut = 0.0;
subsurfaceOut = 0.0;
@@ -4904,15 +4968,15 @@ float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 base
shadow = TraceVisibilityBiased(worldPos, N, L, dist);
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);
? ComputeSkeletalSpecular(N, V, L, baseAlbedo, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo, surfaceRoughness)
: ComputeSpecular(N, V, L, Lgt.color, Lgt.intensity, atten, shadow, specularAlbedo, surfaceRoughness);
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, bool isSkeletal, float subsurfaceMask, Light Lgt, inout uint rng, out float3 specularOut, out float3 subsurfaceOut)
float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V, float3 baseAlbedo, float3 specularAlbedo, float surfaceRoughness, bool isSkeletal, float subsurfaceMask, Light Lgt, inout uint rng, out float3 specularOut, out float3 subsurfaceOut)
{
specularOut = 0.0;
subsurfaceOut = 0.0;
@@ -4981,7 +5045,8 @@ float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V
Lgt.intensity * faceTerm,
1.0,
shadow,
specularAlbedo)
specularAlbedo,
surfaceRoughness)
: ComputeSpecular(
N,
V,
@@ -4990,7 +5055,8 @@ float3 PathTraceDirectRectLight(uint2 pixel, float3 worldPos, float3 N, float3 V
Lgt.intensity * faceTerm,
1.0,
shadow,
specularAlbedo)) * atten;
specularAlbedo,
surfaceRoughness)) * atten;
sssAccum += ComputeSkeletalSubsurfaceRadiance(
N,
@@ -5294,6 +5360,7 @@ float3 EstimateShadowedBounceLight(uint2 hitPixel, float3 hitPos, float3 hitN, f
float3 sss = 0.0;
float3 diffuse = 0.0;
float3 hitSpecularAlbedo = LoadSceneSpecularAlbedo(hitPixel, hitAlbedo);
float hitSurfaceRoughness = StabilizeSpecularSurfaceRoughness(hitPixel, hitN, LoadSceneSurfaceRoughness(LoadSceneNormal(hitPixel)));
float subsurfaceMask = hitIsSkeletal ? EstimateSkeletalSubsurfaceMask(hitAlbedo, hitSpecularAlbedo) * 0.45 : 0.0;
// Use the same visibility-capable direct-light samplers as the primary hit.
@@ -5301,15 +5368,15 @@ float3 EstimateShadowedBounceLight(uint2 hitPixel, float3 hitPos, float3 hitN, f
// old unoccluded light-list approximation.
if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
{
diffuse = PathTraceDirectPointLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, hitIsSkeletal, subsurfaceMask, Lgt, rng, spec, sss);
diffuse = PathTraceDirectPointLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, hitSurfaceRoughness, hitIsSkeletal, subsurfaceMask, Lgt, rng, spec, sss);
}
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_SPOT)
{
diffuse = PathTraceDirectSpotLight(hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, hitIsSkeletal, subsurfaceMask, Lgt, rng, spec, sss);
diffuse = PathTraceDirectSpotLight(hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, hitSurfaceRoughness, hitIsSkeletal, subsurfaceMask, Lgt, rng, spec, sss);
}
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
{
diffuse = PathTraceDirectRectLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, hitIsSkeletal, subsurfaceMask, Lgt, rng, spec, sss);
diffuse = PathTraceDirectRectLight(hitPixel, hitPos, hitN, hitV, hitAlbedo, hitSpecularAlbedo, hitSurfaceRoughness, hitIsSkeletal, subsurfaceMask, Lgt, rng, spec, sss);
}
return clamp(diffuse + sss * 0.35, 0.0, 12.0);
@@ -5848,7 +5915,7 @@ float3 ApplyPrimarySpecularPost(float3 specularAccum, float ao, bool isSkeletal)
// AO is a diffuse/ambient visibility term here. Multiplying specular by AO
// directly made highlights disappear on creases, props, and normal-mapped
// surfaces. Keep a mild occlusion tint, but let direct-light specular read.
float specAo = lerp(0.58, 1.0, saturate(ao));
float specAo = lerp(0.76, 1.0, saturate(ao));
if (isSkeletal)
{
specAo = lerp(specAo, 1.0, 0.50);
@@ -5869,6 +5936,7 @@ float3 PathTraceDeterministicLighting(
float3 V,
float3 baseAlbedo,
float3 specularAlbedo,
float surfaceRoughness,
bool isSkeletal,
float cavity,
float ao,
@@ -5915,15 +5983,15 @@ float3 PathTraceDeterministicLighting(
if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
{
diffuse = PathTraceDirectPointLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, isSkeletal, subsurfaceMask, Lgt, directRng, spec, sss);
diffuse = PathTraceDirectPointLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, surfaceRoughness, isSkeletal, subsurfaceMask, Lgt, directRng, spec, sss);
}
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_SPOT)
{
diffuse = PathTraceDirectSpotLight(worldPos, N, V, baseAlbedo, specularAlbedo, isSkeletal, subsurfaceMask, Lgt, directRng, spec, sss);
diffuse = PathTraceDirectSpotLight(worldPos, N, V, baseAlbedo, specularAlbedo, surfaceRoughness, isSkeletal, subsurfaceMask, Lgt, directRng, spec, sss);
}
else if (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_RECT)
{
diffuse = PathTraceDirectRectLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, isSkeletal, subsurfaceMask, Lgt, directRng, spec, sss);
diffuse = PathTraceDirectRectLight(pixel, worldPos, N, V, baseAlbedo, specularAlbedo, surfaceRoughness, isSkeletal, subsurfaceMask, Lgt, directRng, spec, sss);
}
lightingAccum += diffuse;
@@ -6057,6 +6125,7 @@ float3 EstimateRayTracedSpecularReflection(
float3 V,
float3 baseAlbedo,
float3 specularAlbedo,
float surfaceRoughness,
float cavity,
bool isSkeletal,
inout uint rng)
@@ -6097,8 +6166,8 @@ float3 EstimateRayTracedSpecularReflection(
? saturate(specularAlbedo)
: saturate(lerp(float3(0.02, 0.02, 0.02), specularAlbedo, 0.38));
float3 fresnel = F0 + (1.0 - F0) * pow(1.0 - NoV, 5.0);
float roughness = EstimateSpecularRoughness(specularAlbedo);
roughness = clamp(lerp(roughness, 0.78, smoothstep(0.12, 0.46, normalVariance)), 0.38, 0.82);
float roughness = EstimateSpecularRoughness(specularAlbedo, surfaceRoughness);
roughness = clamp(lerp(roughness, 0.78, smoothstep(0.12, 0.46, normalVariance)), 0.16, 0.84);
// Do not multiply by specPeak again here. specularAlbedo is already F0, and
// double-penalizing it made normal dielectric floors fall below the ray gate.
@@ -6273,9 +6342,12 @@ void RayGen()
uint geoFlag = DecodeGeometryFlag(positionSample.w);
bool isSkeletal = (geoFlag & GEOMETRY_FLAG_SKELETAL) != 0u;
bool isUnlit = (geoFlag & GEOMETRY_FLAG_UNLIT) != 0u;
float4 normalSample = LoadSceneNormal(pixel);
float surfaceRoughness = LoadSceneSurfaceRoughness(normalSample);
float3 N = EnhanceBumpNormal(pixel, worldPos, baseAlbedo, isSkeletal);
if (isSkeletal)
N = StabilizeSkeletalNormal(pixel, worldPos, N);
surfaceRoughness = StabilizeSpecularSurfaceRoughness(pixel, N, surfaceRoughness);
float3 V = normalize(gCameraPos.xyz - worldPos);
if (isUnlit)
@@ -6325,6 +6397,7 @@ void RayGen()
V,
baseAlbedo,
specularAlbedo,
surfaceRoughness,
isSkeletal,
cavity,
ao,
@@ -6370,6 +6443,7 @@ void RayGen()
V,
baseAlbedo,
specularAlbedo,
surfaceRoughness,
cavity,
isSkeletal,
reflectionRng);
@@ -6384,7 +6458,6 @@ void RayGen()
finalColor += baseAlbedo * reactiveFinalGather * gGiAmount;
}
float outputAo = isSkeletal ? lerp(ao, 1.0, 0.55) : ao;
finalColor += subsurfaceAccum;
// Volumetric light scattering is radiance in the camera ray, not surface
@@ -6400,7 +6473,7 @@ void RayGen()
// the eventual swap-chain/backbuffer is LDR.
finalColor += emissiveSurface + emissiveBloom;
gOutputTex[pixel] = float4(PreparePathTraceOutputColor(finalColor) * outputAo, primaryHitDistance);
gOutputTex[pixel] = float4(PreparePathTraceOutputColor(finalColor), primaryHitDistance);
}
)";
+4
View File
@@ -292,6 +292,8 @@ void APIENTRY glTextureSpecularMap(GLuint texture, GLboolean isSpecularMap);
void APIENTRY glBindSpecularMapTexture(GLuint texture);
void APIENTRY glSpecularMapTexture(GLuint texture);
void APIENTRY glSpecularMapStrengthf(GLfloat strength);
void APIENTRY glSurfaceRoughnessf(GLfloat roughness);
void APIENTRY glMaterialTypef(GLfloat materialType);
void APIENTRY glTextureAverageColorQD3D12(GLuint texture, GLfloat r, GLfloat g, GLfloat b, GLfloat a);
void APIENTRY glTerrainBlendEnableQD3D12(GLboolean enable);
void APIENTRY glEnableTerrainBlendQD3D12(GLboolean enable);
@@ -18725,6 +18727,8 @@ PROC WINAPI qd3d12_wglGetProcAddress(LPCSTR name) {
{ "glBindSpecularMapTexture", (PROC)glBindSpecularMapTexture },
{ "glSpecularMapTexture", (PROC)glSpecularMapTexture },
{ "glSpecularMapStrengthf", (PROC)glSpecularMapStrengthf },
{ "glSurfaceRoughnessf", (PROC)glSurfaceRoughnessf },
{ "glMaterialTypef", (PROC)glMaterialTypef },
{ "glTerrainBlendEnableQD3D12", (PROC)glTerrainBlendEnableQD3D12 },
{ "glEnableTerrainBlendQD3D12", (PROC)glEnableTerrainBlendQD3D12 },
{ "glTerrainLayerTextureQD3D12", (PROC)glTerrainLayerTextureQD3D12 },
+2
View File
@@ -2329,6 +2329,8 @@ void APIENTRY glTextureSpecularMap(GLuint texture, GLboolean isSpecularMap);
void APIENTRY glBindSpecularMapTexture(GLuint texture);
void APIENTRY glSpecularMapTexture(GLuint texture);
void APIENTRY glSpecularMapStrengthf(GLfloat strength);
void APIENTRY glSurfaceRoughnessf(GLfloat roughness);
void APIENTRY glMaterialTypef(GLfloat materialType);
void APIENTRY glTextureAverageColorQD3D12(GLuint texture, GLfloat r, GLfloat g, GLfloat b, GLfloat a);
void glUpdateTopLevelAceelStructure(
+93
View File
@@ -32,6 +32,92 @@ If you have questions concerning this license or the applicable additional terms
idCVar r_renderNeuralMaterial("r_renderNeuralMaterial", "0", CVAR_BOOL, "");
static bool RB_MaterialNameHasToken( const idMaterial *shader, const char *token ) {
if ( !shader || !token || !token[0] ) {
return false;
}
idStr name = shader->GetName();
name.ToLower();
return name.Find( token ) >= 0;
}
static float RB_EstimatePathTraceRoughness( const idMaterial *shader, const idImage *specImage, const idImage *glowMapImage ) {
const bool hasSpec = ( specImage != NULL );
const bool hasGlow = ( glowMapImage != NULL );
float roughness = hasSpec ? 0.44f : 0.72f;
if ( RB_MaterialNameHasToken( shader, "glass" ) ||
RB_MaterialNameHasToken( shader, "window" ) ||
RB_MaterialNameHasToken( shader, "screen" ) ||
RB_MaterialNameHasToken( shader, "monitor" ) ||
RB_MaterialNameHasToken( shader, "computer" ) ) {
roughness = hasGlow ? 0.22f : 0.28f;
}
else if ( RB_MaterialNameHasToken( shader, "blood" ) ||
RB_MaterialNameHasToken( shader, "slime" ) ||
RB_MaterialNameHasToken( shader, "water" ) ||
RB_MaterialNameHasToken( shader, "wet" ) ) {
roughness = 0.24f;
}
else if ( RB_MaterialNameHasToken( shader, "floor" ) ||
RB_MaterialNameHasToken( shader, "tile" ) ||
RB_MaterialNameHasToken( shader, "plate" ) ) {
roughness = hasSpec ? 0.34f : 0.52f;
}
else if ( RB_MaterialNameHasToken( shader, "metal" ) ||
RB_MaterialNameHasToken( shader, "panel" ) ||
RB_MaterialNameHasToken( shader, "pipe" ) ||
RB_MaterialNameHasToken( shader, "door" ) ||
RB_MaterialNameHasToken( shader, "trim" ) ||
RB_MaterialNameHasToken( shader, "machine" ) ) {
roughness = hasSpec ? 0.36f : 0.58f;
}
else if ( RB_MaterialNameHasToken( shader, "skin" ) ||
RB_MaterialNameHasToken( shader, "flesh" ) ||
RB_MaterialNameHasToken( shader, "monster" ) ||
RB_MaterialNameHasToken( shader, "char" ) ) {
roughness = 0.62f;
}
else if ( RB_MaterialNameHasToken( shader, "wall" ) ||
RB_MaterialNameHasToken( shader, "ceil" ) ||
RB_MaterialNameHasToken( shader, "concrete" ) ||
RB_MaterialNameHasToken( shader, "rock" ) ||
RB_MaterialNameHasToken( shader, "stone" ) ) {
roughness = hasSpec ? 0.56f : 0.78f;
}
return idMath::ClampFloat( 0.08f, 0.92f, roughness );
}
static float RB_EstimatePathTraceSpecularStrength( const idMaterial *shader, const idImage *specImage, const idImage *glowMapImage ) {
if ( !specImage ) {
return 1.0f;
}
float strength = 1.35f;
if ( RB_MaterialNameHasToken( shader, "floor" ) ||
RB_MaterialNameHasToken( shader, "tile" ) ||
RB_MaterialNameHasToken( shader, "metal" ) ||
RB_MaterialNameHasToken( shader, "panel" ) ||
RB_MaterialNameHasToken( shader, "door" ) ) {
strength = 1.85f;
}
if ( glowMapImage ||
RB_MaterialNameHasToken( shader, "glass" ) ||
RB_MaterialNameHasToken( shader, "screen" ) ||
RB_MaterialNameHasToken( shader, "monitor" ) ) {
strength = 2.10f;
}
if ( RB_MaterialNameHasToken( shader, "skin" ) ||
RB_MaterialNameHasToken( shader, "flesh" ) ||
RB_MaterialNameHasToken( shader, "monster" ) ) {
strength = 0.75f;
}
return idMath::ClampFloat( 0.5f, 2.4f, strength );
}
static idDrawVert *RB_BindAmbientBuffer( const srfTriangles_t *tri ) {
if ( tri->ambientVbo ) {
glBindBufferARB( GL_ARRAY_BUFFER_ARB, tri->ambientVbo );
@@ -498,6 +584,8 @@ void RB_T_FillDepthBuffer(const drawSurf_t* surf) {
idImage* bumpImage = shader->GetBumpImage();
idImage* specImage = shader->GetSpecImage();
idImage* glowMapImage = shader->GetGlowImage(regs);
const float pathTraceRoughness = RB_EstimatePathTraceRoughness( shader, specImage, glowMapImage );
const float pathTraceSpecularStrength = RB_EstimatePathTraceSpecularStrength( shader, specImage, glowMapImage );
// Make sure the material has tried to load/upload its NeuralPOM payload.
// If no neural files exist, this should leave the handle as 0.
@@ -542,11 +630,14 @@ void RB_T_FillDepthBuffer(const drawSurf_t* surf) {
if (specImage) {
specImage->Bind();
glBindSpecularMapTexture(specImage->texnum);
glSpecularMapStrengthf(pathTraceSpecularStrength);
}
else {
globalImages->BindNull();
glBindSpecularMapTexture(0);
glSpecularMapStrengthf(1.0f);
}
glSurfaceRoughnessf(pathTraceRoughness);
// glow fallback
if (glowMapImage) {
@@ -580,6 +671,8 @@ void RB_T_FillDepthBuffer(const drawSurf_t* surf) {
GL_SelectTexture(2);
glBindSpecularMapTexture(0);
glSpecularMapStrengthf(1.0f);
glSurfaceRoughnessf(0.5f);
globalImages->BindNull();
GL_SelectTexture(1);