Files
UnrealEngine/Engine/Source/Programs/UnrealLightmass/Private/Lighting/LightingSystem.h
2025-05-18 13:04:45 +08:00

2830 lines
98 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "CPUSolver.h"
#include "ImportExport.h"
#include "LightingCache.h"
#include "Containers/ChunkedArray.h"
#include "Containers/List.h"
#include "HAL/Runnable.h"
#include "LightmapData.h"
#include "Math/PackedVector.h"
#include "GatheredLightingSample.h"
#include "LightmassScene.h"
namespace Lightmass
{
/** Whether to allow static lighting stats that may affect the system's performance. */
#define ALLOW_STATIC_LIGHTING_STATS 1
/**
* When enabled, makes Lightmass do pretty much no processing at all (NOP).
* Useful when iterating on import / export
*/
#define LIGHTMASS_DO_PROCESSING 1
#if ALLOW_STATIC_LIGHTING_STATS
#define LIGHTINGSTAT(x) x
#else
#define LIGHTINGSTAT(x)
#endif
/**
* The raw data which is used to construct a 2D light-map.
*/
class FGatheredLightMapData2D
{
public:
/** The width of the light-map. */
uint32 SizeX;
/** The height of the light-map. */
uint32 SizeY;
/** The lights which this light-map stores. */
TArray<const FLight*> Lights;
bool bHasSkyShadowing;
FGatheredLightMapData2D(uint32 InSizeX, uint32 InSizeY) :
SizeX(InSizeX),
SizeY(InSizeY),
bHasSkyShadowing(false)
{
Data.Empty(SizeX * SizeY);
Data.AddZeroed(SizeX * SizeY);
}
// Accessors.
const FGatheredLightMapSample& operator()(uint32 X,uint32 Y) const { return Data[SizeX * Y + X]; }
FGatheredLightMapSample& operator()(uint32 X,uint32 Y) { return Data[SizeX * Y + X]; }
uint32 GetSizeX() const { return SizeX; }
uint32 GetSizeY() const { return SizeY; }
void Empty()
{
Data.Empty();
SizeX = SizeY = 0;
Lights.Empty();
}
void AddLight(const FLight* NewLight)
{
Lights.AddUnique(NewLight);
}
FLightMapData2D* ConvertToLightmap2D(bool bDebugThisMapping, int32 PaddedDebugX, int32 PaddedDebugY) const;
private:
TArray<FGatheredLightMapSample> Data;
};
struct FFinalGatherInfo
{
FFinalGatherInfo() :
NumBackfaceHits(0),
NumSamplesOccluded(0)
{}
int32 NumBackfaceHits;
float NumSamplesOccluded;
};
struct FTexelCorner
{
FVector4f WorldPosition;
};
/** Information about a texel's corners */
struct FTexelToCorners
{
/** The position of each corner */
FTexelCorner Corners[NumTexelCorners];
/** The tangent basis of the last valid corner to be rasterized */
FVector4f WorldTangentX;
FVector4f WorldTangentY;
FVector4f WorldTangentZ;
/** Whether each corner lies on the mesh */
bool bValid[NumTexelCorners];
};
/** Map from texel to the corners of that texel. */
class FTexelToCornersMap
{
public:
/** Initialization constructor. */
FTexelToCornersMap(int32 InSizeX,int32 InSizeY):
SizeX(InSizeX),
SizeY(InSizeY)
{
// Clear the map to zero.
Data.AddZeroed(SizeX * SizeY);
}
// Accessors.
FTexelToCorners& operator()(int32 X,int32 Y)
{
const uint32 TexelIndex = Y * SizeX + X;
return Data[TexelIndex];
}
const FTexelToCorners& operator()(int32 X,int32 Y) const
{
const int32 TexelIndex = Y * SizeX + X;
return Data[TexelIndex];
}
int32 GetSizeX() const { return SizeX; }
int32 GetSizeY() const { return SizeY; }
void Empty() { Data.Empty(); }
private:
/** The mapping data. */
TArray<FTexelToCorners> Data;
/** The width of the mapping data. */
int32 SizeX;
/** The height of the mapping data. */
int32 SizeY;
};
/** A particle representing the distribution of a light's radiant power. */
class FPhoton
{
private:
/** Position that the photon was deposited at in XYZ, and Id in W for debugging. */
FVector4f PositionAndId;
/** Direction the photon came from in XYZ, and distance that the photon traveled along its last path before being deposited in W. */
FVector4f IncidentDirectionAndDistance;
/** Normal of the surface the photon was deposited on in XYZ, and fraction of the originating light's power that this photon represents in W. */
FVector4f SurfaceNormalAndPower;
public:
FPhoton(int32 InId, const FVector4f& InPosition, float InDistance, const FVector4f& InIncidentDirection, const FVector4f& InSurfaceNormal, const FLinearColor& InPower)
{
PositionAndId = FVector4f(InPosition, *(float*)&InId);
IncidentDirectionAndDistance = FVector4f(InIncidentDirection, InDistance);
checkSlow(FLinearColorUtils::AreFloatsValid(InPower));
const FColor PowerRGBE = InPower.ToRGBE();
SurfaceNormalAndPower = FVector4f(InSurfaceNormal, *(float*)&PowerRGBE);
}
FORCEINLINE int32 GetId() const
{
return *(int32*)&PositionAndId.W;
}
FORCEINLINE FVector4f GetPosition() const
{
return FVector4f(PositionAndId, 0.0f);
}
FORCEINLINE FVector4f GetIncidentDirection() const
{
return FVector4f(IncidentDirectionAndDistance, 0.0f);
}
FORCEINLINE float GetDistance() const
{
return IncidentDirectionAndDistance.W;
}
FORCEINLINE FVector4f GetSurfaceNormal() const
{
return FVector4f(SurfaceNormalAndPower, 0.0f);
}
FORCEINLINE FLinearColor GetPower() const
{
const FColor PowerRGBE = *(FColor*)&SurfaceNormalAndPower.W;
const FLinearColor OutPower = PowerRGBE.FromRGBE();
checkSlow(FLinearColorUtils::AreFloatsValid(OutPower));
return OutPower;
}
};
/** An octree element that contains a photon */
struct FPhotonElement
{
/** Stores a photon by value so we can discard the original array and avoid a level of indirection */
const FPhoton Photon;
/** Initialization constructor. */
FPhotonElement(const FPhoton& InPhoton) :
Photon(InPhoton)
{}
};
typedef TOctree<FPhotonElement,struct FPhotonMapOctreeSemantics> FPhotonOctree;
/** Octree semantic definitions. */
struct FPhotonMapOctreeSemantics
{
//@todo - evaluate different performance/memory tradeoffs with these
enum { MaxElementsPerLeaf = 16 };
enum { MaxNodeDepth = 12 };
enum { LoosenessDenominator = 16 };
// Using the default heap allocator instead of an inline allocator to reduce memory usage
typedef FDefaultAllocator ElementAllocator;
static FBoxCenterAndExtent GetBoundingBox(const FPhotonElement& PhotonElement)
{
return FBoxCenterAndExtent(PhotonElement.Photon.GetPosition(), FVector4f(0,0,0));
}
};
struct FPhotonSegmentElement
{
const FPhoton* Photon;
FVector3f SegmentCenter;
FVector3f SegmentExtent;
/** Initialization constructor. */
FPhotonSegmentElement(const FPhoton* InPhoton, float InStartOffset, float InSegmentLength) :
Photon(InPhoton)
{
const FVector3f PhotonDirection = Photon->GetIncidentDirection() * Photon->GetDistance();
const FVector3f SegmentStart = Photon->GetPosition() + PhotonDirection * InStartOffset;
const FVector3f SegmentEnd = SegmentStart + PhotonDirection * InSegmentLength;
FBox3f SegmentBounds(ForceInit);
SegmentBounds += SegmentStart;
SegmentBounds += SegmentEnd;
SegmentCenter = SegmentBounds.GetCenter();
// Inflate the segment extent to cover the photon path better
SegmentExtent = SegmentBounds.GetExtent();
}
inline float ComputeSquaredDistanceToPoint(FVector3f InPoint) const
{
float Projection = FVector3f::DotProduct(InPoint - Photon->GetPosition(), Photon->GetIncidentDirection());
Projection = FMath::Clamp(Projection, 0.0f, Photon->GetDistance());
FVector3f ProjectedPosition = Photon->GetPosition() + Photon->GetIncidentDirection() * Projection;
return (InPoint - ProjectedPosition).SizeSquared();
}
};
/** Octree semantic definitions. */
struct FPhotonSegmentMapOctreeSemantics
{
//@todo - evaluate different performance/memory tradeoffs with these
enum { MaxElementsPerLeaf = 16 };
enum { MaxNodeDepth = 12 };
enum { LoosenessDenominator = 16 };
typedef TInlineAllocator<MaxElementsPerLeaf> ElementAllocator;
static FBoxCenterAndExtent GetBoundingBox(const FPhotonSegmentElement& PhotonSegmentElement)
{
return FBoxCenterAndExtent(PhotonSegmentElement.SegmentCenter, PhotonSegmentElement.SegmentExtent);
}
};
typedef TOctree<FPhotonSegmentElement,struct FPhotonSegmentMapOctreeSemantics> FPhotonSegmentOctree;
/** A photon which stores a precalculated irradiance estimate. */
class FIrradiancePhoton : public FIrradiancePhotonData
{
public:
FIrradiancePhoton(const FVector4f& InPosition, const FVector4f& InSurfaceNormal, bool bInHasContributionFromDirectPhotons)
{
PositionAndDirectContribution = FVector4f(InPosition, bInHasContributionFromDirectPhotons);
SurfaceNormalAndIrradiance = FVector4f(InSurfaceNormal, 0.0f);
}
FORCEINLINE bool HasDirectContribution() const
{
return PositionAndDirectContribution.W > 0.0f;
}
FORCEINLINE void SetHasDirectContribution()
{
PositionAndDirectContribution.W = true;
}
FORCEINLINE void SetUsed()
{
SurfaceNormalAndIrradiance.W = 1.0f;
}
FORCEINLINE bool IsUsed() const
{
return SurfaceNormalAndIrradiance.W > 0.0f;
}
FORCEINLINE void SetIrradiance(FLinearColor InIrradiance)
{
checkSlow(FLinearColorUtils::AreFloatsValid(InIrradiance));
const FColor IrradianceRGBE = InIrradiance.ToRGBE();
SurfaceNormalAndIrradiance.W = *(float*)&IrradianceRGBE;
}
FORCEINLINE FLinearColor GetIrradiance() const
{
const FColor IrradianceRGBE = *(FColor*)&SurfaceNormalAndIrradiance.W;
const FLinearColor OutIrradiance = IrradianceRGBE.FromRGBE();
checkSlow(FLinearColorUtils::AreFloatsValid(OutIrradiance));
return OutIrradiance;
}
FORCEINLINE FVector4f GetPosition() const
{
return FVector4f(PositionAndDirectContribution, 0.0f);
}
FORCEINLINE FVector4f GetSurfaceNormal() const
{
return FVector4f(SurfaceNormalAndIrradiance, 0.0f);
}
};
/** An octree element that contains an irradiance photon */
struct FIrradiancePhotonElement
{
public:
/** Initialization constructor. */
FIrradiancePhotonElement(const int32 InPhotonIndex, TArray<FIrradiancePhoton>& InPhotonArray) :
PhotonIndex(InPhotonIndex),
PhotonArray(InPhotonArray)
{}
FIrradiancePhoton& GetPhoton() { return PhotonArray[PhotonIndex]; }
const FIrradiancePhoton& GetPhoton() const { return PhotonArray[PhotonIndex]; }
private:
int32 PhotonIndex;
TArray<FIrradiancePhoton>& PhotonArray;
};
typedef TOctree<FIrradiancePhotonElement,struct FIrradiancePhotonMapOctreeSemantics> FIrradiancePhotonOctree;
/** Octree semantic definitions. */
struct FIrradiancePhotonMapOctreeSemantics
{
//@todo - evaluate different performance/memory tradeoffs with these
enum { MaxElementsPerLeaf = 32 };
enum { MaxNodeDepth = 12 };
enum { LoosenessDenominator = 16 };
typedef FDefaultAllocator ElementAllocator;
static FBoxCenterAndExtent GetBoundingBox(const FIrradiancePhotonElement& PhotonElement)
{
return FBoxCenterAndExtent(PhotonElement.GetPhoton().GetPosition(), FVector4f(0,0,0));
}
};
/** A lighting sample in world space storing incident radiance from a whole sphere of directions. */
class FVolumeLightingSample : public FVolumeLightingSampleData
{
public:
FVolumeLightingSample(const FVector4f& InPositionAndRadius)
{
for (int32 CoefficientIndex = 0; CoefficientIndex < LM_NUM_SH_COEFFICIENTS; CoefficientIndex++)
{
for (int32 ChannelIndex = 0; ChannelIndex < 3; ChannelIndex++)
{
HighQualityCoefficients[CoefficientIndex][ChannelIndex] = 0;
LowQualityCoefficients[CoefficientIndex][ChannelIndex] = 0;
}
}
PositionAndRadius = InPositionAndRadius;
}
inline FVector4f GetPosition() const
{
return FVector4f(PositionAndRadius, 0.0f);
}
inline float GetRadius() const
{
return PositionAndRadius.W;
}
void SetFromSHVector(const FSHVectorRGB3& SHVector);
/** Constructs an SH environment from this lighting sample. */
void ToSHVector(FSHVectorRGB3& SHVector) const;
};
struct FVolumeSampleInterpolationElement
{
const int32 SampleIndex;
const TArray<FVolumeLightingSample>& VolumeSamples;
/** Initialization constructor. */
FVolumeSampleInterpolationElement(const int32 InSampleIndex, const TArray<FVolumeLightingSample>& InVolumeSamples) :
SampleIndex(InSampleIndex),
VolumeSamples(InVolumeSamples)
{}
};
typedef TOctree<FVolumeSampleInterpolationElement,struct FVolumeLightingInterpolationOctreeSemantics> FVolumeLightingInterpolationOctree;
/** Octree semantic definitions. */
struct FVolumeLightingInterpolationOctreeSemantics
{
//@todo - evaluate different performance/memory tradeoffs with these
enum { MaxElementsPerLeaf = 4 };
enum { MaxNodeDepth = 12 };
enum { LoosenessDenominator = 16 };
typedef TInlineAllocator<MaxElementsPerLeaf> ElementAllocator;
static FBoxCenterAndExtent GetBoundingBox(const FVolumeSampleInterpolationElement& Element)
{
const FVolumeLightingSample& Sample = Element.VolumeSamples[Element.SampleIndex];
return FBoxCenterAndExtent(FVector4f(Sample.PositionAndRadius, 0.0f), FVector4f(Sample.PositionAndRadius.W, Sample.PositionAndRadius.W, Sample.PositionAndRadius.W));
}
};
class FPrecomputedVisibilityCell
{
public:
FBox3f Bounds;
TArray<uint8> VisibilityData;
};
/** Stores depth for a single cell of a shadow map for a stationary light. */
class FStaticShadowDepthMapSample : public FStaticShadowDepthMapSampleData
{
public:
FStaticShadowDepthMapSample(FFloat16 InDistance)
{
Distance = InDistance;
}
};
/** Stores information about how ShadowMap was generated. */
class FStaticShadowDepthMap : public FStaticShadowDepthMapData
{
public:
TArray<FStaticShadowDepthMapSample> ShadowMap;
};
/** Number of light bounces that we are keeping track of stats for */
static const int32 NumTrackedBounces = 1;
static const int32 MaxNumRefiningDepths = 6;
/** Stats for a single mapping. All times are thread seconds if the stat was calculated during a multi threaded mapping process. */
class FStaticLightingMappingStats
{
public:
/** Part of TotalLightingThreadTime that was spent on texture mappings. */
float TotalTextureMappingLightingThreadTime;
/** Part of TotalLightingThreadTime that was spent on volume samples. */
float TotalVolumeSampleLightingThreadTime;
/** Part of TotalLightingThreadTime that was spent on volumetric lightmap work. */
float TotalVolumetricLightmapLightingThreadTime;
/** Time taken to generate the FTexelToVertexMap */
float TexelRasterizationTime;
/** Time taken to create vertex samples. */
float VertexSampleCreationTime;
/** Number of texels mapped to geometry in the scene. */
int32 NumMappedTexels;
/** Number of vertex light samples calculated. */
int32 NumVertexSamples;
/** Time taken to calculate direct lighting */
float DirectLightingTime;
/** Thread seconds spent calculating area shadows. */
float AreaShadowsThreadTime;
/** Thread seconds spent calculating light attenuation and influence. */
float AreaLightingThreadTime;
/** Accumulated signed distance field upsample factors for all mappings that used signed distance field shadows. */
float AccumulatedSignedDistanceFieldUpsampleFactors;
/** Number of mappings that used signed distance field shadows. */
int32 NumSignedDistanceFieldCalculations;
/** Number of rays traced during the sparse source data generation pass. */
uint64 NumSignedDistanceFieldAdaptiveSourceRaysFirstPass;
/** Number of rays traced during the refining source data generation pass. */
uint64 NumSignedDistanceFieldAdaptiveSourceRaysSecondPass;
/** Thread seconds spend processing the sparse source data generation pass. */
float SignedDistanceFieldSourceFirstPassThreadTime;
/** Thread seconds spend processing the refining source data generation pass. */
float SignedDistanceFieldSourceSecondPassThreadTime;
/** Number of transition distance scatters during the distance field search pass. */
uint64 NumSignedDistanceFieldScatters;
/** Thread seconds spent searching the source data for the closest transition distance. */
float SignedDistanceFieldSearchThreadTime;
/** Number of cell - mesh queries processed. */
uint64 NumPrecomputedVisibilityQueries;
/** Number of cell - mesh queries considered visible because the mesh was very close to the cell. */
uint64 NumQueriesVisibleByDistanceRatio;
/** Number of cell - mesh queries determined visible from explicitly sampling the mesh's bounds. */
uint64 NumQueriesVisibleExplicitSampling;
/** Number of cell - mesh queries determined visible from importance sampling. */
uint64 NumQueriesVisibleImportanceSampling;
/** Number of rays traced for precomputed visibility. */
uint64 NumPrecomputedVisibilityRayTraces;
/** Number of visibility cells processed on this agent. */
int32 NumPrecomputedVisibilityCellsProcessed;
/** Thread seconds processing visibility cells. */
float PrecomputedVisibilityThreadTime;
/** Thread seconds generating visibility sample positions. */
float PrecomputedVisibilitySampleSetupThreadTime;
/** Thread seconds tracing visibility rays. */
float PrecomputedVisibilityRayTraceThreadTime;
/** Thread seconds importance sampling visibility queries. */
float PrecomputedVisibilityImportanceSampleThreadTime;
/** Number of visibility queries on groups. */
uint64 NumPrecomputedVisibilityGroupQueries;
/** Number of mesh queries that were trivially occluded because their group was already determined to be occluded. */
uint64 NumPrecomputedVisibilityMeshQueriesSkipped;
/** Thread seconds calculating static shadow depth maps. */
float StaticShadowDepthMapThreadTime;
/** Longest time spent on a single static shadow depth map. */
float MaxStaticShadowDepthMapThreadTime;
/** Thread seconds calculating the volume distance field. */
float VolumeDistanceFieldThreadTime;
/** Amount of time the mapping processing threads spent either processing indirect lighting cache tasks, or waiting on another thread to finish its cache task. */
float BlockOnIndirectLightingCacheTasksTime;
/** Amount of time the mapping processing threads spent either processing indirect lighting interpolate tasks, or waiting on another thread to finish its interpolate task. */
float BlockOnIndirectLightingInterpolateTasksTime;
/** Time taken to calculate indirect lighting */
float IndirectLightingCacheTaskThreadTime;
float IndirectLightingCacheTaskThreadTimeSeparateTask;
/** Time taken to gather photons which are used for importance sampling the final gather */
float ImportancePhotonGatherTime;
/** Number of importance photons found */
uint64 TotalFoundImportancePhotons;
/** Time taken to generate a sample direction based on the importance photons, and then calculate the PDF for the generated sample direction. */
float CalculateImportanceSampleTime;
/** Number of elements contributing to the PDF times the number of samples */
uint64 NumImportancePDFCalculations;
/** Time taken to calculate the exitant radiance at the end of each final gather ray */
float CalculateExitantRadianceTime;
/** Number of final gather rays */
uint64 NumFirstBounceRaysTraced;
/** Time taken to trace final gather rays */
float FirstBounceRayTraceTime;
/** Number of shadow rays traced for direct lighting. */
uint64 NumDirectLightingShadowRays;
/** Number of times the nearest irradiance photon was searched for */
uint64 NumIrradiancePhotonMapSearches;
/** Number of unique irradiance photons cached on surfaces. */
int32 NumFoundIrradiancePhotons;
/** Number of nearest irradiance photon samples that were cached on surfaces */
uint64 NumCachedIrradianceSamples;
/** Time taken for irradiance cache interpolation for the final shading pass */
float SecondPassIrradianceCacheInterpolationTime;
float SecondPassIrradianceCacheInterpolationTimeSeparateTask;
/** Number of rays traced to determine visibility of irradiance photons while caching them on surfaces */
uint64 NumIrradiancePhotonSearchRays;
/** Time spent caching irradiance photons on surfaces */
float IrradiancePhotonCachingThreadTime;
float RadiositySetupThreadTime;
float RadiosityIterationThreadTime;
/** Time taken traversing the irradiance photon octree */
float IrradiancePhotonOctreeTraversalTime;
/** Time taken to trace rays determining the visibility of irradiance photons */
float IrradiancePhotonSearchRayTime;
/** The number of final gather samples done at the base resolution. */
uint64 NumBaseFinalGatherSamples;
/** The number of final gather samples done at each refinement depth. */
uint64 NumRefiningFinalGatherSamples[MaxNumRefiningDepths];
/** The number of final gather samples done due to brightness differences between neighbors. */
uint64 NumRefiningSamplesDueToBrightness;
/** The number of final gather samples done due to intersecting importance photons. */
uint64 NumRefiningSamplesDueToImportancePhotons;
uint64 NumRefiningSamplesOther;
/** Amount of time spent computing base final gather samples. */
float BaseFinalGatherSampleTime;
/** Amount of time spent computing refining final gather samples. */
float RefiningFinalGatherSampleTime;
int32 NumVolumetricLightmapSamples;
float VolumetricLightmapVoxelizationTime;
float VolumetricLightmapGatherImportancePhotonsTime;
float VolumetricLightmapDirectLightingTime;
float VolumetricLightmapFinalGatherTime;
FStaticLightingMappingStats() :
TotalTextureMappingLightingThreadTime(0),
TotalVolumeSampleLightingThreadTime(0),
TotalVolumetricLightmapLightingThreadTime(0),
TexelRasterizationTime(0),
VertexSampleCreationTime(0),
NumMappedTexels(0),
NumVertexSamples(0),
DirectLightingTime(0),
AreaShadowsThreadTime(0),
AreaLightingThreadTime(0),
AccumulatedSignedDistanceFieldUpsampleFactors(0),
NumSignedDistanceFieldCalculations(0),
NumSignedDistanceFieldAdaptiveSourceRaysFirstPass(0),
NumSignedDistanceFieldAdaptiveSourceRaysSecondPass(0),
SignedDistanceFieldSourceFirstPassThreadTime(0),
SignedDistanceFieldSourceSecondPassThreadTime(0),
NumSignedDistanceFieldScatters(0),
SignedDistanceFieldSearchThreadTime(0),
NumPrecomputedVisibilityQueries(0),
NumQueriesVisibleByDistanceRatio(0),
NumQueriesVisibleExplicitSampling(0),
NumQueriesVisibleImportanceSampling(0),
NumPrecomputedVisibilityRayTraces(0),
NumPrecomputedVisibilityCellsProcessed(0),
PrecomputedVisibilityThreadTime(0),
PrecomputedVisibilitySampleSetupThreadTime(0),
PrecomputedVisibilityRayTraceThreadTime(0),
PrecomputedVisibilityImportanceSampleThreadTime(0),
NumPrecomputedVisibilityGroupQueries(0),
NumPrecomputedVisibilityMeshQueriesSkipped(0),
StaticShadowDepthMapThreadTime(0),
MaxStaticShadowDepthMapThreadTime(0),
VolumeDistanceFieldThreadTime(0),
BlockOnIndirectLightingCacheTasksTime(0),
BlockOnIndirectLightingInterpolateTasksTime(0),
IndirectLightingCacheTaskThreadTime(0),
IndirectLightingCacheTaskThreadTimeSeparateTask(0),
ImportancePhotonGatherTime(0),
TotalFoundImportancePhotons(0),
CalculateImportanceSampleTime(0),
NumImportancePDFCalculations(0),
CalculateExitantRadianceTime(0),
NumFirstBounceRaysTraced(0),
FirstBounceRayTraceTime(0),
NumDirectLightingShadowRays(0),
NumIrradiancePhotonMapSearches(0),
NumFoundIrradiancePhotons(0),
NumCachedIrradianceSamples(0),
SecondPassIrradianceCacheInterpolationTime(0),
SecondPassIrradianceCacheInterpolationTimeSeparateTask(0),
NumIrradiancePhotonSearchRays(0),
IrradiancePhotonCachingThreadTime(0),
RadiositySetupThreadTime(0),
RadiosityIterationThreadTime(0),
IrradiancePhotonOctreeTraversalTime(0),
IrradiancePhotonSearchRayTime(0),
NumBaseFinalGatherSamples(0),
NumRefiningSamplesDueToBrightness(0),
NumRefiningSamplesDueToImportancePhotons(0),
NumRefiningSamplesOther(0),
BaseFinalGatherSampleTime(0),
RefiningFinalGatherSampleTime(0),
NumVolumetricLightmapSamples(0),
VolumetricLightmapVoxelizationTime(0),
VolumetricLightmapGatherImportancePhotonsTime(0),
VolumetricLightmapDirectLightingTime(0),
VolumetricLightmapFinalGatherTime(0)
{
for (int32 i = 0; i < UE_ARRAY_COUNT(NumRefiningFinalGatherSamples); i++)
{
NumRefiningFinalGatherSamples[i] = 0;
}
}
FStaticLightingMappingStats& operator+=(const FStaticLightingMappingStats& B)
{
TotalTextureMappingLightingThreadTime += B.TotalTextureMappingLightingThreadTime;
TotalVolumeSampleLightingThreadTime += B.TotalVolumeSampleLightingThreadTime;
TotalVolumetricLightmapLightingThreadTime += B.TotalVolumetricLightmapLightingThreadTime;
TexelRasterizationTime += B.TexelRasterizationTime;
VertexSampleCreationTime += B.VertexSampleCreationTime;
NumMappedTexels += B.NumMappedTexels;
NumVertexSamples += B.NumVertexSamples;
DirectLightingTime += B.DirectLightingTime;
AreaShadowsThreadTime += B.AreaShadowsThreadTime;
AreaLightingThreadTime += B.AreaLightingThreadTime;
AccumulatedSignedDistanceFieldUpsampleFactors += B.AccumulatedSignedDistanceFieldUpsampleFactors;
NumSignedDistanceFieldCalculations += B.NumSignedDistanceFieldCalculations;
NumSignedDistanceFieldAdaptiveSourceRaysFirstPass += B.NumSignedDistanceFieldAdaptiveSourceRaysFirstPass;
NumSignedDistanceFieldAdaptiveSourceRaysSecondPass += B.NumSignedDistanceFieldAdaptiveSourceRaysSecondPass;
SignedDistanceFieldSourceFirstPassThreadTime += B.SignedDistanceFieldSourceFirstPassThreadTime;
SignedDistanceFieldSourceSecondPassThreadTime += B.SignedDistanceFieldSourceSecondPassThreadTime;
NumSignedDistanceFieldScatters += B.NumSignedDistanceFieldScatters;
SignedDistanceFieldSearchThreadTime += B.SignedDistanceFieldSearchThreadTime;
NumPrecomputedVisibilityQueries += B.NumPrecomputedVisibilityQueries;
NumQueriesVisibleByDistanceRatio += B.NumQueriesVisibleByDistanceRatio;
NumQueriesVisibleExplicitSampling += B.NumQueriesVisibleExplicitSampling;
NumQueriesVisibleImportanceSampling += B.NumQueriesVisibleImportanceSampling;
NumPrecomputedVisibilityRayTraces += B.NumPrecomputedVisibilityRayTraces;
NumPrecomputedVisibilityCellsProcessed += B.NumPrecomputedVisibilityCellsProcessed;
PrecomputedVisibilityThreadTime += B.PrecomputedVisibilityThreadTime;
PrecomputedVisibilitySampleSetupThreadTime += B.PrecomputedVisibilitySampleSetupThreadTime;
PrecomputedVisibilityRayTraceThreadTime += B.PrecomputedVisibilityRayTraceThreadTime;
PrecomputedVisibilityImportanceSampleThreadTime += B.PrecomputedVisibilityImportanceSampleThreadTime;
NumPrecomputedVisibilityGroupQueries += B.NumPrecomputedVisibilityGroupQueries;
NumPrecomputedVisibilityMeshQueriesSkipped += B.NumPrecomputedVisibilityMeshQueriesSkipped;
StaticShadowDepthMapThreadTime += B.StaticShadowDepthMapThreadTime;
MaxStaticShadowDepthMapThreadTime = FMath::Max(MaxStaticShadowDepthMapThreadTime, B.MaxStaticShadowDepthMapThreadTime);
VolumeDistanceFieldThreadTime += B.VolumeDistanceFieldThreadTime;
BlockOnIndirectLightingCacheTasksTime += B.BlockOnIndirectLightingCacheTasksTime;
BlockOnIndirectLightingInterpolateTasksTime += B.BlockOnIndirectLightingInterpolateTasksTime;
IndirectLightingCacheTaskThreadTime += B.IndirectLightingCacheTaskThreadTime;
IndirectLightingCacheTaskThreadTimeSeparateTask += B.IndirectLightingCacheTaskThreadTimeSeparateTask;
ImportancePhotonGatherTime += B.ImportancePhotonGatherTime;
TotalFoundImportancePhotons += B.TotalFoundImportancePhotons;
CalculateImportanceSampleTime += B.CalculateImportanceSampleTime;
NumImportancePDFCalculations += B.NumImportancePDFCalculations;
CalculateExitantRadianceTime += B.CalculateExitantRadianceTime;
NumFirstBounceRaysTraced += B.NumFirstBounceRaysTraced;
FirstBounceRayTraceTime += B.FirstBounceRayTraceTime;
NumDirectLightingShadowRays += B.NumDirectLightingShadowRays;
NumIrradiancePhotonMapSearches += B.NumIrradiancePhotonMapSearches;
NumFoundIrradiancePhotons += B.NumFoundIrradiancePhotons;
NumCachedIrradianceSamples += B.NumCachedIrradianceSamples;
SecondPassIrradianceCacheInterpolationTime += B.SecondPassIrradianceCacheInterpolationTime;
SecondPassIrradianceCacheInterpolationTimeSeparateTask += B.SecondPassIrradianceCacheInterpolationTimeSeparateTask;
NumIrradiancePhotonSearchRays += B.NumIrradiancePhotonSearchRays;
IrradiancePhotonCachingThreadTime += B.IrradiancePhotonCachingThreadTime;
RadiositySetupThreadTime += B.RadiositySetupThreadTime;
RadiosityIterationThreadTime += B.RadiosityIterationThreadTime;
IrradiancePhotonOctreeTraversalTime += B.IrradiancePhotonOctreeTraversalTime;
IrradiancePhotonSearchRayTime += B.IrradiancePhotonSearchRayTime;
NumBaseFinalGatherSamples += B.NumBaseFinalGatherSamples;
NumRefiningSamplesDueToBrightness += B.NumRefiningSamplesDueToBrightness;
NumRefiningSamplesDueToImportancePhotons += B.NumRefiningSamplesDueToImportancePhotons;
NumRefiningSamplesOther += B.NumRefiningSamplesOther;
BaseFinalGatherSampleTime += B.BaseFinalGatherSampleTime;
RefiningFinalGatherSampleTime += B.RefiningFinalGatherSampleTime;
for (int32 i = 0; i < UE_ARRAY_COUNT(NumRefiningFinalGatherSamples); i++)
{
NumRefiningFinalGatherSamples[i] += B.NumRefiningFinalGatherSamples[i];
}
NumVolumetricLightmapSamples += B.NumVolumetricLightmapSamples;
VolumetricLightmapVoxelizationTime += B.VolumetricLightmapVoxelizationTime;
VolumetricLightmapGatherImportancePhotonsTime += B.VolumetricLightmapGatherImportancePhotonsTime;
VolumetricLightmapDirectLightingTime += B.VolumetricLightmapDirectLightingTime;
VolumetricLightmapFinalGatherTime += B.VolumetricLightmapFinalGatherTime;
return *this;
}
};
/** Stats collected by FLightingSystem::FindNearbyPhotons*() */
struct FFindNearbyPhotonStats
{
/** Number of photon map searches using the iterative search process. */
uint64 NumIterativePhotonMapSearches;
/** Number of size-increasing photon map search iterations until enough photons were found. */
uint64 NumSearchIterations;
/** Thread seconds spent traversing the photon map octree and pushing child nodes onto the traversal stack. */
float PushingOctreeChildrenThreadTime;
/** Thread seconds spent processing photons found in the photon map. */
float ProcessingOctreeElementsThreadTime;
/** Thread seconds spent finding the furthest found photon in order to replace it with the incoming one. */
float FindingFurthestPhotonThreadTime;
/** Number of octree nodes tested during all photon map searches. */
uint64 NumOctreeNodesTested;
/** Number of octree nodes that passed testing and had their elements processed during all photon map searches. */
uint64 NumOctreeNodesVisited;
/** Number of elements tested during all photon map searches. */
uint64 NumElementsTested;
/** Number of elements that passed testing during all photon map searches. */
uint64 NumElementsAccepted;
FFindNearbyPhotonStats() :
NumIterativePhotonMapSearches(0),
NumSearchIterations(0),
PushingOctreeChildrenThreadTime(0),
ProcessingOctreeElementsThreadTime(0),
FindingFurthestPhotonThreadTime(0),
NumOctreeNodesTested(0),
NumOctreeNodesVisited(0),
NumElementsTested(0),
NumElementsAccepted(0)
{}
FFindNearbyPhotonStats& operator+=(const FFindNearbyPhotonStats& B)
{
NumIterativePhotonMapSearches += B.NumIterativePhotonMapSearches;
NumSearchIterations += B.NumSearchIterations;
PushingOctreeChildrenThreadTime += B.PushingOctreeChildrenThreadTime;
ProcessingOctreeElementsThreadTime += B.ProcessingOctreeElementsThreadTime;
FindingFurthestPhotonThreadTime += B.FindingFurthestPhotonThreadTime;
NumOctreeNodesTested += B.NumOctreeNodesTested;
NumOctreeNodesVisited += B.NumOctreeNodesVisited;
NumElementsTested += B.NumElementsTested;
NumElementsAccepted += B.NumElementsAccepted;
return *this;
}
};
/** Stats collected by FStaticLightingSystem::CalculateIrradiancePhotonsThreadLoop() */
struct FCalculateIrradiancePhotonStats : public FFindNearbyPhotonStats
{
/** Thread seconds spent calculating irradiance once the relevant photons have been found. */
float CalculateIrradianceThreadTime;
FCalculateIrradiancePhotonStats() :
FFindNearbyPhotonStats(),
CalculateIrradianceThreadTime(0)
{}
FCalculateIrradiancePhotonStats& operator+=(const FCalculateIrradiancePhotonStats& B)
{
(FFindNearbyPhotonStats&)(*this) += (const FFindNearbyPhotonStats&)B;
CalculateIrradianceThreadTime += B.CalculateIrradianceThreadTime;
return *this;
}
};
/** Stats for the whole lighting system, which belong to the main thread. Other threads must use synchronization to access them. */
class FStaticLightingStats : public FStaticLightingMappingStats
{
public:
/** Main thread seconds setting up the scene */
float SceneSetupTime;
/** Main thread seconds setting up mesh area lights */
float MeshAreaLightSetupTime;
/** Thread seconds spent processing mappings for the final lighting pass */
float TotalLightingThreadTime;
/** Main thread seconds until the final lighting pass was complete */
float MainThreadLightingTime;
/** Number of mappings processed */
int32 NumMappings;
/** Number of texels processed */
int32 NumTexelsProcessed;
/** Number of lights in the scene. */
int32 NumLights;
/** Number of meshes that created mesh area lights. */
int32 NumMeshAreaLightMeshes;
/** Number of mesh area lights created from emissive areas in the scene. */
int32 NumMeshAreaLights;
/** Number of mesh area light primitives before simplification. */
uint64 NumMeshAreaLightPrimitives;
/** Number of simplified mesh area light primitives that are used for lighting. */
uint64 NumSimplifiedMeshAreaLightPrimitives;
/** Number of volume lighting samples created off of surfaces. */
int32 NumDynamicObjectSurfaceSamples;
/** Number of volume lighting samples created based on the importance volume. */
int32 NumDynamicObjectVolumeSamples;
/** Single threaded time setup up sPVS structures for parallel task processing. */
float PrecomputedVisibilitySetupTime;
/** Total number of cells which visibility will be computed for. */
int32 NumPrecomputedVisibilityCellsTotal;
/** Number of visibility cells generated on camera tracks. */
int32 NumPrecomputedVisibilityCellsCamaraTracks;
/** Number of meshes with valid visibility Ids in the scene. */
int32 NumPrecomputedVisibilityMeshes;
/** Number of meshes excluded from visibility groups due to their size. */
int32 NumPrecomputedVisibilityMeshesExcludedFromGroups;
/** Size of the raw visibility data exported. */
SIZE_T PrecomputedVisibilityDataBytes;
/** Main thread time emitting direct photons */
float EmitDirectPhotonsTime;
/** Thread time emitting direct photons. */
float EmitDirectPhotonsThreadTime;
/** Thread time tracing rays for direct photons. */
float DirectPhotonsTracingThreadTime;
/** Thread time generating light samples for direct photons. */
float DirectPhotonsLightSamplingThreadTime;
/** Thread time spent applying non-physical attenuation to direct photons. */
float DirectCustomAttenuationThreadTime;
/** Thread seconds spent processing gathered direct photons and adding them to spatial data structures. */
float ProcessDirectPhotonsThreadTime;
/** Number of direct photons that were deposited on surfaces. */
int32 NumDirectPhotonsGathered;
/** Main thread time letting lights cache information about the indirect photon paths. */
float CachingIndirectPhotonPathsTime;
/** Main thread time emitting indirect photons */
float EmitIndirectPhotonsTime;
/** Thread time emitting indirect photons. */
float EmitIndirectPhotonsThreadTime;
/** Thread seconds spent processing gathered indirect photons and adding them to spatial data structures. */
float ProcessIndirectPhotonsThreadTime;
/** Thread time sampling lights while emitting indirect photons. */
float LightSamplingThreadTime;
/** Thread time spent applying non-physical attenuation to indirect photons. */
float IndirectCustomAttenuationThreadTime;
/** Thread time tracing indirect photons from a light. */
float IntersectLightRayThreadTime;
/** Thread time tracing photons bouncing off of surfaces in the scene. */
float PhotonBounceTracingThreadTime;
/** Number of indirect photons that were deposited on surfaces. */
int32 NumIndirectPhotonsGathered;
/** Main thread time marking photons as having direct lighting influence or not. */
float IrradiancePhotonMarkingTime;
/** Thread time marking photons. */
float IrradiancePhotonMarkingThreadTime;
/** Main thread time calculating irradiance photons */
float IrradiancePhotonCalculatingTime;
/** Thread time calculating irradiance photons */
float IrradiancePhotonCalculatingThreadTime;
/** Main thread time caching irradiance photons on surfaces */
float CacheIrradiancePhotonsTime;
/** Number of irradiance photons */
int32 NumIrradiancePhotons;
/** Number of irradiance photons created off of direct photons. */
int32 NumDirectIrradiancePhotons;
/** Number of times a photon map was searched, excluding irradiance photon searches */
volatile int32 NumPhotonGathers;
/** Number of photons emitted in the first pass */
uint64 NumFirstPassPhotonsEmitted;
/** Number of photons requested to be emitted in the first pass */
uint64 NumFirstPassPhotonsRequested;
/** Number of photons emitted in the second pass */
uint64 NumSecondPassPhotonsEmitted;
/** Number of photons requested to be emitted in the second pass */
uint64 NumSecondPassPhotonsRequested;
/** Total number of first hit rays traced */
uint64 NumFirstHitRaysTraced;
/** Total number of boolean visibility rays traced */
uint64 NumBooleanRaysTraced;
/** Thread seconds spent tracing first hit rays */
float FirstHitRayTraceThreadTime;
/** Thread seconds spent tracing shadow rays */
float BooleanRayTraceThreadTime;
/** Thread seconds spent placing volume lighting samples and then calculating their lighting. */
float VolumeSamplePlacementThreadTime;
/** Irradiance cache stats */
FIrradianceCacheStats Cache[NumTrackedBounces];
/** Stats from irradiance photon calculations. */
FCalculateIrradiancePhotonStats CalculateIrradiancePhotonStats;
/** Critical section that worker threads must acquire before writing to members of this class */
FCriticalSection StatsSync;
FStaticLightingStats() :
SceneSetupTime(0),
MeshAreaLightSetupTime(0),
TotalLightingThreadTime(0),
MainThreadLightingTime(0),
NumMappings(0),
NumTexelsProcessed(0),
NumLights(0),
NumMeshAreaLightMeshes(0),
NumMeshAreaLights(0),
NumMeshAreaLightPrimitives(0),
NumSimplifiedMeshAreaLightPrimitives(0),
NumDynamicObjectSurfaceSamples(0),
NumDynamicObjectVolumeSamples(0),
PrecomputedVisibilitySetupTime(0),
NumPrecomputedVisibilityCellsTotal(0),
NumPrecomputedVisibilityCellsCamaraTracks(0),
NumPrecomputedVisibilityMeshes(0),
NumPrecomputedVisibilityMeshesExcludedFromGroups(0),
PrecomputedVisibilityDataBytes(0),
EmitDirectPhotonsTime(0),
EmitDirectPhotonsThreadTime(0),
DirectPhotonsTracingThreadTime(0),
DirectPhotonsLightSamplingThreadTime(0),
DirectCustomAttenuationThreadTime(0),
ProcessDirectPhotonsThreadTime(0),
NumDirectPhotonsGathered(0),
CachingIndirectPhotonPathsTime(0),
EmitIndirectPhotonsTime(0),
EmitIndirectPhotonsThreadTime(0),
ProcessIndirectPhotonsThreadTime(0),
LightSamplingThreadTime(0),
IndirectCustomAttenuationThreadTime(0),
IntersectLightRayThreadTime(0),
PhotonBounceTracingThreadTime(0),
NumIndirectPhotonsGathered(0),
IrradiancePhotonMarkingTime(0),
IrradiancePhotonMarkingThreadTime(0),
IrradiancePhotonCalculatingTime(0),
IrradiancePhotonCalculatingThreadTime(0),
CacheIrradiancePhotonsTime(0),
NumIrradiancePhotons(0),
NumDirectIrradiancePhotons(0),
NumPhotonGathers(0),
NumFirstPassPhotonsEmitted(0),
NumFirstPassPhotonsRequested(0),
NumSecondPassPhotonsEmitted(0),
NumSecondPassPhotonsRequested(0),
NumFirstHitRaysTraced(0),
NumBooleanRaysTraced(0),
FirstHitRayTraceThreadTime(0),
BooleanRayTraceThreadTime(0),
VolumeSamplePlacementThreadTime(0)
{
for (int32 i = 0; i < NumTrackedBounces; i++)
{
Cache[i] = FIrradianceCacheStats();
}
}
};
template<typename ElementType>
class FSimpleQuadTreeNode
{
public:
ElementType Element;
FSimpleQuadTreeNode* Children[4];
FSimpleQuadTreeNode()
{
Children[0] = NULL;
Children[1] = NULL;
Children[2] = NULL;
Children[3] = NULL;
}
void AddChild(int32 Index, FSimpleQuadTreeNode* Child)
{
Children[Index] = Child;
}
};
template<typename ElementType>
class FSimpleQuadTree
{
public:
const ElementType& GetLeafElement(float U, float V) const
{
const FSimpleQuadTreeNode<ElementType>* CurrentNode = &RootNode;
while (1)
{
const int32 ChildX = U > .5f;
const int32 ChildY = V > .5f;
const int32 ChildIndex = ChildX * 2 + ChildY;
if (CurrentNode->Children[ChildIndex])
{
U = U * 2 - ChildX;
V = V * 2 - ChildY;
CurrentNode = CurrentNode->Children[ChildIndex];
}
else
{
break;
}
}
return CurrentNode->Element;
}
FSimpleQuadTreeNode<ElementType> RootNode;
~FSimpleQuadTree()
{
}
void ReturnToFreeList(TArray<FSimpleQuadTreeNode<ElementType>*>& OutNodes)
{
ReturnToFreeListRecursive(&RootNode, OutNodes);
}
private:
void ReturnToFreeListRecursive(FSimpleQuadTreeNode<ElementType>* Node, TArray<FSimpleQuadTreeNode<ElementType>*>& OutNodes) const
{
for (int32 ChildIndex = 0; ChildIndex < UE_ARRAY_COUNT(Node->Children); ChildIndex++)
{
if (Node->Children[ChildIndex])
{
ReturnToFreeListRecursive(Node->Children[ChildIndex], OutNodes);
}
}
if (Node != &RootNode)
{
OutNodes.Add(Node);
}
}
};
/** Lighting payload used by the adaptive refinement in final gathering. */
class FLightingAndOcclusion
{
public:
FLinearColor Lighting;
FVector3f UnoccludedSkyVector;
FLinearColor StationarySkyLighting;
float NumSamplesOccluded;
FLightingAndOcclusion() :
Lighting(ForceInit),
UnoccludedSkyVector(FVector3f(0)),
StationarySkyLighting(FLinearColor::Black),
NumSamplesOccluded(0)
{}
FLightingAndOcclusion(const FLinearColor& InLighting, FVector3f InUnoccludedSkyVector, const FLinearColor& InStationarySkyLighting, float InNumSamplesOccluded) :
Lighting(InLighting),
UnoccludedSkyVector(InUnoccludedSkyVector),
StationarySkyLighting(InStationarySkyLighting),
NumSamplesOccluded(InNumSamplesOccluded)
{}
friend inline FLightingAndOcclusion operator+ (const FLightingAndOcclusion& A, const FLightingAndOcclusion& B)
{
return FLightingAndOcclusion(A.Lighting + B.Lighting, A.UnoccludedSkyVector + B.UnoccludedSkyVector, A.StationarySkyLighting + B.StationarySkyLighting, A.NumSamplesOccluded + B.NumSamplesOccluded);
}
friend inline FLightingAndOcclusion operator/ (const FLightingAndOcclusion& A, float Divisor)
{
return FLightingAndOcclusion(A.Lighting / Divisor, A.UnoccludedSkyVector / Divisor, A.StationarySkyLighting / Divisor, A.NumSamplesOccluded / Divisor);
}
};
/** Data stored for a sample that may need to be refined. */
class FRefinementElement
{
public:
FLightingAndOcclusion Lighting;
FVector2f Uniforms;
int32 HitPointIndex;
FRefinementElement() :
Uniforms(FVector2f(0, 0)),
HitPointIndex(-1)
{}
FRefinementElement(FLightingAndOcclusion InLighting, FVector2f InUniforms, int32 InHitPointIndex) :
Lighting(InLighting),
Uniforms(InUniforms),
HitPointIndex(InHitPointIndex)
{}
};
/** Local state for a mapping, accessed only by the owning thread. */
class FStaticLightingMappingContext
{
public:
FStaticLightingMappingStats Stats;
/** Lighting caches for the mapping */
TLightingCache<FFinalGatherSample> FirstBounceCache;
FCoherentRayCache RayCache;
TArray<FDebugLightingCacheRecord> DebugCacheRecords;
TArray<FSimpleQuadTreeNode<FRefinementElement>* > RefinementTreeFreePool;
class FStaticLightingSystem& System;
/** This mapping's debug output, if any. */
FDebugLightingOutput* DebugOutput;
public:
FStaticLightingMappingContext(const FStaticLightingMesh* InSubjectMesh, class FStaticLightingSystem& InSystem, FDebugLightingOutput* InDebugOutput = nullptr);
~FStaticLightingMappingContext();
};
/** Information about the power distribution of lights in the scene. */
class FSceneLightPowerDistribution
{
public:
/** Stores an unnormalized step 1D probability distribution function of emitting a photon from a given light */
TArray<float> LightPDFs;
/** Stores the cumulative distribution function of LightPDFs */
TArray<float> LightCDFs;
/** Stores the integral of LightPDFs */
float UnnormalizedIntegral;
};
/** The static lighting data for a texture mapping. */
struct FTextureMappingStaticLightingData
{
FStaticLightingTextureMapping* Mapping;
FLightMapData2D* LightMapData;
TMap<const FLight*,FShadowMapData2D*> ShadowMaps;
TMap<const FLight*,FSignedDistanceFieldShadowMapData2D*> SignedDistanceFieldShadowMaps;
FDebugLightingOutput DebugOutput;
/** Stores the time this mapping took to process */
double ExecutionTime;
};
/** Visibility output data from a single visibility task. */
struct FPrecomputedVisibilityData
{
FGuid Guid;
TArray<FPrecomputedVisibilityCell> PrecomputedVisibilityCells;
TArray<FDebugStaticLightingRay> DebugVisibilityRays;
};
struct FIrradianceBrickData
{
FGuid IntersectingLevelGuid;
/** Position in the global indirection texture. Used for mapping brick positions back to world space. */
FIntVector IndirectionTexturePosition;
/** Depth in the refinement tree, where 0 is the root. */
int32 TreeDepth;
float AverageClosestGeometryDistance;
TArray<FFloat3Packed> AmbientVector;
TArray<FColor> SHCoefficients[6];
TArray<FColor> SkyBentNormal;
TArray<uint8> DirectionalLightShadowing;
TArray<FIrradianceVoxelImportProcessingData> VoxelImportProcessingData;
void SetFromVolumeLightingSample(int32 Index, const FVolumeLightingSample& Sample, bool bInsideGeometry, float MinDistanceToSurface, bool bBorderVoxel);
};
/** Output data from a single volumetric lightmap task. */
struct FVolumetricLightmapTaskData
{
FGuid Guid;
TArray<FIrradianceBrickData> BrickData;
FDebugLightingOutput DebugOutput;
};
/** A thread which processes static lighting mappings. */
class FStaticLightingThreadRunnable : public FRunnable
{
public:
FRunnableThread* Thread;
/** Seconds that the thread spent in Run() */
float ExecutionTime;
float IdleTime;
/** Seconds since GStartupTime that the thread exited Run() */
double EndTime;
int32 ThreadIndex;
FThreadStatistics ThreadStatistics;
/** Initialization constructor. */
FStaticLightingThreadRunnable(FStaticLightingSystem* InSystem, int32 InThreadIndex) :
Thread(NULL),
IdleTime(0),
ThreadIndex(InThreadIndex),
System(InSystem),
bTerminatedByError(false)
{}
/** Checks the thread's health, and passes on any errors that have occurred. Called by the main thread. */
bool CheckHealth(bool bReportError = true) const;
void FixThreadGroupAffinity() const;
protected:
FStaticLightingSystem* System;
/** If the thread has been terminated by an unhandled exception, this contains the error message. */
FString ErrorMessage;
/** true if the thread has been terminated by an unhandled exception. */
bool bTerminatedByError;
};
/** Input required to emit direct photons. */
class FDirectPhotonEmittingInput
{
public:
const FBoxSphereBounds3f& ImportanceBounds;
const FSceneLightPowerDistribution& LightDistribution;
FDirectPhotonEmittingInput(
const FBoxSphereBounds3f& InImportanceBounds,
const FSceneLightPowerDistribution& InLightDistribution)
:
ImportanceBounds(InImportanceBounds),
LightDistribution(InLightDistribution)
{}
};
/** A work range for emitting direct photons, which is the smallest unit that can be parallelized. */
class FDirectPhotonEmittingWorkRange
{
public:
const int32 RangeIndex;
const int32 NumDirectPhotonsToEmit;
const int32 TargetNumIndirectPhotonPaths;
FDirectPhotonEmittingWorkRange(
int32 InRangeIndex,
int32 InNumDirectPhotonsToEmit,
int32 InTargetNumIndirectPhotonPaths)
:
RangeIndex(InRangeIndex),
NumDirectPhotonsToEmit(InNumDirectPhotonsToEmit),
TargetNumIndirectPhotonPaths(InTargetNumIndirectPhotonPaths)
{}
};
/** Direct photon emitting output for a single FDirectPhotonEmittingWorkRange. */
class FDirectPhotonEmittingOutput
{
public:
/**
* A worker thread will increment this counter once the output is complete,
* so that the main thread can process it while the worker thread moves on.
*/
volatile int32 OutputComplete;
int32 NumPhotonsEmittedDirect;
TArray<FPhoton> DirectPhotons;
TArray<FIrradiancePhoton>* IrradiancePhotons;
TArray<TArray<FIndirectPathRay> > IndirectPathRays;
int32 NumPhotonsEmitted;
float DirectPhotonsTracingThreadTime;
float DirectPhotonsLightSamplingThreadTime;
float DirectCustomAttenuationThreadTime;
FDirectPhotonEmittingOutput(TArray<FIrradiancePhoton>* InIrradiancePhotons) :
OutputComplete(0),
NumPhotonsEmittedDirect(0),
IrradiancePhotons(InIrradiancePhotons),
NumPhotonsEmitted(0),
DirectPhotonsTracingThreadTime(0),
DirectPhotonsLightSamplingThreadTime(0),
DirectCustomAttenuationThreadTime(0)
{}
};
/** Thread used to parallelize indirect photon emitting. */
class FDirectPhotonEmittingThreadRunnable : public FStaticLightingThreadRunnable
{
public:
/** Initialization constructor. */
FDirectPhotonEmittingThreadRunnable(
FStaticLightingSystem* InSystem,
int32 InThreadIndex,
const FDirectPhotonEmittingInput& InInput)
:
FStaticLightingThreadRunnable(InSystem, InThreadIndex),
Input(InInput)
{}
// FRunnable interface.
virtual bool Init(void) { return true; }
virtual void Exit(void) {}
virtual void Stop(void) {}
virtual uint32 Run(void);
protected:
const FDirectPhotonEmittingInput& Input;
};
/** Input required to emit indirect photons. */
class FIndirectPhotonEmittingInput
{
public:
const FBoxSphereBounds3f& ImportanceBounds;
const FSceneLightPowerDistribution& LightDistribution;
const TArray<TArray<FIndirectPathRay> >& IndirectPathRays;
FIndirectPhotonEmittingInput(
const FBoxSphereBounds3f& InImportanceBounds,
const FSceneLightPowerDistribution& InLightDistribution,
const TArray<TArray<FIndirectPathRay> >& InIndirectPathRays)
:
ImportanceBounds(InImportanceBounds),
LightDistribution(InLightDistribution),
IndirectPathRays(InIndirectPathRays)
{}
};
/** A work range for emitting indirect photons, which is the smallest unit that can be parallelized. */
class FIndirectPhotonEmittingWorkRange
{
public:
const int32 RangeIndex;
const int32 NumIndirectPhotonsToEmit;
FIndirectPhotonEmittingWorkRange(
int32 InRangeIndex,
int32 InNumIndirectPhotonsToEmit)
:
RangeIndex(InRangeIndex),
NumIndirectPhotonsToEmit(InNumIndirectPhotonsToEmit)
{}
};
/** Indirect photon emitting output for a single FIndirectPhotonEmittingWorkRange. */
class FIndirectPhotonEmittingOutput
{
public:
/**
* A worker thread will increment this counter once the output is complete,
* so that the main thread can process it while the worker thread moves on.
*/
volatile int32 OutputComplete;
int32 NumPhotonsEmittedFirstBounce;
TArray<FPhoton> FirstBouncePhotons;
TArray<FPhoton> FirstBounceEscapedPhotons;
int32 NumPhotonsEmittedSecondBounce;
TArray<FPhoton> SecondBouncePhotons;
TArray<FIrradiancePhoton>* IrradiancePhotons;
int32 NumPhotonsEmitted;
float LightSamplingThreadTime;
float IndirectCustomAttenuationThreadTime;
float IntersectLightRayThreadTime;
float PhotonBounceTracingThreadTime;
FIndirectPhotonEmittingOutput(TArray<FIrradiancePhoton>* InIrradiancePhotons) :
OutputComplete(0),
NumPhotonsEmittedFirstBounce(0),
NumPhotonsEmittedSecondBounce(0),
IrradiancePhotons(InIrradiancePhotons),
NumPhotonsEmitted(0),
LightSamplingThreadTime(0),
IndirectCustomAttenuationThreadTime(0),
IntersectLightRayThreadTime(0),
PhotonBounceTracingThreadTime(0)
{}
};
/** Thread used to parallelize indirect photon emitting. */
class FIndirectPhotonEmittingThreadRunnable : public FStaticLightingThreadRunnable
{
public:
/** Initialization constructor. */
FIndirectPhotonEmittingThreadRunnable(
FStaticLightingSystem* InSystem,
int32 InThreadIndex,
const FIndirectPhotonEmittingInput& InInput)
:
FStaticLightingThreadRunnable(InSystem, InThreadIndex),
Input(InInput)
{}
// FRunnable interface.
virtual bool Init(void) { return true; }
virtual void Exit(void) {}
virtual void Stop(void) {}
virtual uint32 Run(void);
protected:
const FIndirectPhotonEmittingInput& Input;
};
/** Smallest unit of irradiance photon marking work that can be done in parallel. */
class FIrradianceMarkingWorkRange
{
public:
const int32 RangeIndex;
/** Index into IrradiancePhotons that should be processed for this work range. */
const int32 IrradiancePhotonArrayIndex;
FIrradianceMarkingWorkRange(
int32 InRangeIndex,
int32 InIrradiancePhotonArrayIndex)
:
RangeIndex(InRangeIndex),
IrradiancePhotonArrayIndex(InIrradiancePhotonArrayIndex)
{}
};
class FIrradiancePhotonMarkingThreadRunnable : public FStaticLightingThreadRunnable
{
public:
/** Initialization constructor. */
FIrradiancePhotonMarkingThreadRunnable(FStaticLightingSystem* InSystem, int32 InThreadIndex, TArray<TArray<FIrradiancePhoton>>& InIrradiancePhotons) :
FStaticLightingThreadRunnable(InSystem, InThreadIndex),
IrradiancePhotons(InIrradiancePhotons)
{}
// FRunnable interface.
virtual bool Init(void) { return true; }
virtual void Exit(void) {}
virtual void Stop(void) {}
virtual uint32 Run(void);
private:
/** Irradiance photons to operate on */
TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons;
};
/** Smallest unit of irradiance photon calculating work that can be done in parallel. */
class FIrradianceCalculatingWorkRange
{
public:
const int32 RangeIndex;
/** Index into IrradiancePhotons that should be processed for this work range. */
const int32 IrradiancePhotonArrayIndex;
FIrradianceCalculatingWorkRange(
int32 InRangeIndex,
int32 InIrradiancePhotonArrayIndex)
:
RangeIndex(InRangeIndex),
IrradiancePhotonArrayIndex(InIrradiancePhotonArrayIndex)
{}
};
class FIrradiancePhotonCalculatingThreadRunnable : public FStaticLightingThreadRunnable
{
public:
/** Stats for this thread's operations. */
FCalculateIrradiancePhotonStats Stats;
/** Initialization constructor. */
FIrradiancePhotonCalculatingThreadRunnable(FStaticLightingSystem* InSystem, int32 InThreadIndex, TArray<TArray<FIrradiancePhoton>>& InIrradiancePhotons) :
FStaticLightingThreadRunnable(InSystem, InThreadIndex),
IrradiancePhotons(InIrradiancePhotons)
{}
// FRunnable interface.
virtual bool Init(void) { return true; }
virtual void Exit(void) {}
virtual void Stop(void) {}
virtual uint32 Run(void);
private:
/** Irradiance photons to operate on */
TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons;
};
/** Indicates which type of task a FMappingProcessingThreadRunnable should execute */
enum EStaticLightingTaskType
{
StaticLightingTask_ProcessMappings,
StaticLightingTask_CacheIrradiancePhotons,
StaticLightingTask_RadiositySetup,
StaticLightingTask_RadiosityIterations,
StaticLightingTask_FinalizeSurfaceCache
};
/** A thread which processes static lighting mappings. */
class FMappingProcessingThreadRunnable : public FStaticLightingThreadRunnable
{
/** > 0 this thread has finished working */
FThreadSafeCounter FinishedCounter;
public:
EStaticLightingTaskType TaskType;
/** Initialization constructor. */
FMappingProcessingThreadRunnable(FStaticLightingSystem* InSystem, int32 ThreadIndex, EStaticLightingTaskType InTaskType) :
FStaticLightingThreadRunnable(InSystem, ThreadIndex),
FinishedCounter(0),
TaskType(InTaskType)
{}
// FRunnable interface.
virtual bool Init(void) { return true; }
virtual void Exit(void) {}
virtual void Stop(void) {}
virtual uint32 Run(void);
bool IsComplete()
{
return FinishedCounter.GetValue() > 0;
}
};
/** Encapsulates a list of mappings which static lighting has been computed for, but not yet applied. */
template<typename StaticLightingDataType>
class TCompleteStaticLightingList
{
public:
/** Initialization constructor. */
TCompleteStaticLightingList():
FirstElement(NULL)
{}
/** Adds an element to the list. */
void AddElement(TList<StaticLightingDataType>* Element)
{
// Link the element at the beginning of the list.
TList<StaticLightingDataType>* LocalFirstElement;
do
{
LocalFirstElement = FirstElement;
Element->Next = LocalFirstElement;
}
while(FPlatformAtomics::InterlockedCompareExchangePointer((void**)&FirstElement,Element,LocalFirstElement) != LocalFirstElement);
}
/**
* Applies the static lighting to the mappings in the list, and clears the list.
* Also reports back to Unreal after each mapping has been exported.
* @param LightingSystem - Reference to the static lighting system
*/
void ApplyAndClear(FStaticLightingSystem& LightingSystem);
protected:
TList<StaticLightingDataType>* FirstElement;
};
template<typename DataType>
class TCompleteTaskList : public TCompleteStaticLightingList<DataType>
{
public:
void ApplyAndClear(FStaticLightingSystem& LightingSystem);
};
/** Base class for a task that operates on a rectangle of a texture mapping. */
class FBaseTextureTaskDescription
{
public:
int32 StartX;
int32 StartY;
int32 SizeX;
int32 SizeY;
bool bDebugThisMapping;
FStaticLightingTextureMapping* TextureMapping;
FStaticLightingMappingContext MappingContext;
FGatheredLightMapData2D* LightMapData;
const class FTexelToVertexMap* TexelToVertexMap;
bool bProcessedOnMainThread;
FBaseTextureTaskDescription(const FStaticLightingMesh* InSubjectMesh, class FStaticLightingSystem& InSystem) :
StartX(0),
StartY(0),
SizeX(0),
SizeY(0),
bDebugThisMapping(false),
TextureMapping(NULL),
MappingContext(InSubjectMesh, InSystem),
LightMapData(NULL),
TexelToVertexMap(NULL),
bProcessedOnMainThread(false)
{}
};
/** Class for a task that populates the irradiance cache for a texture mapping. */
class FCacheIndirectTaskDescription : public FBaseTextureTaskDescription
{
public:
FCacheIndirectTaskDescription(const FStaticLightingMesh* InSubjectMesh, class FStaticLightingSystem& InSystem) :
FBaseTextureTaskDescription(InSubjectMesh, InSystem)
{}
};
/** Class for a task that interpolates from the irradiance cache for a texture mapping. */
class FInterpolateIndirectTaskDescription : public FBaseTextureTaskDescription
{
public:
TLightingCache<FFinalGatherSample>* FirstBounceCache;
FInterpolateIndirectTaskDescription(const FStaticLightingMesh* InSubjectMesh, class FStaticLightingSystem& InSystem) :
FBaseTextureTaskDescription(InSubjectMesh, InSystem),
FirstBounceCache(NULL)
{}
};
/** */
class FVolumeSamplesTaskDescription
{
public:
FGuid LevelId;
int32 StartIndex;
int32 NumSamples;
FVolumeSamplesTaskDescription(FGuid InLevelId, int32 InStartIndex, int32 InNumSamples) :
LevelId(InLevelId),
StartIndex(InStartIndex),
NumSamples(InNumSamples)
{}
};
class FVisibilityMeshGroup
{
public:
FBox3f GroupBounds;
/** Array of all the meshes contained in the group. These entries index into VisibilityMeshes. */
TArray<int32> VisibilityIds;
};
class FVisibilityMesh
{
public:
bool bInGroup;
TArray<FStaticLightingMesh*> Meshes;
};
enum EFinalGatherRayBiasMode
{
RBM_ConstantNormalOffset,
RBM_ScaledNormalOffset
};
/** The state of the static lighting system. */
class FStaticLightingSystem
{
public:
/** Debug data generated by startup passes (photon mapping) to transfer back to Unreal. */
mutable FDebugLightingOutput StartupDebugOutput;
FVolumeLightingDebugOutput VolumeLightingDebugOutput;
/** Threads must acquire this critical section before reading or writing to StartupDebugOutput or VolumeLightingDebugOutput, if contention is possible. */
mutable FCriticalSection DebugOutputSync;
/**
* Initializes this static lighting system, and builds static lighting based on the provided options.
* @param InOptions - The static lighting build options.
* @param InScene - The scene containing all the lights and meshes
* @param InExporter - The exporter used to send completed data back to Unreal
* @param InNumThreads - Number of concurrent threads to use for lighting building
*/
FStaticLightingSystem( const FLightingBuildOptions& InOptions, class FScene& InScene, class FLightmassSolverExporter& InExporter, int32 InNumThreads );
~FStaticLightingSystem();
/**
* Returns the Lightmass exporter (back to Unreal)
* @return Lightmass exporter
*/
class FLightmassSolverExporter& GetExporter()
{
return Exporter;
}
FGuid GetDebugGuid() const { return Scene.DebugInput.MappingGuid; }
/**
* Whether the Lighting System is in debug mode or not. When in debug mode, Swarm is not completely hooked up
* and the system will process all mappings in the scene file on its own.
* @return true if in debug mode
*/
bool IsDebugMode() const
{
return GDebugMode;
}
bool HasSkyShadowing() const
{
for (int32 SkylightIndex = 0; SkylightIndex < SkyLights.Num(); SkylightIndex++)
{
// Indicating sky shadowing is needed even if the sky lights do not have shadow casting enabled,
// So that shadow casting can be toggled without rebuilding lighting
// This does mean that skylights with shadow casting disabled will generate unused sky occlusion textures
if (!(SkyLights[SkylightIndex]->LightFlags & GI_LIGHT_HASSTATICLIGHTING))
{
return true;
}
}
return false;
}
/** Rasterizes Mesh into TexelToCornersMap */
void CalculateTexelCorners(const FStaticLightingMesh* Mesh, class FTexelToCornersMap& TexelToCornersMap, int32 UVIndex, bool bDebugThisMapping) const;
/** Rasterizes Mesh into TexelToCornersMap, with extra parameters like which material index to rasterize and UV scale and bias. */
void CalculateTexelCorners(
const TArray<int32>& TriangleIndices,
const TArray<FStaticLightingVertex>& Vertices,
FTexelToCornersMap& TexelToCornersMap,
const TArray<int32>& ElementIndices,
int32 MaterialIndex,
int32 UVIndex,
bool bDebugThisMapping,
FVector2f UVBias,
FVector2f UVScale) const;
FStaticLightingAggregateMeshType& GetAggregateMesh()
{
return *AggregateMesh;
}
private:
/** Exports tasks that are not mappings, if they are ready. */
void ExportNonMappingTasks();
/** Internal accessors */
int32 GetNumShadowRays(int32 BounceNumber, bool bPenumbra=false) const;
int32 GetNumUniformHemisphereSamples(int32 BounceNumber) const;
int32 GetNumPhotonImportanceHemisphereSamples() const;
FBoxSphereBounds3f GetImportanceBounds(bool bClampToScene = true) const;
/** Returns true if the specified position is inside any of the importance volumes. */
bool IsPointInImportanceVolume(const FVector4f& Position, float Tolerance = 0.0f) const;
/** Changes the scene's settings if necessary so that only valid combinations are used */
void ValidateSettings(FScene& InScene);
/** Logs solver stats */
void DumpStats(float TotalStaticLightingTime) const;
/** Logs a solver message */
void LogSolverMessage(const FString& Message) const;
/** Logs a progress update message when appropriate */
void UpdateInternalStatus(int32 OldNumTexelsCompleted) const;
/** Caches samples for any sampling distributions that are known ahead of time, which greatly reduces noise in those estimates. */
void CacheSamples();
/** Sets up photon mapping settings. */
void InitializePhotonSettings();
/** Emits photons, builds data structures to accelerate photon map lookups, and does any other photon preprocessing required. */
void EmitPhotons();
/** Gathers direct photons and generates indirect photon paths. */
void EmitDirectPhotons(
const FBoxSphereBounds3f& ImportanceBounds,
TArray<TArray<FIndirectPathRay> >& IndirectPathRays,
TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons);
/** Entrypoint for all threads emitting direct photons. */
void EmitDirectPhotonsThreadLoop(const FDirectPhotonEmittingInput& Input, int32 ThreadIndex);
/** Emits direct photons for a given work range. */
void EmitDirectPhotonsWorkRange(
const FDirectPhotonEmittingInput& Input,
FDirectPhotonEmittingWorkRange WorkRange,
FDirectPhotonEmittingOutput& Output);
void BuildPhotonSegmentMap(const FPhotonOctree& SourcePhotonMap, FPhotonSegmentOctree& OutPhotonSegementMap, float AddToSegmentMapChance);
/** Gathers indirect photons based on the indirect photon paths. */
void EmitIndirectPhotons(
const FBoxSphereBounds3f& ImportanceBounds,
const TArray<TArray<FIndirectPathRay> >& IndirectPathRays,
TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons);
/** Entrypoint for all threads emitting indirect photons. */
void EmitIndirectPhotonsThreadLoop(const FIndirectPhotonEmittingInput& Input, int32 ThreadIndex);
/** Emits indirect photons for a given work range. */
void EmitIndirectPhotonsWorkRange(
const FIndirectPhotonEmittingInput& Input,
FIndirectPhotonEmittingWorkRange WorkRange,
FIndirectPhotonEmittingOutput& Output);
/** Iterates through all irradiance photons, searches for nearby direct photons, and marks the irradiance photon has having direct photon influence if necessary. */
void MarkIrradiancePhotons(const FBoxSphereBounds3f& ImportanceBounds, TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons);
/** Entry point for all threads marking irradiance photons. */
void MarkIrradiancePhotonsThreadLoop(
int32 ThreadIndex,
TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons);
/** Marks irradiance photons specified by a single work range. */
void MarkIrradiancePhotonsWorkRange(
TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons,
FIrradianceMarkingWorkRange WorkRange);
/** Calculates irradiance for photons randomly chosen to precalculate irradiance. */
void CalculateIrradiancePhotons(const FBoxSphereBounds3f& ImportanceBounds, TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons);
/** Main loop that all threads access to calculate irradiance photons. */
void CalculateIrradiancePhotonsThreadLoop(
int32 ThreadIndex,
TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons,
FCalculateIrradiancePhotonStats& Stats);
/** Calculates irradiance for the photons specified by a single work range. */
void CalculateIrradiancePhotonsWorkRange(
TArray<TArray<FIrradiancePhoton>>& IrradiancePhotons,
FIrradianceCalculatingWorkRange WorkRange,
FCalculateIrradiancePhotonStats& Stats);
/** Cache irradiance photons on surfaces. */
void CacheIrradiancePhotons();
/** Main loop that all threads access to cache irradiance photons. */
void CacheIrradiancePhotonsThreadLoop(int32 ThreadIndex, bool bIsMainThread);
/** Caches irradiance photons on a single texture mapping. */
void CacheIrradiancePhotonsTextureMapping(FStaticLightingTextureMapping* TextureMapping);
void SetupRadiosity();
void RadiositySetupThreadLoop(int32 ThreadIndex, bool bIsMainThread);
void RadiositySetupTextureMapping(FStaticLightingTextureMapping* TextureMapping);
void RunRadiosityIterations();
void RadiosityIterationThreadLoop(int32 ThreadIndex, bool bIsMainThread);
/** Cache irradiance photons on surfaces. */
void FinalizeSurfaceCache();
/** Main loop that all threads access to cache irradiance photons. */
void FinalizeSurfaceCacheThreadLoop(int32 ThreadIndex, bool bIsMainThread);
/** Caches irradiance photons on a single texture mapping. */
void FinalizeSurfaceCacheTextureMapping(FStaticLightingTextureMapping* TextureMapping);
void RasterizeToSurfaceCacheTextureMapping(FStaticLightingTextureMapping* TextureMapping, bool bDebugThisMapping, FTexelToVertexMap& TexelToVertexMap);
void AdjustRepresentativeSurfelForTexelsTextureMapping(FStaticLightingTextureMapping* TextureMapping, FTexelToVertexMap& TexelToVertexMap, FTexelToCornersMap& TexelToCornersMap, FGatheredLightMapData2D* LightMapData, FStaticLightingMappingContext& MappingContext, bool bDebugThisMapping) const;
void RadiosityIterationTextureMapping(FStaticLightingTextureMapping* TextureMapping, int32 PassIndex);
void RadiosityIterationCachedHitpointsTextureMapping(const FTexelToVertexMap& TexelToVertexMap, FStaticLightingTextureMapping* TextureMapping, int32 PassIndex);
/** Returns true if a photon was found within MaxPhotonSearchDistance. */
bool FindAnyNearbyPhoton(
const FPhotonOctree& PhotonMap,
const FVector4f& SearchPosition,
float MaxPhotonSearchDistance,
bool bDebugThisLookup) const;
/**
* Searches the given photon map for the nearest NumPhotonsToFind photons to SearchPosition using an iterative process,
* Unless the start and max search distances are the same, in which case all photons in that distance will be returned.
* The iterative search starts at StartPhotonSearchDistance and doubles the search distance until enough photons are found or the distance is greater than MaxPhotonSearchDistance.
* @return - the furthest found photon's distance squared from SearchPosition, unless the start and max search distances are the same,
* in which case FMath::Square(MaxPhotonSearchDistance) will be returned.
*/
float FindNearbyPhotonsIterative(
const FPhotonOctree& PhotonMap,
const FVector4f& SearchPosition,
const FVector4f& SearchNormal,
int32 NumPhotonsToFind,
float StartPhotonSearchDistance,
float MaxPhotonSearchDistance,
bool bDebugSearchResults,
bool bDebugSearchProcess,
TArray<FPhoton>& FoundPhotons,
FFindNearbyPhotonStats& SearchStats) const;
float FindNearbyPhotonsInVolumeIterative(
const FPhotonSegmentOctree& PhotonSegmentMap,
const FVector4f& SearchPosition,
int32 NumPhotonsToFind,
float StartPhotonSearchDistance,
float MaxPhotonSearchDistance,
TArray<FPhotonSegmentElement>& FoundPhotonSegments,
bool bDebugThisLookup) const;
/**
* Searches the given photon map for the nearest NumPhotonsToFind photons to SearchPosition by sorting octree nodes nearest to furthest.
* @return - the furthest found photon's distance squared from SearchPosition.
*/
float FindNearbyPhotonsSorted(
const FPhotonOctree& PhotonMap,
const FVector4f& SearchPosition,
const FVector4f& SearchNormal,
int32 NumPhotonsToFind,
float MaxPhotonSearchDistance,
bool bDebugSearchResults,
bool bDebugSearchProcess,
TArray<FPhoton>& FoundPhotons,
FFindNearbyPhotonStats& SearchStats) const;
/** Finds the nearest irradiance photon, if one exists. */
FIrradiancePhoton* FindNearestIrradiancePhoton(
const FMinimalStaticLightingVertex& Vertex,
FStaticLightingMappingContext& MappingContext,
TArray<FIrradiancePhoton*>& TempIrradiancePhotons,
bool bVisibleOnly,
bool bDebugThisLookup) const;
/** Calculates the irradiance for an irradiance photon */
FLinearColor CalculatePhotonIrradiance(
const FPhotonOctree& PhotonMap,
int32 NumPhotonsEmitted,
int32 NumPhotonsToFind,
float SearchDistance,
const FIrradiancePhoton& IrradiancePhoton,
bool bDebugThisCalculation,
TArray<FPhoton>& TempFoundPhotons,
FCalculateIrradiancePhotonStats& Stats) const;
/** Calculates incident radiance at a vertex from the given photon map. */
FGatheredLightSample CalculatePhotonIncidentRadiance(
const FPhotonOctree& PhotonMap,
int32 NumPhotonsEmitted,
float SearchDistance,
const FStaticLightingVertex& Vertex,
bool bDebugThisDensityEstimation) const;
/** Calculates exitant radiance at a vertex from the given photon map. */
FLinearColor CalculatePhotonExitantRadiance(
const FPhotonOctree& PhotonMap,
int32 NumPhotonsEmitted,
float SearchDistance,
const FStaticLightingMesh* Mesh,
const FMinimalStaticLightingVertex& Vertex,
int32 ElementIndex,
const FVector4f& OutgoingDirection,
bool bDebugThisDensityEstimation) const;
/** Places volume lighting samples and calculates lighting for them. */
void BeginCalculateVolumeSamples();
/**
* Interpolates lighting from the volume lighting samples to a vertex.
* This mirrors FPrecomputedLightVolume::InterpolateIncidentRadiance in Unreal, used for visualizing interpolation from the lighting volume on surfaces.
*/
FGatheredLightSample InterpolatePrecomputedVolumeIncidentRadiance(
const FStaticLightingVertex& Vertex,
float SampleRadius,
FCoherentRayCache& RayCache,
bool bDebugThisTexel) const;
/**
* Computes direct lighting for a volume point.
* Caller is responsible for initializing the outputs to something valid.
*/
template<int32 SHOrder>
void CalculateApproximateDirectLighting(
const FStaticLightingVertex& Vertex,
float SampleRadius,
const TArray<FVector3f, TInlineAllocator<1>>& VertexOffsets,
float LightSampleFraction,
/** Whether to composite all direct lighting into OutStaticDirectLighting, regardless of static or toggleable. */
bool bCompositeAllLights,
bool bCalculateForIndirectLighting,
bool bDebugThisSample,
FStaticLightingMappingContext& MappingContext,
TGatheredLightSample<SHOrder>& OutStaticDirectLighting,
float& OutToggleableDirectionalLightShadowing) const;
void GatherVolumeImportancePhotonDirections(
const FVector3f WorldPosition,
FVector3f FirstHemisphereNormal,
FVector3f SecondHemisphereNormal,
TArray<FVector4f>& FirstHemisphereImportancePhotonDirections,
TArray<FVector4f>& SecondHemisphereImportancePhotonDirections,
bool bDebugThisSample) const;
/** Calculates incident radiance for a given world space position. */
void CalculateVolumeSampleIncidentRadiance(
const TArray<FVector4f>& UniformHemisphereSamples,
const TArray<FVector2f>& UniformHemisphereSampleUniforms,
float MaxUnoccludedLength,
const TArray<FVector3f, TInlineAllocator<1>>& VertexOffsets,
FVolumeLightingSample& LightingSample,
float& OutBackfacingHitsFraction,
float& OutMinDistanceToSurface,
FLMRandomStream& RandomStream,
FStaticLightingMappingContext& MappingContext,
bool bDebugThisSample
) const;
/** Determines visibility cell placement, called once at startup. */
void SetupPrecomputedVisibility();
int32 GetGroupCellIndex(FVector3f BoxCenter) const;
/** Calculates visibility for a given group of cells, called from all threads. */
void CalculatePrecomputedVisibility(int32 BucketIndex);
void RecursivelyBuildBrickTree(
int32 StartCellIndex,
int32 NumCells,
FIntVector CellCoordinate,
int32 TreeDepth,
bool bCoveringDebugPosition,
const FBox3f& TopLevelCellBounds,
const TArray<FVector3f>& VoxelTestPositions,
const FGuid& IntersectingLevelGuid,
TArray<struct FIrradianceBrickBuildData>& OutBrickBuildData);
void ProcessVolumetricLightmapBrickTask(class FVolumetricLightmapBrickTaskDescription* Task);
bool ProcessVolumetricLightmapTaskIfAvailable();
void GenerateVoxelTestPositions(TArray<FVector3f>& VoxelTestPositions) const;
void CalculateAdaptiveVolumetricLightmap(int32 TaskIndex);
bool DoesVoxelIntersectSceneGeometry(const FBox3f& CellBounds, FGuid& OutIntersectingLevelGuid) const;
bool ShouldRefineVoxel(int32 TreeDepth, const FBox3f& AABB, const TArray<FVector3f>& VoxelTestPositions, bool bDebugThisVoxel, FGuid& OutIntersectingLevelGuid) const;
/** Computes a shadow depth map for a stationary light. */
void CalculateStaticShadowDepthMap(FGuid LightGuid);
/** Prepares for multithreaded generation of VolumeDistanceField. */
void BeginCalculateVolumeDistanceField();
/** Generates a single z layer of VolumeDistanceField. */
void CalculateVolumeDistanceFieldWorkRange(int32 ZIndex);
/**
* Calculates shadowing for a given mapping surface point and light.
* @param Mapping - The mapping the point comes from.
* @param WorldSurfacePoint - The point to check shadowing at.
* @param Light - The light to check shadowing from.
* @param CacheGroup - The calling thread's collision cache.
* @return true if the surface point is shadowed from the light.
*/
bool CalculatePointShadowing(
const FStaticLightingMapping* Mapping,
const FVector4f& WorldSurfacePoint,
const FLight* Light,
FStaticLightingMappingContext& MappingContext,
bool bDebugThisSample) const;
/** Calculates area shadowing from a light for the given vertex. */
FVector2f CalculatePointAreaShadowing(
const FStaticLightingMapping* Mapping,
const FStaticLightingVertex& Vertex,
int32 ElementIndex,
float SampleRadius,
const FLight* Light,
FStaticLightingMappingContext& MappingContext,
FLMRandomStream& RandomStream,
FLinearColor& UnnormalizedTransmission,
const TArray<FLightSurfaceSample>& LightPositionSamples,
bool bDebugThisSample
) const;
/** Calculates the lighting contribution of a light to a mapping vertex. */
FGatheredLightSample CalculatePointLighting(
const FStaticLightingMapping* Mapping,
const FStaticLightingVertex& Vertex,
int32 ElementIndex,
const FLight* Light,
const FLinearColor& InLightIntensity,
const FLinearColor& InTransmission
) const;
/** Returns environment lighting for the given direction. */
FLinearColor EvaluateEnvironmentLighting(const FVector4f& IncomingDirection) const;
/** Evaluates the incoming sky lighting from the scene. */
void EvaluateSkyLighting(const FVector4f& IncomingDirection, float PathSolidAngle, bool bShadowed, bool bForDirectLighting, FLinearColor& OutStaticLighting, FLinearColor& OutStationaryLighting) const;
float EvaluateSkyVariance(const FVector4f& IncomingDirection, float PathSolidAngle) const;
/** Returns a light sample that represents the material attribute specified by MaterialSettings.ViewMaterialAttribute at the intersection. */
FGatheredLightSample GetVisualizedMaterialAttribute(const FStaticLightingMapping* Mapping, const FLightRayIntersection& Intersection) const;
/** Calculates exitant radiance at a vertex. */
FLinearColor CalculateExitantRadiance(
const FStaticLightingMapping* HitMapping,
const FStaticLightingMesh* HitMesh,
const FMinimalStaticLightingVertex& Vertex,
int32 ElementIndex,
const FVector4f& OutgoingDirection,
int32 BounceNumber,
EHemisphereGatherClassification GatherClassification,
FStaticLightingMappingContext& MappingContext,
bool bDebugThisTexel) const;
void IntersectLightRay(
const FStaticLightingMapping* Mapping,
const FFullStaticLightingVertex& Vertex,
float SampleRadius,
const FVector4f& WorldPathDirection,
const FVector4f& TangentPathDirection,
EFinalGatherRayBiasMode RayBiasMode,
FStaticLightingMappingContext& MappingContext,
FLightRay& OutLightRay,
FLightRayIntersection& OutLightRayIntersection) const;
/** Takes a final gather sample in the given tangent space direction. */
FLinearColor FinalGatherSample(
const FStaticLightingMapping* Mapping,
const FFullStaticLightingVertex& Vertex,
const FVector4f& WorldPathDirection,
const FVector4f& TangentPathDirection,
const FLightRay& PathRay,
const FLightRayIntersection& RayIntersection,
float PathSolidAngle,
int32 BounceNumber,
EHemisphereGatherClassification GatherClassification,
bool bGatheringForCachedDirectLighting,
bool bDebugThisTexel,
FStaticLightingMappingContext& MappingContext,
FLMRandomStream& RandomStream,
FLightingCacheGatherInfo& GatherInfo,
FFinalGatherInfo& FinalGatherInfo,
FFinalGatherHitPoint& HitPoint,
FVector3f& OutUnoccludedSkyVector,
FLinearColor& OutStationarySkyLighting) const;
/**
* Final gather using adaptive sampling to estimate the incident radiance function.
* Adaptive refinement is done on brightness differences and anywhere that a first bounce photon determined lighting was coming from.
*/
template<class SampleType>
SampleType IncomingRadianceAdaptive(
const FStaticLightingMapping* Mapping,
const FFullStaticLightingVertex& Vertex,
float SampleRadius,
bool bIntersectingSurface,
int32 ElementIndex,
int32 BounceNumber,
EFinalGatherRayBiasMode RayBiasMode,
EHemisphereGatherClassification GatherClassification,
int32 NumAdaptiveRefinementLevels,
float BrightnessThresholdScale,
const TArray<FVector4f>& UniformHemisphereSamples,
const TArray<FVector2f>& UniformHemisphereSampleUniforms,
float MaxUnoccludedLength,
const TArray<FVector4f>& ImportancePhotonDirections,
FStaticLightingMappingContext& MappingContext,
FLMRandomStream& RandomStream,
FLightingCacheGatherInfo& GatherInfo,
bool bGatheringForCachedDirectLighting,
bool bDebugThisTexel) const;
/** Calculates irradiance gradients for a sample position that will be cached. */
void CalculateIrradianceGradients(
int32 BounceNumber,
const FLightingCacheGatherInfo& GatherInfo,
FVector4f& RotationalGradient,
FVector4f& TranslationalGradient) const;
/**
* Interpolates incoming radiance from the lighting cache if possible,
* otherwise estimates incoming radiance for this sample point and adds it to the cache.
*/
FFinalGatherSample CachePointIncomingRadiance(
const FStaticLightingMapping* Mapping,
const FFullStaticLightingVertex& Vertex,
int32 ElementIndex,
float TexelRadius,
float SampleRadius,
bool bIntersectingSurface,
FStaticLightingMappingContext& MappingContext,
FLMRandomStream& RandomStream,
bool bDebugThisTexel) const;
/**
* Builds lighting for a texture mapping.
* @param TextureMapping - The mapping to build lighting for.
*/
void ProcessTextureMapping(FStaticLightingTextureMapping* TextureMapping);
/** Traces a ray to the corner of a texel. */
void TraceToTexelCorner(
const FVector4f& TexelCenterOffset,
const FFullStaticLightingVertex& FullVertex,
FVector2f CornerSigns,
float TexelRadius,
FStaticLightingMappingContext& MappingContext,
FLightRayIntersection& Intersection,
bool& bHitBackface,
bool bDebugThisTexel) const;
/** Calculates TexelToVertexMap and initializes each texel's light sample as mapped or not. */
void SetupTextureMapping(
FStaticLightingTextureMapping* TextureMapping,
FGatheredLightMapData2D& LightMapData,
class FTexelToVertexMap& TexelToVertexMap,
class FTexelToCornersMap& TexelToCornersMap,
FStaticLightingMappingContext& MappingContext,
bool bDebugThisMapping) const;
/** Calculates direct lighting as if all lights were non-area lights, then filters the results in texture space to create approximate soft shadows. */
void CalculateDirectLightingTextureMappingFiltered(
FStaticLightingTextureMapping* TextureMapping,
FStaticLightingMappingContext& MappingContext,
FGatheredLightMapData2D& LightMapData,
TMap<const FLight*, FShadowMapData2D*>& ShadowMaps,
const FTexelToVertexMap& TexelToVertexMap,
bool bDebugThisMapping,
const FLight* Light) const;
/**
* Calculate lighting from area lights, no filtering in texture space.
* Shadow penumbras will be correctly shaped and will be softer for larger light sources and distant shadow casters.
*/
void CalculateDirectAreaLightingTextureMapping(
FStaticLightingTextureMapping* TextureMapping,
FStaticLightingMappingContext& MappingContext,
FGatheredLightMapData2D& LightMapData,
FShadowMapData2D*& ShadowMapData,
const FTexelToVertexMap& TexelToVertexMap,
bool bDebugThisMapping,
const FLight* Light) const;
/**
* Calculate signed distance field shadowing from a single light,
* Based on the paper "Improved Alpha-Tested Magnification for Vector Textures and Special Effects" by Valve.
*/
void CalculateDirectSignedDistanceFieldLightingTextureMappingTextureSpace(
FStaticLightingTextureMapping* TextureMapping,
FStaticLightingMappingContext& MappingContext,
FGatheredLightMapData2D& LightMapData,
TMap<const FLight*, FSignedDistanceFieldShadowMapData2D*>& ShadowMaps,
const FTexelToVertexMap& TexelToVertexMap,
const FTexelToCornersMap& TexelToCornersMap,
bool bDebugThisMapping,
const FLight* Light) const;
/** Experimental method that avoids artifacts due to lightmap seams. */
void CalculateDirectSignedDistanceFieldLightingTextureMappingLightSpace(
FStaticLightingTextureMapping* TextureMapping,
FStaticLightingMappingContext& MappingContext,
FGatheredLightMapData2D& LightMapData,
TMap<const FLight*, FSignedDistanceFieldShadowMapData2D*>& ShadowMaps,
const FTexelToVertexMap& TexelToVertexMap,
const FTexelToCornersMap& TexelToCornersMap,
bool bDebugThisMapping,
const FLight* Light) const;
/**
* Estimate direct lighting using the direct photon map.
* This is only useful for debugging what the final gather rays see.
*/
void CalculateDirectLightingTextureMappingPhotonMap(
FStaticLightingTextureMapping* TextureMapping,
FStaticLightingMappingContext& MappingContext,
FGatheredLightMapData2D& LightMapData,
TMap<const FLight*, FShadowMapData2D*>& ShadowMaps,
const FTexelToVertexMap& TexelToVertexMap,
bool bDebugThisMapping) const;
/**
* Builds an irradiance cache for a given mapping task.
* This can be called from any thread, not just the thread that owns the mapping, so called code must be thread safe in that manner.
*/
void ProcessCacheIndirectLightingTask(FCacheIndirectTaskDescription* Task, bool bProcessedByMappingThread);
/**
* Interpolates from the irradiance cache for a given mapping task.
* This can be called from any thread, not just the thread that owns the mapping, so called code must be thread safe in that manner.
*/
void ProcessInterpolateTask(FInterpolateIndirectTaskDescription* Task, bool bProcessedByMappingThread);
void ProcessVolumeSamplesTask(const FVolumeSamplesTaskDescription& Task);
/** Handles indirect lighting calculations for a single texture mapping. */
void CalculateIndirectLightingTextureMapping(
FStaticLightingTextureMapping* TextureMapping,
FStaticLightingMappingContext& MappingContext,
FGatheredLightMapData2D& LightMapData,
const FTexelToVertexMap& TexelToVertexMap,
bool bDebugThisMapping);
/** Overrides LightMapData with material attributes if MaterialSettings.ViewMaterialAttribute != VMA_None */
void ViewMaterialAttributesTextureMapping(
FStaticLightingTextureMapping* TextureMapping,
FStaticLightingMappingContext& MappingContext,
FGatheredLightMapData2D& LightMapData,
const FTexelToVertexMap& TexelToVertexMap,
bool bDebugThisMapping) const;
/** Colors texels with invalid lightmap UVs to make it obvious that they are wrong. */
void ColorInvalidLightmapUVs(
const FStaticLightingTextureMapping* TextureMapping,
FGatheredLightMapData2D& LightMapData,
bool bDebugThisMapping) const;
/** Adds a texel of padding around texture mappings and copies the nearest texel into the padding. */
void PadTextureMapping(
const FStaticLightingTextureMapping* TextureMapping,
const FGatheredLightMapData2D& LightMapData,
FGatheredLightMapData2D& PaddedLightMapData,
TMap<const FLight*, FShadowMapData2D*>& ShadowMaps,
TMap<const FLight*, FSignedDistanceFieldShadowMapData2D*>& SignedDistanceFieldShadowMaps) const;
/**
* Retrieves the next task from Swarm. Optionally blocking, thread-safe function call. Returns NULL when there are no more tasks.
* @param WaitTime The timeout period in milliseconds for the request
* @param bWaitTimedOut Output parameter; true if the request timed out, false if not
* @return The next mapping task to process.
*/
FStaticLightingMapping* ThreadGetNextMapping(
FThreadStatistics&
ThreadStatistics,
FGuid& TaskGuid,
uint32 WaitTime,
bool& bWaitTimedOut,
bool& bDynamicObjectTask,
int32& PrecomputedVisibilityTaskIndex,
int32& VolumetricLightmapTaskIndex,
bool& DominantShadowTask,
bool& bMeshAreaLightDataTask,
bool& bVolumeDataTask);
/**
* The processing loop for a static lighting thread.
* @param bIsMainThread - true if this is running in the main thread.
* @param ThreadStatistics - [out] Various thread statistics
*/
void ThreadLoop(bool bIsMainThread, int32 ThreadIndex, FThreadStatistics& ThreadStatistics, float& IdleTime);
/**
* Creates multiple worker threads and starts the process locally.
*/
void MultithreadProcess();
/** The lights in the world which the system is building, excluding sky lights. */
TArray<FLight*> Lights;
TArray<FSkyLight*> SkyLights;
/** Mesh area lights in the world. */
TIndirectArray<FMeshAreaLight> MeshAreaLights;
/** The options the system is building lighting with. */
const FLightingBuildOptions Options;
/** Critical section to synchronize the access to Mappings (used only when GDebugMode is true). */
FCriticalSection CriticalSection;
/** References to the scene's settings, for convenience */
FStaticLightingSettings& GeneralSettings;
FStaticLightingSceneConstants& SceneConstants;
FSceneMaterialSettings& MaterialSettings;
FMeshAreaLightSettings& MeshAreaLightSettings;
FDynamicObjectSettings& DynamicObjectSettings;
FVolumetricLightmapSettings& VolumetricLightmapSettings;
FPrecomputedVisibilitySettings& PrecomputedVisibilitySettings;
FVolumeDistanceFieldSettings& VolumeDistanceFieldSettings;
FAmbientOcclusionSettings& AmbientOcclusionSettings;
FStaticShadowSettings& ShadowSettings;
FImportanceTracingSettings& ImportanceTracingSettings;
FPhotonMappingSettings& PhotonMappingSettings;
FIrradianceCachingSettings& IrradianceCachingSettings;
/** Stats of the system */
mutable FStaticLightingStats Stats;
/**
* Counts the number of mapping tasks that have begun, and might need help from other threads with tasks that they generate.
* This is used to keep completed mapping threads running so they can check for tasks.
*/
volatile int32 TasksInProgressThatWillNeedHelp;
/** List of tasks to cache indirect lighting, used by all mapping threads. */
// consider changing this from FIFO to Unordered, which may be faster
TLockFreePointerListLIFO<FCacheIndirectTaskDescription> CacheIndirectLightingTasks;
/** List of tasks to interpolate indirect lighting, used by all mapping threads. */
// consider changing this from FIFO to Unordered, which may be faster
TLockFreePointerListLIFO<FInterpolateIndirectTaskDescription> InterpolateIndirectLightingTasks;
TLockFreePointerListLIFO<FVolumetricLightmapBrickTaskDescription> VolumetricLightmapBrickTasks;
TArray<FVolumeSamplesTaskDescription> VolumeSampleTasks;
volatile int32 bHasVolumeSampleTasks;
volatile int32 NextVolumeSampleTaskIndex;
volatile int32 NumVolumeSampleTasksOutstanding;
volatile int32 bShouldExportVolumeSampleData;
/** Bounds that VolumeLightingSamples were generated in. */
FBoxSphereBounds3f VolumeBounds;
/** Octree used for interpolating the volume lighting samples if DynamicObjectSettings.bVisualizeVolumeLightInterpolation is true. */
FVolumeLightingInterpolationOctree VolumeLightingInterpolationOctree;
/** Map from Level Guid to array of volume lighting samples generated. */
TMap<FGuid,TArray<FVolumeLightingSample> > VolumeLightingSamples;
/** All precomputed visibility cells in the scene. Some of these may be processed on other agents. */
TArray<FPrecomputedVisibilityCell> AllPrecomputedVisibilityCells;
/** Threads must acquire this critical section before reading or writing to CompletedStaticShadowDepthMaps. */
FCriticalSection CompletedStaticShadowDepthMapsSync;
/** Static shadow depth maps ready to be exported by the main thread. */
TMap<const FLight*, FStaticShadowDepthMap*> CompletedStaticShadowDepthMaps;
/** Non-zero if the mesh area light data task should be exported. */
volatile int32 bShouldExportMeshAreaLightData;
/** Non-zero if the volume distance field task should be exported. */
volatile int32 bShouldExportVolumeDistanceField;
/** Number of direct photons to emit */
int32 NumDirectPhotonsToEmit;
/** Number of photons that were emitted until enough direct photons were gathered */
int32 NumPhotonsEmittedDirect;
/** Photon map for direct photons */
FPhotonOctree DirectPhotonMap;
/** The target number of indirect photon paths to gather. */
int32 NumIndirectPhotonPaths;
/** Number of indirect photons to emit */
int32 NumIndirectPhotonsToEmit;
/** Number of photons that were emitted until enough first bounce photons were gathered */
int32 NumPhotonsEmittedFirstBounce;
/**
* Photon map for first bounce indirect photons.
* This is separate from other indirect photons so we can access just first bounce photons and use them for guiding the final gather.
*/
FPhotonOctree FirstBouncePhotonMap;
/** Tracks first bounce photons that did not intersect a surface and escaped. Used when lighting volumes. */
FPhotonOctree FirstBounceEscapedPhotonMap;
/** Stores photon segments, which allows finding photons which travelled near a certain point in space. */
FPhotonSegmentOctree FirstBouncePhotonSegmentMap;
/** Number of photons that were emitted until enough second bounce photons were gathered */
int32 NumPhotonsEmittedSecondBounce;
/** Photon map for second and up bounce photons. */
FPhotonOctree SecondBouncePhotonMap;
/** Fraction of direct photons deposited to calculate irradiance at. */
float DirectIrradiancePhotonFraction;
/** Fraction of indirect photons deposited to calculate irradiance at. */
float IndirectIrradiancePhotonFraction;
/** Photon map storing irradiance photons */
FIrradiancePhotonOctree IrradiancePhotonMap;
/**
* Irradiance photons generated by photon emission.
* Each array was generated on a separate thread, so these are stored as an array of irradiance photon arrays,
* Which avoids copying to one large array, since that can take a while due to the large irradiance photon memory size.
*/
TArray<TArray<FIrradiancePhoton>> mIrradiancePhotons;
/** Maximum distance to trace a ray through the scene. */
float MaxRayDistance;
/** Cached direction samples for hemisphere gathers. */
TArray<FVector4f> CachedHemisphereSamples;
/** Length of all the hemisphere samples averaged, which is also the max length that a bent normal can be. */
float CachedSamplesMaxUnoccludedLength;
TArray<FVector2f> CachedHemisphereSampleUniforms;
TArray<FVector4f> CachedHemisphereSamplesForRadiosity[3];
TArray<FVector2f> CachedHemisphereSamplesForRadiosityUniforms[3];
TArray<FVector4f> CachedVolumetricLightmapUniformHemisphereSamples;
TArray<FVector2f> CachedVolumetricLightmapUniformHemisphereSampleUniforms;
float CachedVolumetricLightmapMaxUnoccludedLength;
TArray<FVector3f, TInlineAllocator<1>> CachedVolumetricLightmapVertexOffsets;
/** The aggregate mesh used for raytracing. */
FStaticLightingAggregateMeshType* AggregateMesh;
FDefaultAggregateMesh* VoxelizationSurfaceAggregateMesh;
FDefaultAggregateMesh* VoxelizationVolumeAggregateMesh;
FDefaultAggregateMesh* LandscapeCullingVoxelizationAggregateMesh;
/** The input scene describing geometry, materials and lights. */
const FScene& Scene;
/** All meshes in the system. */
TArray< FStaticLightingMesh* > Meshes;
/** All meshes involved in sPVS indexed by their visibility id, setup at scene setup time. */
TArray<FVisibilityMesh> VisibilityMeshes;
/** Visibility groups which are clusters of meshes, generated at PVS startup time. */
TArray<FVisibilityMeshGroup> VisibilityGroups;
/** X and Y dimensions of GroupGrid. */
int32 GroupVisibilityGridSizeXY;
/** Z dimension of GroupGrid. */
int32 GroupVisibilityGridSizeZ;
/** World space bounding box of GroupGrid. */
FBox3f VisibilityGridBounds;
/** Grid of indices into VisibilityGroups. */
TArray<int32> GroupGrid;
/** All mappings in the system. */
TArray< FStaticLightingMapping* > AllMappings;
/** All mappings in the system for which lighting will be built. */
TMap< FGuid, FStaticLightingMapping* > Mappings;
/** The next index into Mappings which processing hasn't started for yet. */
FThreadSafeCounter NextMappingToProcess;
/** Stats on how many texels and vertices have been completed, written and read by all threads. */
volatile int32 NumTexelsCompleted;
/** A list of the texture mappings which static lighting has been computed for, but not yet applied. This is accessed by multiple threads and should be written to using interlocked functions. */
TCompleteStaticLightingList<FTextureMappingStaticLightingData> CompleteTextureMappingList;
/** List of complete visibility task data. */
TCompleteTaskList<FPrecomputedVisibilityData> CompleteVisibilityTaskList;
TCompleteTaskList<FVolumetricLightmapTaskData> CompleteVolumetricLightmapTaskList;
// Landscape mapping for Lighting Sample number estimation...
TArray< FStaticLightingMapping* > LandscapeMappings;
int32 VolumeSizeX;
int32 VolumeSizeY;
int32 VolumeSizeZ;
FVector4f::FReal DistanceFieldVoxelSize;
FBox3f DistanceFieldVolumeBounds;
TArray<FColor> VolumeDistanceField;
/** */
volatile int32 NumOutstandingVolumeDataLayers;
/** */
volatile int32 OutstandingVolumeDataLayerIndex;
/** Number of threads to use for static lighting */
const int32 NumStaticLightingThreads;
/** The threads spawned by the static lighting system for processing mappings. */
TIndirectArray<FMappingProcessingThreadRunnable> Threads;
/** Index of the next entry in DirectPhotonEmittingWorkRanges to process. */
FThreadSafeCounter DirectPhotonEmittingWorkRangeIndex;
TArray<FDirectPhotonEmittingWorkRange> DirectPhotonEmittingWorkRanges;
TArray<FDirectPhotonEmittingOutput> DirectPhotonEmittingOutputs;
/** Index of the next entry in IndirectPhotonEmittingWorkRanges to process. */
FThreadSafeCounter IndirectPhotonEmittingWorkRangeIndex;
TArray<FIndirectPhotonEmittingWorkRange> IndirectPhotonEmittingWorkRanges;
TArray<FIndirectPhotonEmittingOutput> IndirectPhotonEmittingOutputs;
/** Index of the next entry in IrradianceMarkWorkRanges to process. */
FThreadSafeCounter IrradianceMarkWorkRangeIndex;
TArray<FIrradianceMarkingWorkRange> IrradianceMarkWorkRanges;
/** Index of the next entry in IrradianceCalculationWorkRanges to process. */
FThreadSafeCounter IrradianceCalcWorkRangeIndex;
TArray<FIrradianceCalculatingWorkRange> IrradianceCalculationWorkRanges;
/** Index of the next mapping in AllMappings to cache irradiance photons on */
FThreadSafeCounter NextMappingToCacheIrradiancePhotonsOn;
/** Index into IrradiancePhotons of the array containing the photon being debugged, or INDEX_NONE if no photon is being debugged. */
int32 DebugIrradiancePhotonCalculationArrayIndex;
/** Index into IrradiancePhotons(DebugIrradiancePhotonCalculationArrayIndex) of the photon being debugged. */
int32 DebugIrradiancePhotonCalculationPhotonIndex;
TIndirectArray<FMappingProcessingThreadRunnable> IrradiancePhotonCachingThreads;
FThreadSafeCounter NextMappingToProcessRadiositySetup;
FThreadSafeCounter NextMappingToProcessRadiosityIterations;
TArray<FThreadSafeCounter> NumCompletedRadiosityIterationMappings;
FThreadSafeCounter NextMappingToFinalizeSurfaceCache;
TIndirectArray<FMappingProcessingThreadRunnable> RadiositySetupThreads;
TIndirectArray<FMappingProcessingThreadRunnable> RadiosityIterationThreads;
TIndirectArray<FMappingProcessingThreadRunnable> FinalizeSurfaceCacheThreads;
/** Lightmass exporter (back to Unreal) */
class FLightmassSolverExporter& Exporter;
// allow the vertex mapper access to the private functions
friend class FStaticLightingMappingContext;
friend class FLightingCacheBase;
friend class FStaticLightingThreadRunnable;
friend class FDirectPhotonEmittingThreadRunnable;
friend class FIndirectPhotonEmittingThreadRunnable;
friend class FIrradiancePhotonMarkingThreadRunnable;
friend class FIrradiancePhotonCalculatingThreadRunnable;
friend class FMappingProcessingThreadRunnable;
friend class FVolumeSamplePlacementRasterPolicy;
friend class FUniformHemisphereRefinementGrid;
friend class FStaticLightingTextureMapping;
};
/**
* Checks if a light is behind a triangle.
* @param TrianglePoint - Any point on the triangle.
* @param TriangleNormal - The (not necessarily normalized) triangle surface normal.
* @param Light - The light to classify.
* @return true if the light is behind the triangle.
*/
extern bool IsLightBehindSurface(const FVector4f& TrianglePoint, const FVector4f& TriangleNormal, const FLight* Light);
/**
* Culls lights that are behind a triangle.
* @param bTwoSidedMaterial - true if the triangle has a two-sided material. If so, lights behind the surface are not culled.
* @param TrianglePoint - Any point on the triangle.
* @param TriangleNormal - The (not necessarily normalized) triangle surface normal.
* @param Lights - The lights to cull.
* @return A map from Lights index to a boolean which is true if the light is in front of the triangle.
*/
extern TBitArray<> CullBackfacingLights(bool bTwoSidedMaterial, const FVector4f& TrianglePoint, const FVector4f& TriangleNormal, const TArray<FLight*>& Lights);
#include "LightingSystem.inl" // IWYU pragma: export
} //namespace Lightmass