6#include "HAL/UnrealMemory.h"
8#include "Math/MathFwd.h"
9#include "Math/UnrealMathSSE.h"
10#include "Math/UnrealMathUtility.h"
11#include "Math/Vector.h"
12#include "Math/Vector4.h"
13#include "Math/VectorRegister.h"
27 return L * (L + 1) + M;
36 enum { MaxSHOrder = Order };
37 enum { MaxSHBasis = MaxSHOrder * MaxSHOrder };
38 enum { NumComponentsPerSIMDVector = 4 };
39 enum { NumSIMDVectors = (MaxSHBasis + NumComponentsPerSIMDVector - 1) / NumComponentsPerSIMDVector };
40 enum { NumTotalFloats = NumSIMDVectors * NumComponentsPerSIMDVector };
41 float V[NumTotalFloats];
44 static constexpr float ConstantBasisIntegral = 3.5449077018110320545963349666823f;
49 FMemory::Memzero(V,
sizeof(V));
52 TSHVector(
float V0,
float V1,
float V2,
float V3)
54 FMemory::Memzero(V,
sizeof(V));
62 explicit TSHVector(
const FVector4f& Vector)
64 FMemory::Memzero(V,
sizeof(V));
73 template<int32 OtherOrder>
74 explicit TSHVector(
const TSHVector<OtherOrder>& Other)
76 if (Order <= OtherOrder)
78 FMemory::Memcpy(V, Other.V,
sizeof(V));
83 FMemory::Memcpy(V, Other.V,
sizeof(V));
89 friend FORCEINLINE TSHVector operator*(
const TSHVector& A,
const float& B)
91 const VectorRegister4Float ReplicatedScalar = VectorLoadFloat1(&B);
94 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
96 VectorRegister4Float MulResult = VectorMultiply(
97 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
100 VectorStoreAligned(MulResult, &Result.V[BasisIndex * NumComponentsPerSIMDVector]);
106 friend FORCEINLINE TSHVector operator/(
const TSHVector& A,
const float& Scalar)
108 const float B = (1.0f / Scalar);
109 const VectorRegister4Float ReplicatedScalar = VectorLoadFloat1(&B);
112 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
114 VectorRegister4Float MulResult = VectorMultiply(
115 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
118 VectorStoreAligned(MulResult, &Result.V[BasisIndex * NumComponentsPerSIMDVector]);
124 friend FORCEINLINE TSHVector operator+(
const TSHVector& A,
const TSHVector& B)
127 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
129 VectorRegister4Float AddResult = VectorAdd(
130 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
131 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
134 VectorStoreAligned(AddResult, &Result.V[BasisIndex * NumComponentsPerSIMDVector]);
140 friend FORCEINLINE TSHVector operator-(
const TSHVector& A,
const TSHVector& B)
143 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
145 VectorRegister4Float SubResult = VectorSubtract(
146 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
147 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
150 VectorStoreAligned(SubResult, &Result.V[BasisIndex * NumComponentsPerSIMDVector]);
156 friend FORCEINLINE float Dot(
const TSHVector& A,
const TSHVector& B)
158 VectorRegister4Float ReplicatedResult = VectorZero();
159 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
161 ReplicatedResult = VectorAdd(
164 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
165 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
170 VectorStoreFloat1(ReplicatedResult,&Result);
177 FORCEINLINE TSHVector& operator+=(
const TSHVector& B)
179 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
181 VectorRegister4Float AddResult = VectorAdd(
182 VectorLoadAligned(&V[BasisIndex * NumComponentsPerSIMDVector]),
183 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
186 VectorStoreAligned(AddResult, &V[BasisIndex * NumComponentsPerSIMDVector]);
194 FORCEINLINE TSHVector& operator-=(
const TSHVector& B)
196 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
198 VectorRegister4Float SubResult = VectorSubtract(
199 VectorLoadAligned(&V[BasisIndex * NumComponentsPerSIMDVector]),
200 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
203 VectorStoreAligned(SubResult, &V[BasisIndex * NumComponentsPerSIMDVector]);
212 FORCEINLINE TSHVector& operator/=(
const float& Scalar)
214 const float B = (1.0f/Scalar);
215 const VectorRegister4Float ReplicatedScalar = VectorLoadFloat1(&B);
217 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
219 VectorRegister4Float MulResult = VectorMultiply(
220 VectorLoadAligned(&V[BasisIndex * NumComponentsPerSIMDVector]),
223 VectorStoreAligned(MulResult, &V[BasisIndex * NumComponentsPerSIMDVector]);
234 const VectorRegister4Float ReplicatedScalar = VectorLoadFloat1(&B);
236 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
238 VectorRegister4Float MulResult = VectorMultiply(
239 VectorLoadAligned(&V[BasisIndex * NumComponentsPerSIMDVector]),
242 VectorStoreAligned(MulResult, &V[BasisIndex * NumComponentsPerSIMDVector]);
249 for (int32 BasisIndex = 0; BasisIndex < MaxSHBasis; BasisIndex++)
251 Ar << SH.V[BasisIndex];
258 float CalcIntegral()
const
260 return V[0] * ConstantBasisIntegral;
266 const float Integral = CalcIntegral();
273 void ApplyWindowing(
float Lambda)
278 for (int32 l = 0; l < TSHVector::MaxSHOrder; l++)
280 const float BandScaleFactor = 1.0f / (1.0f + Lambda *
float(l * l * (l + 1) * (l + 1)));
282 for (int32 m = -l; m <= l; m++)
284 V[SHGetBasisIndex(l, m)] *= BandScaleFactor;
289 bool AreFloatsValid()
const
293 for (int32 BasisIndex = 0; BasisIndex < MaxSHBasis; BasisIndex++)
295 bValid = bValid && FMath::IsFinite(V[BasisIndex]) && !FMath::IsNaN(V[BasisIndex]);
302 FVector GetMaximumDirection()
const
305 return FVector(-V[3], -V[1], V[2]).GetSafeNormal();
308 static TSHVector CalcDiffuseTransfer(
const FVector& Normal)
310 TSHVector Result = SHBasisFunction(Normal);
315 float L1 = 2 *
UE_PI / 3;
316 float L2 =
UE_PI / 4;
319 for(int32 BasisIndex = 0;BasisIndex < MaxSHBasis;BasisIndex++)
327 else if (BasisIndex < 4)
336 Result.V[BasisIndex] *= Scale;
343 static TSHVector SHBasisFunction(
const FVector& Vector)
348 for (int32 BasisIndex = 0; BasisIndex < TSHVector::MaxSHBasis; BasisIndex++)
350 Result.V[BasisIndex] = NormalizationConstants[BasisIndex];
358 const float Phi = (
float)FMath::Atan2(Vector.Y, Vector.X);
360 for (int32 BandIndex = 1; BandIndex < TSHVector::MaxSHOrder; BandIndex++)
362 const float SinPhiM = FMath::Sin((
float)BandIndex * Phi);
363 const float CosPhiM = FMath::Cos((
float)BandIndex * Phi);
365 for (int32 RecurrentBandIndex = BandIndex; RecurrentBandIndex < TSHVector::MaxSHOrder; RecurrentBandIndex++)
367 Result.V[SHGetBasisIndex(RecurrentBandIndex, -BandIndex)] *= SinPhiM;
368 Result.V[SHGetBasisIndex(RecurrentBandIndex, +BandIndex)] *= CosPhiM;
374 for (int32 BasisIndex = 1; BasisIndex < TSHVector::MaxSHBasis; BasisIndex++)
376 Result.V[BasisIndex] *= LegendrePolynomial(BasisL[BasisIndex], FMath::Abs(BasisM[BasisIndex]), (
float)Vector.Z);
383 static TSHVector AmbientFunction()
385 TSHVector AmbientFunctionSH;
386 AmbientFunctionSH.V[0] = 1.0f / (2.0f * FMath::Sqrt(
UE_PI));
387 return AmbientFunctionSH;
390 static float FindWindowingLambda(
const TSHVector& Vector,
float TargetLaplacian)
395 float TableL[TSHVector::MaxSHOrder];
396 float TableB[TSHVector::MaxSHOrder];
401 for (int32 l = 1; l < TSHVector::MaxSHOrder; l++)
403 TableL[l] =
float(l * l * (l + 1) * (l + 1));
406 for (int32 m = -1; m <= l; m++)
408 float Coefficient = Vector.V[SHGetBasisIndex(l, m)];
409 B += Coefficient * Coefficient;
414 float SquaredLaplacian = 0.0f;
416 for (int32 l = 1; l < TSHVector::MaxSHOrder; ++l)
418 SquaredLaplacian += TableL[l] * TableB[l];
421 const float TargetSquaredLaplacian = TargetLaplacian * TargetLaplacian;
422 if (SquaredLaplacian <= TargetSquaredLaplacian)
429 const uint32 IterationLimit = 100;
430 for (uint32 i = 0; i < IterationLimit; i++)
435 for (int32 l = 1; l < TSHVector::MaxSHOrder; ++l)
437 float Temp = 1.0f + Lambda * TableL[l];
438 f += TableL[l] * TableB[l] / (Temp * Temp);
439 fd += (2.0f * TableL[l] * TableL[l] * TableB[l]) / (Temp * Temp * Temp);
442 f = TargetSquaredLaplacian - f;
444 float delta = -f / fd;
460inline TSHVector<2> TSHVector<2>::SHBasisFunction(
const FVector& Vector)
463 Result.V[0] = 0.282095f;
464 Result.V[1] = -0.488603f * (
float)Vector.Y;
465 Result.V[2] = 0.488603f * (
float)Vector.Z;
466 Result.V[3] = -0.488603f * (
float)Vector.X;
472inline TSHVector<3> TSHVector<3>::SHBasisFunction(
const FVector& Vector)
475 Result.V[0] = 0.282095f;
476 Result.V[1] = -0.488603f * (
float)Vector.Y;
477 Result.V[2] = 0.488603f * (
float)Vector.Z;
478 Result.V[3] = -0.488603f * (
float)Vector.X;
480 FVector VectorSquared = Vector * Vector;
481 Result.V[4] = 1.092548f *
float(Vector.X * Vector.Y);
482 Result.V[5] = -1.092548f *
float(Vector.Y * Vector.Z);
483 Result.V[6] = 0.315392f *
float(3.0f * VectorSquared.Z - 1.0f);
484 Result.V[7] = -1.092548f *
float(Vector.X * Vector.Z);
485 Result.V[8] = 0.546274f *
float(VectorSquared.X - VectorSquared.Y);
490template<int32 MaxSHOrder>
495 TSHVector<MaxSHOrder> R;
496 TSHVector<MaxSHOrder> G;
497 TSHVector<MaxSHOrder> B;
501 template<int32 OtherOrder>
502 explicit TSHVectorRGB(
const TSHVectorRGB<OtherOrder>& Other)
504 R = (TSHVector<MaxSHOrder>)Other.R;
505 G = (TSHVector<MaxSHOrder>)Other.G;
506 B = (TSHVector<MaxSHOrder>)Other.B;
510 TSHVector<MaxSHOrder> GetLuminance()
const
512 return R * 0.3f + G * 0.59f + B * 0.11f;
515 void Desaturate(
float DesaturateFraction)
517 TSHVector<MaxSHOrder> Desaturated = GetLuminance() * DesaturateFraction;
519 R = R * (1 - DesaturateFraction) + Desaturated;
520 G = G * (1 - DesaturateFraction) + Desaturated;
521 B = B * (1 - DesaturateFraction) + Desaturated;
525 FLinearColor CalcIntegral()
const
528 Result.R = R.CalcIntegral();
529 Result.G = G.CalcIntegral();
530 Result.B = B.CalcIntegral();
535 void ApplyWindowing(
float Lambda)
537 R.ApplyWindowing(Lambda);
538 G.ApplyWindowing(Lambda);
539 B.ApplyWindowing(Lambda);
542 bool AreFloatsValid()
const
544 return R.AreFloatsValid() && G.AreFloatsValid() && B.AreFloatsValid();
549 friend FORCEINLINE TSHVectorRGB operator*(
const TSHVectorRGB& A,
const float& Scalar)
552 Result.R = A.R * Scalar;
553 Result.G = A.G * Scalar;
554 Result.B = A.B * Scalar;
560 friend FORCEINLINE TSHVectorRGB operator*(
const float& Scalar,
const TSHVectorRGB& A)
563 Result.R = A.R * Scalar;
564 Result.G = A.G * Scalar;
565 Result.B = A.B * Scalar;
570 friend FORCEINLINE TSHVectorRGB operator*(
const TSHVectorRGB& A,
const FLinearColor& Color)
573 Result.R = A.R * Color.R;
574 Result.G = A.G * Color.G;
575 Result.B = A.B * Color.B;
580 friend FORCEINLINE TSHVectorRGB operator*(
const FLinearColor& Color,
const TSHVectorRGB& A)
583 Result.R = A.R * Color.R;
584 Result.G = A.G * Color.G;
585 Result.B = A.B * Color.B;
590 friend FORCEINLINE TSHVectorRGB operator/(
const TSHVectorRGB& A,
const float& InB)
593 Result.R = A.R / InB;
594 Result.G = A.G / InB;
595 Result.B = A.B / InB;
600 friend FORCEINLINE TSHVectorRGB operator+(
const TSHVectorRGB& A,
const TSHVectorRGB& InB)
603 Result.R = A.R + InB.R;
604 Result.G = A.G + InB.G;
605 Result.B = A.B + InB.B;
610 friend FORCEINLINE TSHVectorRGB operator-(
const TSHVectorRGB& A,
const TSHVectorRGB& InB)
613 Result.R = A.R - InB.R;
614 Result.G = A.G - InB.G;
615 Result.B = A.B - InB.B;
620 friend FORCEINLINE FLinearColor Dot(
const TSHVectorRGB& A,
const TSHVector<MaxSHOrder>& InB)
623 Result.R = Dot(A.R,InB);
624 Result.G = Dot(A.G,InB);
625 Result.B = Dot(A.B,InB);
667 friend FArchive& operator<<(FArchive& Ar, TSHVectorRGB& SH)
669 return Ar << SH.R << SH.G << SH.B;
673 inline void AddIncomingRadiance(
const FLinearColor& IncomingRadiance,
float Weight,
const FVector4& WorldSpaceDirection)
675 *
this += TSHVector<MaxSHOrder>::SHBasisFunction(WorldSpaceDirection) * (IncomingRadiance * Weight);
679 inline void AddAmbient(
const FLinearColor& Intensity)
681 *
this += TSHVector<MaxSHOrder>::AmbientFunction() * Intensity;
689 TSHVectorRGB<Order> Result;
TSHVectorRGB< 2 > FSHVectorRGB2
TSHVector< 3 > FSHVector3
TSHVector< 2 > FSHVector2
FORCEINLINE TSHVectorRGB< Order > operator*(const TSHVector< Order > &A, const FLinearColor &B)
TSHVectorRGB< 3 > FSHVectorRGB3
float NormalizationConstants[9]
FORCEINLINE int32 SHGetBasisIndex(int32 L, int32 M)
float LegendrePolynomial(int32 L, int32 M, float X)
#define UE_KINDA_SMALL_NUMBER