Light equation changes and weapon and ai spawn proper muzzle flashes.

This commit is contained in:
Justin Marshall
2026-05-12 21:44:50 -07:00
parent a797428ee5
commit cdb45e4155
5 changed files with 3796 additions and 3165 deletions
+105 -26
View File
@@ -2308,7 +2308,12 @@ cbuffer DrawCB : register(b0)
// Full object-space displacement amplitude for the tessellation domain shader.
// The CPU side keeps this conservative, but clamp here too so a bad material
// strength cannot explode the mesh.
#define gTessellationDisplacement clamp(gMaterialMapPad.w, 0.0, 0.35)
// Raised from the old 0.35 cap so stronger materials can push deeper, while
// the hull shader below uses shared-edge tess factors to prevent crack artifacts.
#define gTessellationDisplacement clamp(gMaterialMapPad.w, 0.0, 0.50)
#define QD3D12_TESS_MIN_FACTOR 2.0
#define QD3D12_TESS_MAX_FACTOR 15.0
#define QD3D12_TESS_TARGET_EDGE_PIXELS 28.0
Texture2D gTex0 : register(t0);
Texture2D gTex1 : register(t1);
@@ -2565,6 +2570,38 @@ float QD3D12_GetHeightFromNormalMapLOD(float2 uv, float lod)
return QD3D12_HeightFromNormalSample(gNormalMap.SampleLevel(gSamp2, uv, lod));
}
float2 QD3D12_NormalMapTexelSize()
{
uint w = 1;
uint h = 1;
gNormalMap.GetDimensions(w, h);
return rcp(max(float2((float)w, (float)h), float2(1.0, 1.0)));
}
float QD3D12_GetFilteredTessHeight(float2 uv)
{
// Hardware tessellation magnifies tiny normal-map compression errors.
// A light cross filter keeps the deeper displacement stable without
// blurring the color/normal sampling path used by the pixel shader.
float2 texel = QD3D12_NormalMapTexelSize();
float center = QD3D12_GetHeightFromNormalMapLOD(uv, 0.0);
float hx0 = QD3D12_GetHeightFromNormalMapLOD(uv - float2(texel.x, 0.0), 0.0);
float hx1 = QD3D12_GetHeightFromNormalMapLOD(uv + float2(texel.x, 0.0), 0.0);
float hy0 = QD3D12_GetHeightFromNormalMapLOD(uv - float2(0.0, texel.y), 0.0);
float hy1 = QD3D12_GetHeightFromNormalMapLOD(uv + float2(0.0, texel.y), 0.0);
return saturate(center * 0.50 + (hx0 + hx1 + hy0 + hy1) * 0.125);
}
float QD3D12_CleanCenteredTessHeight(float height)
{
// Suppress barely-visible single-texel noise before applying the now deeper
// displacement. This removes acne-like spikes while preserving real relief.
float centered = (height - 0.5) * 2.0;
float s = (centered < 0.0) ? -1.0 : 1.0;
float a = saturate((abs(centered) - 0.015) * (1.0 / 0.985));
return s * a;
}
float3 QD3D12_BuildFallbackTangent(float3 n)
{
float3 up = (abs(n.z) < 0.999) ? float3(0.0, 0.0, 1.0) : float3(0.0, 1.0, 0.0);
@@ -2721,7 +2758,8 @@ float4 BuildGlowEmission(VSOut i)
{
return QD3D12_SampleGlow(i);
}
)HLSL"
R"HLSL(
float4 BuildSpecularAlbedo(VSOut i)
{
if (gUseSpecularMap <= 0.0)
@@ -2838,29 +2876,68 @@ TessCP QD3D12_MakeTessCP(VSOut i)
return o;
}
float QD3D12_ComputeNormalMapTessFactor(InputPatch<VSOut, 3> patch)
float2 QD3D12_ClipXYToNdc(float4 clipPos)
{
float h0 = QD3D12_GetHeightFromNormalMapLOD(patch[0].uv0, 0.0);
float h1 = QD3D12_GetHeightFromNormalMapLOD(patch[1].uv0, 0.0);
float h2 = QD3D12_GetHeightFromNormalMapLOD(patch[2].uv0, 0.0);
float heightRange = max(abs(h0 - h1), max(abs(h1 - h2), abs(h2 - h0)));
return clipPos.xy / max(abs(clipPos.w), 1.0e-6);
}
float QD3D12_EdgeLengthPixels(float4 clipA, float4 clipB)
{
float2 ndcA = QD3D12_ClipXYToNdc(clipA);
float2 ndcB = QD3D12_ClipXYToNdc(clipB);
return length((ndcA - ndcB) * max(gRenderSize, float2(1.0, 1.0)) * 0.5);
}
float QD3D12_ComputeNormalMapTessEdgeFactor(VSOut a, VSOut b)
{
if (gUseNormalMap <= 0.5)
return 1.0;
float ha = QD3D12_GetFilteredTessHeight(a.uv0);
float hb = QD3D12_GetFilteredTessHeight(b.uv0);
float hm = QD3D12_GetFilteredTessHeight((a.uv0 + b.uv0) * 0.5);
// This edge-only factor is the crack fix: neighboring triangles that share
// this edge compute the same tessellation factor because they use only the
// two shared vertices and the same midpoint sample.
float heightRange = max(abs(ha - hb), abs(hm - (ha + hb) * 0.5) * 2.0);
float edgePixels = QD3D12_EdgeLengthPixels(a.currClip, b.currClip);
float uvSpan = length(a.uv0 - b.uv0);
// Give displaced normal-mapped surfaces enough subdivision to show the larger
// height push. fractional_odd will quantize these into stable odd partitions,
// so 3/5/7 are the practical quality tiers for default/strong materials.
float strength = clamp(max(gNormalMapStrength, 0.0), 0.0, 4.0);
float factor = 2.0 + strength * 1.0 + heightRange * 8.0;
return (gUseNormalMap > 0.5) ? clamp(factor, 2.0, 7.0) : 1.0;
float screenTerm = sqrt(max(edgePixels, 1.0) / QD3D12_TESS_TARGET_EDGE_PIXELS);
float heightTerm = heightRange * (10.0 + strength * 4.0);
float uvTerm = saturate(uvSpan * 4.0) * 2.0;
float displacementTerm = saturate(gTessellationDisplacement * 6.0) * 2.0;
float factor = 1.0 + strength * 0.75 + screenTerm * 3.0 + heightTerm + uvTerm + displacementTerm;
return clamp(factor, QD3D12_TESS_MIN_FACTOR, QD3D12_TESS_MAX_FACTOR);
}
HSConstOut HSMainConstants(InputPatch<VSOut, 3> patch)
{
HSConstOut o;
float factor = QD3D12_ComputeNormalMapTessFactor(patch);
o.edge[0] = factor;
o.edge[1] = factor;
o.edge[2] = factor;
o.inside = factor;
if (gUseNormalMap <= 0.5)
{
o.edge[0] = 1.0;
o.edge[1] = 1.0;
o.edge[2] = 1.0;
o.inside = 1.0;
return o;
}
// D3D tri patch edge order is opposite the named control point:
// edge 0 = CP1-CP2, edge 1 = CP2-CP0, edge 2 = CP0-CP1.
float e0 = QD3D12_ComputeNormalMapTessEdgeFactor(patch[1], patch[2]);
float e1 = QD3D12_ComputeNormalMapTessEdgeFactor(patch[2], patch[0]);
float e2 = QD3D12_ComputeNormalMapTessEdgeFactor(patch[0], patch[1]);
float maxEdge = max(e0, max(e1, e2));
o.edge[0] = e0;
o.edge[1] = e1;
o.edge[2] = e2;
o.inside = clamp((e0 + e1 + e2 + maxEdge) * 0.25, QD3D12_TESS_MIN_FACTOR, QD3D12_TESS_MAX_FACTOR);
return o;
}
@@ -2869,6 +2946,7 @@ HSConstOut HSMainConstants(InputPatch<VSOut, 3> patch)
[outputtopology("triangle_ccw")]
[outputcontrolpoints(3)]
[patchconstantfunc("HSMainConstants")]
[maxtessfactor(15.0)]
TessCP HSMain(InputPatch<VSOut, 3> patch, uint cpId : SV_OutputControlPointID)
{
return QD3D12_MakeTessCP(patch[cpId]);
@@ -2911,8 +2989,8 @@ VSOut DSMain(HSConstOut tessFactors, float3 bary : SV_DomainLocation, const Outp
VSOut o;
float3 objNormal = QD3D12_SafeNormalize(i.objNormal, float3(0.0, 0.0, 1.0));
float height = QD3D12_GetHeightFromNormalMapLOD(i.uv0, 0.0);
float centeredHeight = (height - 0.5) * 2.0;
float height = QD3D12_GetFilteredTessHeight(i.uv0);
float centeredHeight = QD3D12_CleanCenteredTessHeight(height);
float displacement = centeredHeight * gTessellationDisplacement;
float3 displacedObjPos = i.objPos + objNormal * displacement;
@@ -7629,7 +7707,7 @@ static void QD3D12_FilterMipPixelGammaAware(
center[1] /= centerA;
center[2] /= centerA;
const float sharpen = 0.22f;
const float sharpen = 1.0f;
filtered[0] = ClampValue<float>(filtered[0] + (center[0] - filtered[0]) * sharpen, 0.0f, 1.0f);
filtered[1] = ClampValue<float>(filtered[1] + (center[1] - filtered[1]) * sharpen, 0.0f, 1.0f);
filtered[2] = ClampValue<float>(filtered[2] + (center[2] - filtered[2]) * sharpen, 0.0f, 1.0f);
@@ -8935,14 +9013,15 @@ static void QD3D12_FlushQueuedBatches()
dc->materialMapPad[1] = batch.key.specularMapStrength;
dc->materialMapPad[2] = QD3D12_PipelineUsesAlphaBlend(batch.key.pipeline) ? 1.0f : 0.0f;
// Normal-map strength now drives a visibly stronger object-space displacement.
// Keep a hard upper bound because old RGB-only normal maps are often noisy and
// are not authored as true height maps. Default strength 1.0 gives about
// +/-0.08 object units for authored alpha-height maps and outward lift for
// RGB-only bump detail; glNormalMapStrengthf() can push it higher.
// The hull shader can now subdivide much deeper, so the CPU side permits a
// deeper push too while the shader filters/suppresses tiny bump-map noise.
// Default strength 1.0 gives about +/-0.12 object units for authored alpha
// height maps and outward lift for RGB-only bump detail; glNormalMapStrengthf()
// can push it higher up to the hard 0.50 object-unit safety cap.
const float tessStrength = ClampValue<float>(batch.key.normalMapStrength, 0.0f, 4.0f);
const float tessDisplacementScale = 0.08f;
const float tessDisplacementScale = 0.12f;
dc->materialMapPad[3] = QD3D12_UseNormalMapTessellationPSO(batch.key, nativeColorOnly) ?
ClampValue<float>(tessStrength * tessDisplacementScale, 0.0f, 0.35f) : 0.0f;
ClampValue<float>(tessStrength * tessDisplacementScale, 0.0f, 0.50f) : 0.0f;
if (batch.key.useARBPrograms)
{