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
+1543 -1215
View File
File diff suppressed because it is too large Load Diff
+2136 -1921
View File
File diff suppressed because it is too large Load Diff
+9
View File
@@ -519,6 +519,15 @@ void idAI::MuzzleFlash(const char* jointname) {
idVec3 muzzle; idVec3 muzzle;
idMat3 axis; idMat3 axis;
// Match the idWeapon behavior: the short-lived muzzle light should attach
// to the same joint the script fired from, not blindly to a hardcoded joint.
if (jointname && jointname[0]) {
jointHandle_t joint = animator.GetJointHandle(jointname);
if (joint != INVALID_JOINT) {
flashJointWorld = joint;
}
}
GetMuzzle(jointname, muzzle, axis); GetMuzzle(jointname, muzzle, axis);
TriggerWeaponEffects(muzzle); TriggerWeaponEffects(muzzle);
} }
+105 -26
View File
@@ -2308,7 +2308,12 @@ cbuffer DrawCB : register(b0)
// Full object-space displacement amplitude for the tessellation domain shader. // Full object-space displacement amplitude for the tessellation domain shader.
// The CPU side keeps this conservative, but clamp here too so a bad material // The CPU side keeps this conservative, but clamp here too so a bad material
// strength cannot explode the mesh. // 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 gTex0 : register(t0);
Texture2D gTex1 : register(t1); Texture2D gTex1 : register(t1);
@@ -2565,6 +2570,38 @@ float QD3D12_GetHeightFromNormalMapLOD(float2 uv, float lod)
return QD3D12_HeightFromNormalSample(gNormalMap.SampleLevel(gSamp2, uv, 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 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); 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); return QD3D12_SampleGlow(i);
} }
)HLSL"
R"HLSL(
float4 BuildSpecularAlbedo(VSOut i) float4 BuildSpecularAlbedo(VSOut i)
{ {
if (gUseSpecularMap <= 0.0) if (gUseSpecularMap <= 0.0)
@@ -2838,29 +2876,68 @@ TessCP QD3D12_MakeTessCP(VSOut i)
return o; return o;
} }
float QD3D12_ComputeNormalMapTessFactor(InputPatch<VSOut, 3> patch) float2 QD3D12_ClipXYToNdc(float4 clipPos)
{ {
float h0 = QD3D12_GetHeightFromNormalMapLOD(patch[0].uv0, 0.0); return clipPos.xy / max(abs(clipPos.w), 1.0e-6);
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))); 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 strength = clamp(max(gNormalMapStrength, 0.0), 0.0, 4.0);
float factor = 2.0 + strength * 1.0 + heightRange * 8.0; float screenTerm = sqrt(max(edgePixels, 1.0) / QD3D12_TESS_TARGET_EDGE_PIXELS);
return (gUseNormalMap > 0.5) ? clamp(factor, 2.0, 7.0) : 1.0; 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 HSMainConstants(InputPatch<VSOut, 3> patch)
{ {
HSConstOut o; HSConstOut o;
float factor = QD3D12_ComputeNormalMapTessFactor(patch);
o.edge[0] = factor; if (gUseNormalMap <= 0.5)
o.edge[1] = factor; {
o.edge[2] = factor; o.edge[0] = 1.0;
o.inside = factor; 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; return o;
} }
@@ -2869,6 +2946,7 @@ HSConstOut HSMainConstants(InputPatch<VSOut, 3> patch)
[outputtopology("triangle_ccw")] [outputtopology("triangle_ccw")]
[outputcontrolpoints(3)] [outputcontrolpoints(3)]
[patchconstantfunc("HSMainConstants")] [patchconstantfunc("HSMainConstants")]
[maxtessfactor(15.0)]
TessCP HSMain(InputPatch<VSOut, 3> patch, uint cpId : SV_OutputControlPointID) TessCP HSMain(InputPatch<VSOut, 3> patch, uint cpId : SV_OutputControlPointID)
{ {
return QD3D12_MakeTessCP(patch[cpId]); return QD3D12_MakeTessCP(patch[cpId]);
@@ -2911,8 +2989,8 @@ VSOut DSMain(HSConstOut tessFactors, float3 bary : SV_DomainLocation, const Outp
VSOut o; VSOut o;
float3 objNormal = QD3D12_SafeNormalize(i.objNormal, float3(0.0, 0.0, 1.0)); float3 objNormal = QD3D12_SafeNormalize(i.objNormal, float3(0.0, 0.0, 1.0));
float height = QD3D12_GetHeightFromNormalMapLOD(i.uv0, 0.0); float height = QD3D12_GetFilteredTessHeight(i.uv0);
float centeredHeight = (height - 0.5) * 2.0; float centeredHeight = QD3D12_CleanCenteredTessHeight(height);
float displacement = centeredHeight * gTessellationDisplacement; float displacement = centeredHeight * gTessellationDisplacement;
float3 displacedObjPos = i.objPos + objNormal * displacement; float3 displacedObjPos = i.objPos + objNormal * displacement;
@@ -7629,7 +7707,7 @@ static void QD3D12_FilterMipPixelGammaAware(
center[1] /= centerA; center[1] /= centerA;
center[2] /= 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[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[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); 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[1] = batch.key.specularMapStrength;
dc->materialMapPad[2] = QD3D12_PipelineUsesAlphaBlend(batch.key.pipeline) ? 1.0f : 0.0f; dc->materialMapPad[2] = QD3D12_PipelineUsesAlphaBlend(batch.key.pipeline) ? 1.0f : 0.0f;
// Normal-map strength now drives a visibly stronger object-space displacement. // 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 // The hull shader can now subdivide much deeper, so the CPU side permits a
// are not authored as true height maps. Default strength 1.0 gives about // deeper push too while the shader filters/suppresses tiny bump-map noise.
// +/-0.08 object units for authored alpha-height maps and outward lift for // Default strength 1.0 gives about +/-0.12 object units for authored alpha
// RGB-only bump detail; glNormalMapStrengthf() can push it higher. // 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 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) ? 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) if (batch.key.useARBPrograms)
{ {
+3 -3
View File
@@ -176,7 +176,7 @@ void RB_DXDrawInteractions(void)
const float r = srcLight.shaderParms[SHADERPARM_RED]; const float r = srcLight.shaderParms[SHADERPARM_RED];
const float g = srcLight.shaderParms[SHADERPARM_GREEN]; const float g = srcLight.shaderParms[SHADERPARM_GREEN];
const float b = srcLight.shaderParms[SHADERPARM_BLUE]; const float b = srcLight.shaderParms[SHADERPARM_BLUE];
const float intensity = 6.0f; const float intensity = 4.0f;
glRaytracingLight_t light = {}; glRaytracingLight_t light = {};
bool supported = true; bool supported = true;
@@ -187,8 +187,8 @@ void RB_DXDrawInteractions(void)
vLight->globalLightOrigin.x, vLight->globalLightOrigin.x,
vLight->globalLightOrigin.y, vLight->globalLightOrigin.y,
vLight->globalLightOrigin.z, vLight->globalLightOrigin.z,
srcLight.lightRadius[0] * 1.4f, srcLight.lightRadius[0] * 1.25f,
srcLight.lightRadius[1] * 1.4f, srcLight.lightRadius[1] * 1.25f,
srcLight.lightRadius[2] * 1.4f, srcLight.lightRadius[2] * 1.4f,
r, g, b, r, g, b,
intensity); intensity);