CARLA
Loading...
Searching...
No Matches
CameraModelUtil.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#include "CameraModelUtil.h"
8
9#include <util/ue-header-guard-begin.h>
10#include "Engine/TextureRenderTargetCube.h"
11#include "Engine/TextureRenderTarget2D.h"
12#include "GlobalShader.h"
13#include "ShaderParameterUtils.h"
14#include "PipelineStateCache.h"
15#include "RHIStaticStates.h"
16#include "RenderGraphBuilder.h"
17#include "RenderGraphUtils.h"
18#include <util/ue-header-guard-end.h>
19
20#include <cmath>
21
22
23
29
30
31// @TODO: Actually find out what is the current GPU's subgroup size (warp size).
32static const auto SubgroupSize = 32U;
33static const auto WorkPerInvocation = static_cast<uint32>(64U / sizeof(FVector4f));
34static const auto KannalaBrandtSolverIterations = 32U;
35
36// static constexpr auto DegToRad = PI / 180.0F;
37// static constexpr auto RadToDeg = 180.0F / PI;
38
39static constexpr std::pair<const TCHAR*, uint32> CommonShaderDefinitions[] =
40{
41 std::make_pair(TEXT("THREAD_GROUP_SIZE_X"), SubgroupSize),
42 std::make_pair(TEXT("THREAD_GROUP_SIZE_Y"), 1U),
43 std::make_pair(TEXT("THREAD_GROUP_SIZE_Z"), 1U),
44 std::make_pair(TEXT("WORK_PER_INVOCATION"), WorkPerInvocation),
45 std::make_pair(TEXT("KANNALA_BRANDT_SOLVER_ITERATIONS"), KannalaBrandtSolverIterations),
46};
47
48
49
50template <ECameraModel>
52{
53 BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
54 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, OutImage)
55 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeFront)
56 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeBack)
57 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeRight)
58 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeLeft)
59 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeTop)
60 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeBottom)
61 SHADER_PARAMETER_SAMPLER(SamplerState, FaceSampler)
62 SHADER_PARAMETER(float, YFOVAngle)
63 SHADER_PARAMETER(FVector4f, CameraParams)
64 SHADER_PARAMETER(uint32, Flags)
65 SHADER_PARAMETER(float, LongitudeOffset)
66 SHADER_PARAMETER(float, FOVFadeSize)
67 SHADER_PARAMETER(FVector4f, InvalidColor)
68 END_SHADER_PARAMETER_STRUCT()
69};
70
71template <>
73{
74 BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
75 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, OutImage)
76 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeFront)
77 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeBack)
78 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeRight)
79 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeLeft)
80 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeTop)
81 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeBottom)
82 SHADER_PARAMETER_SAMPLER(SamplerState, FaceSampler)
83 SHADER_PARAMETER(float, YFOVAngle)
84 SHADER_PARAMETER(FVector4f, CameraParams)
85 SHADER_PARAMETER(uint32, Flags)
86 SHADER_PARAMETER(float, LongitudeOffset)
87 SHADER_PARAMETER(float, FOVFadeSize)
88 SHADER_PARAMETER(FVector4f, InvalidColor)
89 SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<float>, Coefficients)
90 SHADER_PARAMETER(uint32, CoefficientCount)
91 END_SHADER_PARAMETER_STRUCT()
92};
93
94// LUT1D: R(Theta) sample table (see CameraModelCommon.ush, LensLUT*).
95template <>
97{
98 BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
99 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, OutImage)
100 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeFront)
101 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeBack)
102 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeRight)
103 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeLeft)
104 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeTop)
105 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, CubeBottom)
106 SHADER_PARAMETER_SAMPLER(SamplerState, FaceSampler)
107 SHADER_PARAMETER(float, YFOVAngle)
108 SHADER_PARAMETER(FVector4f, CameraParams)
109 SHADER_PARAMETER(uint32, Flags)
110 SHADER_PARAMETER(float, LongitudeOffset)
111 SHADER_PARAMETER(float, FOVFadeSize)
112 SHADER_PARAMETER(FVector4f, InvalidColor)
113 SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<float>, LensLUT)
114 SHADER_PARAMETER(uint32, LensLUTSize)
115 SHADER_PARAMETER(float, LensThetaMax)
116 END_SHADER_PARAMETER_STRUCT()
117};
118
119
120
121template <ECameraModel>
123{
124 BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
125 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, Destination)
126 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, Source)
127 SHADER_PARAMETER_SAMPLER(SamplerState, SourceSampler)
128 SHADER_PARAMETER(FVector4f, DestinationCameraParams)
129 SHADER_PARAMETER(FVector4f, SourceCameraParams)
130 END_SHADER_PARAMETER_STRUCT()
131};
132
133template <>
135{
136 BEGIN_SHADER_PARAMETER_STRUCT(FParameters, )
137 SHADER_PARAMETER_RDG_TEXTURE_UAV(RWTexture2D<float4>, Destination)
138 SHADER_PARAMETER_RDG_TEXTURE_SRV(Texture2D, Source)
139 SHADER_PARAMETER_SAMPLER(SamplerState, SourceSampler)
140 SHADER_PARAMETER(FVector4f, DestinationCameraParams)
141 SHADER_PARAMETER(FVector4f, SourceCameraParams)
142 SHADER_PARAMETER_RDG_BUFFER_SRV(StructuredBuffer<float>, Coefficients)
143 SHADER_PARAMETER(uint32, CoefficientCount)
144 END_SHADER_PARAMETER_STRUCT()
145};
146
147
148
149// Depending on which version of clang we're using, templates may not work with IMPLEMENT_SHADER.
150// Macro fallback:
151
152#define DECLARE_WIDE_ANGLE_LENS_SHADER(NAME, CAMERA_MODEL) \
153 class NAME : \
154 public FWideAngleLensShaderBase<CAMERA_MODEL>, \
155 public FGlobalShader \
156 { \
157 public: \
158 \
159 DECLARE_GLOBAL_SHADER(NAME); \
160 SHADER_USE_PARAMETER_STRUCT(NAME, FGlobalShader); \
161 \
162 static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) \
163 { \
164 return true; \
165 } \
166 \
167 static void ModifyCompilationEnvironment( \
168 const FGlobalShaderPermutationParameters& Parameters, \
169 FShaderCompilerEnvironment& OutEnvironment) \
170 { \
171 for (auto Definition : CommonShaderDefinitions) \
172 OutEnvironment.SetDefine(Definition.first, Definition.second); \
173 OutEnvironment.SetDefine(TEXT("CAMERA_TYPE"), static_cast<uint32>(CAMERA_MODEL)); \
174 FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment); \
175 } \
176 }
177
178
179
180#define DECLARE_PERSPECTIVE_SHADER(NAME, CAMERA_MODEL) \
181 class NAME : \
182 public FToPerspectiveShaderBase<CAMERA_MODEL>, \
183 public FGlobalShader \
184 { \
185 public: \
186 \
187 DECLARE_GLOBAL_SHADER(NAME); \
188 SHADER_USE_PARAMETER_STRUCT(NAME, FGlobalShader); \
189 \
190 static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) \
191 { \
192 return true; \
193 } \
194 \
195 static void ModifyCompilationEnvironment( \
196 const FGlobalShaderPermutationParameters& Parameters, \
197 FShaderCompilerEnvironment& OutEnvironment) \
198 { \
199 for (auto Definition : CommonShaderDefinitions) \
200 OutEnvironment.SetDefine(Definition.first, Definition.second); \
201 OutEnvironment.SetDefine(TEXT("CAMERA_TYPE"), static_cast<uint32>(CAMERA_MODEL)); \
202 FGlobalShader::ModifyCompilationEnvironment(Parameters, OutEnvironment); \
203 } \
204 }
205
213
214DECLARE_PERSPECTIVE_SHADER(FToPerspectiveShader_Perspective, ECameraModel::Perspective);
215DECLARE_PERSPECTIVE_SHADER(FToPerspectiveShader_Stereographic, ECameraModel::Stereographic);
216DECLARE_PERSPECTIVE_SHADER(FToPerspectiveShader_Equidistance, ECameraModel::Equidistant);
220
221
222
223template <typename FShaderType>
225 FRDGBuilder& GraphBuilder,
226 FRDGTextureRef Destination,
227 FRDGTextureRef CubeTextures[6],
228 FRHISamplerState* Sampler,
230 FVector4f CameraParams)
231{
232 auto Parameters = GraphBuilder.AllocParameters<typename FShaderType::FParameters>();
233 Parameters->OutImage = GraphBuilder.CreateUAV(Destination);
234 Parameters->CubeFront = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(CubeTextures[0]));
235 Parameters->CubeBack = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(CubeTextures[1]));
236 Parameters->CubeRight = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(CubeTextures[2]));
237 Parameters->CubeLeft = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(CubeTextures[3]));
238 Parameters->CubeTop = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(CubeTextures[4]));
239 Parameters->CubeBottom = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(CubeTextures[5]));
240 Parameters->FaceSampler = Sampler;
241 Parameters->CameraParams = CameraParams;
242 Parameters->YFOVAngle = Options.YFOVAngle;
243 Parameters->LongitudeOffset = Options.LongitudeOffset;
244 Parameters->FOVFadeSize = Options.FOVFadeSize;
245 Parameters->InvalidColor = Options.InvalidColor;
246 Parameters->Flags = 0;
247 if (Options.bRenderEquirectangular)
248 Parameters->Flags |= WAL_SHADER_FLAGS_EQUIRECTANGULAR;
249 if (Options.bFOVMaskEnable)
250 Parameters->Flags |= WAL_SHADER_FLAGS_FOV_MASK;
251 return Parameters;
252}
253
254template <typename FShaderType>
256 FRDGBuilder& GraphBuilder,
257 typename FShaderType::FParameters* Parameters,
258 FIntPoint Size)
259{
260 GraphBuilder.AddPass(
261 RDG_EVENT_NAME("WideAngleLens-Dispatch"),
262 Parameters,
263 ERDGPassFlags::Compute,
264 [Parameters, Size](FRHICommandListImmediate& RHICmdList)
265 {
266 TShaderMapRef<FShaderType> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
267 check(ComputeShader.IsValid());
268
269 FComputeShaderUtils::Dispatch(
270 RHICmdList,
271 ComputeShader,
272 *Parameters,
273 FComputeShaderUtils::GetGroupCount(
274 FIntVector(Size.X, Size.Y, 1),
275 FIntVector(SubgroupSize, 1, 1)));
276 });
277}
278
279template <typename FShaderType>
280static void ApplyDistortion(
281 FRDGBuilder& GraphBuilder,
282 FRDGTextureRef Destination,
283 FRDGTextureRef CubeTextures[6],
284 FRHISamplerState* Sampler,
285 FIntPoint Size,
287 FVector4f CameraParams)
288{
289 auto Parameters = CreateDistortionParameters<FShaderType>(
290 GraphBuilder, Destination, CubeTextures, Sampler, Options, CameraParams);
291 DispatchDistortion<FShaderType>(GraphBuilder, Parameters, Size);
292}
293
295 FRDGBuilder& GraphBuilder,
296 FRDGTextureRef Destination,
297 FRDGTextureRef CubeTextures[6],
298 FRHISamplerState* Sampler,
299 FIntPoint Size,
301 FVector4f CameraParams)
302{
303 using FShaderType = FWideAngleLensShader_Custom;
304
305 auto Parameters = CreateDistortionParameters<FShaderType>(
306 GraphBuilder, Destination, CubeTextures, Sampler, Options, CameraParams);
307
308 const auto& Coefficients = Options.KannalaBrandtCoefficients;
309 auto CoefficientBuffer = CreateStructuredBuffer(
310 GraphBuilder,
311 TEXT("CoefficientBuffer"),
312 sizeof(float),
313 Coefficients.Num(),
314 Coefficients.GetData(),
315 Coefficients.Num() * sizeof(float),
316 ERDGInitialDataFlags::None);
317
318 Parameters->Coefficients = GraphBuilder.CreateSRV(FRDGBufferSRVDesc(CoefficientBuffer));
319 Parameters->CoefficientCount = static_cast<uint32>(Coefficients.Num());
320 DispatchDistortion<FShaderType>(GraphBuilder, Parameters, Size);
321}
322
324 FRDGBuilder& GraphBuilder,
325 FRDGTextureRef Destination,
326 FRDGTextureRef CubeTextures[6],
327 FRHISamplerState* Sampler,
328 FIntPoint Size,
330 FVector4f CameraParams)
331{
332 using FShaderType = FWideAngleLensShader_LUT1D;
333
334 auto Parameters = CreateDistortionParameters<FShaderType>(
335 GraphBuilder, Destination, CubeTextures, Sampler, Options, CameraParams);
336
337 // An empty table would map every pixel to Theta = 0; substitute a single
338 // zero sample so the shader's out-of-range test marks the frame invalid
339 // instead of sampling a zero-sized buffer.
340 static const float EmptyLUT[1] = { 0.0F };
341 const TArrayView<const float> LUT = Options.LUT.Num() > 0
342 ? Options.LUT
343 : TArrayView<const float>(EmptyLUT, 1);
344
345 auto LUTBuffer = CreateStructuredBuffer(
346 GraphBuilder,
347 TEXT("LensLUTBuffer"),
348 sizeof(float),
349 LUT.Num(),
350 LUT.GetData(),
351 LUT.Num() * sizeof(float),
352 ERDGInitialDataFlags::None);
353
354 Parameters->LensLUT = GraphBuilder.CreateSRV(FRDGBufferSRVDesc(LUTBuffer));
355 Parameters->LensLUTSize = static_cast<uint32>(LUT.Num());
356 Parameters->LensThetaMax = Options.ThetaMax;
357 DispatchDistortion<FShaderType>(GraphBuilder, Parameters, Size);
358}
359
360template <typename FShaderType>
361static void ToPerspective(
362 FRDGBuilder& GraphBuilder,
363 FRDGTextureRef Destination,
364 FRDGTextureRef Source,
365 FRHISamplerState* Sampler,
366 float YFOVAngle,
367 float DestinationFocalDistance,
368 float SourceFocalDistance,
369 FIntPoint Size)
370{
371 const auto Center = Size / 2;
372
373 auto Parameters = GraphBuilder.AllocParameters<typename FShaderType::FParameters>();
374 Parameters->Destination = GraphBuilder.CreateUAV(Destination);
375 Parameters->Source = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(Source));
376 Parameters->SourceSampler = Sampler;
377 Parameters->SourceCameraParams = FVector4f(SourceFocalDistance, SourceFocalDistance, Center.X, Center.Y);
378 Parameters->DestinationCameraParams = FVector4f(DestinationFocalDistance, DestinationFocalDistance, Center.X, Center.Y);
379
380 GraphBuilder.AddPass(
381 RDG_EVENT_NAME("ToPerspective-Dispatch"),
382 Parameters,
383 ERDGPassFlags::Compute,
384 [Parameters, Size](FRHICommandListImmediate& RHICmdList)
385 {
386 TShaderMapRef<FShaderType> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
387 check(ComputeShader.IsValid());
388
389 FComputeShaderUtils::Dispatch(RHICmdList, ComputeShader, *Parameters,
390 FComputeShaderUtils::GetGroupCount(
391 FIntVector(Size.X, Size.Y, 1),
392 FIntVector(SubgroupSize * WorkPerInvocation, 1, 1)));
393 });
394}
395
396static void ToPerspective(
397 FRDGBuilder& GraphBuilder,
398 FRDGTextureRef Destination,
399 FRDGTextureRef Source,
400 FRHISamplerState* Sampler,
401 float YFOVAngle,
402 float DestinationFocalDistance,
403 float SourceFocalDistance,
404 FIntPoint Size,
405 TArrayView<const float> KannalaBrandtCoefficients)
406{
407 using FShaderType = FToPerspectiveShader_Custom;
408
409 const auto Center = Size / 2;
410
411 auto CoefficientBuffer = CreateStructuredBuffer(
412 GraphBuilder,
413 TEXT("CoefficientBuffer"),
414 sizeof(float),
415 KannalaBrandtCoefficients.Num(),
416 KannalaBrandtCoefficients.GetData(),
417 KannalaBrandtCoefficients.Num() * sizeof(float),
418 ERDGInitialDataFlags::None);
419
420 auto Parameters = GraphBuilder.AllocParameters<typename FShaderType::FParameters>();
421 Parameters->Destination = GraphBuilder.CreateUAV(Destination);
422 Parameters->Source = GraphBuilder.CreateSRV(FRDGTextureSRVDesc::Create(Source));
423 Parameters->SourceSampler = Sampler;
424 Parameters->SourceCameraParams = FVector4f(SourceFocalDistance, SourceFocalDistance, Center.X, Center.Y);
425 Parameters->DestinationCameraParams = FVector4f(DestinationFocalDistance, DestinationFocalDistance, Center.X, Center.Y);
426 Parameters->Coefficients = GraphBuilder.CreateSRV(FRDGBufferSRVDesc(CoefficientBuffer));
427 Parameters->CoefficientCount = static_cast<uint32>(KannalaBrandtCoefficients.Num());
428
429 GraphBuilder.AddPass(
430 RDG_EVENT_NAME("ToPerspective-Dispatch"),
431 Parameters,
432 ERDGPassFlags::Compute,
433 [Parameters, Size](FRHICommandListImmediate& RHICmdList)
434 {
435 TShaderMapRef<FShaderType> ComputeShader(GetGlobalShaderMap(GMaxRHIFeatureLevel));
436 check(ComputeShader.IsValid());
437
438 FComputeShaderUtils::Dispatch(RHICmdList, ComputeShader, *Parameters,
439 FComputeShaderUtils::GetGroupCount(
440 FIntVector(Size.X, Size.Y, 1),
441 FIntVector(SubgroupSize * WorkPerInvocation, 1, 1)));
442 });
443}
444
445
446
448{
450 {
452 float Theta,
453 TArrayView<const float> Coefficients)
454 {
455 auto Result = 1.0F;
456 auto Theta2 = Theta * Theta;
457 auto ThetaN = 1.0F;
458
459 for (auto K : Coefficients)
460 {
461 ThetaN *= Theta2;
462 Result += K * ThetaN;
463 }
464
465 return Result * Theta;
466 }
467
469 float Theta,
470 TArrayView<const float> Coefficients)
471 {
472 auto Result = 1.0F;
473 auto Theta2 = Theta * Theta;
474 auto ThetaN = Theta2;
475 auto A = 3.0F;
476
477 for (auto K : Coefficients)
478 {
479 Result += A * K * ThetaN;
480 A += 2.0F;
481 ThetaN *= Theta2;
482 }
483
484 return Result;
485 }
486
487 }
488
490 ECameraModel CameraModel,
491 float Distance,
492 TArrayView<const float> Coefficients)
493 {
494 switch (CameraModel)
495 {
497 return std::atan(Distance);
499 return std::atan(Distance * 0.5F) * 2;
501 return Distance;
503 return std::asin(FMath::Clamp(Distance * 0.5F, -1.0F, 1.0F)) * 2;
505 return std::asin(FMath::Clamp(Distance, -1.0F, 1.0F));
507 {
508 float Theta = Distance;
509 for (uint8 i = 0; i != KannalaBrandtSolverIterations; ++i)
510 {
511 float N = Distance - KannalaBrandt::ComputeCameraPolynomial(Theta, Coefficients);
512 float D = -KannalaBrandt::ComputeCameraPolynomialDerivative(Theta, Coefficients);
513 Theta -= N / D;
514 }
515 return Theta;
516 }
517 default:
518 check(false);
519 return 0.0F;
520 }
521 }
522
524 ECameraModel CameraModel,
525 float Angle,
526 int32 ImageHeight,
527 TArrayView<const float> Coefficients)
528 {
529 const auto H = static_cast<float>(ImageHeight);
530 const auto R = H * 0.5F;
531 float F = 0.0F;
532
533 Angle *= 0.5F;
534 switch (CameraModel)
535 {
537 F = R / std::tan(Angle);
538 break;
540 F = R / (std::tan(Angle * 0.5F) * 2);
541 break;
543 F = R / Angle;
544 break;
546 F = R / (std::sin(Angle * 0.5F) * 2);
547 break;
549 F = R / std::sin(Angle);
550 break;
552 F = R / KannalaBrandt::ComputeCameraPolynomial(Angle, Coefficients);
553 break;
554 default:
555 check(false);
556 break;
557 }
558 return F;
559 }
560
562 FRDGBuilder& GraphBuilder,
563 FRDGTexture* Destination,
564 FRDGTexture** CubeTextures,
565 FRHISamplerState* Sampler,
566 const FDistortCubemapToImageOptions& Options)
567 {
568 auto& DestinationDesc = Destination->Desc;
569 auto SizeVector = DestinationDesc.GetSize();
570 auto Size = FIntPoint(SizeVector.X, SizeVector.Y);
571
572 auto DistortedTexture =
573 GraphBuilder.CreateTexture(
574 FRDGTextureDesc::Create2D(
575 Size,
576 DestinationDesc.Format,
577 DestinationDesc.ClearValue,
578 TexCreate_ShaderResource | TexCreate_UAV),
579 TEXT("DistortedTexture"));
580
581 // (fx, fy, cx, cy) in pixels. Legacy path: square focal length from
582 // the FOV, principal point at the image centre.
583 const FVector4f CameraParams = Options.bExplicitIntrinsics
584 ? Options.Intrinsics
585 : FVector4f(Options.YFocalLength, Options.YFocalLength, (Size / 2).X, (Size / 2).Y);
586
587 switch (Options.CameraModel)
588 {
590 case ECameraModel::BrownConrady: // no cubemap implementation; undistorted pinhole
591 ApplyDistortion<FWideAngleLensShader_Perspective>(
592 GraphBuilder, DistortedTexture, CubeTextures, Sampler, Size, Options, CameraParams);
593 break;
595 ApplyDistortion<FWideAngleLensShader_Stereographic>(
596 GraphBuilder, DistortedTexture, CubeTextures, Sampler, Size, Options, CameraParams);
597 break;
599 ApplyDistortion<FWideAngleLensShader_Equidistance>(
600 GraphBuilder, DistortedTexture, CubeTextures, Sampler, Size, Options, CameraParams);
601 break;
603 ApplyDistortion<FWideAngleLensShader_Equisolid>(
604 GraphBuilder, DistortedTexture, CubeTextures, Sampler, Size, Options, CameraParams);
605 break;
607 ApplyDistortion<FWideAngleLensShader_Orthogonal>(
608 GraphBuilder, DistortedTexture, CubeTextures, Sampler, Size, Options, CameraParams);
609 break;
612 GraphBuilder, DistortedTexture, CubeTextures, Sampler, Size, Options, CameraParams);
613 break;
616 GraphBuilder, DistortedTexture, CubeTextures, Sampler, Size, Options, CameraParams);
617 break;
618 default:
619 check(false);
620 }
621
622 const bool bCanRenderPerspective =
623 Options.CameraModel != ECameraModel::LUT1D &&
625
626 if (Options.bRenderPerspective && !Options.bRenderEquirectangular && bCanRenderPerspective)
627 {
628 auto PerspectiveTexture =
629 GraphBuilder.CreateTexture(
630 FRDGTextureDesc::Create2D(
631 Size,
632 DestinationDesc.Format,
633 FClearValueBinding::Black,
634 TexCreate_ShaderResource | TexCreate_UAV),
635 TEXT("PerspectiveTexture"));
636
637 auto FocalDistancePerspective = ComputeDistance(
639 Options.YFOVAngle,
640 Size.Y,
642
643 switch (Options.CameraModel)
644 {
646 ToPerspective<FToPerspectiveShader_Perspective>(
647 GraphBuilder,
648 PerspectiveTexture,
649 DistortedTexture,
650 Sampler,
651 Options.YFOVAngle,
652 Options.YFocalLength,
653 FocalDistancePerspective,
654 Size);
655 break;
657 ToPerspective<FToPerspectiveShader_Stereographic>(
658 GraphBuilder,
659 PerspectiveTexture,
660 DistortedTexture,
661 Sampler,
662 Options.YFOVAngle,
663 Options.YFocalLength,
664 FocalDistancePerspective,
665 Size);
666 break;
668 ToPerspective<FToPerspectiveShader_Equidistance>(
669 GraphBuilder,
670 PerspectiveTexture,
671 DistortedTexture,
672 Sampler,
673 Options.YFOVAngle,
674 Options.YFocalLength,
675 FocalDistancePerspective,
676 Size);
677 break;
679 ToPerspective<FToPerspectiveShader_Equisolid>(
680 GraphBuilder,
681 PerspectiveTexture,
682 DistortedTexture,
683 Sampler,
684 Options.YFOVAngle,
685 Options.YFocalLength,
686 FocalDistancePerspective,
687 Size);
688 break;
690 ToPerspective<FToPerspectiveShader_Orthogonal>(
691 GraphBuilder,
692 PerspectiveTexture,
693 DistortedTexture,
694 Sampler,
695 Options.YFOVAngle,
696 Options.YFocalLength,
697 FocalDistancePerspective,
698 Size);
699 break;
702 GraphBuilder,
703 PerspectiveTexture,
704 DistortedTexture,
705 Sampler,
706 Options.YFOVAngle,
707 Options.YFocalLength,
708 FocalDistancePerspective,
709 Size,
711 break;
712 default:
713 check(false);
714 }
715
716 AddCopyTexturePass(
717 GraphBuilder,
718 PerspectiveTexture,
719 Destination);
720 }
721 else
722 {
723 AddCopyTexturePass(
724 GraphBuilder,
725 DistortedTexture,
726 Destination);
727 }
728 }
729
731 FRDGBuilder& GraphBuilder,
732 UTextureRenderTarget2D* Destination,
733 UTextureRenderTarget2D** CubeRenderTargets,
734 FRHISamplerState* Sampler,
735 const FDistortCubemapToImageOptions& Options)
736 {
737 FTextureRHIRef TextureRHIs[6] = {};
738
739 for (uint8 i = 0; i != 6; ++i)
740 {
741 TextureRHIs[i] = CubeRenderTargets[i]
742 ->GetRenderTargetResource()
743 ->GetTextureRenderTarget2DResource()
744 ->GetTextureRHI();
745 }
746
747 auto DestinationRHI = Destination
748 ->GetRenderTargetResource()
749 ->GetTextureRenderTarget2DResource()
750 ->GetTextureRHI();
751
752 TRefCountPtr<IPooledRenderTarget> PRTs[] =
753 {
754 CreateRenderTarget(TextureRHIs[0], TEXT("CubeTextures[0]")),
755 CreateRenderTarget(TextureRHIs[1], TEXT("CubeTextures[1]")),
756 CreateRenderTarget(TextureRHIs[2], TEXT("CubeTextures[2]")),
757 CreateRenderTarget(TextureRHIs[3], TEXT("CubeTextures[3]")),
758 CreateRenderTarget(TextureRHIs[4], TEXT("CubeTextures[4]")),
759 CreateRenderTarget(TextureRHIs[5], TEXT("CubeTextures[5]"))
760 };
761
762 auto CaptureRenderTargetTexture = GraphBuilder.RegisterExternalTexture(
763 CreateRenderTarget(DestinationRHI, TEXT("CaptureRenderTargetTexture")));
764
765 FRDGTextureRef CubeTextures[6] = { };
766
767 for (uint8 i = 0; i != 6; ++i)
768 {
769 CubeTextures[i] = GraphBuilder.RegisterExternalTexture(PRTs[i]);
770 }
771
773 GraphBuilder,
774 CaptureRenderTargetTexture,
775 CubeTextures,
776 Sampler,
777 Options);
778 }
779
780 FRHISamplerState* GetSampler(ESamplerFilter Filter)
781 {
782 switch (Filter)
783 {
784
785 case SF_Point:
786 return TStaticSamplerState< SF_Point>::GetRHI();
787 case SF_Bilinear:
788 return TStaticSamplerState< SF_Bilinear>::GetRHI();
789 case SF_Trilinear:
790 return TStaticSamplerState< SF_Trilinear>::GetRHI();
791 case SF_AnisotropicPoint:
792 return TStaticSamplerState< SF_AnisotropicPoint>::GetRHI();
793 case SF_AnisotropicLinear:
794 return TStaticSamplerState< SF_AnisotropicLinear>::GetRHI();
795 default:
796 check(false);
797 return nullptr;
798 }
799 }
800
801
802
803 // -----------------------------------------------------------------------
804 // FLensModelDescriptor forward/inverse core.
805 // -----------------------------------------------------------------------
806
807 namespace BrownConrady
808 {
809 // Evaluates Distort() and its Jacobian in one pass, so Undistort()'s
810 // Newton-Raphson loop only pays for the distortion math once per iteration.
811 static void EvalWithJacobian(
812 float Xn,
813 float Yn,
814 TArrayView<const float> C,
815 float& OutXd,
816 float& OutYd,
817 float OutJ[4]) // row-major [dXd/dXn, dXd/dYn, dYd/dXn, dYd/dYn]
818 {
819 const float K1 = C.Num() > 0 ? C[0] : 0.0F;
820 const float K2 = C.Num() > 1 ? C[1] : 0.0F;
821 const float K3 = C.Num() > 2 ? C[2] : 0.0F;
822 const float P1 = C.Num() > 3 ? C[3] : 0.0F;
823 const float P2 = C.Num() > 4 ? C[4] : 0.0F;
824
825 const float R2 = Xn * Xn + Yn * Yn;
826 const float R4 = R2 * R2;
827 const float Radial = 1.0F + K1 * R2 + K2 * R4 + K3 * R4 * R2;
828 const float DRadialDR2 = K1 + 2.0F * K2 * R2 + 3.0F * K3 * R4;
829
830 OutXd = Xn * Radial + 2.0F * P1 * Xn * Yn + P2 * (R2 + 2.0F * Xn * Xn);
831 OutYd = Yn * Radial + P1 * (R2 + 2.0F * Yn * Yn) + 2.0F * P2 * Xn * Yn;
832
833 const float DRadialDXn = 2.0F * Xn * DRadialDR2;
834 const float DRadialDYn = 2.0F * Yn * DRadialDR2;
835
836 OutJ[0] = Radial + Xn * DRadialDXn + 2.0F * P1 * Yn + 6.0F * P2 * Xn; // dXd/dXn
837 OutJ[1] = Xn * DRadialDYn + 2.0F * P1 * Xn + 2.0F * P2 * Yn; // dXd/dYn
838 OutJ[2] = Yn * DRadialDXn + 2.0F * P1 * Xn + 2.0F * P2 * Yn; // dYd/dXn
839 OutJ[3] = Radial + Yn * DRadialDYn + 6.0F * P1 * Yn + 2.0F * P2 * Xn; // dYd/dYn
840 }
841
842 FVector2f Distort(
843 float Xn,
844 float Yn,
845 TArrayView<const float> Coefficients)
846 {
847 float Xd, Yd, J[4];
848 EvalWithJacobian(Xn, Yn, Coefficients, Xd, Yd, J);
849 return FVector2f(Xd, Yd);
850 }
851
852 FVector2f Undistort(
853 float Xd,
854 float Yd,
855 TArrayView<const float> Coefficients,
856 int32 Iterations)
857 {
858 float Xn = Xd, Yn = Yd; // initial guess: undistorted ~ distorted for small distortion
859 for (int32 i = 0; i != Iterations; ++i)
860 {
861 float Fx, Fy, J[4];
862 EvalWithJacobian(Xn, Yn, Coefficients, Fx, Fy, J);
863 Fx -= Xd;
864 Fy -= Yd;
865
866 const float Det = J[0] * J[3] - J[1] * J[2];
867 if (FMath::Abs(Det) < 1e-12F)
868 break;
869
870 const float InvDet = 1.0F / Det;
871 const float DXn = InvDet * (J[3] * Fx - J[1] * Fy);
872 const float DYn = InvDet * (-J[2] * Fx + J[0] * Fy);
873
874 Xn -= DXn;
875 Yn -= DYn;
876 }
877 return FVector2f(Xn, Yn);
878 }
879 } // BrownConrady
880
881 namespace FTheta
882 {
883 float Polynomial(float Distance, TArrayView<const float> Coefficients)
884 {
885 float Result = 0.0F, RN = 1.0F;
886 const int32 N = FMath::Min(Coefficients.Num(), 8);
887 for (int32 i = 0; i < N; ++i) { Result += Coefficients[i] * RN; RN *= Distance; }
888 return Result;
889 }
890 float SolveRadius(float Theta, TArrayView<const float> Coefficients, int32 Iterations)
891 {
892 const int32 N = FMath::Min(Coefficients.Num(), 8);
893 const float C0 = N > 0 ? Coefficients[0] : 0.0F, C1 = N > 1 ? Coefficients[1] : 0.0F;
894 float R = FMath::Abs(C1) > 1e-12F ? (Theta - C0) / C1 : Theta;
895 for (int32 It = 0; It < Iterations; ++It)
896 {
897 float D = 0.0F, RN = 1.0F;
898 for (int32 i = 1; i < N; ++i) { D += float(i) * Coefficients[i] * RN; RN *= R; }
899 if (FMath::Abs(D) < 1e-12F) break;
900 R -= (Polynomial(R, Coefficients) - Theta) / D;
901 }
902 return FMath::Max(R, 0.0F);
903 }
904 }
905
906 namespace LUT1D
907 {
909 float Theta,
910 TArrayView<const float> Samples,
911 float ThetaMax)
912 {
913 const int32 Count = Samples.Num();
914 if (Count == 0)
915 return 0.0F;
916 if (Count == 1)
917 return Samples[0];
918
919 const float Clamped = FMath::Clamp(Theta, 0.0F, ThetaMax);
920 const float T = ThetaMax > 0.0F ? (Clamped / ThetaMax) * static_cast<float>(Count - 1) : 0.0F;
921 const int32 I0 = FMath::Clamp(static_cast<int32>(FMath::FloorToFloat(T)), 0, Count - 1);
922 const int32 I1 = FMath::Min(I0 + 1, Count - 1);
923 const float Frac = T - static_cast<float>(I0);
924 return FMath::Lerp(Samples[I0], Samples[I1], Frac);
925 }
926
928 float Distance,
929 TArrayView<const float> Samples,
930 float ThetaMax)
931 {
932 const int32 Count = Samples.Num();
933 if (Count < 2)
934 return 0.0F;
935 if (Distance <= Samples[0])
936 return 0.0F;
937 if (Distance >= Samples[Count - 1])
938 return ThetaMax;
939
940 // Samples is assumed monotonically non-decreasing.
941 int32 Lo = 0;
942 int32 Hi = Count - 1;
943 while (Hi - Lo > 1)
944 {
945 const int32 Mid = (Lo + Hi) / 2;
946 if (Samples[Mid] <= Distance)
947 Lo = Mid;
948 else
949 Hi = Mid;
950 }
951
952 const float R0 = Samples[Lo];
953 const float R1 = Samples[Hi];
954 const float Frac = R1 > R0 ? (Distance - R0) / (R1 - R0) : 0.0F;
955 const float IndexF = static_cast<float>(Lo) + Frac;
956 return (IndexF / static_cast<float>(Count - 1)) * ThetaMax;
957 }
958 } // LUT1D
959
960 // R(Theta) for every model except BrownConrady, which is not radially symmetric.
961 static float RadialForward(
962 ECameraModel Model,
963 float Theta,
964 TArrayView<const float> Coeffs,
965 TArrayView<const float> LUT,
966 float ThetaMax)
967 {
968 switch (Model)
969 {
971 return std::tan(Theta);
973 return std::tan(Theta * 0.5F) * 2.0F;
975 return Theta;
977 return std::sin(Theta * 0.5F) * 2.0F;
979 return std::sin(Theta);
981 return KannalaBrandt::ComputeCameraPolynomial(Theta, Coeffs);
983 return LUT1D::SampleForward(Theta, LUT, ThetaMax);
985 return FTheta::SolveRadius(Theta, Coeffs);
986 default:
987 check(false);
988 return 0.0F;
989 }
990 }
991
992 // Theta(R) for every model except BrownConrady.
993 static float RadialInverse(
994 ECameraModel Model,
995 float Distance,
996 TArrayView<const float> Coeffs,
997 TArrayView<const float> LUT,
998 float ThetaMax)
999 {
1000 switch (Model)
1001 {
1003 return std::atan(Distance);
1005 return std::atan(Distance * 0.5F) * 2.0F;
1007 return Distance;
1009 return std::asin(FMath::Clamp(Distance * 0.5F, -1.0F, 1.0F)) * 2.0F;
1011 return std::asin(FMath::Clamp(Distance, -1.0F, 1.0F));
1013 {
1014 float Theta = Distance;
1015 for (uint8 i = 0; i != KannalaBrandtSolverIterations; ++i)
1016 {
1017 float N = Distance - KannalaBrandt::ComputeCameraPolynomial(Theta, Coeffs);
1018 float D = -KannalaBrandt::ComputeCameraPolynomialDerivative(Theta, Coeffs);
1019 Theta -= N / D;
1020 }
1021 return Theta;
1022 }
1024 return LUT1D::SampleInverse(Distance, LUT, ThetaMax);
1026 return FTheta::Polynomial(Distance, Coeffs);
1027 default:
1028 check(false);
1029 return 0.0F;
1030 }
1031 }
1032
1033 static float SelectCAScale(const FLensModelDescriptor& Descriptor, ELensColorChannel Channel)
1034 {
1035 switch (Channel)
1036 {
1038 return Descriptor.CAScaleR;
1040 return Descriptor.CAScaleB;
1041 default:
1042 return 1.0F;
1043 }
1044 }
1045
1047 const FLensModelDescriptor& Descriptor,
1048 FVector Direction,
1049 ELensColorChannel Channel)
1050 {
1051 Direction = Direction.GetSafeNormal();
1052 if (Direction.IsNearlyZero())
1053 Direction = FVector(0, 0, 1);
1054
1055 const float CAScale = SelectCAScale(Descriptor, Channel);
1056
1057 float Xn, Yn;
1058
1059 if (Descriptor.Model == ECameraModel::BrownConrady)
1060 {
1061 const float Z = FMath::Max(static_cast<float>(Direction.Z), KINDA_SMALL_NUMBER);
1062 const float PinholeX = static_cast<float>(Direction.X) / Z;
1063 const float PinholeY = static_cast<float>(Direction.Y) / Z;
1064 const FVector2f Distorted = BrownConrady::Distort(PinholeX, PinholeY, Descriptor.Coeffs);
1065 Xn = Distorted.X;
1066 Yn = Distorted.Y;
1067 }
1068 else
1069 {
1070 const float Theta = std::acos(FMath::Clamp(static_cast<float>(Direction.Z), -1.0F, 1.0F));
1071 const float Phi = std::atan2(static_cast<float>(Direction.Y), static_cast<float>(Direction.X));
1072 const float R = RadialForward(Descriptor.Model, Theta, Descriptor.Coeffs, Descriptor.LUT, Descriptor.ThetaMax);
1073 Xn = R * std::cos(Phi);
1074 Yn = R * std::sin(Phi);
1075 }
1076
1077 Xn *= CAScale;
1078 Yn *= CAScale;
1079
1080 return FVector2f(
1081 Descriptor.CenterX + Descriptor.FocalX * Xn,
1082 Descriptor.CenterY + Descriptor.FocalY * Yn);
1083 }
1084
1086 const FLensModelDescriptor& Descriptor,
1087 FVector2f ImagePoint,
1088 ELensColorChannel Channel)
1089 {
1090 const float CAScale = SelectCAScale(Descriptor, Channel);
1091 const float SafeCAScale = FMath::IsNearlyZero(CAScale) ? 1.0F : CAScale;
1092
1093 const float Xn = (ImagePoint.X - Descriptor.CenterX) / (Descriptor.FocalX * SafeCAScale);
1094 const float Yn = (ImagePoint.Y - Descriptor.CenterY) / (Descriptor.FocalY * SafeCAScale);
1095
1096 if (Descriptor.Model == ECameraModel::BrownConrady)
1097 {
1098 const FVector2f Pinhole = BrownConrady::Undistort(Xn, Yn, Descriptor.Coeffs);
1099 return FVector(Pinhole.X, Pinhole.Y, 1.0F).GetSafeNormal();
1100 }
1101
1102 const float R = std::sqrt(Xn * Xn + Yn * Yn);
1103 const float Phi = std::atan2(Yn, Xn);
1104 const float Theta = RadialInverse(Descriptor.Model, R, Descriptor.Coeffs, Descriptor.LUT, Descriptor.ThetaMax);
1105 const float SinTheta = std::sin(Theta);
1106 return FVector(
1107 SinTheta * std::cos(Phi),
1108 SinTheta * std::sin(Phi),
1109 std::cos(Theta));
1110 }
1111
1112 FVector LensDirToUE(FVector LensDir)
1113 {
1114 // Lens: +X right, +Y down, +Z forward -> UE: +X forward, +Y right, +Z up
1115 return FVector(LensDir.Z, LensDir.X, -LensDir.Y);
1116 }
1117
1118 FVector UEDirToLens(FVector UEDir)
1119 {
1120 // UE: +X forward, +Y right, +Z up -> Lens: +X right, +Y down, +Z forward
1121 return FVector(UEDir.Y, -UEDir.Z, UEDir.X);
1122 }
1123
1124} // CameraModelUtil
1125
1126
1127
1129 FWideAngleLensShader_Perspective,
1130 TEXT("/Plugin/Carla/WideAngleLens.usf"),
1131 TEXT("MainCS"),
1132 SF_Compute);
1133
1135 FWideAngleLensShader_Stereographic,
1136 TEXT("/Plugin/Carla/WideAngleLens.usf"),
1137 TEXT("MainCS"),
1138 SF_Compute);
1139
1141 FWideAngleLensShader_Equidistance,
1142 TEXT("/Plugin/Carla/WideAngleLens.usf"),
1143 TEXT("MainCS"),
1144 SF_Compute);
1145
1147 FWideAngleLensShader_Equisolid,
1148 TEXT("/Plugin/Carla/WideAngleLens.usf"),
1149 TEXT("MainCS"),
1150 SF_Compute);
1151
1153 FWideAngleLensShader_Orthogonal,
1154 TEXT("/Plugin/Carla/WideAngleLens.usf"),
1155 TEXT("MainCS"),
1156 SF_Compute);
1157
1159 FWideAngleLensShader_Custom,
1160 TEXT("/Plugin/Carla/WideAngleLens.usf"),
1161 TEXT("MainCS"),
1162 SF_Compute);
1163
1165 FWideAngleLensShader_LUT1D,
1166 TEXT("/Plugin/Carla/WideAngleLens.usf"),
1167 TEXT("MainCS"),
1168 SF_Compute);
1169
1170
1171
1173 FToPerspectiveShader_Perspective,
1174 TEXT("/Plugin/Carla/ToPerspective.usf"),
1175 TEXT("MainCS"),
1176 SF_Compute);
1177
1179 FToPerspectiveShader_Stereographic,
1180 TEXT("/Plugin/Carla/ToPerspective.usf"),
1181 TEXT("MainCS"),
1182 SF_Compute);
1183
1185 FToPerspectiveShader_Equidistance,
1186 TEXT("/Plugin/Carla/ToPerspective.usf"),
1187 TEXT("MainCS"),
1188 SF_Compute);
1189
1191 FToPerspectiveShader_Equisolid,
1192 TEXT("/Plugin/Carla/ToPerspective.usf"),
1193 TEXT("MainCS"),
1194 SF_Compute);
1195
1197 FToPerspectiveShader_Orthogonal,
1198 TEXT("/Plugin/Carla/ToPerspective.usf"),
1199 TEXT("MainCS"),
1200 SF_Compute);
1201
1203 FToPerspectiveShader_Custom,
1204 TEXT("/Plugin/Carla/ToPerspective.usf"),
1205 TEXT("MainCS"),
1206 SF_Compute);
static void ApplyDistortionLUT1D(FRDGBuilder &GraphBuilder, FRDGTextureRef Destination, FRDGTextureRef CubeTextures[6], FRHISamplerState *Sampler, FIntPoint Size, const CameraModelUtil::FDistortCubemapToImageOptions &Options, FVector4f CameraParams)
static void DispatchDistortion(FRDGBuilder &GraphBuilder, typename FShaderType::FParameters *Parameters, FIntPoint Size)
WideAngleLensShaderFlags
@ WAL_SHADER_FLAGS_EQUIRECTANGULAR
@ WAL_SHADER_FLAGS_FOV_MASK
static constexpr std::pair< const TCHAR *, uint32 > CommonShaderDefinitions[]
static void ApplyDistortion(FRDGBuilder &GraphBuilder, FRDGTextureRef Destination, FRDGTextureRef CubeTextures[6], FRHISamplerState *Sampler, FIntPoint Size, const CameraModelUtil::FDistortCubemapToImageOptions &Options, FVector4f CameraParams)
static void ToPerspective(FRDGBuilder &GraphBuilder, FRDGTextureRef Destination, FRDGTextureRef Source, FRHISamplerState *Sampler, float YFOVAngle, float DestinationFocalDistance, float SourceFocalDistance, FIntPoint Size)
static void ApplyDistortionKannalaBrandt(FRDGBuilder &GraphBuilder, FRDGTextureRef Destination, FRDGTextureRef CubeTextures[6], FRHISamplerState *Sampler, FIntPoint Size, const CameraModelUtil::FDistortCubemapToImageOptions &Options, FVector4f CameraParams)
#define DECLARE_PERSPECTIVE_SHADER(NAME, CAMERA_MODEL)
#define DECLARE_WIDE_ANGLE_LENS_SHADER(NAME, CAMERA_MODEL)
static const auto KannalaBrandtSolverIterations
IMPLEMENT_SHADER_TYPE(, FWideAngleLensShader_Perspective, TEXT("/Plugin/Carla/WideAngleLens.usf"), TEXT("MainCS"), SF_Compute)
static auto CreateDistortionParameters(FRDGBuilder &GraphBuilder, FRDGTextureRef Destination, FRDGTextureRef CubeTextures[6], FRHISamplerState *Sampler, const CameraModelUtil::FDistortCubemapToImageOptions &Options, FVector4f CameraParams)
static const auto SubgroupSize
static const auto WorkPerInvocation
ECameraModel
carla::rpc::Response< T > R
FVector2f Undistort(float Xd, float Yd, TArrayView< const float > Coefficients, int32 Iterations)
static void EvalWithJacobian(float Xn, float Yn, TArrayView< const float > C, float &OutXd, float &OutYd, float OutJ[4])
FVector2f Distort(float Xn, float Yn, TArrayView< const float > Coefficients)
float SolveRadius(float Theta, TArrayView< const float > Coefficients, int32 Iterations)
float Polynomial(float Distance, TArrayView< const float > Coefficients)
float ComputeCameraPolynomialDerivative(float Theta, TArrayView< const float > Coefficients)
float ComputeCameraPolynomial(float Theta, TArrayView< const float > Coefficients)
float SampleForward(float Theta, TArrayView< const float > Samples, float ThetaMax)
float SampleInverse(float Distance, TArrayView< const float > Samples, float ThetaMax)
static float RadialForward(ECameraModel Model, float Theta, TArrayView< const float > Coeffs, TArrayView< const float > LUT, float ThetaMax)
float ComputeAngle(ECameraModel CameraModel, float Distance, TArrayView< const float > Coefficients)
float ComputeDistance(ECameraModel CameraModel, float Angle, int32 ImageHeight, TArrayView< const float > Coefficients)
FVector LensDirToUE(FVector LensDir)
FRHISamplerState * GetSampler(ESamplerFilter Filter)
FVector UEDirToLens(FVector UEDir)
void DistortCubemapToImage(FRDGBuilder &GraphBuilder, FRDGTexture *Destination, FRDGTexture **CubeTextures, FRHISamplerState *Sampler, const FDistortCubemapToImageOptions &Options)
FVector ComputeLensRayDirection(const FLensModelDescriptor &Descriptor, FVector2f ImagePoint, ELensColorChannel Channel)
FVector2f ComputeLensImagePoint(const FLensModelDescriptor &Descriptor, FVector Direction, ELensColorChannel Channel)
static float SelectCAScale(const FLensModelDescriptor &Descriptor, ELensColorChannel Channel)
static float RadialInverse(ECameraModel Model, float Distance, TArrayView< const float > Coeffs, TArrayView< const float > LUT, float ThetaMax)
TArrayView< const float > KannalaBrandtCoefficients
TArray< float > LUT
TArray< float > Coeffs