Skip to content

AcresLidarGpu.h#

Acres/Source/Acres/AcresLidarGpu.h Generated

GPU LiDAR: traces scan rays against the renderer's ray-tracing scene with inline ray queries.

Unreal already builds a ray-tracing acceleration structure (the TLAS, top-level acceleration structure) of the rendered world every frame, with Nanite meshes, crop instances and runtime rut tiles in it. Instead of keeping a second, CPU-side copy of that geometry, the recorder hands each scan to FAcresLidarViewExtension. A scene view extension is Unreal's plug-in point for code that must run inside the renderer; this one runs on the render thread right after the TLAS build of the next main view, adds a compute pass (Shaders/AcresLidar.usf) to the render graph (RDG, Unreal's per-frame graph of GPU passes), and copies the hits back to the CPU asynchronously. The game thread polls FAcresGpuScan::State.

Needs ray tracing enabled for the project and inline ray tracing on the RHI (Unreal's graphics API layer, Vulkan SM6 on Linux here). Without it the recorder falls back to the CPU collision/proxy path.

FAcresGpuScan#

struct FAcresGpuScan

One LiDAR scan traced on the GPU.

Submitted from the game thread, dispatched after the TLAS build of the next main view, read back asynchronously. Hits carry the renderer's primitive component id so the CPU can classify them.

Name Type Unit Default Description
OriginCm FVector cm FVector::ZeroVector Sensor origin, Unreal world cm.
Rays TArray<FVector4f> One entry per sub-ray: xyz world unit direction, w = max distance, cm.
Origins TArray<FVector4f> Optional, empty or one entry per sub-ray: xyz = ray origin minus OriginCm, cm (w unused). A rolling scan (motion distortion) fires each column from the sensor position at its own firing time.
SelfIds TArray<uint32> Primitive component ids the beams pass through (the tractor and trailer).
PassIds TArray<uint32> Sorted component ids that are partially transmissive (foliage): the ray records them and continues.
HitsPerRay uint32 1 Surfaces recorded per ray, 1-8 (foliage continues, anything else stops).
ContinueCm float cm 25 Skip distance after a pass-through hit, cm.
Hits TArray<FUintVector4> Result, Rays.Num() x HitsPerRay entries: x = asuint(distance cm), y = component id, z = packed octahedral world normal (2 x snorm16), w = flags (1 hit, 2 normal valid). Unused slots are all zero.
State std::atomic<int> 0 queued or in flight, 1 complete (Hits valid), 2 failed, 3 stopped before dispatch.
bCancelled std::atomic<bool> Set by the game thread when it stops waiting for this scan (timeout or recording stop). The render thread then skips the dispatch, or discards the readback if the scan is already in flight.
Readback TUniquePtr<FRHIGPUBufferReadback> GPU-to-CPU copy of the hit buffer; created and read on the render thread.

FAcresLidarViewExtension#

class FAcresLidarViewExtension final : public FSceneViewExtensionBase

Scene view extension that runs queued LiDAR scans on the GPU, one at a time.

Created once by Get() on the game thread; the engine keeps it registered and calls PostTLASBuild_RenderThread for every rendered view. Scene captures and views without ray tracing are skipped, so a scan waits for the next main-view frame.

Example

if (auto Extension = FAcresLidarViewExtension::Get())
    Extension->Submit(Scan); // later: Scan->State == 1 -> read Scan->Hits on the game thread

FAcresLidarViewExtension::FAcresLidarViewExtension#

Called by FSceneViewExtensions::NewExtension; use Get() instead.

FAcresLidarViewExtension(const FAutoRegister& AutoRegister);

FAcresLidarViewExtension::Get#

Returns the shared extension, creating it on first use.

Returns: The extension, or null when the RHI is not initialised, ray tracing is disabled for the project, or the RHI lacks inline ray tracing.

Note

Game thread only.

static TSharedPtr<FAcresLidarViewExtension, ESPMode::ThreadSafe> Get();

FAcresLidarViewExtension::Submit#

Queues a scan for the GPU. Thread-safe (lock-free multi-producer queue).

Argument Description
Scan The scan; the render thread fills Hits and sets State.
void Submit(TSharedPtr<FAcresGpuScan> Scan) ;

FAcresLidarViewExtension::FinishScans#

Finish submitted GPU copies and release their readbacks before renderer shutdown. Scans still waiting for a main view are cancelled with state 3; the recorder keeps their CPU result. Game thread, synchronous.

void FinishScans(const TArray<TSharedPtr<FAcresGpuScan>>& Scans);

FAcresLidarViewExtension::SetupViewFamily#

Unused view-extension hook (required override).

virtual void SetupViewFamily(FSceneViewFamily&) override ;

FAcresLidarViewExtension::SetupView#

Unused view-extension hook (required override).

virtual void SetupView(FSceneViewFamily&, FSceneView&) override ;

FAcresLidarViewExtension::BeginRenderViewFamily#

Unused view-extension hook (required override).

virtual void BeginRenderViewFamily(FSceneViewFamily&) override ;

FAcresLidarViewExtension::PostTLASBuild_RenderThread#

Render-thread hook after the ray-tracing scene is built for a view.

First finishes the scan in flight if its readback is ready (copies Hits, sets State), then dequeues the next scan, uploads its rays and id lists, adds the AcresLidar compute pass (64 rays per thread group) and an asynchronous copy of the hit buffer.

Argument Description
GraphBuilder The render graph for this frame.
InView The view being rendered (must be an FViewInfo with a ray-tracing scene).

Note

Render thread. Only one scan is in flight at a time.

virtual void PostTLASBuild_RenderThread(FRDGBuilder& GraphBuilder, FSceneView& InView) override;

FAcresLidarViewExtension::GetFlags#

The renderer only invokes the TLAS hook on extensions that declare it.

virtual ESceneViewExtensionFlags GetFlags() const override ;