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

239 lines
7.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "ImportExport.h"
#include "Math/SHMath.h"
namespace Lightmass
{
/**
* The light incident for a point on a surface, in the representation used when gathering lighting.
* This representation is additive, and allows for accumulating lighting contributions in-place.
*/
template <int32 SHOrder>
class TGatheredLightSample
{
public:
/** World space incident lighting. */
TSHVectorRGB<SHOrder> SHVector;
/** Incident lighting including dot(N, L) where N is the smoothed vertex normal. */
FLinearColor IncidentLighting;
/** Correction factor to force SH as applied to a flat normal map to be 1 to get purely directional data. */
float SHCorrection;
/** Sky bent normal, points toward the most unoccluded direction, and the length is the visibility amount (0 = occluded, 1 = visible). */
FVector3f SkyOcclusion;
float AOMaterialMask;
/** Initialization constructor. */
TGatheredLightSample()
{
SHCorrection = 0.0f;
IncidentLighting = FLinearColor(0, 0, 0, 0);
SkyOcclusion = FVector3f(0);
AOMaterialMask = 0;
}
TGatheredLightSample(EForceInit)
{
SHCorrection = 0.0f;
IncidentLighting = FLinearColor(0, 0, 0, 0);
SkyOcclusion = FVector3f(0);
AOMaterialMask = 0;
}
/**
* Adds a weighted light sample to this light sample.
* @param OtherSample - The sample to add.
* @param Weight - The weight to multiply the other sample by before addition.
*/
void AddWeighted(const TGatheredLightSample& OtherSample, float Weight);
void ApplyOcclusion(float Occlusion);
inline void SetSkyOcclusion(FVector3f InSkyOcclusion)
{
SkyOcclusion = InSkyOcclusion;
}
bool AreFloatsValid() const;
TGatheredLightSample operator*(float Scalar) const
{
TGatheredLightSample Result;
Result.SHVector = SHVector * Scalar;
Result.SHCorrection = SHCorrection * Scalar;
Result.IncidentLighting = IncidentLighting * Scalar;
Result.SkyOcclusion = SkyOcclusion * Scalar;
Result.AOMaterialMask = AOMaterialMask * Scalar;
return Result;
}
TGatheredLightSample operator+(const TGatheredLightSample& SampleB) const
{
TGatheredLightSample Result;
Result.SHVector = SHVector + SampleB.SHVector;
Result.SHCorrection = SHCorrection + SampleB.SHCorrection;
Result.IncidentLighting = IncidentLighting + SampleB.IncidentLighting;
Result.SkyOcclusion = SkyOcclusion + SampleB.SkyOcclusion;
Result.AOMaterialMask = AOMaterialMask + SampleB.AOMaterialMask;
return Result;
}
};
class FGatheredLightSampleUtil
{
public:
/**
* Constructs a light sample representing an ambient light.
* Note: Lighting contributed through this method won't have the same final brightness as PointLightWorldSpace, because of the dot(N, L)
* @param Color - The color/intensity of the light at the sample point.
*/
template <int32 SHOrder>
static TGatheredLightSample<SHOrder> AmbientLight(const FLinearColor& Color);
/**
* Constructs a light sample representing a point light.
* @param Color - The color/intensity of the light at the sample point.
* @param Direction - The direction toward the light at the sample point.
*/
template <int32 SHOrder>
static TGatheredLightSample<SHOrder> PointLightWorldSpace(const FLinearColor& Color, const FVector4f& TangentDirection, const FVector4f& WorldDirection);
};
typedef TGatheredLightSample<2> FGatheredLightSample;
typedef TGatheredLightSample<3> FGatheredLightSample3;
class FGatheredLightMapSample
{
public:
FGatheredLightSample HighQuality;
FGatheredLightSample LowQuality;
/** True if this sample maps to a valid point on a triangle. This is only meaningful for texture lightmaps. */
bool bIsMapped;
FGatheredLightMapSample()
: bIsMapped(false)
{}
FGatheredLightMapSample(const FGatheredLightSample& Sample)
: HighQuality(Sample)
, LowQuality(Sample)
, bIsMapped(false)
{}
FGatheredLightMapSample& operator=(const FGatheredLightSample& Sample)
{
HighQuality = Sample;
LowQuality = Sample;
return *this;
}
/**
* Adds a weighted light sample to this light sample.
* @param OtherSample - The sample to add.
* @param Weight - The weight to multiply the other sample by before addition.
*/
void AddWeighted(const FGatheredLightSample& OtherSample, float Weight)
{
HighQuality.AddWeighted( OtherSample, Weight );
LowQuality.AddWeighted( OtherSample, Weight );
}
void ApplyOcclusion(float Occlusion)
{
HighQuality.ApplyOcclusion(Occlusion);
LowQuality.ApplyOcclusion(Occlusion);
}
/** Converts an FGatheredLightMapSample into a FLightSample. */
FLightSample ConvertToLightSample(bool bDebugThisSample) const;
};
/** The lighting information gathered for one final gather sample */
template <int32 SHOrder>
class TFinalGatherSample : public TGatheredLightSample<SHOrder>
{
public:
/** Occlusion factor of the sample, 0 is completely unoccluded, 1 is completely occluded. */
float Occlusion;
/**
* A light sample for sky lighting. This has to be stored separately to support stationary sky lights only contributing to low quality lightmaps.
*/
TGatheredLightSample<SHOrder> StationarySkyLighting;
/** Initialization constructor. */
TFinalGatherSample() :
TGatheredLightSample<SHOrder>(),
Occlusion(0.0f)
{}
TFinalGatherSample(EForceInit) :
TGatheredLightSample<SHOrder>(ForceInit),
Occlusion(0.0f)
{}
/**
* Adds a weighted light sample to this light sample.
* @param OtherSample - The sample to add.
* @param Weight - The weight to multiply the other sample by before addition.
*/
void AddWeighted(const TFinalGatherSample& OtherSample, float Weight);
/**
* Adds a weighted light sample to this light sample.
* @param OtherSample - The sample to add.
* @param Weight - The weight to multiply the other sample by before addition.
*/
template<int32 OtherOrder>
inline void AddWeighted(const TGatheredLightSample<OtherOrder>& OtherSample, float Weight)
{
TGatheredLightSample<SHOrder>::AddWeighted(OtherSample, Weight);
}
inline void SetOcclusion(float InOcclusion)
{
Occlusion = InOcclusion;
}
inline void AddIncomingRadiance(const FLinearColor& IncomingRadiance, float Weight, const FVector4f& TangentSpaceDirection, const FVector4f& WorldSpaceDirection)
{
AddWeighted(FGatheredLightSampleUtil::PointLightWorldSpace<SHOrder>(IncomingRadiance, TangentSpaceDirection, WorldSpaceDirection), Weight);
}
bool AreFloatsValid() const;
TFinalGatherSample operator*(float Scalar) const
{
TFinalGatherSample Result;
(TGatheredLightSample<SHOrder>&)Result = (const TGatheredLightSample<SHOrder>&)(*this) * Scalar;
Result.Occlusion = Occlusion * Scalar;
return Result;
}
TFinalGatherSample operator+(const TFinalGatherSample& SampleB) const
{
TFinalGatherSample Result;
(TGatheredLightSample<SHOrder>&)Result = (const TGatheredLightSample<SHOrder>&)(*this) + (const TGatheredLightSample<SHOrder>&)SampleB;
Result.Occlusion = Occlusion + SampleB.Occlusion;
return Result;
}
};
typedef TFinalGatherSample<2> FFinalGatherSample;
typedef TFinalGatherSample<3> FFinalGatherSample3;
} //namespace Lightmass