446 lines
17 KiB
HLSL
446 lines
17 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "../../HeterogeneousVolumes/HeterogeneousVolumesTracingUtils.ush"
|
|
#include "../../HeterogeneousVolumes/HeterogeneousVolumesVoxelGridTraversal.ush"
|
|
#include "../Utilities/PathTracingRandomSequence.ush"
|
|
#include "PathTracingVolumeSampling.ush"
|
|
|
|
float3 GetTranslatedWorldPos(float3 WorldPos)
|
|
{
|
|
float3 TranslatedWorldPos = DFFastToTranslatedWorld(WorldPos, PrimaryView.PreViewTranslation);
|
|
return TranslatedWorldPos;
|
|
}
|
|
|
|
float GetPhaseG()
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
FVolumeIntersection HeterogeneousVolumesIntersect(float3 Origin, float3 Direction, float TMin, float TMax)
|
|
{
|
|
float3 WorldBoundsMin = FrustumGridUniformBuffer.TopLevelGridWorldBoundsMin;
|
|
float3 WorldBoundsMax = FrustumGridUniformBuffer.TopLevelGridWorldBoundsMax;
|
|
if (OrthoGridUniformBuffer.bUseOrthoGrid)
|
|
{
|
|
WorldBoundsMin = OrthoGridUniformBuffer.TopLevelGridWorldBoundsMin;
|
|
WorldBoundsMax = OrthoGridUniformBuffer.TopLevelGridWorldBoundsMax;
|
|
}
|
|
|
|
if (OrthoGridUniformBuffer.bUseOrthoGrid || FrustumGridUniformBuffer.bUseFrustumGrid)
|
|
{
|
|
float3 TranslatedWorldBoundsMin = GetTranslatedWorldPos(WorldBoundsMin);
|
|
float3 TranslatedWorldBoundsMax = GetTranslatedWorldPos(WorldBoundsMax);
|
|
|
|
float2 RayHitT = IntersectAABB(
|
|
Origin,
|
|
Direction,
|
|
TMin,
|
|
TMax,
|
|
TranslatedWorldBoundsMin,
|
|
TranslatedWorldBoundsMax
|
|
);
|
|
|
|
return CreateVolumeIntersection(RayHitT.x, RayHitT.y);
|
|
}
|
|
return CreateEmptyVolumeIntersection();
|
|
}
|
|
|
|
FVolumeDensityBounds HeterogeneousVolumesGetDensityBounds(float3 Origin, float3 Direction, float TMin, float TMax)
|
|
{
|
|
// Density bounds are iteratively discovered when executing the DDA on the majorant grid
|
|
return CreateVolumeDensityBound(0, 0);
|
|
}
|
|
|
|
FVolumeShadedResult GetOrthoVoxelGridDensity(float3 TranslatedWorldPos)
|
|
{
|
|
float3 SigmaT = 0.0;
|
|
float3 Albedo = 0.0;
|
|
float3 Emission = 0.0;
|
|
|
|
float3 TranslatedWorldBoundsMin = GetTranslatedWorldPos(OrthoGridUniformBuffer.TopLevelGridWorldBoundsMin);
|
|
float3 TranslatedWorldBoundsMax = GetTranslatedWorldPos(OrthoGridUniformBuffer.TopLevelGridWorldBoundsMax);
|
|
float3 TranslatedWorldBoundsExtent = TranslatedWorldBoundsMax - TranslatedWorldBoundsMin;
|
|
float3 GridUV = (TranslatedWorldPos - TranslatedWorldBoundsMin) / TranslatedWorldBoundsExtent;
|
|
if (all(GridUV >= 0.0) && all(GridUV <= 1.0))
|
|
{
|
|
float3 TopLevelVoxelPos = GridUV * OrthoGridUniformBuffer.TopLevelGridResolution;
|
|
uint LinearTopLevelVoxelPos = GetLinearIndex(TopLevelVoxelPos, OrthoGridUniformBuffer.TopLevelGridResolution);
|
|
|
|
if (OrthoGridUniformBuffer.bEnableIndirectionGrid)
|
|
{
|
|
FTopLevelGridData TopLevelGridData = OrthoGridUniformBuffer.TopLevelGridBuffer[LinearTopLevelVoxelPos];
|
|
if (IsBottomLevelAllocated(TopLevelGridData))
|
|
{
|
|
uint IndirectionGridIndex = GetBottomLevelIndex(TopLevelGridData);
|
|
uint3 IndirectionGridVoxelResolution = GetBottomLevelVoxelResolution(TopLevelGridData);
|
|
|
|
// Convert to Indirection voxel-space
|
|
float3 IndirectionGridVoxelPos = frac(TopLevelVoxelPos) * IndirectionGridVoxelResolution;
|
|
int3 IndirectionGridVoxelPosAsInt = clamp(IndirectionGridVoxelPos, 0, IndirectionGridVoxelResolution - 1);
|
|
FTopLevelGridData IndirectionData = OrthoGridUniformBuffer.IndirectionGridBuffer[IndirectionGridIndex + MortonEncode3(IndirectionGridVoxelPosAsInt)];
|
|
if (IsBottomLevelAllocated(IndirectionData))
|
|
{
|
|
uint BottomLevelIndex = GetBottomLevelIndex(IndirectionData);
|
|
uint3 BottomLevelVoxelResolution = GetBottomLevelVoxelResolution(IndirectionData);
|
|
|
|
// Constant interpolation
|
|
float3 BottomLevelVoxelPos = frac(IndirectionGridVoxelPos) * BottomLevelVoxelResolution;
|
|
int3 BottomLevelVoxelPosAsInt = clamp(BottomLevelVoxelPos, 0, BottomLevelVoxelResolution - 1);
|
|
uint LinearBottomLevelVoxelPos = BottomLevelIndex + MortonEncode3(BottomLevelVoxelPosAsInt);
|
|
SigmaT = GetExtinction(OrthoGridUniformBuffer.ExtinctionGridBuffer[LinearBottomLevelVoxelPos]);
|
|
Albedo = GetAlbedo(OrthoGridUniformBuffer.ScatteringGridBuffer[LinearBottomLevelVoxelPos]);
|
|
Emission = GetEmission(OrthoGridUniformBuffer.EmissionGridBuffer[LinearBottomLevelVoxelPos]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FTopLevelGridData TopLevelData = OrthoGridUniformBuffer.TopLevelGridBuffer[LinearTopLevelVoxelPos];
|
|
if (IsBottomLevelAllocated(TopLevelData))
|
|
{
|
|
uint BottomLevelIndex = GetBottomLevelIndex(OrthoGridUniformBuffer.TopLevelGridBuffer[LinearTopLevelVoxelPos]);
|
|
uint3 BottomLevelVoxelResolution = GetBottomLevelVoxelResolution(OrthoGridUniformBuffer.TopLevelGridBuffer[LinearTopLevelVoxelPos]);
|
|
|
|
// Constant Interpolation
|
|
float3 BottomLevelVoxelPos = frac(TopLevelVoxelPos) * BottomLevelVoxelResolution;
|
|
int3 BottomLevelVoxelPosAsInt = clamp(BottomLevelVoxelPos, 0, BottomLevelVoxelResolution - 1);
|
|
uint LinearBottomLevelVoxelPos = BottomLevelIndex + MortonEncode3(BottomLevelVoxelPosAsInt);
|
|
|
|
SigmaT = GetExtinction(OrthoGridUniformBuffer.ExtinctionGridBuffer[LinearBottomLevelVoxelPos]);
|
|
Albedo = GetAlbedo(OrthoGridUniformBuffer.ScatteringGridBuffer[LinearBottomLevelVoxelPos]);
|
|
Emission = GetEmission(OrthoGridUniformBuffer.EmissionGridBuffer[LinearBottomLevelVoxelPos]);
|
|
}
|
|
}
|
|
}
|
|
|
|
FVolumeShadedResult Result = (FVolumeShadedResult)0;
|
|
Result.SigmaT = SigmaT;
|
|
Result.SigmaSHG = Albedo;
|
|
Result.PhaseG = GetPhaseG();
|
|
Result.Emission = Emission;
|
|
|
|
return Result;
|
|
}
|
|
|
|
FVolumeShadedResult GetFrustumVoxelGridDensity(float3 TranslatedWorldPos, inout bool bInFrustum)
|
|
{
|
|
float3 SigmaT = 0.0;
|
|
float3 Albedo = 0.0;
|
|
float3 Emission = 0.0;
|
|
|
|
// Convert TranslatedWorldPos to voxel space
|
|
float3 WorldPos = DFHackToFloat(DFFastSubtract(TranslatedWorldPos, PrimaryView.PreViewTranslation));
|
|
float3 ViewPos = mul(float4(WorldPos, 1), FrustumGridUniformBuffer.WorldToView).xyz;
|
|
|
|
int3 VoxelDimensions = FrustumGridUniformBuffer.VoxelDimensions;
|
|
float NearPlaneDepth = FrustumGridUniformBuffer.NearPlaneDepth;
|
|
float FarPlaneDepth = FrustumGridUniformBuffer.FarPlaneDepth;
|
|
float TanHalfFOV = FrustumGridUniformBuffer.TanHalfFOV;
|
|
float3 VoxelPos = ViewToVoxel(ViewPos, VoxelDimensions, NearPlaneDepth, FarPlaneDepth, TanHalfFOV);
|
|
|
|
bInFrustum = all(VoxelPos > 0) && all(VoxelPos < FrustumGridUniformBuffer.TopLevelFroxelGridResolution);
|
|
if (bInFrustum)
|
|
{
|
|
uint LinearTopLevelVoxelPos = GetLinearIndex(VoxelPos, FrustumGridUniformBuffer.TopLevelFroxelGridResolution);
|
|
FTopLevelGridData TopLevelGridData = FrustumGridUniformBuffer.TopLevelFroxelGridBuffer[LinearTopLevelVoxelPos];
|
|
if (IsBottomLevelAllocated(TopLevelGridData))
|
|
{
|
|
uint BottomLevelIndex = GetBottomLevelIndex(TopLevelGridData);
|
|
uint3 BottomLevelVoxelResolution = GetBottomLevelVoxelResolution(TopLevelGridData);
|
|
|
|
float3 BottomLevelVoxelPos = frac(VoxelPos) * BottomLevelVoxelResolution;
|
|
uint LinearBottomLevelVoxelPos = BottomLevelIndex + MortonEncode3(uint3(BottomLevelVoxelPos));
|
|
SigmaT = GetExtinction(FrustumGridUniformBuffer.ExtinctionFroxelGridBuffer[LinearBottomLevelVoxelPos]);
|
|
Albedo = GetAlbedo(FrustumGridUniformBuffer.ScatteringFroxelGridBuffer[LinearBottomLevelVoxelPos]);
|
|
Emission = GetEmission(FrustumGridUniformBuffer.EmissionFroxelGridBuffer[LinearBottomLevelVoxelPos]);
|
|
}
|
|
}
|
|
|
|
// Return struct
|
|
FVolumeShadedResult Result = (FVolumeShadedResult) 0;
|
|
Result.SigmaT = SigmaT;
|
|
Result.SigmaSHG = Albedo;
|
|
Result.PhaseG = GetPhaseG();
|
|
Result.Emission = Emission;
|
|
return Result;
|
|
}
|
|
|
|
FVolumeShadedResult HeterogeneousVolumesGetDensity(float3 TranslatedWorldPos)
|
|
{
|
|
FVolumeShadedResult Result = (FVolumeShadedResult) 0;
|
|
|
|
bool bInFrustum = false;
|
|
if (FrustumGridUniformBuffer.bUseFrustumGrid)
|
|
{
|
|
Result = GetFrustumVoxelGridDensity(TranslatedWorldPos, bInFrustum);
|
|
}
|
|
if (!bInFrustum && OrthoGridUniformBuffer.bUseOrthoGrid)
|
|
{
|
|
Result = GetOrthoVoxelGridDensity(TranslatedWorldPos);
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
struct FVolumeTrackingResult
|
|
{
|
|
float3 Throughput;
|
|
float Pdf;
|
|
float Distance;
|
|
float3 SigmaBar;
|
|
bool bIsCollision;
|
|
};
|
|
|
|
FVolumeTrackingResult CreateVolumeTrackingResult(float Distance)
|
|
{
|
|
FVolumeTrackingResult Result = (FVolumeTrackingResult)0;
|
|
Result.Throughput = 1;
|
|
Result.Pdf = 0;
|
|
Result.Distance = Distance;
|
|
Result.SigmaBar = 0;
|
|
Result.bIsCollision = false;
|
|
|
|
return Result;
|
|
}
|
|
|
|
// Concatenates the result of rhs onto lhs
|
|
FVolumeTrackingResult ConcatenateVolumeTrackingResult(FVolumeTrackingResult lhs, FVolumeTrackingResult rhs)
|
|
{
|
|
FVolumeTrackingResult Result;
|
|
Result.Throughput = lhs.Throughput * rhs.Throughput;
|
|
Result.Pdf = lhs.Pdf * rhs.Pdf;
|
|
Result.Distance = lhs.Distance + rhs.Distance;
|
|
Result.SigmaBar = rhs.SigmaBar;
|
|
Result.bIsCollision = rhs.bIsCollision;
|
|
return Result;
|
|
}
|
|
|
|
FVolumeTrackingResult HeterogeneousVolumesDeltaTracking(float3 PathThroughput, float3 Origin, float3 Direction, float TMax, FMajorantData MajorantData, inout RandomSequence RandSequence)
|
|
{
|
|
FVolumeTrackingResult Sample = CreateVolumeTrackingResult(0);
|
|
Sample.SigmaBar = max(MajorantData.Majorant, 0);
|
|
|
|
float RandValue = RandomSequence_GenerateSample1D(RandSequence);
|
|
#define SAMPLE_ACHROMATIC 0
|
|
#if SAMPLE_ACHROMATIC
|
|
float DeltaT = -log(1.0 - RandValue) / Sample.SigmaBar.x;
|
|
#else
|
|
float DeltaT = SampleSpectralTransmittance(RandValue, Sample.SigmaBar, PathThroughput);
|
|
if (DeltaT < 0)
|
|
{
|
|
Sample.Throughput = 0;
|
|
Sample.Distance = -1;
|
|
return Sample;
|
|
}
|
|
#endif
|
|
|
|
Sample.Distance = min(Sample.Distance + DeltaT, TMax);
|
|
if (Sample.Distance < TMax)
|
|
{
|
|
Sample.bIsCollision = true;
|
|
float CollisionWeight = 1.0;
|
|
#if SAMPLE_ACHROMATIC
|
|
Sample.Throughput *= CollisionWeight / Sample.SigmaBar.x;
|
|
float Transmittance = exp(-Sample.SigmaBar.x * Sample.Distance);
|
|
Sample.Pdf = Transmittance * Sample.SigmaBar.x;
|
|
#else
|
|
float4 EvalResult = EvaluateSpectralTransmittanceHit(Sample.Distance, Sample.SigmaBar, PathThroughput);
|
|
Sample.Throughput = CollisionWeight * EvalResult.xyz;
|
|
Sample.Pdf = EvalResult.w;
|
|
}
|
|
else
|
|
{
|
|
float4 EvalResult = EvaluateSpectralTransmittanceMiss(Sample.Distance, Sample.SigmaBar, PathThroughput);
|
|
Sample.Throughput = EvalResult.xyz;
|
|
Sample.Pdf = EvalResult.w;
|
|
#endif
|
|
}
|
|
|
|
return Sample;
|
|
}
|
|
|
|
FVolumeTrackingResult HeterogeneousVolumesRatioTracking(float3 PathThroughput, float3 Origin, float3 Direction, float TMax, FMajorantData MajorantData, inout RandomSequence RandSequence)
|
|
{
|
|
FVolumeTrackingResult Sample = CreateVolumeTrackingResult(0);
|
|
Sample.SigmaBar = max(MajorantData.Majorant, 0);
|
|
|
|
while ((Sample.Distance < TMax))
|
|
{
|
|
float RandValue = RandomSequence_GenerateSample1D(RandSequence);
|
|
#if SAMPLE_ACHROMATIC
|
|
float DeltaT = -log(1.0 - RandValue) / Sample.SigmaBar.x;
|
|
#else
|
|
float3 CombinedThroughput = PathThroughput * Sample.Throughput;
|
|
float DeltaT = SampleSpectralTransmittance(RandValue, Sample.SigmaBar, CombinedThroughput);
|
|
if (DeltaT < 0)
|
|
{
|
|
Sample.Throughput = 0;
|
|
Sample.Distance = -1;
|
|
return Sample;
|
|
}
|
|
#endif
|
|
|
|
float CollisionDistance = Sample.Distance + DeltaT;
|
|
if (CollisionDistance < TMax)
|
|
{
|
|
float3 SamplePos = Origin + Direction * CollisionDistance;
|
|
float3 SigmaT = HeterogeneousVolumesGetDensity(SamplePos).SigmaT;
|
|
float3 SpectralNullCollisionWeight = max(Sample.SigmaBar - SigmaT, 0);
|
|
#if SAMPLE_ACHROMATIC
|
|
Sample.Throughput *= SpectralNullCollisionWeight / Sample.SigmaBar.x;
|
|
float Transmittance = exp(-Sample.SigmaBar.x * DeltaT);
|
|
Sample.Pdf *= Transmittance * Sample.SigmaBar.x;
|
|
#else
|
|
float4 EvalResult = EvaluateSpectralTransmittanceHit(DeltaT, Sample.SigmaBar, CombinedThroughput);
|
|
Sample.Throughput *= SpectralNullCollisionWeight * EvalResult.xyz;
|
|
Sample.Pdf *= EvalResult.w;
|
|
}
|
|
else
|
|
{
|
|
float4 EvalResult = EvaluateSpectralTransmittanceMiss(TMax - Sample.Distance, Sample.SigmaBar, CombinedThroughput);
|
|
Sample.Throughput *= EvalResult.xyz;
|
|
Sample.Pdf *= EvalResult.w;
|
|
#endif
|
|
}
|
|
|
|
Sample.Distance = min(CollisionDistance, TMax);
|
|
}
|
|
|
|
return Sample;
|
|
}
|
|
|
|
FVolumeTrackingResult HeterogeneousVolumesMajorantBasedTracking(float3 PathThroughput, float3 WorldRayOrigin, float3 Direction, float TMin, float TMax, int bTransmittanceOnly, FMajorantData OverlappingMajorant, inout RandomSequence RandSequence)
|
|
{
|
|
FVolumeTrackingResult Result = CreateVolumeTrackingResult(TMin);
|
|
Result.Throughput = PathThroughput;
|
|
|
|
float3 WorldRayBegin = WorldRayOrigin + Direction * TMin;
|
|
float3 WorldRayEnd = WorldRayOrigin + Direction * TMax;
|
|
float WorldRayTMax = length(WorldRayEnd - WorldRayBegin);
|
|
|
|
// Transform to voxel-space
|
|
float3 WorldBoundsMin = GetTranslatedWorldPos(OrthoGridUniformBuffer.TopLevelGridWorldBoundsMin);
|
|
float3 WorldBoundsMax = GetTranslatedWorldPos(OrthoGridUniformBuffer.TopLevelGridWorldBoundsMax);
|
|
float3 TopLevelGridWorldBoundsExtent = WorldBoundsMax - WorldBoundsMin;
|
|
float3 VoxelRayBegin = (WorldRayBegin - WorldBoundsMin) / TopLevelGridWorldBoundsExtent * OrthoGridUniformBuffer.TopLevelGridResolution;
|
|
float3 VoxelRayEnd = (WorldRayEnd - WorldBoundsMin) / TopLevelGridWorldBoundsExtent * OrthoGridUniformBuffer.TopLevelGridResolution;
|
|
float3 VoxelRayDirection = VoxelRayEnd - VoxelRayBegin;
|
|
float VoxelRayTMin = 0.0;
|
|
float VoxelRayTMax = length(VoxelRayDirection);
|
|
|
|
if (VoxelRayTMin >= VoxelRayTMax && !bTransmittanceOnly)
|
|
{
|
|
FVolumeTrackingResult Sample = HeterogeneousVolumesDeltaTracking(Result.Throughput, WorldRayBegin, Direction, TMax - TMin, OverlappingMajorant, RandSequence);
|
|
if (Sample.Distance > 0.0)
|
|
{
|
|
Result = ConcatenateVolumeTrackingResult(Result, Sample);
|
|
}
|
|
return Result;
|
|
}
|
|
VoxelRayDirection /= VoxelRayTMax;
|
|
|
|
float VoxelToWorldScale = WorldRayTMax / VoxelRayTMax;
|
|
|
|
// March majorant grid via DDA
|
|
float3 VoxelRayDirectionInv = 1.0 / VoxelRayDirection;
|
|
|
|
float VoxelRayMarchT = VoxelRayTMin;
|
|
float3 VoxelRayMarchPos = VoxelRayBegin;
|
|
|
|
float3 VoxelBoundsPos;
|
|
VoxelBoundsPos.x = sign(VoxelRayDirection.x) > 0 ? floor(VoxelRayMarchPos.x) + 1 : ceil(VoxelRayMarchPos.x) - 1;
|
|
VoxelBoundsPos.y = sign(VoxelRayDirection.y) > 0 ? floor(VoxelRayMarchPos.y) + 1 : ceil(VoxelRayMarchPos.y) - 1;
|
|
VoxelBoundsPos.z = sign(VoxelRayDirection.z) > 0 ? floor(VoxelRayMarchPos.z) + 1 : ceil(VoxelRayMarchPos.z) - 1;
|
|
|
|
float3 VoxelBoundsHitT = (VoxelBoundsPos - VoxelRayMarchPos) * VoxelRayDirectionInv;
|
|
|
|
// Remove floating-point rounding error
|
|
float Epsilon = 1.0e-4;
|
|
if (VoxelBoundsHitT.x <= Epsilon) VoxelBoundsHitT.x += abs(VoxelRayDirectionInv.x);
|
|
if (VoxelBoundsHitT.y <= Epsilon) VoxelBoundsHitT.y += abs(VoxelRayDirectionInv.y);
|
|
if (VoxelBoundsHitT.z <= Epsilon) VoxelBoundsHitT.z += abs(VoxelRayDirectionInv.z);
|
|
|
|
while ((VoxelRayMarchT < VoxelRayTMax) && any(Result.Throughput > Epsilon) && !Result.bIsCollision)
|
|
{
|
|
float VoxelRayMarchDeltaT = 0.0;
|
|
if (VoxelBoundsHitT.x < VoxelBoundsHitT.y)
|
|
{
|
|
if (VoxelBoundsHitT.x < VoxelBoundsHitT.z)
|
|
{
|
|
VoxelRayMarchDeltaT = VoxelBoundsHitT.x - VoxelRayMarchT;
|
|
VoxelBoundsHitT.x += abs(VoxelRayDirectionInv.x);
|
|
}
|
|
else
|
|
{
|
|
VoxelRayMarchDeltaT = VoxelBoundsHitT.z - VoxelRayMarchT;
|
|
VoxelBoundsHitT.z += abs(VoxelRayDirectionInv.z);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (VoxelBoundsHitT.y < VoxelBoundsHitT.z)
|
|
{
|
|
VoxelRayMarchDeltaT = VoxelBoundsHitT.y - VoxelRayMarchT;
|
|
VoxelBoundsHitT.y += abs(VoxelRayDirectionInv.y);
|
|
}
|
|
else
|
|
{
|
|
VoxelRayMarchDeltaT = VoxelBoundsHitT.z - VoxelRayMarchT;
|
|
VoxelBoundsHitT.z += abs(VoxelRayDirectionInv.z);
|
|
}
|
|
}
|
|
|
|
// Clip voxel delta-t by overall voxel ray-length.
|
|
if (VoxelRayMarchT + VoxelRayMarchDeltaT > VoxelRayTMax)
|
|
{
|
|
VoxelRayMarchDeltaT = VoxelRayTMax - VoxelRayMarchT;
|
|
}
|
|
|
|
// Sample at the midpoint of the voxel ray
|
|
float3 VoxelEndPos = VoxelRayMarchPos + VoxelRayDirection * VoxelRayMarchDeltaT;
|
|
float3 VoxelSamplePos = (VoxelRayMarchPos + VoxelEndPos) * 0.5;
|
|
uint VoxelSampleLinearPos = GetLinearIndex(VoxelSamplePos, OrthoGridUniformBuffer.TopLevelGridResolution);
|
|
FMajorantData MajorantData = GetMajorantData(OrthoGridUniformBuffer.MajorantGridBuffer[VoxelSampleLinearPos]);
|
|
MergeMajorantData(MajorantData, OverlappingMajorant);
|
|
|
|
float3 TrackingOrigin = WorldRayBegin + Direction * VoxelRayMarchT * VoxelToWorldScale;
|
|
float WorldRayMarchDeltaT = VoxelRayMarchDeltaT * VoxelToWorldScale;
|
|
|
|
FVolumeTrackingResult Sample;
|
|
if (bTransmittanceOnly)
|
|
{
|
|
Sample = HeterogeneousVolumesRatioTracking(Result.Throughput, TrackingOrigin, Direction, WorldRayMarchDeltaT, MajorantData, RandSequence);
|
|
}
|
|
else
|
|
{
|
|
Sample = HeterogeneousVolumesDeltaTracking(Result.Throughput, TrackingOrigin, Direction, WorldRayMarchDeltaT, MajorantData, RandSequence);
|
|
}
|
|
|
|
if (Sample.Distance < 0)
|
|
{
|
|
return Sample;
|
|
}
|
|
|
|
Result = ConcatenateVolumeTrackingResult(Result, Sample);
|
|
|
|
VoxelRayMarchT += VoxelRayMarchDeltaT;
|
|
VoxelRayMarchPos = VoxelEndPos;
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
float3 HeterogeneousVolumesGetTransmittance(float3 PathThroughput, float3 Origin, float3 Direction, float TMin, float TMax, inout RandomSequence RandSequence)
|
|
{
|
|
bool bTransmittanceOnly = true;
|
|
FMajorantData EmptyOverlappingMajorant = CreateMajorantData(0.0f, 0.0f);
|
|
return HeterogeneousVolumesMajorantBasedTracking(PathThroughput, Origin, Direction, TMin, TMax, bTransmittanceOnly, EmptyOverlappingMajorant, RandSequence).Throughput;
|
|
}
|
|
|
|
FVolumeTrackingResult HeterogeneousVolumesSampleDistance(float3 PathThroughput, float3 Origin, float3 Direction, float TMin, float TMax, FMajorantData OverlappingMajorant, inout RandomSequence RandSequence)
|
|
{
|
|
bool bTransmittanceOnly = false;
|
|
return HeterogeneousVolumesMajorantBasedTracking(PathThroughput, Origin, Direction, TMin, TMax, bTransmittanceOnly, OverlappingMajorant, RandSequence);
|
|
}
|