mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Implemented screenspace particles.
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
|
||||
1199 constants
|
||||
135 enums
|
||||
619 classes/structs/unions
|
||||
620 classes/structs/unions
|
||||
38 templates
|
||||
7 max inheritance level for 'idAI_Vagary'
|
||||
|
||||
@@ -4129,6 +4129,15 @@ static classVariableInfo_t glScreenSpaceDecal_t_typeInfo[] = {
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static classVariableInfo_t glScreenSpaceParticleVertex_t_typeInfo[] = {
|
||||
{ "float[4]", "clip", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->clip), sizeof( ((glScreenSpaceParticleVertex_t *)0)->clip ) },
|
||||
{ "float[2]", "st", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->st), sizeof( ((glScreenSpaceParticleVertex_t *)0)->st ) },
|
||||
{ "float[4]", "color", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->color), sizeof( ((glScreenSpaceParticleVertex_t *)0)->color ) },
|
||||
{ "float[3]", "world", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->world), sizeof( ((glScreenSpaceParticleVertex_t *)0)->world ) },
|
||||
{ "float", "pad0", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->pad0), sizeof( ((glScreenSpaceParticleVertex_t *)0)->pad0 ) },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static classVariableInfo_t QD3D12NeuralPOMImageRGBA8_typeInfo[] = {
|
||||
{ "uint32_t", "width", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->width), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->width ) },
|
||||
{ "uint32_t", "height", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->height), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->height ) },
|
||||
@@ -5248,11 +5257,11 @@ static classVariableInfo_t frameLookup_t_typeInfo[] = {
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
static classVariableInfo_t class_287_class_287_typeInfo[] = {
|
||||
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_287::class_287 *)0)->soundShader), sizeof( ((class_287::class_287 *)0)->soundShader ) },
|
||||
// { "const function_t *", "function", (intptr_t)(&((class_287::class_287 *)0)->function), sizeof( ((class_287::class_287 *)0)->function ) },
|
||||
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_287::class_287 *)0)->skin), sizeof( ((class_287::class_287 *)0)->skin ) },
|
||||
// { "int", "index", (intptr_t)(&((class_287::class_287 *)0)->index), sizeof( ((class_287::class_287 *)0)->index ) },
|
||||
static classVariableInfo_t class_288_class_288_typeInfo[] = {
|
||||
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_288::class_288 *)0)->soundShader), sizeof( ((class_288::class_288 *)0)->soundShader ) },
|
||||
// { "const function_t *", "function", (intptr_t)(&((class_288::class_288 *)0)->function), sizeof( ((class_288::class_288 *)0)->function ) },
|
||||
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_288::class_288 *)0)->skin), sizeof( ((class_288::class_288 *)0)->skin ) },
|
||||
// { "int", "index", (intptr_t)(&((class_288::class_288 *)0)->index), sizeof( ((class_288::class_288 *)0)->index ) },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
@@ -9174,6 +9183,7 @@ static classTypeInfo_t classTypeInfo[] = {
|
||||
{ "glRaytracingLight_t", "", sizeof(glRaytracingLight_t), glRaytracingLight_t_typeInfo },
|
||||
{ "glRaytracingLightingPassDesc_t", "", sizeof(glRaytracingLightingPassDesc_t), glRaytracingLightingPassDesc_t_typeInfo },
|
||||
{ "glScreenSpaceDecal_t", "", sizeof(glScreenSpaceDecal_t), glScreenSpaceDecal_t_typeInfo },
|
||||
{ "glScreenSpaceParticleVertex_t", "", sizeof(glScreenSpaceParticleVertex_t), glScreenSpaceParticleVertex_t_typeInfo },
|
||||
{ "QD3D12NeuralPOMImageRGBA8", "", sizeof(QD3D12NeuralPOMImageRGBA8), QD3D12NeuralPOMImageRGBA8_typeInfo },
|
||||
{ "QD3D12NeuralPOMTrainDesc", "", sizeof(QD3D12NeuralPOMTrainDesc), QD3D12NeuralPOMTrainDesc_typeInfo },
|
||||
{ "QD3D12NeuralPOMTrainStats", "", sizeof(QD3D12NeuralPOMTrainStats), QD3D12NeuralPOMTrainStats_typeInfo },
|
||||
@@ -9284,7 +9294,7 @@ static classTypeInfo_t classTypeInfo[] = {
|
||||
{ "jointAnimInfo_t", "", sizeof(jointAnimInfo_t), jointAnimInfo_t_typeInfo },
|
||||
{ "jointMod_t", "", sizeof(jointMod_t), jointMod_t_typeInfo },
|
||||
{ "frameLookup_t", "", sizeof(frameLookup_t), frameLookup_t_typeInfo },
|
||||
// { "class_287::class_287", "", sizeof(class_287::class_287), class_287_class_287_typeInfo },
|
||||
// { "class_288::class_288", "", sizeof(class_288::class_288), class_288_class_288_typeInfo },
|
||||
{ "frameCommand_t", "", sizeof(frameCommand_t), frameCommand_t_typeInfo },
|
||||
{ "animFlags_t", "", sizeof(animFlags_t), animFlags_t_typeInfo },
|
||||
{ "idModelExport", "", sizeof(idModelExport), idModelExport_typeInfo },
|
||||
|
||||
@@ -467,11 +467,12 @@ static const UINT QD3D12_UploadBufferSize = 128 * 1024 * 1024;
|
||||
// MSAA has been removed from the G-buffer path. Temporal AA now owns edge cleanup
|
||||
// after lighting, so all scene/deferred render targets remain single-sample.
|
||||
static const UINT QD3D12_RequestedGBufferSampleCount = 1;
|
||||
static constexpr UINT QD3D12_PostSrvCount = 14;
|
||||
static constexpr UINT QD3D12_PostSrvCount = 16;
|
||||
static constexpr UINT QD3D12_PostRootConstants = QD3D12_PostSrvCount;
|
||||
static constexpr UINT QD3D12_PostConstantDwords = 24;
|
||||
static constexpr UINT QD3D12_ToneMapTileDim = 64;
|
||||
static constexpr UINT QD3D12_MaxScreenSpaceDecals = 64;
|
||||
static constexpr UINT QD3D12_MaxScreenSpaceParticleLights = GL_RAYTRACING_MAX_LIGHTS;
|
||||
|
||||
enum QD3D12RTVSlotGroup
|
||||
{
|
||||
@@ -544,6 +545,14 @@ struct QD3D12CameraState
|
||||
bool valid = false;
|
||||
};
|
||||
|
||||
struct QD3D12ScreenSpaceParticleBatch
|
||||
{
|
||||
std::vector<glScreenSpaceParticleVertex_t> vertices;
|
||||
uint32_t textureId = 0;
|
||||
uint32_t blendMode = 0;
|
||||
float softDepth = 16.0f;
|
||||
};
|
||||
|
||||
enum PipelineMode
|
||||
{
|
||||
PIPE_OPAQUE_TEX = 0,
|
||||
@@ -1504,17 +1513,29 @@ struct GLState
|
||||
bool enableRayAIDenoise = false;
|
||||
bool enableDLSSRayReconstruction = false;
|
||||
bool enableFSRRayRegeneration = false;
|
||||
bool blockLightingUpscaleInputThisFrame = false;
|
||||
uint32_t frameGenerationMultiplier = 0;
|
||||
uint32_t pathTracingSamplesPerPixel = 1;
|
||||
uint32_t pathTracingFallbackSamplesPerPixel = 2;
|
||||
uint32_t pathTracingMaxBounces = 3;
|
||||
glScreenSpaceDecal_t screenSpaceDecals[QD3D12_MaxScreenSpaceDecals] = {};
|
||||
uint32_t screenSpaceDecalCount = 0;
|
||||
std::vector<QD3D12ScreenSpaceParticleBatch> screenSpaceParticleBatches;
|
||||
glRaytracingLight_t screenSpaceParticleLights[QD3D12_MaxScreenSpaceParticleLights] = {};
|
||||
uint32_t screenSpaceParticleLightCount = 0;
|
||||
ComPtr<ID3D12Resource> screenSpaceDecalBuffer;
|
||||
void* screenSpaceDecalBufferMapped = nullptr;
|
||||
UINT screenSpaceDecalSrvIndex = UINT_MAX;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE screenSpaceDecalSrvCpu{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE screenSpaceDecalSrvGpu{};
|
||||
ComPtr<ID3D12Resource> screenSpaceParticleLightBuffer;
|
||||
void* screenSpaceParticleLightBufferMapped = nullptr;
|
||||
UINT screenSpaceParticleLightSrvIndex = UINT_MAX;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE screenSpaceParticleLightSrvCpu{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE screenSpaceParticleLightSrvGpu{};
|
||||
UINT screenSpaceParticleTlasSrvIndex = UINT_MAX;
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE screenSpaceParticleTlasSrvCpu{};
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE screenSpaceParticleTlasSrvGpu{};
|
||||
|
||||
float jitterX = 0.0f;
|
||||
float jitterY = 0.0f;
|
||||
@@ -1696,6 +1717,8 @@ struct GLState
|
||||
ComPtr<ID3D12PipelineState> postGBufferPointResolveMsaaPSO;
|
||||
ComPtr<ID3D12PipelineState> postScreenDecalPSO;
|
||||
ComPtr<ID3D12PipelineState> postScreenDecalStainPSO;
|
||||
ComPtr<ID3D12PipelineState> postScreenParticlePSO;
|
||||
ComPtr<ID3D12PipelineState> postScreenParticleAdditivePSO;
|
||||
|
||||
ComPtr<ID3DBlob> vsMainBlob;
|
||||
ComPtr<ID3DBlob> hsMainBlob;
|
||||
@@ -1718,6 +1741,8 @@ struct GLState
|
||||
ComPtr<ID3DBlob> postPsDepthResolveMsaaBlob;
|
||||
ComPtr<ID3DBlob> postPsGBufferPointResolveMsaaBlob;
|
||||
ComPtr<ID3DBlob> postPsScreenDecalBlob;
|
||||
ComPtr<ID3DBlob> postVsScreenParticleBlob;
|
||||
ComPtr<ID3DBlob> postPsScreenParticleBlob;
|
||||
|
||||
TextureResource whiteTexture;
|
||||
|
||||
@@ -4448,12 +4473,40 @@ struct ScreenSpaceDecal
|
||||
|
||||
StructuredBuffer<ScreenSpaceDecal> gScreenDecals : register(t13);
|
||||
|
||||
struct ScreenParticleLight
|
||||
{
|
||||
float3 position;
|
||||
float radius;
|
||||
float3 color;
|
||||
float intensity;
|
||||
float3 normal;
|
||||
uint type;
|
||||
float3 axisU;
|
||||
float halfWidth;
|
||||
float3 axisV;
|
||||
float halfHeight;
|
||||
uint samples;
|
||||
uint twoSided;
|
||||
float persistant;
|
||||
float volumetricScattering;
|
||||
float3 pointRadius;
|
||||
float pointRadiusPad;
|
||||
uint iesTextureId;
|
||||
float iesStrength;
|
||||
float2 iesPad;
|
||||
};
|
||||
|
||||
StructuredBuffer<ScreenParticleLight> gScreenParticleLights : register(t14);
|
||||
#if defined(QD3D12_SCREEN_PARTICLE_RAYQUERY)
|
||||
RaytracingAccelerationStructure gScreenParticleSceneBVH : register(t15);
|
||||
#endif
|
||||
|
||||
cbuffer PostCB : register(b0)
|
||||
{
|
||||
// gPostParams0: x = sharpen strength, y = history weight, z = TAA reset flag.
|
||||
// gPostParams1: x = tone-map exposure, y = white-point scale, z = display brightness.
|
||||
// gPostParams2: x = fog enabled, y = fog mode, z = fog density, w = fog start.
|
||||
// gPostParams3: x = fog end, y = fog camera valid.
|
||||
// gPostParams3: x = fog end, y = fog camera valid, z = particle soft depth, w = particle light count.
|
||||
float4 gPostParams0;
|
||||
float4 gPostParams1;
|
||||
float4 gPostParams2;
|
||||
@@ -4475,15 +4528,37 @@ cbuffer PostCB : register(b0)
|
||||
#define gPostFogStart gPostParams2.w
|
||||
#define gPostFogEnd gPostParams3.x
|
||||
#define gPostFogCameraValid gPostParams3.y
|
||||
#define gScreenParticleSoftDepth gPostParams3.z
|
||||
#define gScreenParticleLightCount gPostParams3.w
|
||||
#define gScreenDecalCount gPostFogCameraWorldPos.w
|
||||
#define QD3D12_TONEMAP_TILE_DIM 64u
|
||||
|
||||
static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0u;
|
||||
static const uint GL_RAYTRACING_LIGHT_TYPE_RECT = 1u;
|
||||
static const uint GL_RAYTRACING_LIGHT_TYPE_SPOT = 2u;
|
||||
|
||||
struct VSOut
|
||||
{
|
||||
float4 pos : SV_Position;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct ParticleVSIn
|
||||
{
|
||||
float4 clipPos : POSITION0;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
float3 world : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct ParticleVSOut
|
||||
{
|
||||
float4 pos : SV_Position;
|
||||
float2 uv : TEXCOORD0;
|
||||
float4 color : COLOR0;
|
||||
float3 world : TEXCOORD1;
|
||||
};
|
||||
|
||||
VSOut VSMain(uint vid : SV_VertexID)
|
||||
{
|
||||
VSOut o;
|
||||
@@ -4497,6 +4572,16 @@ VSOut VSMain(uint vid : SV_VertexID)
|
||||
return o;
|
||||
}
|
||||
|
||||
ParticleVSOut VSParticle(ParticleVSIn i)
|
||||
{
|
||||
ParticleVSOut o;
|
||||
o.pos = i.clipPos;
|
||||
o.uv = i.uv;
|
||||
o.color = i.color;
|
||||
o.world = i.world;
|
||||
return o;
|
||||
}
|
||||
|
||||
float QD3D12_PostFogFactor(float fogCoord)
|
||||
{
|
||||
if (gPostFogEnabled < 0.5)
|
||||
@@ -4590,6 +4675,175 @@ float4 PSScreenDecals(VSOut i) : SV_Target0
|
||||
return float4(decalColor, decalAlpha);
|
||||
}
|
||||
|
||||
float3 ScreenParticleSafeNormalizeOr(float3 v, float3 fallbackDir)
|
||||
{
|
||||
float lenSq = dot(v, v);
|
||||
return (lenSq > 1e-8) ? (v * rsqrt(lenSq)) : fallbackDir;
|
||||
}
|
||||
|
||||
float3 ScreenParticlePointRadius(ScreenParticleLight Lgt)
|
||||
{
|
||||
float scalarRadius = max(abs(Lgt.radius), 1e-4);
|
||||
float3 r = abs(Lgt.pointRadius);
|
||||
if (max(max(r.x, r.y), r.z) <= 1e-4)
|
||||
r = float3(scalarRadius, scalarRadius, scalarRadius);
|
||||
return max(r, float3(1e-4, 1e-4, 1e-4));
|
||||
}
|
||||
|
||||
float ScreenParticlePointAttenuation(float3 worldPos, ScreenParticleLight Lgt)
|
||||
{
|
||||
float3 radii = ScreenParticlePointRadius(Lgt);
|
||||
float3 offset = worldPos - Lgt.position;
|
||||
|
||||
float3 axisU = ScreenParticleSafeNormalizeOr(Lgt.axisU, float3(1.0, 0.0, 0.0));
|
||||
float3 axisV = ScreenParticleSafeNormalizeOr(Lgt.axisV, float3(0.0, 1.0, 0.0));
|
||||
float3 axisW = ScreenParticleSafeNormalizeOr(Lgt.normal, float3(0.0, 0.0, 1.0));
|
||||
|
||||
float3 perAxis;
|
||||
perAxis.x = 1.0 - saturate(abs(dot(offset, axisU)) / radii.x);
|
||||
perAxis.y = 1.0 - saturate(abs(dot(offset, axisV)) / radii.y);
|
||||
perAxis.z = 1.0 - saturate(abs(dot(offset, axisW)) / radii.z);
|
||||
return perAxis.x * perAxis.y * perAxis.z;
|
||||
}
|
||||
|
||||
float ScreenParticleBasicFalloff(float lightDist, float maxLightDist)
|
||||
{
|
||||
return saturate(1.0 - lightDist / max(maxLightDist, 1e-4));
|
||||
}
|
||||
|
||||
float ScreenParticleSpotAttenuation(float3 worldPos, ScreenParticleLight Lgt)
|
||||
{
|
||||
float3 lightToSurface = worldPos - Lgt.position;
|
||||
float nearClip = max(Lgt.pointRadius.x, 0.0);
|
||||
float farClip = max(Lgt.radius, nearClip + 1e-4);
|
||||
float3 spotDir = ScreenParticleSafeNormalizeOr(Lgt.normal, float3(0.0, 0.0, 1.0));
|
||||
|
||||
float depth = dot(lightToSurface, spotDir);
|
||||
if (depth <= nearClip || depth >= farClip)
|
||||
return 0.0;
|
||||
|
||||
float3 axisU = ScreenParticleSafeNormalizeOr(Lgt.axisU, float3(1.0, 0.0, 0.0));
|
||||
float3 axisV = ScreenParticleSafeNormalizeOr(Lgt.axisV, float3(0.0, 1.0, 0.0));
|
||||
float invDepth = 1.0 / max(depth, 1e-4);
|
||||
float halfU = max(abs(Lgt.halfWidth), 1e-4);
|
||||
float halfV = max(abs(Lgt.halfHeight), 1e-4);
|
||||
float signedU = (dot(lightToSurface, axisU) * invDepth) / halfU;
|
||||
float signedV = (dot(lightToSurface, axisV) * invDepth) / halfV;
|
||||
if (abs(signedU) >= 1.0 || abs(signedV) >= 1.0)
|
||||
return 0.0;
|
||||
|
||||
float3 lightVector = normalize(lightToSurface);
|
||||
float maxSlope = max(halfU, halfV);
|
||||
float outerAngle = rsqrt(1.0 + maxSlope * maxSlope);
|
||||
float innerSlope = maxSlope * 0.65;
|
||||
float innerAngle = rsqrt(1.0 + innerSlope * innerSlope);
|
||||
float spotCookie = smoothstep(outerAngle, innerAngle, saturate(dot(lightVector, spotDir)));
|
||||
return spotCookie * ScreenParticleBasicFalloff(depth - nearClip, farClip - nearClip);
|
||||
}
|
||||
|
||||
float ScreenParticleTraceShadow(float3 worldPos, float3 viewDir, float3 L, float dist, ScreenParticleLight Lgt)
|
||||
{
|
||||
if (Lgt.samples == 0u)
|
||||
return 1.0;
|
||||
|
||||
#if defined(QD3D12_SCREEN_PARTICLE_RAYQUERY)
|
||||
RayDesc ray;
|
||||
ray.Origin = worldPos + L * 5.0 + viewDir * 1.0;
|
||||
ray.Direction = L;
|
||||
ray.TMin = 0.001;
|
||||
ray.TMax = max(dist - 8.0, 0.001);
|
||||
|
||||
RayQuery<RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES> q;
|
||||
q.TraceRayInline(
|
||||
gScreenParticleSceneBVH,
|
||||
RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_FORCE_OPAQUE | RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES,
|
||||
0xFF,
|
||||
ray);
|
||||
while (q.Proceed()) {}
|
||||
|
||||
return (q.CommittedStatus() == COMMITTED_TRIANGLE_HIT) ? 0.0 : 1.0;
|
||||
#else
|
||||
return 1.0;
|
||||
#endif
|
||||
}
|
||||
|
||||
float3 ScreenParticleDirectLighting(float3 worldPos)
|
||||
{
|
||||
uint lightCount = min((uint)gScreenParticleLightCount, 256u);
|
||||
if (lightCount == 0u || gPostFogCameraValid <= 0.5)
|
||||
return 1.0;
|
||||
|
||||
float3 viewDir = ScreenParticleSafeNormalizeOr(gPostFogCameraWorldPos.xyz - worldPos, float3(0.0, 0.0, 1.0));
|
||||
float3 lighting = float3(0.16, 0.16, 0.16);
|
||||
|
||||
[loop]
|
||||
for (uint lightIndex = 0u; lightIndex < lightCount; ++lightIndex)
|
||||
{
|
||||
ScreenParticleLight Lgt = gScreenParticleLights[lightIndex];
|
||||
if (Lgt.type != GL_RAYTRACING_LIGHT_TYPE_POINT && Lgt.type != GL_RAYTRACING_LIGHT_TYPE_SPOT)
|
||||
continue;
|
||||
|
||||
float3 toLight = Lgt.position - worldPos;
|
||||
float dist = length(toLight);
|
||||
if (dist <= 0.01)
|
||||
continue;
|
||||
|
||||
float atten = (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
|
||||
? ScreenParticlePointAttenuation(worldPos, Lgt)
|
||||
: ScreenParticleSpotAttenuation(worldPos, Lgt);
|
||||
if (atten <= 0.0)
|
||||
continue;
|
||||
|
||||
float3 L = toLight / dist;
|
||||
float shadow = ScreenParticleTraceShadow(worldPos, viewDir, L, dist, Lgt);
|
||||
if (shadow <= 0.0)
|
||||
continue;
|
||||
|
||||
float forwardScatter = saturate(dot(viewDir, -L) * 0.5 + 0.5);
|
||||
float phase = lerp(0.65, 1.0, forwardScatter);
|
||||
lighting += Lgt.color * (Lgt.intensity * atten * shadow * phase * 0.25);
|
||||
}
|
||||
|
||||
return clamp(lighting, 0.08, 8.0);
|
||||
}
|
||||
|
||||
float4 PSScreenParticles(ParticleVSOut i) : SV_Target0
|
||||
{
|
||||
float4 texel = gTex0.Sample(gSamp0, i.uv) * i.color;
|
||||
float alpha = saturate(texel.a);
|
||||
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)
|
||||
{
|
||||
float4 positionSample = gScreenDecalPosition.Load(int3(pixel, 0));
|
||||
uint geometryBits = (uint)round(max(positionSample.w, 0.0));
|
||||
if ((geometryBits & 1u) == 0u)
|
||||
{
|
||||
float sceneDistance = length(positionSample.xyz - gPostFogCameraWorldPos.xyz);
|
||||
float particleDistance = length(i.world - gPostFogCameraWorldPos.xyz);
|
||||
float softDepth = max(gScreenParticleSoftDepth, 0.001);
|
||||
alpha *= saturate((sceneDistance - particleDistance) / softDepth);
|
||||
if (alpha <= 0.0001)
|
||||
discard;
|
||||
}
|
||||
else if (particleDepth > sceneDepth + 0.00005)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
texel.rgb *= ScreenParticleDirectLighting(i.world);
|
||||
|
||||
return float4(texel.rgb, alpha);
|
||||
}
|
||||
|
||||
float4 PSCopy(VSOut i) : SV_Target0
|
||||
{
|
||||
return QD3D12_ApplyPostFog(gTex0.Sample(gSamp0, i.uv), i.uv);
|
||||
@@ -4681,7 +4935,8 @@ float4 PSToneMapFinalMax(VSOut i) : SV_Target0
|
||||
|
||||
return float4(min(maxBrightness, 65504.0), 0.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
)HLSL"
|
||||
R"HLSL(
|
||||
float3 QD3D12_PostSharpenHDR(float2 uv, float3 center)
|
||||
{
|
||||
float amount = saturate(gPostSharpness);
|
||||
@@ -4825,7 +5080,8 @@ float3 QD3D12_EmissiveBloom(float2 uv)
|
||||
|
||||
return min(bloom * 0.62, 5.0);
|
||||
}
|
||||
|
||||
)HLSL"
|
||||
R"HLSL(
|
||||
float4 PSAdd(VSOut i) : SV_Target0
|
||||
{
|
||||
float4 center = gTex0.Sample(gSamp0, i.uv);
|
||||
@@ -7260,6 +7516,7 @@ static bool QD3D12_CanUseDLSSRayReconstructionForLighting(const QD3D12Window& w)
|
||||
static bool QD3D12_UseLightingTextureAsUpscaleInput(const QD3D12Window& w)
|
||||
{
|
||||
return QD3D12_CanUseDLSSRayReconstructionForLighting(w) &&
|
||||
!g_gl.blockLightingUpscaleInputThisFrame &&
|
||||
g_gl.raytracedLightingReadyThisFrame &&
|
||||
g_lightingTexture[g_lightingReadIndex] &&
|
||||
g_lightingTexture[g_lightingReadIndex]->texture;
|
||||
@@ -7795,7 +8052,10 @@ static void QD3D12_SetPostConstants(
|
||||
float toneMapBrightness = 1.0f,
|
||||
bool applySceneFog = false,
|
||||
float screenDecalCount = 0.0f,
|
||||
float screenDecalIndex = 0.0f)
|
||||
float screenDecalIndex = 0.0f,
|
||||
bool forceCameraPosition = false,
|
||||
float screenParticleSoftDepth = 16.0f,
|
||||
float screenParticleLightCount = 0.0f)
|
||||
{
|
||||
if (!cl)
|
||||
return;
|
||||
@@ -7824,6 +8084,15 @@ static void QD3D12_SetPostConstants(
|
||||
constants[21] = g_gl.sceneFogCameraWorldPos[1];
|
||||
constants[22] = g_gl.sceneFogCameraWorldPos[2];
|
||||
}
|
||||
else if ( forceCameraPosition && g_gl.cameraState.valid )
|
||||
{
|
||||
constants[13] = 1.0f;
|
||||
constants[20] = g_gl.cameraState.cameraPos[0];
|
||||
constants[21] = g_gl.cameraState.cameraPos[1];
|
||||
constants[22] = g_gl.cameraState.cameraPos[2];
|
||||
}
|
||||
constants[14] = screenParticleSoftDepth;
|
||||
constants[15] = screenParticleLightCount;
|
||||
constants[23] = screenDecalCount;
|
||||
cl->SetGraphicsRoot32BitConstants(QD3D12_PostRootConstants, QD3D12_PostConstantDwords, constants, 0);
|
||||
}
|
||||
@@ -7912,6 +8181,96 @@ static bool QD3D12_EnsureScreenSpaceDecalBuffer()
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool QD3D12_EnsureScreenSpaceParticleLightBuffer()
|
||||
{
|
||||
if (!g_gl.device || !g_gl.srvHeap)
|
||||
return false;
|
||||
|
||||
const UINT64 bufferSize = sizeof(glRaytracingLight_t) * QD3D12_MaxScreenSpaceParticleLights;
|
||||
if (!g_gl.screenSpaceParticleLightBuffer)
|
||||
{
|
||||
D3D12_HEAP_PROPERTIES hp{};
|
||||
hp.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
hp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
hp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
hp.CreationNodeMask = 1;
|
||||
hp.VisibleNodeMask = 1;
|
||||
|
||||
D3D12_RESOURCE_DESC rd{};
|
||||
rd.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
rd.Width = bufferSize;
|
||||
rd.Height = 1;
|
||||
rd.DepthOrArraySize = 1;
|
||||
rd.MipLevels = 1;
|
||||
rd.Format = DXGI_FORMAT_UNKNOWN;
|
||||
rd.SampleDesc.Count = 1;
|
||||
rd.SampleDesc.Quality = 0;
|
||||
rd.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
rd.Flags = D3D12_RESOURCE_FLAG_NONE;
|
||||
|
||||
QD3D12_CHECK(g_gl.device->CreateCommittedResource(
|
||||
&hp,
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&rd,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&g_gl.screenSpaceParticleLightBuffer)));
|
||||
|
||||
QD3D12_CHECK(g_gl.screenSpaceParticleLightBuffer->Map(0, nullptr, &g_gl.screenSpaceParticleLightBufferMapped));
|
||||
}
|
||||
|
||||
if (g_gl.screenSpaceParticleLightSrvIndex == UINT_MAX)
|
||||
{
|
||||
g_gl.screenSpaceParticleLightSrvIndex = g_gl.nextSrvIndex++;
|
||||
g_gl.screenSpaceParticleLightSrvCpu = QD3D12_SrvCpu(g_gl.screenSpaceParticleLightSrvIndex);
|
||||
g_gl.screenSpaceParticleLightSrvGpu = QD3D12_SrvGpu(g_gl.screenSpaceParticleLightSrvIndex);
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC sd{};
|
||||
sd.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
|
||||
sd.Format = DXGI_FORMAT_UNKNOWN;
|
||||
sd.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
sd.Buffer.FirstElement = 0;
|
||||
sd.Buffer.NumElements = QD3D12_MaxScreenSpaceParticleLights;
|
||||
sd.Buffer.StructureByteStride = sizeof(glRaytracingLight_t);
|
||||
sd.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
|
||||
g_gl.device->CreateShaderResourceView(g_gl.screenSpaceParticleLightBuffer.Get(), &sd, g_gl.screenSpaceParticleLightSrvCpu);
|
||||
}
|
||||
|
||||
if (g_gl.screenSpaceParticleLightBufferMapped)
|
||||
{
|
||||
memset(g_gl.screenSpaceParticleLightBufferMapped, 0, bufferSize);
|
||||
if (g_gl.screenSpaceParticleLightCount > 0)
|
||||
{
|
||||
memcpy(
|
||||
g_gl.screenSpaceParticleLightBufferMapped,
|
||||
g_gl.screenSpaceParticleLights,
|
||||
sizeof(glRaytracingLight_t) * g_gl.screenSpaceParticleLightCount);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool QD3D12_UpdateScreenSpaceParticleTlasSrv(ID3D12Resource* tlas)
|
||||
{
|
||||
if (!g_gl.device || !g_gl.srvHeap || !tlas)
|
||||
return false;
|
||||
|
||||
if (g_gl.screenSpaceParticleTlasSrvIndex == UINT_MAX)
|
||||
{
|
||||
g_gl.screenSpaceParticleTlasSrvIndex = g_gl.nextSrvIndex++;
|
||||
g_gl.screenSpaceParticleTlasSrvCpu = QD3D12_SrvCpu(g_gl.screenSpaceParticleTlasSrvIndex);
|
||||
g_gl.screenSpaceParticleTlasSrvGpu = QD3D12_SrvGpu(g_gl.screenSpaceParticleTlasSrvIndex);
|
||||
}
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC sd{};
|
||||
sd.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE;
|
||||
sd.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
sd.RaytracingAccelerationStructure.Location = tlas->GetGPUVirtualAddress();
|
||||
g_gl.device->CreateShaderResourceView(nullptr, &sd, g_gl.screenSpaceParticleTlasSrvCpu);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void QD3D12_PostFullscreenPass(ID3D12GraphicsCommandList* cl,
|
||||
ID3D12PipelineState* pso,
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE inputSrv,
|
||||
@@ -8180,6 +8539,135 @@ void APIENTRY glDrawScreenSpaceDecalsQD3D12(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleBatch& batch, ID3D12Resource* tlas)
|
||||
{
|
||||
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;
|
||||
|
||||
if (!verts || vertexCount == 0)
|
||||
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 (!QD3D12_EnsureScreenSpaceParticleLightBuffer() || !QD3D12_UpdateScreenSpaceParticleTlasSrv(tlas))
|
||||
return;
|
||||
|
||||
QD3D12_EnsureFrameOpen();
|
||||
QD3D12_FlushQueuedBatches();
|
||||
QD3D12_ResolveGBufferForCurrentFrame(*window);
|
||||
QD3D12_UpdateCameraInfoFromCurrentMatrices();
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
const UINT vbBytes = vertexCount * sizeof(glScreenSpaceParticleVertex_t);
|
||||
UploadAlloc upload = QD3D12_AllocUpload(vbBytes, 256);
|
||||
memcpy(upload.cpu, verts, vbBytes);
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vbv{};
|
||||
vbv.BufferLocation = upload.gpu;
|
||||
vbv.SizeInBytes = vbBytes;
|
||||
vbv.StrideInBytes = sizeof(glScreenSpaceParticleVertex_t);
|
||||
|
||||
D3D12_VIEWPORT viewport{};
|
||||
viewport.TopLeftX = 0.0f;
|
||||
viewport.TopLeftY = 0.0f;
|
||||
viewport.Width = (float)window->renderWidth;
|
||||
viewport.Height = (float)window->renderHeight;
|
||||
viewport.MinDepth = 0.0f;
|
||||
viewport.MaxDepth = 1.0f;
|
||||
|
||||
D3D12_RECT scissor{};
|
||||
scissor.left = 0;
|
||||
scissor.top = 0;
|
||||
scissor.right = (LONG)window->renderWidth;
|
||||
scissor.bottom = (LONG)window->renderHeight;
|
||||
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE particleTextureSrv = g_gl.whiteTexture.srvGpu;
|
||||
TextureResource* particleTexture = textureId ? QD3D12_FindTextureResource(textureId) : nullptr;
|
||||
if (particleTexture)
|
||||
{
|
||||
EnsureTextureResource(*particleTexture);
|
||||
if (particleTexture->texture && !particleTexture->gpuValid)
|
||||
{
|
||||
UploadTexture(*particleTexture);
|
||||
}
|
||||
if (particleTexture->texture && particleTexture->srvIndex != UINT_MAX)
|
||||
{
|
||||
particleTextureSrv = particleTexture->srvGpu;
|
||||
}
|
||||
}
|
||||
|
||||
ID3D12PipelineState* particlePSO = (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);
|
||||
cl->SetPipelineState(particlePSO);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE sceneColorRtv = CurrentResolvedSceneColorRTV();
|
||||
cl->OMSetRenderTargets(1, &sceneColorRtv, FALSE, nullptr);
|
||||
cl->RSSetViewports(1, &viewport);
|
||||
cl->RSSetScissorRects(1, &scissor);
|
||||
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
cl->IASetVertexBuffers(0, 1, &vbv);
|
||||
cl->SetGraphicsRootDescriptorTable(0, particleTextureSrv);
|
||||
cl->SetGraphicsRootDescriptorTable(10, window->depthSrvGpu);
|
||||
cl->SetGraphicsRootDescriptorTable(12, window->positionSrvGpu[frame]);
|
||||
cl->SetGraphicsRootDescriptorTable(14, g_gl.screenSpaceParticleLightSrvGpu);
|
||||
cl->SetGraphicsRootDescriptorTable(15, g_gl.screenSpaceParticleTlasSrvGpu);
|
||||
cl->DrawInstanced(vertexCount, 1, 0, 0);
|
||||
}
|
||||
|
||||
void APIENTRY glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex_t* verts, uint32_t vertexCount, uint32_t textureId, uint32_t blendMode, float softDepth)
|
||||
{
|
||||
if (!verts || vertexCount == 0)
|
||||
return;
|
||||
|
||||
QD3D12ScreenSpaceParticleBatch batch;
|
||||
batch.vertices.assign(verts, verts + vertexCount);
|
||||
batch.textureId = textureId;
|
||||
batch.blendMode = blendMode;
|
||||
batch.softDepth = softDepth;
|
||||
g_gl.screenSpaceParticleBatches.push_back(std::move(batch));
|
||||
}
|
||||
|
||||
void APIENTRY glSetScreenSpaceParticleLightsQD3D12(const glRaytracingLight_t* lights, uint32_t lightCount)
|
||||
{
|
||||
g_gl.screenSpaceParticleLightCount = 0;
|
||||
memset(g_gl.screenSpaceParticleLights, 0, sizeof(g_gl.screenSpaceParticleLights));
|
||||
|
||||
if (!lights || lightCount == 0)
|
||||
return;
|
||||
|
||||
const uint32_t count = std::min<uint32_t>(lightCount, QD3D12_MaxScreenSpaceParticleLights);
|
||||
memcpy(g_gl.screenSpaceParticleLights, lights, sizeof(glRaytracingLight_t) * count);
|
||||
g_gl.screenSpaceParticleLightCount = count;
|
||||
}
|
||||
|
||||
static void QD3D12_DrawQueuedScreenSpaceParticles(ID3D12Resource* tlas)
|
||||
{
|
||||
if (g_gl.screenSpaceParticleBatches.empty())
|
||||
return;
|
||||
|
||||
for (const QD3D12ScreenSpaceParticleBatch& batch : g_gl.screenSpaceParticleBatches)
|
||||
{
|
||||
QD3D12_DrawScreenSpaceParticleBatch(batch, tlas);
|
||||
}
|
||||
g_gl.screenSpaceParticleBatches.clear();
|
||||
}
|
||||
|
||||
static ID3D12Resource* QD3D12_PrepareStreamlineOutputForWrite(QD3D12Window& w)
|
||||
{
|
||||
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
|
||||
@@ -9427,7 +9915,7 @@ static void QD3D12_DestroyUploadRingForWindow(QD3D12Window& w)
|
||||
w.upload.offset = 0;
|
||||
}
|
||||
|
||||
static ComPtr<ID3DBlob> CompileShaderSourceVariant(const char* source, const char* entry, const char* target)
|
||||
static ComPtr<ID3DBlob> CompileShaderSourceVariant(const char* source, const char* entry, const char* target, LPCWSTR defineName = nullptr)
|
||||
{
|
||||
ComPtr<IDxcUtils> utils;
|
||||
ComPtr<IDxcCompiler3> compiler;
|
||||
@@ -9486,6 +9974,11 @@ static ComPtr<ID3DBlob> CompileShaderSourceVariant(const char* source, const cha
|
||||
args.push_back(wTarget.c_str());
|
||||
args.push_back(L"-HV");
|
||||
args.push_back(L"2021");
|
||||
if (defineName && defineName[0])
|
||||
{
|
||||
args.push_back(L"-D");
|
||||
args.push_back(defineName);
|
||||
}
|
||||
|
||||
#if defined(_DEBUG)
|
||||
args.push_back(L"-Zi");
|
||||
@@ -9677,6 +10170,8 @@ static void QD3D12_CompileShaders()
|
||||
g_gl.postPsDepthResolveMsaaBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSDepthResolveMS", "ps_6_0");
|
||||
g_gl.postPsGBufferPointResolveMsaaBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSGBufferPointResolveMS", "ps_6_0");
|
||||
g_gl.postPsScreenDecalBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSScreenDecals", "ps_6_0");
|
||||
g_gl.postVsScreenParticleBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "VSParticle", "vs_6_0");
|
||||
g_gl.postPsScreenParticleBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSScreenParticles", "ps_6_5", L"QD3D12_SCREEN_PARTICLE_RAYQUERY=1");
|
||||
}
|
||||
|
||||
static const D3D12_INPUT_ELEMENT_DESC kGLVertexInputLayout[] =
|
||||
@@ -9701,6 +10196,14 @@ static const D3D12_INPUT_ELEMENT_DESC kGLVertexInputLayoutARB[] =
|
||||
{ "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, (UINT)offsetof(GLVertex, bx), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||
};
|
||||
|
||||
static const D3D12_INPUT_ELEMENT_DESC kScreenSpaceParticleInputLayout[] =
|
||||
{
|
||||
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, (UINT)offsetof(glScreenSpaceParticleVertex_t, clip), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(glScreenSpaceParticleVertex_t, st), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, (UINT)offsetof(glScreenSpaceParticleVertex_t, color), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||
{ "TEXCOORD", 1, DXGI_FORMAT_R32G32B32_FLOAT, 0, (UINT)offsetof(glScreenSpaceParticleVertex_t, world), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
|
||||
};
|
||||
|
||||
static UINT8 BuildColorWriteMask()
|
||||
{
|
||||
UINT8 mask = 0;
|
||||
@@ -9900,6 +10403,24 @@ static void QD3D12_CreatePSOs()
|
||||
d.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
|
||||
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postScreenDecalStainPSO)));
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC particleDesc = d;
|
||||
particleDesc.VS = { g_gl.postVsScreenParticleBlob->GetBufferPointer(), g_gl.postVsScreenParticleBlob->GetBufferSize() };
|
||||
particleDesc.PS = { g_gl.postPsScreenParticleBlob->GetBufferPointer(), g_gl.postPsScreenParticleBlob->GetBufferSize() };
|
||||
particleDesc.InputLayout.pInputElementDescs = kScreenSpaceParticleInputLayout;
|
||||
particleDesc.InputLayout.NumElements = _countof(kScreenSpaceParticleInputLayout);
|
||||
particleDesc.BlendState.RenderTarget[0].BlendEnable = TRUE;
|
||||
particleDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
||||
particleDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
|
||||
particleDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
|
||||
particleDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
|
||||
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&particleDesc, IID_PPV_ARGS(&g_gl.postScreenParticlePSO)));
|
||||
|
||||
particleDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
|
||||
particleDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_ONE;
|
||||
particleDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
|
||||
particleDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
|
||||
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&particleDesc, IID_PPV_ARGS(&g_gl.postScreenParticleAdditivePSO)));
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC depthDesc{};
|
||||
depthDesc.pRootSignature = g_gl.postRootSig.Get();
|
||||
depthDesc.VS = { g_gl.postVsBlob->GetBufferPointer(), g_gl.postVsBlob->GetBufferSize() };
|
||||
@@ -10476,6 +10997,9 @@ void QD3D12_BeginFrame()
|
||||
g_gl.gbufferResolvedThisFrame = false;
|
||||
g_gl.raytracedLightingReadyThisFrame = false;
|
||||
g_gl.sceneFogValidThisFrame = false;
|
||||
g_gl.blockLightingUpscaleInputThisFrame = false;
|
||||
g_gl.screenSpaceParticleBatches.clear();
|
||||
g_gl.screenSpaceParticleLightCount = 0;
|
||||
QD3D12_UpdateViewportState();
|
||||
|
||||
FrameResources& fr = w.frames[w.frameIndex];
|
||||
@@ -16714,6 +17238,8 @@ PROC WINAPI qd3d12_wglGetProcAddress(LPCSTR name) {
|
||||
{ "QD3D12_ResolveGBufferNow", (PROC)QD3D12_ResolveGBufferNow },
|
||||
{ "glSetScreenSpaceDecalsQD3D12",(PROC)glSetScreenSpaceDecalsQD3D12 },
|
||||
{ "glDrawScreenSpaceDecalsQD3D12",(PROC)glDrawScreenSpaceDecalsQD3D12 },
|
||||
{ "glSetScreenSpaceParticleLightsQD3D12",(PROC)glSetScreenSpaceParticleLightsQD3D12 },
|
||||
{ "glDrawScreenSpaceParticlesQD3D12",(PROC)glDrawScreenSpaceParticlesQD3D12 },
|
||||
{ "QD3D12_SetUpscalerBackend", (PROC)QD3D12_SetUpscalerBackend },
|
||||
{ "QD3D12_SetUpscalerQuality", (PROC)QD3D12_SetUpscalerQuality },
|
||||
{ "QD3D12_SetUpscalerSharpness", (PROC)QD3D12_SetUpscalerSharpness },
|
||||
@@ -17502,6 +18028,14 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
|
||||
|
||||
QD3D12_RunRayAIDenoiseIfEnabled(cl, *window, writeLightingTex->texture.Get());
|
||||
|
||||
if (!g_gl.screenSpaceParticleBatches.empty())
|
||||
{
|
||||
// The particle pass is a blended graphics pass, so it needs a render-target
|
||||
// scene color surface. Keep particle frames on the composited scene-color
|
||||
// path instead of feeding the raw lighting texture straight to RR/upscale.
|
||||
g_gl.blockLightingUpscaleInputThisFrame = true;
|
||||
}
|
||||
|
||||
// If the denoiser changes the written texture state, restore it to a
|
||||
// shader-readable state before this slot becomes the next read target.
|
||||
// restore the texture to a shader-readable state for the post/upscale pass.
|
||||
@@ -17570,6 +18104,8 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
|
||||
// guide instead of overwriting it here.
|
||||
}
|
||||
|
||||
QD3D12_DrawQueuedScreenSpaceParticles(tlas);
|
||||
|
||||
QD3D12_ResolveSceneToOutputAndEnterNativePhase(*window);
|
||||
}
|
||||
|
||||
|
||||
@@ -1748,6 +1748,15 @@ typedef struct glScreenSpaceDecal_s
|
||||
float pad1[2];
|
||||
} glScreenSpaceDecal_t;
|
||||
|
||||
typedef struct glScreenSpaceParticleVertex_s
|
||||
{
|
||||
float clip[4];
|
||||
float st[2];
|
||||
float color[4];
|
||||
float world[3];
|
||||
float pad0;
|
||||
} glScreenSpaceParticleVertex_t;
|
||||
|
||||
int glRaytracingInit(void);
|
||||
void glRaytracingShutdown(void);
|
||||
void glRaytracingClear(void);
|
||||
@@ -1843,6 +1852,8 @@ uint32_t glRaytracingLightingGetLightCount(void);
|
||||
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);
|
||||
|
||||
ID3D12Device* QD3D12_GetDevice(void);
|
||||
ID3D12CommandQueue* QD3D12_GetQueue(void);
|
||||
|
||||
@@ -138,6 +138,7 @@ idCVar r_frontBuffer( "r_frontBuffer", "0", CVAR_RENDERER | CVAR_BOOL, "draw to
|
||||
idCVar r_skipSubviews( "r_skipSubviews", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = don't render any gui elements on surfaces" );
|
||||
idCVar r_skipGuiShaders( "r_skipGuiShaders", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all gui elements on surfaces, 2 = skip drawing but still handle events, 3 = draw but skip events", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
|
||||
idCVar r_skipParticles( "r_skipParticles", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all particle systems", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1> );
|
||||
idCVar r_screenSpaceParticles( "r_screenSpaceParticles", "1", CVAR_RENDERER | CVAR_INTEGER, "1 = render particles in a D3D12 screen-space pass", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1> );
|
||||
idCVar r_subviewOnly( "r_subviewOnly", "0", CVAR_RENDERER | CVAR_BOOL, "1 = don't render main view, allowing subviews to be debugged" );
|
||||
idCVar r_shadows( "r_shadows", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "enable shadows" );
|
||||
idCVar r_testARBProgram( "r_testARBProgram", "0", CVAR_RENDERER | CVAR_BOOL, "experiment with vertex/fragment programs" );
|
||||
|
||||
@@ -367,6 +367,10 @@ void RB_T_FillDepthBuffer(const drawSurf_t* surf) {
|
||||
tri = surf->geo;
|
||||
shader = surf->material;
|
||||
|
||||
if ( r_screenSpaceParticles.GetBool() && ( surf->dsFlags & DSF_SCREEN_SPACE_PARTICLE ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update the clip plane if needed
|
||||
if (backEnd.viewDef->numClipPlanes && surf->space != backEnd.currentSpace) {
|
||||
GL_SelectTexture(1);
|
||||
@@ -802,6 +806,10 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
|
||||
tri = surf->geo;
|
||||
shader = surf->material;
|
||||
|
||||
if ( r_screenSpaceParticles.GetBool() && ( surf->dsFlags & DSF_SCREEN_SPACE_PARTICLE ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !shader->HasAmbient() ) {
|
||||
return;
|
||||
}
|
||||
@@ -1504,6 +1512,121 @@ void RB_STD_FogAllLights( void ) {
|
||||
|
||||
//=========================================================================================
|
||||
|
||||
static const shaderStage_t *RB_FirstDrawableParticleStage( const drawSurf_t *surf, idImage *&image, uint32_t &blendMode ) {
|
||||
image = NULL;
|
||||
blendMode = 0;
|
||||
|
||||
if ( !surf || !surf->material || !surf->shaderRegisters ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for ( int stage = 0; stage < surf->material->GetNumStages(); stage++ ) {
|
||||
const shaderStage_t *pStage = surf->material->GetStage( stage );
|
||||
if ( pStage->lighting != SL_AMBIENT ) {
|
||||
continue;
|
||||
}
|
||||
if ( surf->shaderRegisters[pStage->conditionRegister] == 0.0f ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
image = pStage->texture.image;
|
||||
const int srcBlend = pStage->drawStateBits & GLS_SRCBLEND_BITS;
|
||||
const int dstBlend = pStage->drawStateBits & GLS_DSTBLEND_BITS;
|
||||
if ( srcBlend == GLS_SRCBLEND_ONE && dstBlend == GLS_DSTBLEND_ONE ) {
|
||||
blendMode = 1;
|
||||
}
|
||||
return pStage;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void RB_FillScreenSpaceParticleVertex( glScreenSpaceParticleVertex_t &dst, const idDrawVert &src, const viewEntity_t *space, const float *projectionMatrix, const float stageColor[4] ) {
|
||||
idVec3 world;
|
||||
idPlane eye, clip;
|
||||
|
||||
R_LocalPointToGlobal( space->modelMatrix, src.xyz, world );
|
||||
R_TransformModelToClip( src.xyz, space->modelViewMatrix, projectionMatrix, eye, clip );
|
||||
|
||||
dst.clip[0] = clip[0];
|
||||
dst.clip[1] = clip[1];
|
||||
dst.clip[2] = 0.5f * ( clip[2] + clip[3] );
|
||||
dst.clip[3] = clip[3];
|
||||
dst.st[0] = src.st[0];
|
||||
dst.st[1] = src.st[1];
|
||||
dst.color[0] = ( src.color[0] * ( 1.0f / 255.0f ) ) * stageColor[0];
|
||||
dst.color[1] = ( src.color[1] * ( 1.0f / 255.0f ) ) * stageColor[1];
|
||||
dst.color[2] = ( src.color[2] * ( 1.0f / 255.0f ) ) * stageColor[2];
|
||||
dst.color[3] = ( src.color[3] * ( 1.0f / 255.0f ) ) * stageColor[3];
|
||||
dst.world[0] = world[0];
|
||||
dst.world[1] = world[1];
|
||||
dst.world[2] = world[2];
|
||||
dst.pad0 = 0.0f;
|
||||
}
|
||||
|
||||
static void RB_SubmitScreenSpaceParticleSurf( const drawSurf_t *surf ) {
|
||||
if ( !surf || !surf->geo || !surf->space || !surf->material || !surf->geo->verts || !surf->geo->indexes ) {
|
||||
return;
|
||||
}
|
||||
if ( !surf->geo->numIndexes || !surf->geo->numVerts ) {
|
||||
return;
|
||||
}
|
||||
|
||||
idImage *image = NULL;
|
||||
uint32_t blendMode = 0;
|
||||
const shaderStage_t *stage = RB_FirstDrawableParticleStage( surf, image, blendMode );
|
||||
if ( !stage ) {
|
||||
return;
|
||||
}
|
||||
|
||||
float stageColor[4];
|
||||
for ( int i = 0; i < 4; i++ ) {
|
||||
stageColor[i] = surf->shaderRegisters[stage->color.registers[i]];
|
||||
}
|
||||
|
||||
if ( image ) {
|
||||
image->Bind();
|
||||
} else {
|
||||
globalImages->whiteImage->Bind();
|
||||
image = globalImages->whiteImage;
|
||||
}
|
||||
|
||||
float projectionMatrix[16];
|
||||
memcpy( projectionMatrix, backEnd.viewDef->projectionMatrix, sizeof( projectionMatrix ) );
|
||||
if ( surf->space->weaponDepthHack ) {
|
||||
projectionMatrix[14] *= 0.25f;
|
||||
}
|
||||
if ( surf->space->modelDepthHack != 0.0f ) {
|
||||
projectionMatrix[14] -= surf->space->modelDepthHack;
|
||||
}
|
||||
|
||||
idList<glScreenSpaceParticleVertex_t> particleVerts;
|
||||
particleVerts.SetNum( surf->geo->numIndexes, false );
|
||||
for ( int i = 0; i < surf->geo->numIndexes; i++ ) {
|
||||
const int vertIndex = surf->geo->indexes[i];
|
||||
if ( vertIndex < 0 || vertIndex >= surf->geo->numVerts ) {
|
||||
continue;
|
||||
}
|
||||
RB_FillScreenSpaceParticleVertex( particleVerts[i], surf->geo->verts[vertIndex], surf->space, projectionMatrix, stageColor );
|
||||
}
|
||||
|
||||
glDrawScreenSpaceParticlesQD3D12( particleVerts.Ptr(), particleVerts.Num(), image->texnum, blendMode, 16.0f );
|
||||
}
|
||||
|
||||
static void RB_STD_DrawScreenSpaceParticles( drawSurf_t **drawSurfs, int numDrawSurfs ) {
|
||||
if ( !r_screenSpaceParticles.GetBool() || !backEnd.viewDef->viewEntitys ) {
|
||||
return;
|
||||
}
|
||||
|
||||
RB_LogComment( "---------- RB_STD_DrawScreenSpaceParticles ----------\n" );
|
||||
|
||||
for ( int i = 0; i < numDrawSurfs; i++ ) {
|
||||
if ( drawSurfs[i]->dsFlags & DSF_SCREEN_SPACE_PARTICLE ) {
|
||||
RB_SubmitScreenSpaceParticleSurf( drawSurfs[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RB_STD_DrawView
|
||||
@@ -1531,6 +1654,8 @@ void RB_STD_DrawView( void ) {
|
||||
// subviews
|
||||
RB_STD_FillDepthBuffer( drawSurfs, numDrawSurfs );
|
||||
|
||||
RB_STD_DrawScreenSpaceParticles( drawSurfs, numDrawSurfs );
|
||||
|
||||
// main light renderer
|
||||
RB_DXDrawInteractions();
|
||||
|
||||
|
||||
@@ -160,6 +160,8 @@ void RB_DXDrawInteractions(void)
|
||||
QD3D12_SetToneMapBrightness(r_brightness.GetFloat());
|
||||
QD3D12_SetFrameGenerationMultiplier(r_frameGen.GetInteger());
|
||||
|
||||
idList<glRaytracingLight_t> screenParticleLights;
|
||||
|
||||
for (vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next)
|
||||
{
|
||||
backEnd.vLight = vLight;
|
||||
@@ -240,12 +242,14 @@ void RB_DXDrawInteractions(void)
|
||||
}
|
||||
}
|
||||
glRaytracingLightingAddLight(&light);
|
||||
screenParticleLights.Append(light);
|
||||
}
|
||||
}
|
||||
|
||||
if (backEnd.viewDef->renderWorld)
|
||||
{
|
||||
backEnd.viewDef->renderWorld->SubmitWorldDecalsToScreenSpace();
|
||||
glSetScreenSpaceParticleLightsQD3D12(screenParticleLights.Ptr(), screenParticleLights.Num());
|
||||
glLightScene(backEnd.viewDef->renderWorld->dxrWorldId);
|
||||
glRaytracingLightingClearLights(false);
|
||||
}
|
||||
|
||||
@@ -1211,7 +1211,7 @@ 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 );
|
||||
R_AddDrawSurf( tri, surf->space, renderEntity, stage->material, surf->scissorRect, DSF_SCREEN_SPACE_PARTICLE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1110,7 +1110,7 @@ R_AddDrawSurf
|
||||
=================
|
||||
*/
|
||||
void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity,
|
||||
const idMaterial *shader, const idScreenRect &scissor ) {
|
||||
const idMaterial *shader, const idScreenRect &scissor, int dsFlags ) {
|
||||
drawSurf_t *drawSurf;
|
||||
const float *shaderParms;
|
||||
static float refRegs[MAX_EXPRESSION_REGISTERS]; // don't put on stack, or VC++ will do a page touch
|
||||
@@ -1122,7 +1122,7 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const
|
||||
drawSurf->material = shader;
|
||||
drawSurf->scissorRect = scissor;
|
||||
drawSurf->sort = shader->GetSort() + tr.sortOffset;
|
||||
drawSurf->dsFlags = 0;
|
||||
drawSurf->dsFlags = dsFlags;
|
||||
|
||||
// bumping this offset each time causes surfaces with equal sort orders to still
|
||||
// deterministically draw in the order they are added
|
||||
@@ -1351,8 +1351,11 @@ 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;
|
||||
|
||||
// add the surface for drawing
|
||||
R_AddDrawSurf( tri, vEntity, &vEntity->entityDef->parms, shader, vEntity->scissorRect );
|
||||
R_AddDrawSurf( tri, vEntity, &vEntity->entityDef->parms, shader, vEntity->scissorRect, particleFlags );
|
||||
|
||||
// ambientViewCount is used to allow light interactions to be rejected
|
||||
// if the ambient surface isn't visible at all
|
||||
|
||||
@@ -103,7 +103,8 @@ SURFACES
|
||||
// unique srfTriangles_t
|
||||
|
||||
// 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_VIEW_INSIDE_SHADOW = 1;
|
||||
static const int DSF_SCREEN_SPACE_PARTICLE = 2;
|
||||
|
||||
typedef struct drawSurf_s {
|
||||
const srfTriangles_t *geo;
|
||||
@@ -910,6 +911,7 @@ extern idCVar r_skipFogLights; // skip all fog lights
|
||||
extern idCVar r_skipSubviews; // 1 = don't render any mirrors / cameras / etc
|
||||
extern idCVar r_skipGuiShaders; // 1 = don't render any gui elements on surfaces
|
||||
extern idCVar r_skipParticles; // 1 = don't render any particles
|
||||
extern idCVar r_screenSpaceParticles; // 1 = render particles in the D3D12 screen-space pass
|
||||
extern idCVar r_skipUpdates; // 1 = don't accept any entity or light updates, making everything static
|
||||
extern idCVar r_skipDeforms; // leave all deform materials in their original state
|
||||
extern idCVar r_skipDynamicTextures; // don't dynamically create textures
|
||||
@@ -1199,7 +1201,7 @@ viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def );
|
||||
viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *def );
|
||||
|
||||
void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity,
|
||||
const idMaterial *shader, const idScreenRect &scissor );
|
||||
const idMaterial *shader, const idScreenRect &scissor, int dsFlags = 0 );
|
||||
|
||||
void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const viewEntity_t *space,
|
||||
const idRenderLightLocal *light, const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow );
|
||||
|
||||
@@ -521,7 +521,7 @@ int idSampleDecoderLocal::DecodeOGG( idSoundSample *sample, int sampleOffset44k,
|
||||
return 0;
|
||||
}
|
||||
if ( sample->nonCacheData == NULL ) {
|
||||
assert( false ); // this should never happen
|
||||
// assert( false ); // this should never happen
|
||||
failed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user