Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
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"
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"
14
15class FArchive;
16
17// Constants.
18extern float NormalizationConstants[9];
19extern int32 BasisL[9];
20extern int32 BasisM[9];
21
22extern float LegendrePolynomial(int32 L, int32 M, float X);
23
24/** Returns the basis index of the SH basis L,M. */
25FORCEINLINE int32 SHGetBasisIndex(int32 L,int32 M)
26{
27 return L * (L + 1) + M;
28}
29
30/** A vector of spherical harmonic coefficients. */
31template<int32 Order>
32class MS_ALIGN(16) TSHVector
33{
34public:
35
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];
42
43 /** The integral of the constant SH basis. */
44 static constexpr float ConstantBasisIntegral = 3.5449077018110320545963349666823f; // 2 * Sqrt(PI)
45
46 /** Default constructor. */
47 TSHVector()
48 {
49 FMemory::Memzero(V,sizeof(V));
50 }
51
52 TSHVector(float V0, float V1, float V2, float V3)
53 {
54 FMemory::Memzero(V,sizeof(V));
55
56 V[0] = V0;
57 V[1] = V1;
58 V[2] = V2;
59 V[3] = V3;
60 }
61
62 explicit TSHVector(const FVector4f& Vector)
63 {
64 FMemory::Memzero(V,sizeof(V));
65
66 V[0] = Vector.X;
67 V[1] = Vector.Y;
68 V[2] = Vector.Z;
69 V[3] = Vector.W;
70 }
71
72
73 template<int32 OtherOrder>
74 explicit TSHVector(const TSHVector<OtherOrder>& Other)
75 {
76 if (Order <= OtherOrder)
77 {
78 FMemory::Memcpy(V, Other.V, sizeof(V));
79 }
80 else
81 {
82 FMemory::Memzero(V);
83 FMemory::Memcpy(V, Other.V, sizeof(V));
84 }
85 }
86
87 /** Scalar multiplication operator. */
88 /** Changed to float& from float to avoid LHS **/
89 friend FORCEINLINE TSHVector operator*(const TSHVector& A,const float& B)
90 {
91 const VectorRegister4Float ReplicatedScalar = VectorLoadFloat1(&B);
92
93 TSHVector Result;
94 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
95 {
96 VectorRegister4Float MulResult = VectorMultiply(
97 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
98 ReplicatedScalar
99 );
100 VectorStoreAligned(MulResult, &Result.V[BasisIndex * NumComponentsPerSIMDVector]);
101 }
102 return Result;
103 }
104
105 /** Scalar division operator. */
106 friend FORCEINLINE TSHVector operator/(const TSHVector& A,const float& Scalar)
107 {
108 const float B = (1.0f / Scalar);
109 const VectorRegister4Float ReplicatedScalar = VectorLoadFloat1(&B);
110
111 TSHVector Result;
112 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
113 {
114 VectorRegister4Float MulResult = VectorMultiply(
115 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
116 ReplicatedScalar
117 );
118 VectorStoreAligned(MulResult, &Result.V[BasisIndex * NumComponentsPerSIMDVector]);
119 }
120 return Result;
121 }
122
123 /** Addition operator. */
124 friend FORCEINLINE TSHVector operator+(const TSHVector& A,const TSHVector& B)
125 {
126 TSHVector Result;
127 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
128 {
129 VectorRegister4Float AddResult = VectorAdd(
130 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
131 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
132 );
133
134 VectorStoreAligned(AddResult, &Result.V[BasisIndex * NumComponentsPerSIMDVector]);
135 }
136 return Result;
137 }
138
139 /** Subtraction operator. */
140 friend FORCEINLINE TSHVector operator-(const TSHVector& A,const TSHVector& B)
141 {
142 TSHVector Result;
143 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
144 {
145 VectorRegister4Float SubResult = VectorSubtract(
146 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
147 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
148 );
149
150 VectorStoreAligned(SubResult, &Result.V[BasisIndex * NumComponentsPerSIMDVector]);
151 }
152 return Result;
153 }
154
155 /** Dot product operator. */
156 friend FORCEINLINE float Dot(const TSHVector& A,const TSHVector& B)
157 {
158 VectorRegister4Float ReplicatedResult = VectorZero();
159 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
160 {
161 ReplicatedResult = VectorAdd(
162 ReplicatedResult,
163 VectorDot4(
164 VectorLoadAligned(&A.V[BasisIndex * NumComponentsPerSIMDVector]),
165 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
166 )
167 );
168 }
169 float Result;
170 VectorStoreFloat1(ReplicatedResult,&Result);
171 return Result;
172 }
173
174 /** In-place addition operator. */
175 /** Changed from (*this = *this + B;} to calculate here to avoid LHS **/
176 /** Now this avoids TSHVector + operator thus LHS on *this as well as Result and more **/
177 FORCEINLINE TSHVector& operator+=(const TSHVector& B)
178 {
179 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
180 {
181 VectorRegister4Float AddResult = VectorAdd(
182 VectorLoadAligned(&V[BasisIndex * NumComponentsPerSIMDVector]),
183 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
184 );
185
186 VectorStoreAligned(AddResult, &V[BasisIndex * NumComponentsPerSIMDVector]);
187 }
188 return *this;
189 }
190
191 /** In-place subtraction operator. */
192 /** Changed from (*this = *this - B;} to calculate here to avoid LHS **/
193 /** Now this avoids TSHVector - operator thus LHS on *this as well as Result and **/
194 FORCEINLINE TSHVector& operator-=(const TSHVector& B)
195 {
196 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
197 {
198 VectorRegister4Float SubResult = VectorSubtract(
199 VectorLoadAligned(&V[BasisIndex * NumComponentsPerSIMDVector]),
200 VectorLoadAligned(&B.V[BasisIndex * NumComponentsPerSIMDVector])
201 );
202
203 VectorStoreAligned(SubResult, &V[BasisIndex * NumComponentsPerSIMDVector]);
204 }
205 return *this;
206 }
207
208 /** In-place scalar division operator. */
209 /** Changed to float& from float to avoid LHS **/
210 /** Changed from (*this = *this * (1.0f/B);) to calculate here to avoid LHS **/
211 /** Now this avoids TSHVector * operator thus LHS on *this as well as Result and LHS **/
212 FORCEINLINE TSHVector& operator/=(const float& Scalar)
213 {
214 const float B = (1.0f/Scalar);
215 const VectorRegister4Float ReplicatedScalar = VectorLoadFloat1(&B);
216
217 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
218 {
219 VectorRegister4Float MulResult = VectorMultiply(
220 VectorLoadAligned(&V[BasisIndex * NumComponentsPerSIMDVector]),
221 ReplicatedScalar
222 );
223 VectorStoreAligned(MulResult, &V[BasisIndex * NumComponentsPerSIMDVector]);
224 }
225 return *this;
226 }
227
228 /** In-place scalar multiplication operator. */
229 /** Changed to float& from float to avoid LHS **/
230 /** Changed from (*this = *this * B;) to calculate here to avoid LHS **/
231 /** Now this avoids TSHVector * operator thus LHS on *this as well as Result and LHS **/
232 FORCEINLINE TSHVector& operator*=(const float& B)
233 {
234 const VectorRegister4Float ReplicatedScalar = VectorLoadFloat1(&B);
235
236 for(int32 BasisIndex = 0;BasisIndex < NumSIMDVectors;BasisIndex++)
237 {
238 VectorRegister4Float MulResult = VectorMultiply(
239 VectorLoadAligned(&V[BasisIndex * NumComponentsPerSIMDVector]),
240 ReplicatedScalar
241 );
242 VectorStoreAligned(MulResult, &V[BasisIndex * NumComponentsPerSIMDVector]);
243 }
244 return *this;
245 }
246
247 friend FArchive& operator<<(FArchive& Ar, TSHVector& SH)
248 {
249 for (int32 BasisIndex = 0; BasisIndex < MaxSHBasis; BasisIndex++)
250 {
251 Ar << SH.V[BasisIndex];
252 }
253
254 return Ar;
255 }
256
257 /** Calculates the integral of the function over the surface of the sphere. */
258 float CalcIntegral() const
259 {
260 return V[0] * ConstantBasisIntegral;
261 }
262
263 /** Scales the function uniformly so its integral equals one. */
264 void Normalize()
265 {
266 const float Integral = CalcIntegral();
267 if(Integral > UE_DELTA)
268 {
269 *this /= Integral;
270 }
271 }
272
273 void ApplyWindowing(float Lambda)
274 {
275 // "Stupid Spherical Harmonics (SH) Tricks"
276 // Minimizing the weighted squared Laplacian
277
278 for (int32 l = 0; l < TSHVector::MaxSHOrder; l++)
279 {
280 const float BandScaleFactor = 1.0f / (1.0f + Lambda * float(l * l * (l + 1) * (l + 1)));
281
282 for (int32 m = -l; m <= l; m++)
283 {
284 V[SHGetBasisIndex(l, m)] *= BandScaleFactor;
285 }
286 }
287 }
288
289 bool AreFloatsValid() const
290 {
291 bool bValid = true;
292
293 for (int32 BasisIndex = 0; BasisIndex < MaxSHBasis; BasisIndex++)
294 {
295 bValid = bValid && FMath::IsFinite(V[BasisIndex]) && !FMath::IsNaN(V[BasisIndex]);
296 }
297
298 return bValid;
299 }
300
301 /** Compute the direction which the spherical harmonic is highest at. */
302 FVector GetMaximumDirection() const
303 {
304 // This is an approximation which only takes into account first and second order spherical harmonics.
305 return FVector(-V[3], -V[1], V[2]).GetSafeNormal();
306 }
307
308 static TSHVector CalcDiffuseTransfer(const FVector& Normal)
309 {
310 TSHVector Result = SHBasisFunction(Normal);
311
312 // These formula are scaling factors for each SH band that convolve a SH with the circularly symmetric function
313 // max(0,cos(theta))
314 float L0 = UE_PI;
315 float L1 = 2 * UE_PI / 3;
316 float L2 = UE_PI / 4;
317
318 // Multiply the coefficients in each band with the appropriate band scaling factor.
319 for(int32 BasisIndex = 0;BasisIndex < MaxSHBasis;BasisIndex++)
320 {
321 float Scale = 1.0f;
322
323 if (BasisIndex < 1)
324 {
325 Scale = L0;
326 }
327 else if (BasisIndex < 4)
328 {
329 Scale = L1;
330 }
331 else
332 {
333 Scale = L2;
334 }
335
336 Result.V[BasisIndex] *= Scale;
337 }
338
339 return Result;
340 }
341
342 /** Returns the value of the SH basis L,M at the point on the sphere defined by the unit vector Vector. */
343 static TSHVector SHBasisFunction(const FVector& Vector)
344 {
345 TSHVector Result;
346
347 // Initialize the result to the normalization constant.
348 for (int32 BasisIndex = 0; BasisIndex < TSHVector::MaxSHBasis; BasisIndex++)
349 {
350 Result.V[BasisIndex] = NormalizationConstants[BasisIndex];
351 }
352
353 // Multiply the result by the phi-dependent part of the SH bases.
354 // Skip this for X=0 and Y=0, because atan will be undefined and
355 // we know the Vector will be (0,0,+1) or (0,0,-1).
356 if (FMath::Abs(Vector.X) > UE_KINDA_SMALL_NUMBER || FMath::Abs(Vector.Y) > UE_KINDA_SMALL_NUMBER)
357 {
358 const float Phi = (float)FMath::Atan2(Vector.Y, Vector.X);
359
360 for (int32 BandIndex = 1; BandIndex < TSHVector::MaxSHOrder; BandIndex++)
361 {
362 const float SinPhiM = FMath::Sin((float)BandIndex * Phi);
363 const float CosPhiM = FMath::Cos((float)BandIndex * Phi);
364
365 for (int32 RecurrentBandIndex = BandIndex; RecurrentBandIndex < TSHVector::MaxSHOrder; RecurrentBandIndex++)
366 {
367 Result.V[SHGetBasisIndex(RecurrentBandIndex, -BandIndex)] *= SinPhiM;
368 Result.V[SHGetBasisIndex(RecurrentBandIndex, +BandIndex)] *= CosPhiM;
369 }
370 }
371 }
372
373 // Multiply the result by the theta-dependent part of the SH bases.
374 for (int32 BasisIndex = 1; BasisIndex < TSHVector::MaxSHBasis; BasisIndex++)
375 {
376 Result.V[BasisIndex] *= LegendrePolynomial(BasisL[BasisIndex], FMath::Abs(BasisM[BasisIndex]), (float)Vector.Z);
377 }
378
379 return Result;
380 }
381
382 /** The ambient incident lighting function. */
383 static TSHVector AmbientFunction()
384 {
385 TSHVector AmbientFunctionSH;
386 AmbientFunctionSH.V[0] = 1.0f / (2.0f * FMath::Sqrt(UE_PI));
387 return AmbientFunctionSH;
388 }
389
390 static float FindWindowingLambda(const TSHVector& Vector, float TargetLaplacian)
391 {
392 // "Stupid Spherical Harmonics (SH) Tricks"
393 // Appendix A7: Solving for Lamba to Reduce the Squared Laplacian
394
395 float TableL[TSHVector::MaxSHOrder];
396 float TableB[TSHVector::MaxSHOrder];
397
398 TableL[0] = 0.0f;
399 TableB[0] = 0.0f;
400
401 for (int32 l = 1; l < TSHVector::MaxSHOrder; l++)
402 {
403 TableL[l] = float(l * l * (l + 1) * (l + 1));
404
405 float B = 0.0f;
406 for (int32 m = -1; m <= l; m++)
407 {
408 float Coefficient = Vector.V[SHGetBasisIndex(l, m)];
409 B += Coefficient * Coefficient;
410 }
411 TableB[l] = B;
412 }
413
414 float SquaredLaplacian = 0.0f;
415
416 for (int32 l = 1; l < TSHVector::MaxSHOrder; ++l)
417 {
418 SquaredLaplacian += TableL[l] * TableB[l];
419 }
420
421 const float TargetSquaredLaplacian = TargetLaplacian * TargetLaplacian;
422 if (SquaredLaplacian <= TargetSquaredLaplacian)
423 {
424 return 0.0f;
425 }
426
427 float Lambda = 0.0f;
428
429 const uint32 IterationLimit = 100;
430 for (uint32 i = 0; i < IterationLimit; i++)
431 {
432 float f = 0.0f;
433 float fd = 0.0f;
434
435 for (int32 l = 1; l < TSHVector::MaxSHOrder; ++l)
436 {
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);
440 }
441
442 f = TargetSquaredLaplacian - f;
443
444 float delta = -f / fd;
445 Lambda += delta;
446
447 if (FMath::Abs(delta) < UE_KINDA_SMALL_NUMBER)
448 {
449 break;
450 }
451 }
452
453 return Lambda;
454 }
456
457
458/** Specialization for 2nd order to avoid expensive trig functions. */
459template<>
460inline TSHVector<2> TSHVector<2>::SHBasisFunction(const FVector& Vector)
461{
462 TSHVector<2> Result;
463 Result.V[0] = 0.282095f;
464 Result.V[1] = -0.488603f * (float)Vector.Y; // LWC_TODO: Precision loss
465 Result.V[2] = 0.488603f * (float)Vector.Z;
466 Result.V[3] = -0.488603f * (float)Vector.X;
467 return Result;
468}
469
470/** Specialization for 3rd order to avoid expensive trig functions. */
471template<>
472inline TSHVector<3> TSHVector<3>::SHBasisFunction(const FVector& Vector)
473{
474 TSHVector<3> Result;
475 Result.V[0] = 0.282095f;
476 Result.V[1] = -0.488603f * (float)Vector.Y; // LWC_TODO: Precision loss
477 Result.V[2] = 0.488603f * (float)Vector.Z;
478 Result.V[3] = -0.488603f * (float)Vector.X;
479
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);
486 return Result;
487}
488
489/** A vector of colored spherical harmonic coefficients. */
490template<int32 MaxSHOrder>
491class TSHVectorRGB
492{
493public:
494
495 TSHVector<MaxSHOrder> R;
496 TSHVector<MaxSHOrder> G;
497 TSHVector<MaxSHOrder> B;
498
499 TSHVectorRGB() {}
500
501 template<int32 OtherOrder>
502 explicit TSHVectorRGB(const TSHVectorRGB<OtherOrder>& Other)
503 {
504 R = (TSHVector<MaxSHOrder>)Other.R;
505 G = (TSHVector<MaxSHOrder>)Other.G;
506 B = (TSHVector<MaxSHOrder>)Other.B;
507 }
508
509 /** Calculates greyscale spherical harmonic coefficients. */
510 TSHVector<MaxSHOrder> GetLuminance() const
511 {
512 return R * 0.3f + G * 0.59f + B * 0.11f;
513 }
514
515 void Desaturate(float DesaturateFraction)
516 {
517 TSHVector<MaxSHOrder> Desaturated = GetLuminance() * DesaturateFraction;
518
519 R = R * (1 - DesaturateFraction) + Desaturated;
520 G = G * (1 - DesaturateFraction) + Desaturated;
521 B = B * (1 - DesaturateFraction) + Desaturated;
522 }
523
524 /** Calculates the integral of the function over the surface of the sphere. */
525 FLinearColor CalcIntegral() const
526 {
527 FLinearColor Result;
528 Result.R = R.CalcIntegral();
529 Result.G = G.CalcIntegral();
530 Result.B = B.CalcIntegral();
531 Result.A = 1.0f;
532 return Result;
533 }
534
535 void ApplyWindowing(float Lambda)
536 {
537 R.ApplyWindowing(Lambda);
538 G.ApplyWindowing(Lambda);
539 B.ApplyWindowing(Lambda);
540 }
541
542 bool AreFloatsValid() const
543 {
544 return R.AreFloatsValid() && G.AreFloatsValid() && B.AreFloatsValid();
545 }
546
547 /** Scalar multiplication operator. */
548 /** Changed to float& from float to avoid LHS **/
549 friend FORCEINLINE TSHVectorRGB operator*(const TSHVectorRGB& A, const float& Scalar)
550 {
551 TSHVectorRGB Result;
552 Result.R = A.R * Scalar;
553 Result.G = A.G * Scalar;
554 Result.B = A.B * Scalar;
555 return Result;
556 }
557
558 /** Scalar multiplication operator. */
559 /** Changed to float& from float to avoid LHS **/
560 friend FORCEINLINE TSHVectorRGB operator*(const float& Scalar,const TSHVectorRGB& A)
561 {
562 TSHVectorRGB Result;
563 Result.R = A.R * Scalar;
564 Result.G = A.G * Scalar;
565 Result.B = A.B * Scalar;
566 return Result;
567 }
568
569 /** Color multiplication operator. */
570 friend FORCEINLINE TSHVectorRGB operator*(const TSHVectorRGB& A,const FLinearColor& Color)
571 {
572 TSHVectorRGB Result;
573 Result.R = A.R * Color.R;
574 Result.G = A.G * Color.G;
575 Result.B = A.B * Color.B;
576 return Result;
577 }
578
579 /** Color multiplication operator. */
580 friend FORCEINLINE TSHVectorRGB operator*(const FLinearColor& Color,const TSHVectorRGB& A)
581 {
582 TSHVectorRGB Result;
583 Result.R = A.R * Color.R;
584 Result.G = A.G * Color.G;
585 Result.B = A.B * Color.B;
586 return Result;
587 }
588
589 /** Division operator. */
590 friend FORCEINLINE TSHVectorRGB operator/(const TSHVectorRGB& A,const float& InB)
591 {
592 TSHVectorRGB Result;
593 Result.R = A.R / InB;
594 Result.G = A.G / InB;
595 Result.B = A.B / InB;
596 return Result;
597 }
598
599 /** Addition operator. */
600 friend FORCEINLINE TSHVectorRGB operator+(const TSHVectorRGB& A,const TSHVectorRGB& InB)
601 {
602 TSHVectorRGB Result;
603 Result.R = A.R + InB.R;
604 Result.G = A.G + InB.G;
605 Result.B = A.B + InB.B;
606 return Result;
607 }
608
609 /** Subtraction operator. */
610 friend FORCEINLINE TSHVectorRGB operator-(const TSHVectorRGB& A,const TSHVectorRGB& InB)
611 {
612 TSHVectorRGB Result;
613 Result.R = A.R - InB.R;
614 Result.G = A.G - InB.G;
615 Result.B = A.B - InB.B;
616 return Result;
617 }
618
619 /** Dot product operator. */
620 friend FORCEINLINE FLinearColor Dot(const TSHVectorRGB& A,const TSHVector<MaxSHOrder>& InB)
621 {
622 FLinearColor Result;
623 Result.R = Dot(A.R,InB);
624 Result.G = Dot(A.G,InB);
625 Result.B = Dot(A.B,InB);
626 Result.A = 1.0f;
627 return Result;
628 }
629
630 /** In-place addition operator. */
631 /** Changed from (*this = *this + InB;) to separate all calc to avoid LHS **/
632
633 /** Now it calls directly += operator in TSHVector (avoid TSHVectorRGB + operator) **/
634 FORCEINLINE TSHVectorRGB& operator+=(const TSHVectorRGB& InB)
635 {
636 R += InB.R;
637 G += InB.G;
638 B += InB.B;
639
640 return *this;
641 }
642
643 /** In-place subtraction operator. */
644 /** Changed from (*this = *this - InB;) to separate all calc to avoid LHS **/
645 /** Now it calls directly -= operator in TSHVector (avoid TSHVectorRGB - operator) **/
646 FORCEINLINE TSHVectorRGB& operator-=(const TSHVectorRGB& InB)
647 {
648 R -= InB.R;
649 G -= InB.G;
650 B -= InB.B;
651
652 return *this;
653 }
654
655 /** In-place scalar multiplication operator. */
656 /** Changed from (*this = *this * InB;) to separate all calc to avoid LHS **/
657 /** Now it calls directly *= operator in TSHVector (avoid TSHVectorRGB * operator) **/
658 FORCEINLINE TSHVectorRGB& operator*=(const float& Scalar)
659 {
660 R *= Scalar;
661 G *= Scalar;
662 B *= Scalar;
663
664 return *this;
665 }
666
667 friend FArchive& operator<<(FArchive& Ar, TSHVectorRGB& SH)
668 {
669 return Ar << SH.R << SH.G << SH.B;
670 }
671
672 /** Adds an impulse to the SH environment. */
673 inline void AddIncomingRadiance(const FLinearColor& IncomingRadiance, float Weight, const FVector4& WorldSpaceDirection)
674 {
675 *this += TSHVector<MaxSHOrder>::SHBasisFunction(WorldSpaceDirection) * (IncomingRadiance * Weight);
676 }
677
678 /** Adds ambient lighting. */
679 inline void AddAmbient(const FLinearColor& Intensity)
680 {
681 *this += TSHVector<MaxSHOrder>::AmbientFunction() * Intensity;
682 }
683};
684
685/** Color multiplication operator. */
686template<int32 Order>
688{
689 TSHVectorRGB<Order> Result;
690 Result.R = A * B.R;
691 Result.G = A * B.G;
692 Result.B = A * B.B;
693
694 return Result;
695}
696
697typedef TSHVector<3> FSHVector3;
698typedef TSHVector<2> FSHVector2;
#define MS_ALIGN(n)
Definition Platform.h:796
#define FORCEINLINE
Definition Platform.h:644
#define GCC_ALIGN(n)
Definition Platform.h:793
TSHVectorRGB< 2 > FSHVectorRGB2
Definition SHMath.h:700
TSHVector< 3 > FSHVector3
Definition SHMath.h:697
TSHVector< 2 > FSHVector2
Definition SHMath.h:698
FORCEINLINE TSHVectorRGB< Order > operator*(const TSHVector< Order > &A, const FLinearColor &B)
Definition SHMath.h:687
int32 BasisL[9]
TSHVectorRGB< 3 > FSHVectorRGB3
Definition SHMath.h:699
int32 BasisM[9]
float NormalizationConstants[9]
FORCEINLINE int32 SHGetBasisIndex(int32 L, int32 M)
Definition SHMath.h:25
float LegendrePolynomial(int32 L, int32 M, float X)
#define UE_PI
#define UE_KINDA_SMALL_NUMBER
#define UE_DELTA