CARLA
Loading...
Searching...
No Matches
SceneCaptureCamera_RayTracedLensDistance.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
8#include "Carla.h"
12
14
15#include <util/ue-header-guard-begin.h>
16#include "Components/SceneCaptureComponent2D.h"
17#include "Engine/TextureRenderTarget2D.h"
18#include <util/ue-header-guard-end.h>
19
20// FPostProcessSettings::PathTracingLensAOV values, mirrored from
21// Engine/Shaders/Private/PathTracing/PathTracingCore.ush.
22static constexpr int32 GPathTracingLensAOVDistance = 1;
23
24// Unreal world units are centimetres; the CARLA sensor API reports metres.
25static constexpr float GUnrealUnitsToMeters = 0.01f;
26
28{
29 // Same attribute surface as sensor.camera.rt_lens (camera_model,
30 // distortion_coeffs, fx/fy/cx/cy, theta_max_deg, fov, show_only_*, ...) so a
31 // colour/distance pair can be configured from one dictionary. Post-process
32 // attributes are deliberately absent: this capture never goes through the
33 // post-process chain at all.
34 constexpr bool bEnableModifyingPostProcessEffects = false;
35 FActorDefinition Definition =
37 TEXT("rt_lens_distance"),
38 bEnableModifyingPostProcessEffects);
39
40 // The AOV is deterministic and noise-free by construction (one pixel-centre
41 // primary ray, no reconstruction filter, no denoiser), so the colour camera's
42 // sample budget would only cost time. Retune the inherited defaults rather
43 // than duplicating the whole definition.
44 for (auto &Variation : Definition.Variations)
45 {
46 if (Variation.Id == TEXT("samples_per_pixel"))
47 {
48 Variation.RecommendedValues = {TEXT("1")};
49 }
50 else if (Variation.Id == TEXT("enable_denoiser"))
51 {
52 Variation.RecommendedValues = {TEXT("false")};
53 }
54 }
55 return Definition;
56}
57
59 const FObjectInitializer &ObjectInitializer)
60 : Super(ObjectInitializer)
61{
62 // Nothing on this sensor's route touches the post-process chain: the capture
63 // source resolves the path tracer's AOV texture straight into the render
64 // target. Disabling post-processing keeps the show flags (and therefore the
65 // work the renderer does per capture) down to what a geometry pass needs.
68}
69
71{
72 if (CaptureComponent2D == nullptr)
73 {
74 return;
75 }
76 auto &PostProcessSettings = CaptureComponent2D->PostProcessSettings;
77
78 // Per-view AOV selection (Engine/Classes/Engine/Scene.h). Per-view rather
79 // than a cvar so a rig can run colour and distance cameras simultaneously.
80 PostProcessSettings.bOverride_PathTracingLensAOV = true;
81 PostProcessSettings.PathTracingLensAOV = GPathTracingLensAOVDistance;
82
83 // One sample is all the AOV needs, and the denoiser must never touch it.
84 // These are the inherited knobs (reasserted by the base's PostPhysTick), so
85 // they have to be written through the base's members, not just the settings.
87 bEnableDenoiser = false;
88 PostProcessSettings.bOverride_PathTracingSamplesPerPixel = true;
89 PostProcessSettings.bOverride_PathTracingEnableDenoiser = true;
90 PostProcessSettings.PathTracingSamplesPerPixel = SamplesPerPixel;
91 PostProcessSettings.PathTracingEnableDenoiser = bEnableDenoiser;
92
93 // Depth of field would scatter the primary ray origin across the aperture and
94 // turn a distance measurement into an average over the circle of confusion.
95 // DepthOfFieldFocalDistance == 0 is what the path tracer tests for
96 // (PathTracing.cpp, PathTracingData.CameraLensRadius).
97 SetFocalDistance(0.0f);
98}
99
101{
102 // Lens model, resolution, fov, show_only_* -- everything is parsed by the
103 // colour sensor's Set(); this class only changes what the capture outputs.
104 Super::Set(Description);
106}
107
109{
110 Super::BeginPlay();
111
112 // The AOV is metric data: an 8-bit target would quantize 1000 m into 4 m
113 // steps and even FP16 loses 6 cm at 100 m. ASceneCaptureSensor::BeginPlay
114 // hard-codes its choice between PF_B8G8R8A8 and PF_FloatRGBA, so re-init the
115 // target here, after it ran, with a single float32 channel.
116 if (UTextureRenderTarget2D *RenderTarget = GetCaptureRenderTarget())
117 {
118 RenderTarget->InitCustomFormat(
121 PF_R32_FLOAT,
122 /*bInForceLinearGamma=*/true);
123 }
124
126}
127
129 UWorld *World,
130 ELevelTick TickType,
131 float DeltaSeconds)
132{
133 TRACE_CPUPROFILER_EVENT_SCOPE(ASceneCaptureCamera_RayTracedLensDistance::PostPhysTick);
134
135 if (AreClientsListening() && CaptureComponent2D != nullptr)
136 {
137 // Same reason as ASceneCaptureCamera_RayTracedLens::PostPhysTick: code
138 // paths such as ApplyPostProcessVolumeToSensor replace PostProcessSettings
139 // wholesale and would silently turn this back into an undistorted pinhole
140 // colour camera.
143 CaptureComponent2D->CaptureSource = ESceneCaptureSource::SCS_PathTracingLensDistance;
144 }
145
146 // Deliberately skips ASceneCaptureCamera_RayTracedLens::PostPhysTick: its body
147 // is the colour readback (an FColor decode of what is here a float32 distance
148 // buffer, serialized as the colour sensor's type). The lens reassertion above
149 // reproduces what else it does, and the capture/readback ORDER -- which is
150 // what keeps a colour and a distance camera on the same frame -- comes from
151 // the base class's TickCaptureAndReadback so both sensors share one policy.
152 TickCaptureAndReadback(World, TickType, DeltaSeconds,
153 [this](bool bNonBlocking, const FSensorCaptureContext &CaptureContext)
154 {
155 UTextureRenderTarget2D *RenderTarget = GetCaptureRenderTarget();
156 if (RenderTarget == nullptr)
157 {
158 return;
159 }
161 *RenderTarget,
163 [this, CaptureContext](
164 const void *MappedPtr,
165 size_t RowPitch, // in pixels, not bytes
166 size_t BufferHeight,
167 EPixelFormat Format,
168 FIntPoint Extent) -> bool
169 {
170 if (MappedPtr == nullptr || Format != PF_R32_FLOAT)
171 {
172 return false;
173 }
174 check(RowPitch >= (size_t)Extent.X);
175 check(BufferHeight >= (size_t)Extent.Y);
176
177 TArray<float> Distances;
178 Distances.Reserve(Extent.X * Extent.Y);
179 auto RowPtr = reinterpret_cast<const float *>(MappedPtr);
180 for (int32 Y = 0; Y != Extent.Y; ++Y)
181 {
182 for (int32 X = 0; X != Extent.X; ++X)
183 {
184 Distances.Add(RowPtr[X] * GUnrealUnitsToMeters);
185 }
186 RowPtr += RowPitch;
187 }
188 SendDataToClient(*this, TArrayView<float>(Distances), CaptureContext);
189 return true;
190 },
191 bNonBlocking);
192 });
193}
static constexpr float GUnrealUnitsToMeters
static constexpr int32 GPathTracingLensAOVDistance
void PostPhysTick(UWorld *World, ELevelTick TickType, float DeltaSeconds) override
void Set(const FActorDescription &ActorDescription) override
ASceneCaptureCamera_RayTracedLensDistance(const FObjectInitializer &ObjectInitializer)
void ApplyDistanceAOVConfig()
Re-asserts everything that makes this capture a geometry AOV rather than a colour render.
FLensModelDescriptor LensModel
Resolved lens-model parameters, rebuilt in Set() from the camera_model / distortion_coeffs / lut / fx...
void TickCaptureAndReadback(UWorld *World, ELevelTick TickType, float DeltaSeconds, TFunctionRef< void(bool bNonBlocking, const FSensorCaptureContext &Context)> EnqueueReadback)
Runs this tick's capture and this tick's readback in the order the world's synchronization mode requi...
UTextureRenderTarget2D * GetCaptureRenderTarget()
TObjectPtr< USceneCaptureComponent2D_CARLA > CaptureComponent2D
Scene capture component.
void EnablePostProcessingEffects(bool Enable=true)
void SetFocalDistance(float Distance)
uint32 GetImageHeight() const
uint32 GetImageWidth() const
FRHIGPUReadbackPoolPtr GetReadbackPool() const
Per-sensor pool of recyclable RHI readback objects.
static void SendDataToClient(SensorType &&Sensor, TArrayView< ElementType > SensorData, const FSensorCaptureContext &CaptureContext)
static FActorDefinition MakeRayTracedLensCameraDefinition(const FString &Id, bool bEnableModifyingPostProcessEffects=false)
bool ReadImageDataAsync(UTextureRenderTarget2D &RenderTarget, FRHIGPUReadbackPoolPtr Pool, ReadImageDataAsyncCallback &&Callback, bool bNonBlocking)
void ApplyLensModel(FPostProcessSettings &PostProcessSettings, const FLensModelDescriptor &Descriptor)
A definition of a Carla Actor with all the variation and attributes.
TArray< FActorVariation > Variations
Variations represent variables the user can modify to generate variations of the actor.
A description of a Carla Actor with all its variation.
Sensor frame metadata snapshotted at capture time, carried by value through async delivery instead of...