UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
SHMath.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "HAL/UnrealMemory.h"
7#include "Math/Color.h"
8#include "Math/MathFwd.h"
11#include "Math/Vector.h"
12#include "Math/Vector4.h"
13#include "Math/VectorRegister.h"
14
15class FArchive;
16
17// Constants.
18extern CORE_API float NormalizationConstants[9];
19extern CORE_API int32 BasisL[9];
20extern CORE_API int32 BasisM[9];
21
22extern CORE_API float LegendrePolynomial(int32 L, int32 M, float X);
23
25
28{
29 return L * (L + 1) + M;
30}
31
33template<int32 Order>
34class MS_ALIGN(16) TSHVector
35{
36public:
37
38 enum { MaxSHOrder = Order };
39 enum { MaxSHBasis = MaxSHOrder * MaxSHOrder };
40 enum { NumComponentsPerSIMDVector = 4 };
43 float V[NumTotalFloats];
44
46 static constexpr float ConstantBasisIntegral = 3.5449077018110320545963349666823f; // 2 * Sqrt(PI)
47
50 {
51 FMemory::Memzero(V,sizeof(V));
52 }
53
54 [[nodiscard]] TSHVector(float V0, float V1, float V2, float V3)
55 {
56 FMemory::Memzero(V,sizeof(V));
57
58 V[0] = V0;
59 V[1] = V1;
60 V[2] = V2;
61 V[3] = V3;
62 }
63
64 [[nodiscard]] explicit TSHVector(const FVector4f& Vector)
65 {
66 FMemory::Memzero(V,sizeof(V));
67
68 V[0] = Vector.X;
69 V[1] = Vector.Y;
70 V[2] = Vector.Z;
71 V[3] = Vector.W;
72 }
73
74
75 template<int32 OtherOrder>
77 {
78 if (Order <= OtherOrder)
79 {
80 FMemory::Memcpy(V, Other.V, sizeof(V));
81 }
82 else
83 {
85 FMemory::Memcpy(V, Other.V, sizeof(V));
86 }
87 }
88
91 [[nodiscard]] friend inline TSHVector operator*(const TSHVector& A,const float& B)
92 {
94
97 {
101 );
103 }
104 return Result;
105 }
106
108 [[nodiscard]] friend inline TSHVector operator/(const TSHVector& A,const float& Scalar)
109 {
110 const float B = (1.0f / Scalar);
112
115 {
119 );
121 }
122 return Result;
123 }
124
126 [[nodiscard]] friend inline TSHVector operator+(const TSHVector& A,const TSHVector& B)
127 {
130 {
134 );
135
137 }
138 return Result;
139 }
140
142 [[nodiscard]] friend inline TSHVector operator-(const TSHVector& A,const TSHVector& B)
143 {
146 {
150 );
151
153 }
154 return Result;
155 }
156
158 [[nodiscard]] friend inline float Dot(const TSHVector& A,const TSHVector& B)
159 {
162 {
168 )
169 );
170 }
171 float Result;
173 return Result;
174 }
175
179 inline TSHVector& operator+=(const TSHVector& B)
180 {
182 {
186 );
187
189 }
190 return *this;
191 }
192
196 inline TSHVector& operator-=(const TSHVector& B)
197 {
199 {
203 );
204
206 }
207 return *this;
208 }
209
214 inline TSHVector& operator/=(const float& Scalar)
215 {
216 const float B = (1.0f/Scalar);
218
220 {
224 );
226 }
227 return *this;
228 }
229
234 inline TSHVector& operator*=(const float& B)
235 {
237
239 {
243 );
245 }
246 return *this;
247 }
248
250 {
252 {
253 Ar << SH.V[BasisIndex];
254 }
255
256 return Ar;
257 }
258
260 [[nodiscard]] float CalcIntegral() const
261 {
262 return V[0] * ConstantBasisIntegral;
263 }
264
266 void Normalize()
267 {
268 const float Integral = CalcIntegral();
269 if(Integral > UE_DELTA)
270 {
271 *this /= Integral;
272 }
273 }
274
275 void ApplyWindowing(float Lambda)
276 {
277 // "Stupid Spherical Harmonics (SH) Tricks"
278 // Minimizing the weighted squared Laplacian
279
280 for (int32 l = 0; l < TSHVector::MaxSHOrder; l++)
281 {
282 const float BandScaleFactor = 1.0f / (1.0f + Lambda * float(l * l * (l + 1) * (l + 1)));
283
284 for (int32 m = -l; m <= l; m++)
285 {
287 }
288 }
289 }
290
291 [[nodiscard]] bool AreFloatsValid() const
292 {
293 bool bValid = true;
294
296 {
297 bValid = bValid && FMath::IsFinite(V[BasisIndex]) && !FMath::IsNaN(V[BasisIndex]);
298 }
299
300 return bValid;
301 }
302
305 {
306 // This is an approximation which only takes into account first and second order spherical harmonics.
307 return FVector(-V[3], -V[1], V[2]).GetSafeNormal();
308 }
309
311 {
313
314 // These formula are scaling factors for each SH band that convolve a SH with the circularly symmetric function
315 // max(0,cos(theta))
316 float L0 = UE_PI;
317 float L1 = 2 * UE_PI / 3;
318 float L2 = UE_PI / 4;
319
320 // Multiply the coefficients in each band with the appropriate band scaling factor.
322 {
323 float Scale = 1.0f;
324
325 if (BasisIndex < 1)
326 {
327 Scale = L0;
328 }
329 else if (BasisIndex < 4)
330 {
331 Scale = L1;
332 }
333 else
334 {
335 Scale = L2;
336 }
337
338 Result.V[BasisIndex] *= Scale;
339 }
340
341 return Result;
342 }
343
346 {
348
349 // Initialize the result to the normalization constant.
350 for (int32 BasisIndex = 0; BasisIndex < TSHVector::MaxSHBasis; BasisIndex++)
351 {
353 }
354
355 // Multiply the result by the phi-dependent part of the SH bases.
356 // Skip this for X=0 and Y=0, because atan will be undefined and
357 // we know the Vector will be (0,0,+1) or (0,0,-1).
358 if (FMath::Abs(Vector.X) > UE_KINDA_SMALL_NUMBER || FMath::Abs(Vector.Y) > UE_KINDA_SMALL_NUMBER)
359 {
360 const float Phi = (float)FMath::Atan2(Vector.Y, Vector.X);
361
362 for (int32 BandIndex = 1; BandIndex < TSHVector::MaxSHOrder; BandIndex++)
363 {
364 const float SinPhiM = FMath::Sin((float)BandIndex * Phi);
365 const float CosPhiM = FMath::Cos((float)BandIndex * Phi);
366
368 {
371 }
372 }
373 }
374
375 // Multiply the result by the theta-dependent part of the SH bases.
376 for (int32 BasisIndex = 1; BasisIndex < TSHVector::MaxSHBasis; BasisIndex++)
377 {
379 }
380
381 return Result;
382 }
383
386 {
388 AmbientFunctionSH.V[0] = 1.0f / (2.0f * FMath::Sqrt(UE_PI));
389 return AmbientFunctionSH;
390 }
391
392 [[nodiscard]] static float FindWindowingLambda(const TSHVector& Vector, float TargetLaplacian)
393 {
394 // "Stupid Spherical Harmonics (SH) Tricks"
395 // Appendix A7: Solving for Lamba to Reduce the Squared Laplacian
396
397 float TableL[TSHVector::MaxSHOrder];
398 float TableB[TSHVector::MaxSHOrder];
399
400 TableL[0] = 0.0f;
401 TableB[0] = 0.0f;
402
403 for (int32 l = 1; l < TSHVector::MaxSHOrder; l++)
404 {
405 TableL[l] = float(l * l * (l + 1) * (l + 1));
406
407 float B = 0.0f;
408 for (int32 m = -1; m <= l; m++)
409 {
410 float Coefficient = Vector.V[SHGetBasisIndex(l, m)];
411 B += Coefficient * Coefficient;
412 }
413 TableB[l] = B;
414 }
415
416 float SquaredLaplacian = 0.0f;
417
418 for (int32 l = 1; l < TSHVector::MaxSHOrder; ++l)
419 {
420 SquaredLaplacian += TableL[l] * TableB[l];
421 }
422
425 {
426 return 0.0f;
427 }
428
429 float Lambda = 0.0f;
430
431 const uint32 IterationLimit = 100;
432 for (uint32 i = 0; i < IterationLimit; i++)
433 {
434 float f = 0.0f;
435 float fd = 0.0f;
436
437 for (int32 l = 1; l < TSHVector::MaxSHOrder; ++l)
438 {
439 float Temp = 1.0f + Lambda * TableL[l];
440 f += TableL[l] * TableB[l] / (Temp * Temp);
441 fd += (2.0f * TableL[l] * TableL[l] * TableB[l]) / (Temp * Temp * Temp);
442 }
443
445
446 float delta = -f / fd;
447 Lambda += delta;
448
449 if (FMath::Abs(delta) < UE_KINDA_SMALL_NUMBER)
450 {
451 break;
452 }
453 }
454
455 return Lambda;
456 }
458
459
461template<>
462[[nodiscard]] inline TSHVector<2> TSHVector<2>::SHBasisFunction(const FVector& Vector)
463{
465 Result.V[0] = 0.282095f;
466 Result.V[1] = -0.488603f * (float)Vector.Y; // LWC_TODO: Precision loss
467 Result.V[2] = 0.488603f * (float)Vector.Z;
468 Result.V[3] = -0.488603f * (float)Vector.X;
469 return Result;
470}
471
473template<>
474[[nodiscard]] inline TSHVector<3> TSHVector<3>::SHBasisFunction(const FVector& Vector)
475{
477 Result.V[0] = 0.282095f;
478 Result.V[1] = -0.488603f * (float)Vector.Y; // LWC_TODO: Precision loss
479 Result.V[2] = 0.488603f * (float)Vector.Z;
480 Result.V[3] = -0.488603f * (float)Vector.X;
481
483 Result.V[4] = 1.092548f * float(Vector.X * Vector.Y);
484 Result.V[5] = -1.092548f * float(Vector.Y * Vector.Z);
485 Result.V[6] = 0.315392f * float(3.0f * VectorSquared.Z - 1.0f);
486 Result.V[7] = -1.092548f * float(Vector.X * Vector.Z);
487 Result.V[8] = 0.546274f * float(VectorSquared.X - VectorSquared.Y);
488 return Result;
489}
490
492template<int32 MaxSHOrder>
494{
495public:
496
500
502
503 template<int32 OtherOrder>
510
513 {
514 static const FLinearColor LuminanceFactors = SHGetLuminanceFactors();
515
516 return R * LuminanceFactors.R + G * LuminanceFactors.G + B * LuminanceFactors.B;
517 }
518
527
530 {
531 FLinearColor Result;
532 Result.R = R.CalcIntegral();
533 Result.G = G.CalcIntegral();
534 Result.B = B.CalcIntegral();
535 Result.A = 1.0f;
536 return Result;
537 }
538
539 void ApplyWindowing(float Lambda)
540 {
541 R.ApplyWindowing(Lambda);
542 G.ApplyWindowing(Lambda);
543 B.ApplyWindowing(Lambda);
544 }
545
546 [[nodiscard]] bool AreFloatsValid() const
547 {
548 return R.AreFloatsValid() && G.AreFloatsValid() && B.AreFloatsValid();
549 }
550
553 [[nodiscard]] friend inline TSHVectorRGB operator*(const TSHVectorRGB& A, const float& Scalar)
554 {
555 TSHVectorRGB Result;
556 Result.R = A.R * Scalar;
557 Result.G = A.G * Scalar;
558 Result.B = A.B * Scalar;
559 return Result;
560 }
561
564 [[nodiscard]] friend inline TSHVectorRGB operator*(const float& Scalar,const TSHVectorRGB& A)
565 {
566 TSHVectorRGB Result;
567 Result.R = A.R * Scalar;
568 Result.G = A.G * Scalar;
569 Result.B = A.B * Scalar;
570 return Result;
571 }
572
575 {
576 TSHVectorRGB Result;
577 Result.R = A.R * Color.R;
578 Result.G = A.G * Color.G;
579 Result.B = A.B * Color.B;
580 return Result;
581 }
582
585 {
586 TSHVectorRGB Result;
587 Result.R = A.R * Color.R;
588 Result.G = A.G * Color.G;
589 Result.B = A.B * Color.B;
590 return Result;
591 }
592
594 [[nodiscard]] friend inline TSHVectorRGB operator/(const TSHVectorRGB& A,const float& InB)
595 {
596 TSHVectorRGB Result;
597 Result.R = A.R / InB;
598 Result.G = A.G / InB;
599 Result.B = A.B / InB;
600 return Result;
601 }
602
605 {
606 TSHVectorRGB Result;
607 Result.R = A.R + InB.R;
608 Result.G = A.G + InB.G;
609 Result.B = A.B + InB.B;
610 return Result;
611 }
612
615 {
616 TSHVectorRGB Result;
617 Result.R = A.R - InB.R;
618 Result.G = A.G - InB.G;
619 Result.B = A.B - InB.B;
620 return Result;
621 }
622
625 {
626 FLinearColor Result;
627 Result.R = Dot(A.R,InB);
628 Result.G = Dot(A.G,InB);
629 Result.B = Dot(A.B,InB);
630 Result.A = 1.0f;
631 return Result;
632 }
633
639 {
640 R += InB.R;
641 G += InB.G;
642 B += InB.B;
643
644 return *this;
645 }
646
651 {
652 R -= InB.R;
653 G -= InB.G;
654 B -= InB.B;
655
656 return *this;
657 }
658
662 inline TSHVectorRGB& operator*=(const float& Scalar)
663 {
664 R *= Scalar;
665 G *= Scalar;
666 B *= Scalar;
667
668 return *this;
669 }
670
672 {
673 return Ar << SH.R << SH.G << SH.B;
674 }
675
678 {
679 *this += TSHVector<MaxSHOrder>::SHBasisFunction(WorldSpaceDirection) * (IncomingRadiance * Weight);
680 }
681
683 inline void AddAmbient(const FLinearColor& Intensity)
684 {
685 *this += TSHVector<MaxSHOrder>::AmbientFunction() * Intensity;
686 }
687};
688
690template<int32 Order>
692{
693 TSHVectorRGB<Order> Result;
694 Result.R = A * B.R;
695 Result.G = A * B.G;
696 Result.B = A * B.B;
697
698 return Result;
699}
700
@ Normal
Definition AndroidInputInterface.h:116
#define GCC_ALIGN(n)
Definition AndroidPlatform.h:163
UE_FORCEINLINE_HINT FLinearColor operator*(float Scalar, const FLinearColor &Color)
Definition Color.h:473
#define MS_ALIGN(n)
Definition Platform.h:916
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
#define UE_FORCEINLINE_HINT
Definition Platform.h:723
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
FArchive & operator<<(FArchive &Ar, FEnvQueryDebugProfileData::FStep &Data)
Definition EnvQueryTypes.cpp:489
#define X(Name, Desc)
Definition FormatStringSan.h:47
constexpr EIOSEventType operator+(EIOSEventType type, int Index)
Definition IOSInputInterface.cpp:138
#define FVector
Definition IOSSystemIncludes.h:8
FFrameTime & operator*=(FFrameTime &InTime, const FMovieSceneSequenceTransform &RHS)
Definition MovieSceneSequenceTransform.h:1072
int32 BasisL[9]
Definition SHMath.cpp:13
int32 BasisM[9]
Definition SHMath.cpp:14
float NormalizationConstants[9]
Definition SHMath.cpp:12
float LegendrePolynomial(int32 L, int32 M, float X)
Definition SHMath.cpp:67
TSHVectorRGB< 2 > FSHVectorRGB2
Definition SHMath.h:704
UE_FORCEINLINE_HINT int32 SHGetBasisIndex(int32 L, int32 M)
Definition SHMath.h:27
TSHVector< 3 > FSHVector3
Definition SHMath.h:701
TSHVectorRGB< Order > operator*(const TSHVector< Order > &A, const FLinearColor &B)
Definition SHMath.h:691
CORE_API int32 BasisM[9]
Definition SHMath.cpp:14
CORE_API float LegendrePolynomial(int32 L, int32 M, float X)
Definition SHMath.cpp:67
TSHVector< 2 > FSHVector2
Definition SHMath.h:702
CORE_API FLinearColor SHGetLuminanceFactors()
Definition SHMath.cpp:128
CORE_API int32 BasisL[9]
Definition SHMath.cpp:13
TSHVectorRGB< 3 > FSHVectorRGB3
Definition SHMath.h:703
CORE_API float NormalizationConstants[9]
Definition SHMath.cpp:12
FScreenTransform operator/(const FScreenTransform &AToB, const FVector2f &InvertedScale)
Definition ScreenPass.inl:280
FScreenTransform operator-(const FScreenTransform &AToB, const FVector2f &Bias)
Definition ScreenPass.inl:264
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
FStringBuilderBase & operator+=(FStringBuilderBase &Builder, ANSICHAR Char)
Definition StringBuilder.h:582
FORCEINLINE VectorRegister4Float VectorSubtract(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:731
FORCEINLINE VectorRegister4Float VectorDot4(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:901
FORCEINLINE VectorRegister4Float VectorMultiply(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:758
FORCEINLINE VectorRegister4Float VectorLoadFloat1(const float *Ptr)
Definition UnrealMathFPU.h:468
VectorRegister4Float VectorLoadAligned(const float *Ptr)
Definition UnrealMathFPU.h:451
FORCEINLINE VectorRegister4Float VectorAdd(const VectorRegister4Float &Vec1, const VectorRegister4Float &Vec2)
Definition UnrealMathFPU.h:704
void VectorStoreAligned(const VectorRegister4Float &Vec, float *Ptr)
Definition UnrealMathFPU.h:534
FORCEINLINE void VectorStoreFloat1(const VectorRegister4Float &Vec, float *Dst)
Definition UnrealMathFPU.h:610
#define UE_PI
Definition UnrealMathUtility.h:129
#define UE_KINDA_SMALL_NUMBER
Definition UnrealMathUtility.h:131
#define UE_DELTA
Definition UnrealMathUtility.h:186
FORCEINLINE VectorRegister4Float VectorZero(void)
Definition UnrealMathVectorCommon.h.inl:16
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Archive.h:1208
Definition SHMath.h:494
void Desaturate(float DesaturateFraction)
Definition SHMath.h:519
FLinearColor CalcIntegral() const
Definition SHMath.h:529
void AddIncomingRadiance(const FLinearColor &IncomingRadiance, float Weight, const FVector4 &WorldSpaceDirection)
Definition SHMath.h:677
TSHVector< MaxSHOrder > GetLuminance() const
Definition SHMath.h:512
friend TSHVectorRGB operator*(const float &Scalar, const TSHVectorRGB &A)
Definition SHMath.h:564
friend TSHVectorRGB operator*(const TSHVectorRGB &A, const FLinearColor &Color)
Definition SHMath.h:574
void AddAmbient(const FLinearColor &Intensity)
Definition SHMath.h:683
TSHVector< MaxSHOrder > G
Definition SHMath.h:498
TSHVectorRGB & operator+=(const TSHVectorRGB &InB)
Definition SHMath.h:638
friend TSHVectorRGB operator+(const TSHVectorRGB &A, const TSHVectorRGB &InB)
Definition SHMath.h:604
TSHVectorRGB()
Definition SHMath.h:501
friend TSHVectorRGB operator/(const TSHVectorRGB &A, const float &InB)
Definition SHMath.h:594
TSHVector< MaxSHOrder > R
Definition SHMath.h:497
TSHVectorRGB & operator*=(const float &Scalar)
Definition SHMath.h:662
friend TSHVectorRGB operator*(const TSHVectorRGB &A, const float &Scalar)
Definition SHMath.h:553
TSHVectorRGB(const TSHVectorRGB< OtherOrder > &Other)
Definition SHMath.h:504
TSHVector< MaxSHOrder > B
Definition SHMath.h:499
friend TSHVectorRGB operator*(const FLinearColor &Color, const TSHVectorRGB &A)
Definition SHMath.h:584
void ApplyWindowing(float Lambda)
Definition SHMath.h:539
bool AreFloatsValid() const
Definition SHMath.h:546
TSHVectorRGB & operator-=(const TSHVectorRGB &InB)
Definition SHMath.h:650
friend TSHVectorRGB operator-(const TSHVectorRGB &A, const TSHVectorRGB &InB)
Definition SHMath.h:614
friend FArchive & operator<<(FArchive &Ar, TSHVectorRGB &SH)
Definition SHMath.h:671
friend FLinearColor Dot(const TSHVectorRGB &A, const TSHVector< MaxSHOrder > &InB)
Definition SHMath.h:624
T Normalize(UE::Math::TVector2< T > &Vector, const T Epsilon=0)
Definition VectorTypes.h:46
@ V2
Definition NNEModelData.cpp:18
@ V1
Definition NNEModelData.cpp:17
@ V0
Definition NNEModelData.cpp:16
@ V3
Definition NNEModelData.cpp:19
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
const int32 Order[8][8]
Definition VorbisAudioInfo.cpp:47
Definition Color.h:48
float G
Definition Color.h:54
float B
Definition Color.h:55
float R
Definition Color.h:53
static UE_FORCEINLINE_HINT void * Memzero(void *Dest, SIZE_T Count)
Definition UnrealMemory.h:131
static UE_FORCEINLINE_HINT void * Memcpy(void *Dest, const void *Src, SIZE_T Count)
Definition UnrealMemory.h:160
TVector< T > GetSafeNormal(T Tolerance=UE_SMALL_NUMBER, const TVector< T > &ResultIfZero=ZeroVector) const
Definition Vector.h:2060
Definition UnrealMathFPU.h:20