474 lines
18 KiB
HLSL
474 lines
18 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#define LIGHT_LOOP_METHOD 2 // 0: stochastic (like ref PT) 1: loop over all lights 2: RIS (take N samples but trace a single shadow ray)
|
|
|
|
#define USE_BSDF_SAMPLING 1 // 0: light sampling only (no MIS) 1: light sampling and BSDF sampling (with MIS)
|
|
|
|
#define USE_PATH_TRACING_LIGHT_GRID 1
|
|
#define USE_RAY_TRACING_DECAL_GRID 1
|
|
|
|
|
|
#include "../Common.ush"
|
|
#include "../BlueNoise.ush"
|
|
#include "../RayTracing/RayTracingCommon.ush"
|
|
#include "../RayTracing/RayTracingDecalGrid.ush"
|
|
#include "PathTracingCommon.ush"
|
|
#include "Material/PathTracingMaterialSampling.ush"
|
|
#include "Utilities/PathTracingRandomSequence.ush"
|
|
#include "Utilities/PathTracingRIS.ush"
|
|
#include "Light/PathTracingLightSampling.ush"
|
|
#include "Light/PathTracingLightGrid.ush"
|
|
|
|
#if PATH_TRACER_USE_SER
|
|
|
|
#define NV_HITOBJECT_USE_MACRO_API
|
|
#include "/Engine/Shared/ThirdParty/NVIDIA/nvHLSLExtns.h"
|
|
|
|
#endif
|
|
|
|
RWTexture2D<float4> RWSceneColor;
|
|
RWTexture2D<float> RWSceneDepth;
|
|
RaytracingAccelerationStructure TLAS;
|
|
|
|
int DebugMode;
|
|
int NumLightSamples;
|
|
int NumIndirectSamples;
|
|
|
|
float3 TraceShadowRay(FRayDesc Ray, float PathRoughness, float PreviousPathRoughness, uint MissShaderIndex, bool bCastShadows)
|
|
{
|
|
if (!bCastShadows && MissShaderIndex == 0)
|
|
{
|
|
// no work to do
|
|
return 1.0;
|
|
}
|
|
|
|
const uint RayFlags = RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_SKIP_CLOSEST_HIT_SHADER;
|
|
const uint InstanceInclusionMask = PATHTRACER_MASK_SHADOW;
|
|
const uint RayContributionToHitGroupIndex = RAY_TRACING_SHADER_SLOT_SHADOW;
|
|
const uint MultiplierForGeometryContributionToShaderIndex = RAY_TRACING_NUM_SHADER_SLOTS;
|
|
|
|
FPackedPathTracingPayload PackedPayload = InitPathTracingVisibilityPayload(PathRoughness);
|
|
|
|
if (!bCastShadows)
|
|
{
|
|
// ray should not cast shadows, make it degenerate so we can still run the miss shader
|
|
Ray.TMin = POSITIVE_INFINITY;
|
|
Ray.TMax = POSITIVE_INFINITY;
|
|
}
|
|
TraceRay(
|
|
TLAS,
|
|
RayFlags,
|
|
InstanceInclusionMask,
|
|
RayContributionToHitGroupIndex,
|
|
MultiplierForGeometryContributionToShaderIndex,
|
|
MissShaderIndex,
|
|
Ray.GetNativeDesc(),
|
|
PackedPayload);
|
|
|
|
if (PackedPayload.IsHit())
|
|
{
|
|
// We didn't run the miss shader, therefore we must have hit something opaque (or reached full opacity)
|
|
return 0.0;
|
|
}
|
|
|
|
float3 Throughput = PackedPayload.GetRayThroughput();
|
|
|
|
return Throughput;
|
|
}
|
|
|
|
struct PathTracingResult {
|
|
float4 Radiance;
|
|
float Z;
|
|
};
|
|
|
|
PathTracingResult MakeResult(float3 Radiance, float Alpha, float Z)
|
|
{
|
|
PathTracingResult Result;
|
|
Result.Radiance.rgb = Radiance;
|
|
Result.Radiance.a = Alpha;
|
|
Result.Z = Z;
|
|
return Result;
|
|
}
|
|
|
|
float3 GetLightingChannelMaskDebugColor(int LightingChannelMask)
|
|
{
|
|
float r = LightingChannelMask & 1 ? 1.0 : 0.1;
|
|
float g = LightingChannelMask & 2 ? 1.0 : 0.1;
|
|
float b = LightingChannelMask & 4 ? 1.0 : 0.1;
|
|
return float3(r, g, b);
|
|
}
|
|
|
|
float3 AnisoDebugColor(float InAniso)
|
|
{
|
|
// Follow same mapping than raster buffer visualization (BP located in Engine/Contents/Anisotropy)
|
|
float AniG = saturate( InAniso);
|
|
float AniB = saturate(-InAniso);
|
|
return float3(0.0, pow(AniG, 2.2), pow(AniB, 2.2));
|
|
}
|
|
|
|
#define INCLUDE_TRANSLUCENT 0
|
|
|
|
PathTracingResult PathTracingDebugCore(FRayDesc Ray, uint2 LaunchIndex)
|
|
{
|
|
const uint RayFlags = RAY_FLAG_CULL_BACK_FACING_TRIANGLES;
|
|
#if INCLUDE_TRANSLUCENT
|
|
const uint InstanceInclusionMask = PATHTRACER_MASK_CAMERA | PATHTRACER_MASK_CAMERA_TRANSLUCENT;
|
|
#else
|
|
const uint InstanceInclusionMask = PATHTRACER_MASK_CAMERA;
|
|
#endif
|
|
const uint MissShaderIndex = 0;
|
|
|
|
FPackedPathTracingPayload PackedPayload = InitPathTracingPayload(PATHTRACER_SCATTER_CAMERA, 0.0);
|
|
{
|
|
RandomSequence RandSequence;
|
|
RandomSequence_Initialize(RandSequence, LaunchIndex, 0, View.StateFrameIndex, 1);
|
|
PackedPayload.SetStochasticSlabRand(RandomSequence_GenerateSample1D(RandSequence));
|
|
}
|
|
#if !INCLUDE_TRANSLUCENT
|
|
PackedPayload.SetFlag(PATH_TRACING_PAYLOAD_INPUT_FLAG_IGNORE_TRANSLUCENT);
|
|
#endif
|
|
TraceRay(
|
|
TLAS,
|
|
RayFlags,
|
|
InstanceInclusionMask,
|
|
RAY_TRACING_SHADER_SLOT_MATERIAL,
|
|
RAY_TRACING_NUM_SHADER_SLOTS,
|
|
MissShaderIndex,
|
|
Ray.GetNativeDesc(),
|
|
PackedPayload);
|
|
float4 Result = float4(0, 0, 0, 1);
|
|
float Z = 0;
|
|
if (PackedPayload.IsHit())
|
|
{
|
|
const float3 ViewZ = View.ViewToTranslatedWorld[2].xyz;
|
|
Z = ConvertToDeviceZ(dot(Ray.Origin + PackedPayload.HitT * Ray.Direction, ViewZ));
|
|
}
|
|
|
|
|
|
|
|
if (DebugMode == PATH_TRACER_DEBUG_VIZ_VOLUME_LIGHT_COUNT)
|
|
{
|
|
float TMax = PackedPayload.IsHit() ? PackedPayload.HitT : Ray.TMax;
|
|
int NumLights = 0;
|
|
for (int LightId = SceneInfiniteLightCount; LightId < SceneLightCount; LightId++)
|
|
{
|
|
FVolumeLightSampleSetup LightSetup = PrepareLightVolumeSample(LightId, Ray.Origin, Ray.Direction, Ray.TMin, TMax);
|
|
if (LightSetup.IsValid())
|
|
{
|
|
float LightProb = LightSetup.LightImportance * GetVolumetricScatteringIntensity(LightId);
|
|
if (LightProb > 0)
|
|
{
|
|
NumLights++;
|
|
if (NumLights == RAY_TRACING_LIGHT_COUNT_MAXIMUM)
|
|
{
|
|
// reached max
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
float NumLightsMax = min(SceneLightCount - SceneInfiniteLightCount, RAY_TRACING_LIGHT_COUNT_MAXIMUM);
|
|
Result.rgb = NumLights > 0 ? BlueGreenRedColorMap(saturate(float(NumLights) / NumLightsMax)) : 0.18;
|
|
if (PackedPayload.IsHit())
|
|
{
|
|
Result.rgb *= abs(dot(PackedPayload.UnpackWorldNormal(), Ray.Direction));
|
|
}
|
|
return MakeResult(Result.rgb, Result.a, Z);
|
|
}
|
|
|
|
|
|
|
|
float LightPickingCdf[RAY_TRACING_LIGHT_COUNT_MAXIMUM];
|
|
float LightPickingCdfSum = 0;
|
|
float3 PathThroughput = 1;
|
|
if (PackedPayload.IsHit())
|
|
{
|
|
const float3 TranslatedWorldPos = Ray.Origin + PackedPayload.HitT * Ray.Direction;
|
|
const float3 WorldNormal = PackedPayload.UnpackWorldNormal();
|
|
const uint PrimitiveLightingChannelMask = PackedPayload.GetPrimitiveLightingChannelMask();
|
|
|
|
FLightLoopCount LightLoopCount = LightGridLookup(TranslatedWorldPos);
|
|
|
|
switch (DebugMode)
|
|
{
|
|
case PATH_TRACER_DEBUG_VIZ_RADIANCE: return MakeResult(PackedPayload.UnpackRadiance() * View.PreExposure, 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_WORLD_NORMAL: return MakeResult(WorldNormal * 0.5 + 0.5, 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_WORLD_SMOOTH_NORMAL: return MakeResult(PackedPayload.UnpackWorldSmoothNormal() * 0.5 + 0.5, 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_WORLD_GEO_NORMAL: return MakeResult(PackedPayload.UnpackWorldGeoNormal() * 0.5 + 0.5, 0.0, Z);
|
|
default:
|
|
#if SUBSTRATE_ENABLED
|
|
// TODO: implement more visualizations for this case
|
|
case PATH_TRACER_DEBUG_VIZ_BASE_COLOR: return MakeResult(lerp(PackedPayload.UnpackDiffuseColor(), PackedPayload.UnpackSpecularColor(), F0RGBToMetallic(PackedPayload.UnpackSpecularColor())), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_DIFFUSE_COLOR: return MakeResult(PackedPayload.UnpackDiffuseColor(), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_SPECULAR_COLOR: return MakeResult(PackedPayload.UnpackSpecularColor(), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_METALLIC: return MakeResult(F0RGBToMetallic(PackedPayload.UnpackSpecularColor()), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_SPECULAR: return MakeResult(F0RGBToDielectricSpecular(PackedPayload.UnpackSpecularColor()), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_ROUGHNESS: return MakeResult(PackedPayload.UnpackRoughnessAniso().xyz, 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_ANISOTROPY: return MakeResult(AnisoDebugColor(PackedPayload.UnpackRoughnessAniso().w), 0.0, Z);
|
|
#else
|
|
case PATH_TRACER_DEBUG_VIZ_BASE_COLOR: return MakeResult(PackedPayload.UnpackBaseColor(), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_DIFFUSE_COLOR: return MakeResult(PackedPayload.UnpackBaseColor() * (1 - PackedPayload.UnpackMetallic()), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_SPECULAR_COLOR: return MakeResult(lerp(0.08 * PackedPayload.UnpackSpecular(), PackedPayload.UnpackBaseColor(), PackedPayload.UnpackMetallic()), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_METALLIC: return MakeResult(PackedPayload.UnpackMetallic(), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_SPECULAR: return MakeResult(PackedPayload.UnpackSpecular(), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_ROUGHNESS: return MakeResult(PackedPayload.UnpackRoughness(), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_ANISOTROPY: return MakeResult(AnisoDebugColor(PackedPayload.UnpackAnisotropy()), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_CUSTOM_DATA0: return MakeResult(PackedPayload.UnpackCustomData0().rgb * View.PreExposure, PackedPayload.UnpackCustomData0().a, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_CUSTOM_DATA1: return MakeResult(PackedPayload.UnpackCustomData1().rgb * View.PreExposure, PackedPayload.UnpackCustomData1().a, Z);
|
|
#endif
|
|
case PATH_TRACER_DEBUG_VIZ_OPACITY: return MakeResult(PackedPayload.UnpackTransparencyColor(), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_IOR: return MakeResult(PackedPayload.UnpackIor(), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_SHADING_MODEL: return MakeResult(GetShadingModelColor(PackedPayload.GetShadingModelID()), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_LIGHTING_CHANNEL_MASK: return MakeResult(GetLightingChannelMaskDebugColor(PackedPayload.GetPrimitiveLightingChannelMask()), 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_WORLD_POSITION: {
|
|
float3 AbsoluteWorldPosition = DFDemote(DFFastSubtract(TranslatedWorldPos, ResolvedView.PreViewTranslation));
|
|
const float CellWidth = 10.0f; // 10cm
|
|
int3 Coord = int3(round(AbsoluteWorldPosition / CellWidth));
|
|
uint HashIndex = Rand3DPCG32(Coord).x;
|
|
float3 Color = HUEtoRGB((HashIndex & 0xFFFFFF) * 5.96046447754e-08);
|
|
Color *= abs(dot(WorldNormal, Ray.Direction));
|
|
return MakeResult(Color * View.PreExposure, 0.0, Z);
|
|
}
|
|
case PATH_TRACER_DEBUG_VIZ_PRIMARY_RAYS: break; // fallthrough to implementation below
|
|
case PATH_TRACER_DEBUG_VIZ_WORLD_TANGENT: return MakeResult(PackedPayload.UnpackWorldTangent() * 0.5 + 0.5, 0.0, Z);
|
|
case PATH_TRACER_DEBUG_VIZ_LIGHT_GRID_COUNT:
|
|
case PATH_TRACER_DEBUG_VIZ_LIGHT_GRID_AXIS:
|
|
{
|
|
|
|
float3 Color = LightGridVisualize(LightLoopCount, DebugMode == PATH_TRACER_DEBUG_VIZ_LIGHT_GRID_AXIS ? 4 : 1);
|
|
Color *= abs(dot(WorldNormal, Ray.Direction));
|
|
return MakeResult(Color, 0.0, Z);
|
|
}
|
|
case PATH_TRACER_DEBUG_VIZ_DECAL_GRID_COUNT:
|
|
case PATH_TRACER_DEBUG_VIZ_DECAL_GRID_AXIS:
|
|
{
|
|
FDecalLoopCount DecalLoopCount = DecalGridLookup(TranslatedWorldPos);
|
|
float3 Color = PackedPayload.IsDecalReceiver() ? DecalGridVisualize(DecalLoopCount, DebugMode == PATH_TRACER_DEBUG_VIZ_DECAL_GRID_AXIS ? 3 : 1) : 0.18;
|
|
Color *= abs(dot(WorldNormal, Ray.Direction));
|
|
return MakeResult(Color, 0.0, Z);
|
|
}
|
|
case PATH_TRACER_DEBUG_VIZ_HITKIND:
|
|
{
|
|
return MakeResult((PackedPayload.IsFrontFace() ? float3(0, 1, 0) : float3(1, 0, 0)) * abs(dot(WorldNormal, Ray.Direction)), 0.0, Z);
|
|
}
|
|
}
|
|
|
|
FPathTracingPayload Payload = UnpackPathTracingPayload(PackedPayload, Ray);
|
|
AdjustPayloadAfterUnpack(Payload, true);
|
|
#if LIGHT_LOOP_METHOD == 0
|
|
for (uint Index = 0, Num = LightLoopCount.NumLights; Index < Num; ++Index)
|
|
{
|
|
uint LightIndex = GetLightId(Index, LightLoopCount);
|
|
float LightEstimate = EstimateLight(LightIndex, TranslatedWorldPos, WorldNormal, PrimitiveLightingChannelMask, false);
|
|
LightPickingCdfSum += LightEstimate;
|
|
LightPickingCdf[Index] = LightPickingCdfSum;
|
|
}
|
|
|
|
if (LightPickingCdfSum > 0)
|
|
{
|
|
// init worked
|
|
int LightId;
|
|
float LightPickPdf = 0;
|
|
|
|
for (int Sample = 0; Sample < NumLightSamples; Sample++)
|
|
{
|
|
RandomSequence RandSequence;
|
|
RandomSequence_Initialize(RandSequence, LaunchIndex, Sample, View.StateFrameIndex, NumLightSamples);
|
|
float4 RandSample = RandomSequence_GenerateSample4D(RandSequence);
|
|
|
|
FMaterialSample MaterialSample = SampleMaterial(-Ray.Direction, Payload, RandSample.xyz);
|
|
|
|
SelectLight(RandSample.x * LightPickingCdfSum, LightLoopCount.NumLights, LightPickingCdf, LightId, LightPickPdf);
|
|
LightPickPdf /= LightPickingCdfSum;
|
|
float2 LightRandSample = RandSample.yz;
|
|
LightId = GetLightId(LightId, LightLoopCount);
|
|
#else
|
|
for (int Sample = 0; Sample < NumLightSamples; Sample++)
|
|
{
|
|
RandomSequence RandSequence;
|
|
RandomSequence_Initialize(RandSequence, LaunchIndex, Sample, View.StateFrameIndex, NumLightSamples);
|
|
float3 RandSample = RandomSequence_GenerateSample3D(RandSequence);
|
|
float2 LightRandSample = RandSample.xy;
|
|
|
|
#if LIGHT_LOOP_METHOD == 2
|
|
FRISContext TraceSample = InitRISContext(RandSample.z);
|
|
FRayDesc ShadowRaySample;
|
|
float3 ShadowRayContrib = 0;
|
|
uint ShadowRayLightId;
|
|
#endif
|
|
|
|
FMaterialSample MaterialSample = SampleMaterial(-Ray.Direction, Payload, RandSample.xyz);
|
|
for (uint Index = 0, Num = LightLoopCount.NumLights; Index < Num; ++Index)
|
|
{
|
|
uint LightId = GetLightId(Index, LightLoopCount);
|
|
const float LightPickPdf = 1;
|
|
#endif
|
|
|
|
FLightSample LightSample = SampleLight(LightId, LightRandSample, TranslatedWorldPos, WorldNormal);
|
|
|
|
if (LightSample.Pdf > 0)
|
|
{
|
|
LightSample.RadianceOverPdf /= LightPickPdf;
|
|
LightSample.Pdf *= LightPickPdf;
|
|
|
|
#if 1
|
|
FMaterialEval MaterialEval = EvalMaterial(-Ray.Direction, LightSample.Direction, Payload, 1.0);
|
|
float3 LightContrib = PathThroughput * LightSample.RadianceOverPdf * MaterialEval.Weight * MaterialEval.Pdf;
|
|
#if USE_BSDF_SAMPLING
|
|
LightContrib *= MISWeightPower(LightSample.Pdf, MaterialEval.Pdf);
|
|
#endif
|
|
|
|
#else
|
|
#if SUBSTRATE_ENABLED
|
|
float3 MaterialEvalWeight = PackedPayload.UnpackDiffuseColor();
|
|
#else
|
|
float3 MaterialEvalWeight = PackedPayload.UnpackBaseColor();
|
|
#endif
|
|
float MaterialEvalPdf = saturate(dot(WorldNormal, LightSample.Direction)) / PI;
|
|
float3 LightContrib = PathThroughput * LightSample.RadianceOverPdf * MaterialEvalWeight * MaterialEvalPdf;
|
|
#endif
|
|
{
|
|
FRayDesc ShadowRay;
|
|
ShadowRay.Origin = TranslatedWorldPos;
|
|
ShadowRay.Direction = LightSample.Direction;
|
|
ShadowRay.TMin = 0;
|
|
ShadowRay.TMax = LightSample.Distance;
|
|
|
|
ApplyRayBias(ShadowRay.Origin, PackedPayload.HitT, PackedPayload.UnpackWorldGeoNormal());
|
|
|
|
#if LIGHT_LOOP_METHOD == 2
|
|
float SelectionWeight = LightContrib.x + LightContrib.y + LightContrib.z;
|
|
if (TraceSample.Accept(SelectionWeight))
|
|
{
|
|
ShadowRaySample = ShadowRay;
|
|
ShadowRayContrib = LightContrib / SelectionWeight;
|
|
ShadowRayLightId = LightId;
|
|
}
|
|
#else
|
|
const bool bCastShadows = CastsShadow(LightId);
|
|
const uint MissShaderIndex = GetLightMissShaderIndex(LightId);
|
|
Result.xyz += LightContrib * TraceShadowRay(ShadowRay, 1.0, 0.0, MissShaderIndex, bCastShadows);
|
|
#endif
|
|
}
|
|
}
|
|
#if USE_BSDF_SAMPLING
|
|
{
|
|
FRayDesc ShadowRay;
|
|
ShadowRay.Origin = TranslatedWorldPos;
|
|
ShadowRay.Direction = MaterialSample.Direction;
|
|
ShadowRay.TMin = 0;
|
|
ShadowRay.TMax = RAY_DEFAULT_T_MAX;
|
|
|
|
ApplyRayBias(ShadowRay.Origin, PackedPayload.HitT, PackedPayload.UnpackWorldGeoNormal());
|
|
|
|
FLightHit LightResult = TraceLight(ShadowRay, LightId);
|
|
if (LightResult.IsHit())
|
|
{
|
|
ShadowRay.TMax = LightResult.HitT;
|
|
float3 LightContrib = PathThroughput * MaterialSample.Weight * LightResult.Radiance;
|
|
LightContrib *= MISWeightPower(MaterialSample.Pdf, LightResult.Pdf * LightPickPdf);
|
|
#if LIGHT_LOOP_METHOD == 2
|
|
float SelectionWeight = LightContrib.x + LightContrib.y + LightContrib.z;
|
|
if (TraceSample.Accept(SelectionWeight))
|
|
{
|
|
ShadowRaySample = ShadowRay;
|
|
ShadowRayContrib = LightContrib / SelectionWeight;
|
|
ShadowRayLightId = LightId;
|
|
}
|
|
#else
|
|
const bool bCastShadows = CastsShadow(LightId);
|
|
const uint MissShaderIndex = GetLightMissShaderIndex(LightId);
|
|
Result.xyz += LightContrib * TraceShadowRay(ShadowRay, 1.0, 0.0, MissShaderIndex, bCastShadows);
|
|
#endif
|
|
}
|
|
}
|
|
#endif // USE_BSDF_SAMPLING
|
|
}
|
|
#if LIGHT_LOOP_METHOD == 2
|
|
if (TraceSample.HasSample())
|
|
{
|
|
const bool bCastShadows = CastsShadow(ShadowRayLightId);
|
|
const uint MissShaderIndex = GetLightMissShaderIndex(ShadowRayLightId);
|
|
ShadowRayContrib *= TraceSample.GetNormalization();
|
|
Result.xyz += ShadowRayContrib * TraceShadowRay(ShadowRaySample, 1.0, 0.0, MissShaderIndex, bCastShadows);
|
|
}
|
|
#endif
|
|
}
|
|
Result.rgb = Result.rgb * (NumLightSamples > 1 ? 1.0 / NumLightSamples : 1.0) + PackedPayload.UnpackRadiance();
|
|
float3 IndirectRadiance = 0;
|
|
for (int Sample = 0; Sample < NumIndirectSamples; Sample++)
|
|
{
|
|
RandomSequence RandSequence;
|
|
RandomSequence_Initialize(RandSequence, LaunchIndex, Sample, View.StateFrameIndex, NumIndirectSamples);
|
|
float3 RandSample = RandomSequence_GenerateSample3D(RandSequence);
|
|
FMaterialSample MaterialSample = SampleMaterial(-Ray.Direction, Payload, RandSample.xyz);
|
|
|
|
const uint RayFlags = 0;
|
|
const uint InstanceInclusionMask = PATHTRACER_MASK_INDIRECT;
|
|
const uint RayContributionToHitGroupIndex = RAY_TRACING_SHADER_SLOT_MATERIAL;
|
|
const uint MultiplierForGeometryContributionToShaderIndex = RAY_TRACING_NUM_SHADER_SLOTS;
|
|
|
|
FRayDesc Ray;
|
|
Ray.Origin = TranslatedWorldPos;
|
|
Ray.Direction = MaterialSample.Direction;
|
|
Ray.TMin = 0;
|
|
Ray.TMax = RAY_DEFAULT_T_MAX;
|
|
|
|
ApplyRayBias(Ray.Origin, PackedPayload.HitT, PackedPayload.UnpackWorldGeoNormal());
|
|
|
|
FPackedPathTracingPayload PackedPayloadIndirect = InitPathTracingPayload(MaterialSample.ScatterType, MaterialSample.Roughness);
|
|
#if PATH_TRACER_USE_SER
|
|
NvHitObject Hit;
|
|
NvTraceRayHitObject(
|
|
TLAS,
|
|
RayFlags,
|
|
InstanceInclusionMask,
|
|
RayContributionToHitGroupIndex,
|
|
MultiplierForGeometryContributionToShaderIndex,
|
|
MissShaderIndex,
|
|
Ray.GetNativeDesc(),
|
|
PackedPayloadIndirect,
|
|
Hit);
|
|
NvReorderThread(Hit);
|
|
NvInvokeHitObject(TLAS, Hit, PackedPayloadIndirect);
|
|
#else
|
|
TraceRay(
|
|
TLAS,
|
|
RayFlags,
|
|
InstanceInclusionMask,
|
|
RayContributionToHitGroupIndex,
|
|
MultiplierForGeometryContributionToShaderIndex,
|
|
MissShaderIndex,
|
|
Ray.GetNativeDesc(),
|
|
PackedPayloadIndirect);
|
|
#endif
|
|
IndirectRadiance += MaterialSample.Weight * PackedPayloadIndirect.UnpackRadiance();
|
|
}
|
|
Result.rgb += IndirectRadiance * (NumIndirectSamples > 1 ? 1.0 / NumIndirectSamples : 1.0);
|
|
Result.a = 0;
|
|
}
|
|
return MakeResult(Result.rgb * View.PreExposure, Result.a, Z);
|
|
}
|
|
|
|
|
|
RAY_TRACING_ENTRY_RAYGEN(PathTracingDebugRG)
|
|
{
|
|
uint2 DispatchIdx = DispatchRaysIndex().xy;
|
|
const uint2 DispatchDim = DispatchRaysDimensions().xy;
|
|
|
|
ResolvedView = ResolveView();
|
|
|
|
uint2 LaunchIndex = DispatchIdx + View.ViewRectMin.xy;
|
|
|
|
|
|
const float2 AAJitter = 0.5; // trace through pixel center
|
|
const float2 ViewportUV = (LaunchIndex + AAJitter) * View.BufferSizeAndInvSize.zw;
|
|
|
|
|
|
PathTracingResult Result = PathTracingDebugCore(CreatePrimaryRay(ViewportUV), LaunchIndex);
|
|
|
|
RWSceneColor[DispatchIdx] = Result.Radiance;
|
|
RWSceneDepth[DispatchIdx] = Result.Z;
|
|
}
|