mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Added lit particle emissive support.
This commit is contained in:
@@ -3868,6 +3868,7 @@ static classVariableInfo_t idParticleStage_typeInfo[] = {
|
||||
{ "idParticleParm", "aspect", (intptr_t)(&((idParticleStage *)0)->aspect), sizeof( ((idParticleStage *)0)->aspect ) },
|
||||
{ "idVec4", "color", (intptr_t)(&((idParticleStage *)0)->color), sizeof( ((idParticleStage *)0)->color ) },
|
||||
{ "idVec4", "fadeColor", (intptr_t)(&((idParticleStage *)0)->fadeColor), sizeof( ((idParticleStage *)0)->fadeColor ) },
|
||||
{ "float", "emissive", (intptr_t)(&((idParticleStage *)0)->emissive), sizeof( ((idParticleStage *)0)->emissive ) },
|
||||
{ "float", "fadeInFraction", (intptr_t)(&((idParticleStage *)0)->fadeInFraction), sizeof( ((idParticleStage *)0)->fadeInFraction ) },
|
||||
{ "float", "fadeOutFraction", (intptr_t)(&((idParticleStage *)0)->fadeOutFraction), sizeof( ((idParticleStage *)0)->fadeOutFraction ) },
|
||||
{ "float", "fadeIndexFraction", (intptr_t)(&((idParticleStage *)0)->fadeIndexFraction), sizeof( ((idParticleStage *)0)->fadeIndexFraction ) },
|
||||
@@ -4371,6 +4372,7 @@ static classVariableInfo_t srfTriangles_t_typeInfo[] = {
|
||||
{ "unsigned int", "ambientVbo", (intptr_t)(&((srfTriangles_t *)0)->ambientVbo), sizeof( ((srfTriangles_t *)0)->ambientVbo ) },
|
||||
{ "unsigned int", "indexVbo", (intptr_t)(&((srfTriangles_t *)0)->indexVbo), sizeof( ((srfTriangles_t *)0)->indexVbo ) },
|
||||
{ "bool", "isSkeletal", (intptr_t)(&((srfTriangles_t *)0)->isSkeletal), sizeof( ((srfTriangles_t *)0)->isSkeletal ) },
|
||||
{ "float", "particleEmissiveScale", (intptr_t)(&((srfTriangles_t *)0)->particleEmissiveScale), sizeof( ((srfTriangles_t *)0)->particleEmissiveScale ) },
|
||||
{ "int", "numAllocedVerts", (intptr_t)(&((srfTriangles_t *)0)->numAllocedVerts), sizeof( ((srfTriangles_t *)0)->numAllocedVerts ) },
|
||||
{ "int", "numAllocedIndices", (intptr_t)(&((srfTriangles_t *)0)->numAllocedIndices), sizeof( ((srfTriangles_t *)0)->numAllocedIndices ) },
|
||||
{ NULL, 0 }
|
||||
|
||||
@@ -252,6 +252,9 @@ static bool IsParticleStageToken(const idToken& token) {
|
||||
if (!token.Icmp("fadeColor")) {
|
||||
return true;
|
||||
}
|
||||
if (!token.Icmp("emissive") || !token.Icmp("emsive")) {
|
||||
return true;
|
||||
}
|
||||
if (!token.Icmp("offset")) {
|
||||
return true;
|
||||
}
|
||||
@@ -582,6 +585,16 @@ idParticleStage* idDeclParticle::ParseParticleStage(idLexer& src) {
|
||||
stage->fadeColor[3] = src.ParseFloat();
|
||||
continue;
|
||||
}
|
||||
if (!token.Icmp("emissive") || !token.Icmp("emsive")) {
|
||||
if (src.ReadTokenOnLine(&token)) {
|
||||
token.StripQuotes();
|
||||
stage->emissive = atof(token.c_str());
|
||||
}
|
||||
else {
|
||||
stage->emissive = 1.0f;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!token.Icmp("offset")) {
|
||||
stage->offset[0] = src.ParseFloat();
|
||||
stage->offset[1] = src.ParseFloat();
|
||||
@@ -874,6 +887,9 @@ void idDeclParticle::WriteStage( idFile *f, idParticleStage *stage ) {
|
||||
|
||||
f->WriteFloatString( "\t\tcolor \t\t\t\t%.3f %.3f %.3f %.3f\n", stage->color.x, stage->color.y, stage->color.z, stage->color.w );
|
||||
f->WriteFloatString( "\t\tfadeColor \t\t\t%.3f %.3f %.3f %.3f\n", stage->fadeColor.x, stage->fadeColor.y, stage->fadeColor.z, stage->fadeColor.w );
|
||||
if ( stage->emissive > 0.0f ) {
|
||||
f->WriteFloatString( "\t\temissive \t\t\t%.3f\n", stage->emissive );
|
||||
}
|
||||
|
||||
f->WriteFloatString( "\t\toffset \t\t\t\t%.3f %.3f %.3f\n", stage->offset.x, stage->offset.y, stage->offset.z );
|
||||
f->WriteFloatString( "\t\tgravity \t\t\t" );
|
||||
@@ -996,6 +1012,7 @@ idParticleStage::idParticleStage( void ) {
|
||||
// idParticleParm aspect
|
||||
color.Zero();
|
||||
fadeColor.Zero();
|
||||
emissive = 0.0f;
|
||||
fadeInFraction = 0.0f;
|
||||
fadeOutFraction = 0.0f;
|
||||
fadeIndexFraction = 0.0f;
|
||||
@@ -1071,6 +1088,7 @@ void idParticleStage::Default() {
|
||||
fadeColor.y = 0.0f;
|
||||
fadeColor.z = 0.0f;
|
||||
fadeColor.w = 0.0f;
|
||||
emissive = 0.0f;
|
||||
fadeInFraction = 0.1f;
|
||||
fadeOutFraction = 0.25f;
|
||||
fadeIndexFraction = 0.0f;
|
||||
@@ -1698,6 +1716,7 @@ void idParticleStage::operator=( const idParticleStage &src ) {
|
||||
aspect = src.aspect;
|
||||
color = src.color;
|
||||
fadeColor = src.fadeColor;
|
||||
emissive = src.emissive;
|
||||
fadeInFraction = src.fadeInFraction;
|
||||
fadeOutFraction = src.fadeOutFraction;
|
||||
fadeIndexFraction = src.fadeIndexFraction;
|
||||
|
||||
@@ -183,6 +183,7 @@ public:
|
||||
|
||||
idVec4 color;
|
||||
idVec4 fadeColor; // either 0 0 0 0 for additive, or 1 1 1 0 for blended materials
|
||||
float emissive; // screen-space particle emissive radiance scale, 0 disables
|
||||
float fadeInFraction; // in 0.0 to 1.0 range
|
||||
float fadeOutFraction; // in 0.0 to 1.0 range
|
||||
float fadeIndexFraction; // in 0.0 to 1.0 range, causes later index smokes to be more faded
|
||||
|
||||
@@ -142,6 +142,7 @@ typedef struct srfTriangles_s {
|
||||
unsigned int indexVbo; // model-owned index GL buffer
|
||||
|
||||
bool isSkeletal;
|
||||
float particleEmissiveScale;
|
||||
int numAllocedVerts;
|
||||
int numAllocedIndices;
|
||||
} srfTriangles_t;
|
||||
|
||||
@@ -236,6 +236,7 @@ idRenderModel *idRenderModelPrt::InstantiateDynamicModel( const struct renderEnt
|
||||
surf->geometry->numVerts = numVerts;
|
||||
surf->geometry->numIndexes = numIndexes;
|
||||
surf->geometry->bounds = stage->bounds; // just always draw the particles
|
||||
surf->geometry->particleEmissiveScale = stage->emissive;
|
||||
}
|
||||
|
||||
return staticModel;
|
||||
|
||||
@@ -3899,45 +3899,55 @@ float3 LoadEmissiveRadianceClamped(int2 p)
|
||||
{
|
||||
int2 maxPixel = int2((int)gScreenSize.x - 1, (int)gScreenSize.y - 1);
|
||||
p = clamp(p, int2(0, 0), maxPixel);
|
||||
return CompressEmissiveRadiance(gEmissiveTex.Load(int3(p, 0)).rgb, 7.50);
|
||||
float3 radiance = CompressEmissiveRadiance(gEmissiveTex.Load(int3(p, 0)).rgb, 18.0);
|
||||
return min(radiance + sqrt(max(radiance, 0.0)) * 0.35, 22.0);
|
||||
}
|
||||
|
||||
float3 EstimateEmissiveBloomAtPixel(uint2 pixel)
|
||||
{
|
||||
int2 p = int2(pixel);
|
||||
|
||||
// Strong threshold-free bloom. This stays direct/bloom-only: no extra
|
||||
// TraceRay calls, and no emissive lighting contribution. The goal is to make
|
||||
// visible glow maps read as hot emissive surfaces in the DXR output.
|
||||
// Strong threshold-free bloom in the ray output. Particle emissive lighting
|
||||
// is injected separately below; this is the visible camera halo.
|
||||
float3 bloom = 0.0;
|
||||
bloom += LoadEmissiveRadianceClamped(p) * 0.180;
|
||||
bloom += LoadEmissiveRadianceClamped(p) * 0.320;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 1, 0)) * 0.220;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-1, 0)) * 0.220;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 1)) * 0.220;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -1)) * 0.220;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 1, 0)) * 0.420;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-1, 0)) * 0.420;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 1)) * 0.420;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -1)) * 0.420;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 2, 2)) * 0.135;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-2, 2)) * 0.135;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 2, -2)) * 0.135;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-2, -2)) * 0.135;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 2, 2)) * 0.260;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-2, 2)) * 0.260;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 2, -2)) * 0.260;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-2, -2)) * 0.260;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 4, 0)) * 0.090;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-4, 0)) * 0.090;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 4)) * 0.090;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -4)) * 0.090;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 4, 0)) * 0.180;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-4, 0)) * 0.180;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 4)) * 0.180;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -4)) * 0.180;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 8, 0)) * 0.060;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-8, 0)) * 0.060;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 8)) * 0.060;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -8)) * 0.060;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 8, 0)) * 0.120;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-8, 0)) * 0.120;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 8)) * 0.120;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -8)) * 0.120;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 14, 0)) * 0.035;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-14, 0)) * 0.035;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 14)) * 0.035;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -14)) * 0.035;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 14, 0)) * 0.075;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-14, 0)) * 0.075;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 14)) * 0.075;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -14)) * 0.075;
|
||||
|
||||
return bloom * 0.78;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 24, 0)) * 0.045;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-24, 0)) * 0.045;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 24)) * 0.045;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -24)) * 0.045;
|
||||
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 42, 0)) * 0.025;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2(-42, 0)) * 0.025;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, 42)) * 0.025;
|
||||
bloom += LoadEmissiveRadianceClamped(p + int2( 0, -42)) * 0.025;
|
||||
|
||||
return min(bloom * 1.45, 28.0);
|
||||
}
|
||||
|
||||
float3 SafeNormalizeOr(float3 v, float3 fallback)
|
||||
@@ -3948,6 +3958,103 @@ float3 SafeNormalizeOr(float3 v, float3 fallback)
|
||||
return v * rsqrt(lenSq);
|
||||
}
|
||||
|
||||
bool TryScreenParticleWorldCandidate(float4 clip, float3 receiverPos, inout float bestDistSq, inout float3 bestWorld)
|
||||
{
|
||||
float4 worldA = mul(clip, gInvViewProj);
|
||||
if (abs(worldA.w) > 1e-6)
|
||||
{
|
||||
float3 candidate = worldA.xyz / worldA.w;
|
||||
float distSq = dot(candidate - receiverPos, candidate - receiverPos);
|
||||
if (distSq < bestDistSq && distSq > 1e-4 && distSq < 147456.0)
|
||||
{
|
||||
bestDistSq = distSq;
|
||||
bestWorld = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
float4 worldB = mul(gInvViewProj, clip);
|
||||
if (abs(worldB.w) > 1e-6)
|
||||
{
|
||||
float3 candidate = worldB.xyz / worldB.w;
|
||||
float distSq = dot(candidate - receiverPos, candidate - receiverPos);
|
||||
if (distSq < bestDistSq && distSq > 1e-4 && distSq < 147456.0)
|
||||
{
|
||||
bestDistSq = distSq;
|
||||
bestWorld = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return bestDistSq < 147456.0;
|
||||
}
|
||||
|
||||
bool TryReconstructScreenParticleWorld(uint2 particlePixel, float particleDepth, float3 receiverPos, out float3 particleWorld)
|
||||
{
|
||||
float2 uv = ((float2)particlePixel + 0.5) / max(gScreenSize.xy, float2(1.0, 1.0));
|
||||
float x = uv.x * 2.0 - 1.0;
|
||||
float yUp = 1.0 - uv.y * 2.0;
|
||||
float yDown = uv.y * 2.0 - 1.0;
|
||||
|
||||
float bestDistSq = 1.0e30;
|
||||
particleWorld = receiverPos;
|
||||
TryScreenParticleWorldCandidate(float4(x, yUp, particleDepth, 1.0), receiverPos, bestDistSq, particleWorld);
|
||||
TryScreenParticleWorldCandidate(float4(x, yDown, particleDepth, 1.0), receiverPos, bestDistSq, particleWorld);
|
||||
return bestDistSq < 147456.0;
|
||||
}
|
||||
|
||||
float3 EstimateScreenSpaceEmissiveParticleLighting(uint2 pixel, float3 worldPos, float3 N)
|
||||
{
|
||||
static const int2 kParticleLightTaps[17] =
|
||||
{
|
||||
int2( 0, 0),
|
||||
int2( 7, 0), int2( -7, 0), int2( 0, 7), int2( 0, -7),
|
||||
int2( 10, 10), int2(-10, 10), int2( 10, -10), int2(-10, -10),
|
||||
int2( 18, 4), int2(-18, -4), int2( 4, 18), int2( -4, -18),
|
||||
int2( 30, 0), int2(-30, 0), int2( 0, 30), int2( 0, -30)
|
||||
};
|
||||
|
||||
int2 maxPixel = int2((int)gScreenSize.x - 1, (int)gScreenSize.y - 1);
|
||||
float pixelScale = max(1.0, round(min(gScreenSize.x, gScreenSize.y) / 720.0));
|
||||
float3 lighting = 0.0;
|
||||
|
||||
[unroll]
|
||||
for (uint i = 0u; i < 17u; ++i)
|
||||
{
|
||||
int2 sp = int2(pixel) + int2(round((float2)kParticleLightTaps[i] * pixelScale));
|
||||
sp = clamp(sp, int2(0, 0), maxPixel);
|
||||
|
||||
float4 particleEmission = gEmissiveTex.Load(int3(sp, 0));
|
||||
if (particleEmission.a <= 1.5)
|
||||
continue;
|
||||
|
||||
float particleDepth = saturate(particleEmission.a - 2.0);
|
||||
float3 particleWorld;
|
||||
if (!TryReconstructScreenParticleWorld(uint2(sp), particleDepth, worldPos, particleWorld))
|
||||
continue;
|
||||
|
||||
float3 toParticle = particleWorld - worldPos;
|
||||
float distSq = dot(toParticle, toParticle);
|
||||
if (distSq <= 1e-4 || distSq >= 147456.0)
|
||||
continue;
|
||||
|
||||
float dist = sqrt(distSq);
|
||||
float3 L = toParticle / dist;
|
||||
float NoL = saturate(dot(N, L));
|
||||
if (NoL <= 0.01)
|
||||
continue;
|
||||
|
||||
float visibility = TraceVisibilityBiased(worldPos, N, L, dist);
|
||||
if (visibility <= 0.0)
|
||||
continue;
|
||||
|
||||
float distanceFade = saturate(1.0 - dist / 640.0);
|
||||
distanceFade *= distanceFade;
|
||||
float attenuation = distanceFade / (1.0 + distSq * 0.000075);
|
||||
lighting += CompressEmissiveRadiance(particleEmission.rgb, 24.0) * (NoL * visibility * attenuation);
|
||||
}
|
||||
|
||||
return lighting * 9.0;
|
||||
}
|
||||
|
||||
bool ProjectClipToGBufferCandidate(
|
||||
float4 clipPos,
|
||||
bool flipY,
|
||||
@@ -4151,7 +4258,8 @@ float3 PathTraceDirectPointLight(uint2 pixel, float3 worldPos, float3 N, float3
|
||||
specularOut = specAccum * 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)
|
||||
{
|
||||
specularOut = 0.0;
|
||||
@@ -4175,7 +4283,8 @@ float3 PathTraceDirectSpotLight(float3 worldPos, float3 N, float3 V, float3 base
|
||||
|
||||
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)
|
||||
{
|
||||
specularOut = 0.0;
|
||||
@@ -5304,6 +5413,7 @@ void RayGen()
|
||||
skyVis,
|
||||
ambientSkyVis,
|
||||
specularAccum);
|
||||
lightingAccum += EstimateScreenSpaceEmissiveParticleLighting(pixel, worldPos, N);
|
||||
|
||||
// Only the indirect bounce path uses per-SPP randomness now. Direct lights,
|
||||
// AO, sky visibility, cavity, and final gather are deterministic and should
|
||||
|
||||
@@ -469,7 +469,7 @@ static const UINT QD3D12_UploadBufferSize = 128 * 1024 * 1024;
|
||||
static const UINT QD3D12_RequestedGBufferSampleCount = 1;
|
||||
static constexpr UINT QD3D12_PostSrvCount = 16;
|
||||
static constexpr UINT QD3D12_PostRootConstants = QD3D12_PostSrvCount;
|
||||
static constexpr UINT QD3D12_PostConstantDwords = 24;
|
||||
static constexpr UINT QD3D12_PostConstantDwords = 28;
|
||||
static constexpr UINT QD3D12_ToneMapTileDim = 64;
|
||||
static constexpr UINT QD3D12_MaxScreenSpaceDecals = 64;
|
||||
static constexpr UINT QD3D12_MaxScreenSpaceParticleLights = GL_RAYTRACING_MAX_LIGHTS;
|
||||
@@ -551,6 +551,7 @@ struct QD3D12ScreenSpaceParticleBatch
|
||||
uint32_t textureId = 0;
|
||||
uint32_t blendMode = 0;
|
||||
float softDepth = 16.0f;
|
||||
float emissiveScale = 0.0f;
|
||||
};
|
||||
|
||||
enum PipelineMode
|
||||
@@ -1719,6 +1720,7 @@ struct GLState
|
||||
ComPtr<ID3D12PipelineState> postScreenDecalStainPSO;
|
||||
ComPtr<ID3D12PipelineState> postScreenParticlePSO;
|
||||
ComPtr<ID3D12PipelineState> postScreenParticleAdditivePSO;
|
||||
ComPtr<ID3D12PipelineState> postScreenParticleEmissivePSO;
|
||||
|
||||
ComPtr<ID3DBlob> vsMainBlob;
|
||||
ComPtr<ID3DBlob> hsMainBlob;
|
||||
@@ -3891,11 +3893,10 @@ float4 QD3D12_SampleGlowAtUV(VSOut i, float2 uv0)
|
||||
float glowMask = alphaLooksForcedOpaque ? rgbMask : saturate(max(glow.a, rgbMask));
|
||||
float emissionMask = alphaLooksForcedOpaque ? 1.0 : glowMask;
|
||||
|
||||
// Store bright HDR radiance in the FP16 emissive G-buffer. This is still
|
||||
// direct/bloom-only; emissive lighting has intentionally stayed disabled.
|
||||
// The higher baseline lets normal idTech glow maps read as obvious emission
|
||||
// without every material having to call glGlowMapStrengthf(3+).
|
||||
const float kDefaultGlowBloomRadiance = 3.25;
|
||||
// Store cinematic HDR radiance in the FP16 emissive G-buffer. The bloom pass
|
||||
// and particle-light gather both expect a strong source value here so small
|
||||
// Doom 3 glow sheets survive tone mapping and denoise.
|
||||
const float kDefaultGlowBloomRadiance = 7.25;
|
||||
float strength = max(gGlowMapStrength, 0.0);
|
||||
|
||||
// Low-value glow maps looked too weak after the no-light hotfix. Give the
|
||||
@@ -4513,6 +4514,7 @@ cbuffer PostCB : register(b0)
|
||||
float4 gPostParams3;
|
||||
float4 gPostFogColor;
|
||||
float4 gPostFogCameraWorldPos;
|
||||
float4 gPostParticleParams;
|
||||
};
|
||||
|
||||
#define gPostSharpness gPostParams0.x
|
||||
@@ -4531,6 +4533,8 @@ cbuffer PostCB : register(b0)
|
||||
#define gScreenParticleSoftDepth gPostParams3.z
|
||||
#define gScreenParticleLightCount gPostParams3.w
|
||||
#define gScreenDecalCount gPostFogCameraWorldPos.w
|
||||
#define gScreenParticleEmissiveScale gPostParticleParams.x
|
||||
#define gScreenParticleOutputMode gPostParticleParams.y
|
||||
#define QD3D12_TONEMAP_TILE_DIM 64u
|
||||
|
||||
static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0u;
|
||||
@@ -4814,12 +4818,17 @@ float4 PSScreenParticles(ParticleVSOut i) : SV_Target0
|
||||
if (alpha <= 0.0001)
|
||||
discard;
|
||||
|
||||
if (gPostFogCameraValid > 0.5)
|
||||
uint2 pixel = uint2(i.pos.xy);
|
||||
float sceneDepth = gFogDepth.Load(int3(pixel, 0));
|
||||
float particleDepth = saturate(i.pos.z);
|
||||
if (sceneDepth < 0.99999)
|
||||
{
|
||||
uint2 pixel = uint2(i.pos.xy);
|
||||
float sceneDepth = gFogDepth.Load(int3(pixel, 0));
|
||||
float particleDepth = saturate(i.pos.z);
|
||||
if (sceneDepth < 0.99999)
|
||||
if (particleDepth > sceneDepth + 0.00005)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
if (gPostFogCameraValid > 0.5)
|
||||
{
|
||||
float4 positionSample = gScreenDecalPosition.Load(int3(pixel, 0));
|
||||
uint geometryBits = (uint)round(max(positionSample.w, 0.0));
|
||||
@@ -4832,13 +4841,16 @@ float4 PSScreenParticles(ParticleVSOut i) : SV_Target0
|
||||
if (alpha <= 0.0001)
|
||||
discard;
|
||||
}
|
||||
else if (particleDepth > sceneDepth + 0.00005)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gScreenParticleOutputMode > 0.5)
|
||||
{
|
||||
const float kScreenParticleEmissionBoost = 3.0;
|
||||
float emissiveAlpha = alpha;
|
||||
return float4(texel.rgb * (emissiveAlpha * max(gScreenParticleEmissiveScale, 0.0) * kScreenParticleEmissionBoost), 2.0 + particleDepth);
|
||||
}
|
||||
|
||||
texel.rgb *= ScreenParticleDirectLighting(i.world);
|
||||
|
||||
return float4(texel.rgb, alpha);
|
||||
@@ -5035,10 +5047,10 @@ float4 PSTAA(VSOut i) : SV_Target0
|
||||
|
||||
float3 QD3D12_LoadPostRadiance(float2 uv)
|
||||
{
|
||||
// Clamp bloom taps so a single bad HDR edge sample cannot flood the LDR
|
||||
// scene-color composite. The direct center emissive value is still added by
|
||||
// PSAdd below, so this only limits the halo.
|
||||
return min(max(gTex0.Sample(gSamp0, saturate(uv)).rgb, 0.0), 12.0);
|
||||
// Keep bloom HDR enough to look cinematic, but use a soft lift instead of an
|
||||
// unbounded add so one malformed texel cannot bleach the whole frame.
|
||||
float3 radiance = min(max(gTex0.Sample(gSamp0, saturate(uv)).rgb, 0.0), 32.0);
|
||||
return min(radiance + sqrt(radiance) * 0.45, 40.0);
|
||||
}
|
||||
|
||||
float3 QD3D12_EmissiveBloom(float2 uv)
|
||||
@@ -5047,38 +5059,48 @@ float3 QD3D12_EmissiveBloom(float2 uv)
|
||||
gTex0.GetDimensions(srcW, srcH);
|
||||
float2 texel = 1.0 / max(float2((float)srcW, (float)srcH), float2(1.0, 1.0));
|
||||
|
||||
// Strong threshold-free bloom kernel. Direct emissive is still added by
|
||||
// PSAdd; this wider halo makes glow maps read even when the final color
|
||||
// buffer is LDR and clamps the swap-chain output.
|
||||
// Wide threshold-free bloom kernel. Direct emissive is still added by PSAdd;
|
||||
// these outer taps make fire and plasma read as real camera bloom instead of
|
||||
// a thin one-pixel glow.
|
||||
float3 bloom = 0.0;
|
||||
bloom += QD3D12_LoadPostRadiance(uv) * 0.180;
|
||||
bloom += QD3D12_LoadPostRadiance(uv) * 0.320;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 1.0, 0.0)) * 0.220;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-1.0, 0.0)) * 0.220;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 1.0)) * 0.220;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -1.0)) * 0.220;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 1.0, 0.0)) * 0.420;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-1.0, 0.0)) * 0.420;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 1.0)) * 0.420;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -1.0)) * 0.420;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 2.0, 2.0)) * 0.135;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-2.0, 2.0)) * 0.135;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 2.0, -2.0)) * 0.135;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-2.0, -2.0)) * 0.135;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 2.0, 2.0)) * 0.260;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-2.0, 2.0)) * 0.260;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 2.0, -2.0)) * 0.260;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-2.0, -2.0)) * 0.260;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 4.0, 0.0)) * 0.090;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-4.0, 0.0)) * 0.090;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 4.0)) * 0.090;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -4.0)) * 0.090;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 4.0, 0.0)) * 0.180;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-4.0, 0.0)) * 0.180;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 4.0)) * 0.180;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -4.0)) * 0.180;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 8.0, 0.0)) * 0.060;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-8.0, 0.0)) * 0.060;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 8.0)) * 0.060;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -8.0)) * 0.060;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 8.0, 0.0)) * 0.120;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-8.0, 0.0)) * 0.120;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 8.0)) * 0.120;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -8.0)) * 0.120;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 14.0, 0.0)) * 0.035;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-14.0, 0.0)) * 0.035;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 14.0)) * 0.035;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -14.0)) * 0.035;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 14.0, 0.0)) * 0.075;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-14.0, 0.0)) * 0.075;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 14.0)) * 0.075;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -14.0)) * 0.075;
|
||||
|
||||
return min(bloom * 0.62, 5.0);
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 24.0, 0.0)) * 0.045;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-24.0, 0.0)) * 0.045;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 24.0)) * 0.045;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -24.0)) * 0.045;
|
||||
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 42.0, 0.0)) * 0.025;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2(-42.0, 0.0)) * 0.025;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, 42.0)) * 0.025;
|
||||
bloom += QD3D12_LoadPostRadiance(uv + texel * float2( 0.0, -42.0)) * 0.025;
|
||||
|
||||
return min(bloom * 1.15, 24.0);
|
||||
}
|
||||
)HLSL"
|
||||
R"HLSL(
|
||||
@@ -5088,7 +5110,7 @@ float4 PSAdd(VSOut i) : SV_Target0
|
||||
float3 direct = max(center.rgb, 0.0);
|
||||
float3 bloom = QD3D12_EmissiveBloom(i.uv);
|
||||
|
||||
return float4(direct + bloom, saturate(center.a));
|
||||
return float4(direct * 1.08 + bloom, saturate(center.a));
|
||||
}
|
||||
|
||||
float PSDepthCopy(VSOut i) : SV_Depth
|
||||
@@ -8055,7 +8077,9 @@ static void QD3D12_SetPostConstants(
|
||||
float screenDecalIndex = 0.0f,
|
||||
bool forceCameraPosition = false,
|
||||
float screenParticleSoftDepth = 16.0f,
|
||||
float screenParticleLightCount = 0.0f)
|
||||
float screenParticleLightCount = 0.0f,
|
||||
float screenParticleEmissiveScale = 0.0f,
|
||||
float screenParticleOutputMode = 0.0f)
|
||||
{
|
||||
if (!cl)
|
||||
return;
|
||||
@@ -8094,6 +8118,8 @@ static void QD3D12_SetPostConstants(
|
||||
constants[14] = screenParticleSoftDepth;
|
||||
constants[15] = screenParticleLightCount;
|
||||
constants[23] = screenDecalCount;
|
||||
constants[24] = screenParticleEmissiveScale;
|
||||
constants[25] = screenParticleOutputMode;
|
||||
cl->SetGraphicsRoot32BitConstants(QD3D12_PostRootConstants, QD3D12_PostConstantDwords, constants, 0);
|
||||
}
|
||||
|
||||
@@ -8539,22 +8565,27 @@ void APIENTRY glDrawScreenSpaceDecalsQD3D12(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleBatch& batch, ID3D12Resource* tlas)
|
||||
static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleBatch& batch, ID3D12Resource* tlas, bool emissiveOnly)
|
||||
{
|
||||
const glScreenSpaceParticleVertex_t* verts = batch.vertices.empty() ? nullptr : batch.vertices.data();
|
||||
const uint32_t vertexCount = (uint32_t)batch.vertices.size();
|
||||
const uint32_t textureId = batch.textureId;
|
||||
const uint32_t blendMode = batch.blendMode;
|
||||
const float softDepth = batch.softDepth;
|
||||
const float emissiveScale = batch.emissiveScale;
|
||||
|
||||
if (!verts || vertexCount == 0)
|
||||
return;
|
||||
if (emissiveOnly && emissiveScale <= 0.0f)
|
||||
return;
|
||||
|
||||
QD3D12Window* window = g_currentWindow;
|
||||
if (!window || !g_gl.device || !g_gl.cmdList || !g_gl.postScreenParticlePSO)
|
||||
return;
|
||||
if (!window->sceneColorBuffers[window->frameIndex] || !window->positionBuffers[window->frameIndex] || !window->depthBuffer)
|
||||
return;
|
||||
if (emissiveOnly && !window->emissiveBuffers[window->frameIndex])
|
||||
return;
|
||||
if (!QD3D12_EnsureScreenSpaceParticleLightBuffer() || !QD3D12_UpdateScreenSpaceParticleTlasSrv(tlas))
|
||||
return;
|
||||
|
||||
@@ -8565,7 +8596,14 @@ static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleB
|
||||
|
||||
const UINT frame = window->frameIndex;
|
||||
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
|
||||
QD3D12_TransitionResource(cl, window->sceneColorBuffers[frame].Get(), window->sceneColorState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
if (emissiveOnly)
|
||||
{
|
||||
QD3D12_TransitionResource(cl, window->emissiveBuffers[frame].Get(), window->emissiveBufferState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
}
|
||||
else
|
||||
{
|
||||
QD3D12_TransitionResource(cl, window->sceneColorBuffers[frame].Get(), window->sceneColorState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
}
|
||||
QD3D12_TransitionResource(cl, window->depthBuffer.Get(), window->depthState, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
QD3D12_TransitionResource(cl, window->positionBuffers[frame].Get(), window->positionBufferState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
||||
@@ -8607,17 +8645,19 @@ static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleB
|
||||
}
|
||||
}
|
||||
|
||||
ID3D12PipelineState* particlePSO = (blendMode == 1 && g_gl.postScreenParticleAdditivePSO.Get() != nullptr)
|
||||
ID3D12PipelineState* particlePSO = emissiveOnly && g_gl.postScreenParticleEmissivePSO.Get()
|
||||
? g_gl.postScreenParticleEmissivePSO.Get()
|
||||
: (blendMode == 1 && g_gl.postScreenParticleAdditivePSO.Get() != nullptr)
|
||||
? g_gl.postScreenParticleAdditivePSO.Get()
|
||||
: g_gl.postScreenParticlePSO.Get();
|
||||
|
||||
ID3D12DescriptorHeap* heaps[] = { g_gl.srvHeap.Get() };
|
||||
cl->SetDescriptorHeaps(_countof(heaps), heaps);
|
||||
cl->SetGraphicsRootSignature(g_gl.postRootSig.Get());
|
||||
QD3D12_SetPostConstants(cl, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, false, 0.0f, 0.0f, true, softDepth, (float)g_gl.screenSpaceParticleLightCount);
|
||||
QD3D12_SetPostConstants(cl, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, false, 0.0f, 0.0f, true, softDepth, (float)g_gl.screenSpaceParticleLightCount, emissiveScale, emissiveOnly ? 1.0f : 0.0f);
|
||||
cl->SetPipelineState(particlePSO);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE sceneColorRtv = CurrentResolvedSceneColorRTV();
|
||||
cl->OMSetRenderTargets(1, &sceneColorRtv, FALSE, nullptr);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE particleRtv = emissiveOnly ? CurrentResolvedEmissiveRTV() : CurrentResolvedSceneColorRTV();
|
||||
cl->OMSetRenderTargets(1, &particleRtv, FALSE, nullptr);
|
||||
cl->RSSetViewports(1, &viewport);
|
||||
cl->RSSetScissorRects(1, &scissor);
|
||||
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
@@ -8630,7 +8670,7 @@ static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleB
|
||||
cl->DrawInstanced(vertexCount, 1, 0, 0);
|
||||
}
|
||||
|
||||
void APIENTRY glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex_t* verts, uint32_t vertexCount, uint32_t textureId, uint32_t blendMode, float softDepth)
|
||||
void APIENTRY glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex_t* verts, uint32_t vertexCount, uint32_t textureId, uint32_t blendMode, float softDepth, float emissiveScale)
|
||||
{
|
||||
if (!verts || vertexCount == 0)
|
||||
return;
|
||||
@@ -8640,6 +8680,7 @@ void APIENTRY glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex
|
||||
batch.textureId = textureId;
|
||||
batch.blendMode = blendMode;
|
||||
batch.softDepth = softDepth;
|
||||
batch.emissiveScale = emissiveScale;
|
||||
g_gl.screenSpaceParticleBatches.push_back(std::move(batch));
|
||||
}
|
||||
|
||||
@@ -8663,11 +8704,22 @@ static void QD3D12_DrawQueuedScreenSpaceParticles(ID3D12Resource* tlas)
|
||||
|
||||
for (const QD3D12ScreenSpaceParticleBatch& batch : g_gl.screenSpaceParticleBatches)
|
||||
{
|
||||
QD3D12_DrawScreenSpaceParticleBatch(batch, tlas);
|
||||
QD3D12_DrawScreenSpaceParticleBatch(batch, tlas, false);
|
||||
}
|
||||
g_gl.screenSpaceParticleBatches.clear();
|
||||
}
|
||||
|
||||
static void QD3D12_DrawQueuedScreenSpaceParticleEmissive(ID3D12Resource* tlas)
|
||||
{
|
||||
if (g_gl.screenSpaceParticleBatches.empty())
|
||||
return;
|
||||
|
||||
for (const QD3D12ScreenSpaceParticleBatch& batch : g_gl.screenSpaceParticleBatches)
|
||||
{
|
||||
QD3D12_DrawScreenSpaceParticleBatch(batch, tlas, true);
|
||||
}
|
||||
}
|
||||
|
||||
static ID3D12Resource* QD3D12_PrepareStreamlineOutputForWrite(QD3D12Window& w)
|
||||
{
|
||||
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
|
||||
@@ -10421,6 +10473,14 @@ static void QD3D12_CreatePSOs()
|
||||
particleDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
|
||||
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&particleDesc, IID_PPV_ARGS(&g_gl.postScreenParticleAdditivePSO)));
|
||||
|
||||
particleDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_ONE;
|
||||
particleDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_ONE;
|
||||
particleDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
|
||||
particleDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
|
||||
particleDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
|
||||
particleDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
|
||||
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&particleDesc, IID_PPV_ARGS(&g_gl.postScreenParticleEmissivePSO)));
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC depthDesc{};
|
||||
depthDesc.pRootSignature = g_gl.postRootSig.Get();
|
||||
depthDesc.VS = { g_gl.postVsBlob->GetBufferPointer(), g_gl.postVsBlob->GetBufferSize() };
|
||||
@@ -17860,6 +17920,7 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
|
||||
|
||||
QD3D12_FlushQueuedBatches();
|
||||
QD3D12_ResolveGBufferForCurrentFrame(*window);
|
||||
QD3D12_DrawQueuedScreenSpaceParticleEmissive(tlas);
|
||||
|
||||
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
|
||||
ID3D12Resource* sceneColor = window->sceneColorBuffers[frameIndex].Get();
|
||||
|
||||
@@ -1853,7 +1853,7 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle);
|
||||
void glSetScreenSpaceDecalsQD3D12(const glScreenSpaceDecal_t* decals, uint32_t decalCount);
|
||||
void glDrawScreenSpaceDecalsQD3D12(void);
|
||||
void glSetScreenSpaceParticleLightsQD3D12(const glRaytracingLight_t* lights, uint32_t lightCount);
|
||||
void glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex_t* verts, uint32_t vertexCount, uint32_t textureId, uint32_t blendMode, float softDepth);
|
||||
void glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex_t* verts, uint32_t vertexCount, uint32_t textureId, uint32_t blendMode, float softDepth, float emissiveScale);
|
||||
|
||||
ID3D12Device* QD3D12_GetDevice(void);
|
||||
ID3D12CommandQueue* QD3D12_GetQueue(void);
|
||||
|
||||
@@ -1610,7 +1610,8 @@ static void RB_SubmitScreenSpaceParticleSurf( const drawSurf_t *surf ) {
|
||||
RB_FillScreenSpaceParticleVertex( particleVerts[i], surf->geo->verts[vertIndex], surf->space, projectionMatrix, stageColor );
|
||||
}
|
||||
|
||||
glDrawScreenSpaceParticlesQD3D12( particleVerts.Ptr(), particleVerts.Num(), image->texnum, blendMode, 16.0f );
|
||||
const float emissiveScale = ( surf->dsFlags & DSF_SCREEN_SPACE_PARTICLE_EMISSIVE ) ? surf->geo->particleEmissiveScale : 0.0f;
|
||||
glDrawScreenSpaceParticlesQD3D12( particleVerts.Ptr(), particleVerts.Num(), image->texnum, blendMode, 16.0f, emissiveScale );
|
||||
}
|
||||
|
||||
static void RB_STD_DrawScreenSpaceParticles( drawSurf_t **drawSurfs, int numDrawSurfs ) {
|
||||
|
||||
@@ -1093,6 +1093,7 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) {
|
||||
|
||||
// just always draw the particles
|
||||
tri->bounds = stage->bounds;
|
||||
tri->particleEmissiveScale = stage->emissive;
|
||||
|
||||
tri->numVerts = 0;
|
||||
|
||||
@@ -1211,7 +1212,11 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) {
|
||||
tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( idDrawVert ) );
|
||||
if ( tri->ambientCache ) {
|
||||
// add the drawsurf
|
||||
R_AddDrawSurf( tri, surf->space, renderEntity, stage->material, surf->scissorRect, DSF_SCREEN_SPACE_PARTICLE );
|
||||
int dsFlags = DSF_SCREEN_SPACE_PARTICLE;
|
||||
if ( stage->emissive > 0.0f ) {
|
||||
dsFlags |= DSF_SCREEN_SPACE_PARTICLE_EMISSIVE;
|
||||
}
|
||||
R_AddDrawSurf( tri, surf->space, renderEntity, stage->material, surf->scissorRect, dsFlags );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1351,8 +1351,13 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) {
|
||||
R_CreateIndexCache( tri );
|
||||
}
|
||||
|
||||
const int particleFlags = ( def->dynamicModel &&
|
||||
idStr::Icmp( model->Name(), "_ParametricParticle_Snapshot_" ) == 0 ) ? DSF_SCREEN_SPACE_PARTICLE : 0;
|
||||
int particleFlags = 0;
|
||||
if ( def->dynamicModel && idStr::Icmp( model->Name(), "_ParametricParticle_Snapshot_" ) == 0 ) {
|
||||
particleFlags = DSF_SCREEN_SPACE_PARTICLE;
|
||||
if ( tri->particleEmissiveScale > 0.0f ) {
|
||||
particleFlags |= DSF_SCREEN_SPACE_PARTICLE_EMISSIVE;
|
||||
}
|
||||
}
|
||||
|
||||
// add the surface for drawing
|
||||
R_AddDrawSurf( tri, vEntity, &vEntity->entityDef->parms, shader, vEntity->scissorRect, particleFlags );
|
||||
|
||||
@@ -105,6 +105,7 @@ SURFACES
|
||||
// drawSurf_t are always allocated and freed every frame, they are never cached
|
||||
static const int DSF_VIEW_INSIDE_SHADOW = 1;
|
||||
static const int DSF_SCREEN_SPACE_PARTICLE = 2;
|
||||
static const int DSF_SCREEN_SPACE_PARTICLE_EMISSIVE = 4;
|
||||
|
||||
typedef struct drawSurf_s {
|
||||
const srfTriangles_t *geo;
|
||||
|
||||
Reference in New Issue
Block a user