|
1 | | -// Copyright 2020-2023 Rapyuta Robotics Co., Ltd. |
2 | | - |
3 | | -#include "Sensors/RRROS2CameraComponent.h" |
4 | | - |
5 | | -#include "BufferVisualizationData.h" |
6 | | - |
7 | | -URRROS2CameraComponent::URRROS2CameraComponent() |
8 | | -{ |
9 | | - // component initialization |
10 | | - SceneCaptureComponent = CreateDefaultSubobject<USceneCaptureComponent2D>(TEXT("SceneCaptureComponent")); |
11 | | - SceneCaptureComponent->SetupAttachment(this); |
12 | | - |
13 | | - CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent")); |
14 | | - CameraComponent->SetupAttachment(this); |
15 | | - |
16 | | - TopicName = TEXT("raw_image"); |
17 | | - MsgClass = UROS2ImgMsg::StaticClass(); |
18 | | -} |
19 | | - |
20 | | -void URRROS2CameraComponent::PreInitializePublisher(UROS2NodeComponent* InROS2Node, const FString& InTopicName) |
21 | | -{ |
22 | | - SceneCaptureComponent->FOVAngle = CameraComponent->FieldOfView; |
23 | | - SceneCaptureComponent->OrthoWidth = CameraComponent->OrthoWidth; |
24 | | - |
25 | | - if (CameraType == EROS2CameraType::DEPTH) |
26 | | - { |
27 | | - FWeightedBlendable blendable(1.0f, GetBufferVisualizationData().GetMaterial(TEXT("SceneDepth"))); |
28 | | - CameraComponent->PostProcessSettings.WeightedBlendables.Array.Add(blendable); |
29 | | - SceneCaptureComponent->PostProcessSettings = CameraComponent->PostProcessSettings; |
30 | | - SceneCaptureComponent->CaptureSource = ESceneCaptureSource::SCS_FinalColorHDR; |
31 | | - } |
32 | | - |
33 | | - RenderTarget = NewObject<UTextureRenderTarget2D>(this, UTextureRenderTarget2D::StaticClass()); |
34 | | - RenderTarget->InitCustomFormat(Width, Height, EPixelFormat::PF_B8G8R8A8, true); |
35 | | - SceneCaptureComponent->TextureTarget = RenderTarget; |
36 | | - |
37 | | - // Initialize image data |
38 | | - Data.Header.FrameId = FrameId; |
39 | | - Data.Width = Width; |
40 | | - Data.Height = Height; |
41 | | - Data.Encoding = Encoding; |
42 | | - Data.Step = Width * 3; // todo should be variable based on encoding |
43 | | - Data.Data.AddUninitialized(Width * Height * 3); |
44 | | - |
45 | | - QueueSize = QueueSize < 1 ? 1 : QueueSize; // QueueSize should be more than 1 |
46 | | - |
47 | | - Super::PreInitializePublisher(InROS2Node, InTopicName); |
48 | | -} |
49 | | - |
50 | | -void URRROS2CameraComponent::SensorUpdate() |
51 | | -{ |
52 | | - SceneCaptureComponent->CaptureScene(); |
53 | | - CaptureNonBlocking(); |
54 | | -} |
55 | | - |
56 | | -// reference https://github.com/TimmHess/UnrealImageCapture |
57 | | -void URRROS2CameraComponent::CaptureNonBlocking() |
58 | | -{ |
59 | | - SceneCaptureComponent->TextureTarget->TargetGamma = GEngine->GetDisplayGamma(); |
60 | | - // Get RenderContext |
61 | | - FTextureRenderTargetResource* renderTargetResource = SceneCaptureComponent->TextureTarget->GameThread_GetRenderTargetResource(); |
62 | | - |
63 | | - struct FReadSurfaceContext |
64 | | - { |
65 | | - FRenderTarget* SrcRenderTarget; |
66 | | - TArray<FColor>* OutData; |
67 | | - FIntRect Rect; |
68 | | - FReadSurfaceDataFlags Flags; |
69 | | - }; |
70 | | - |
71 | | - // Init new RenderRequest |
72 | | - FRenderRequest* renderRequest = new FRenderRequest(); |
73 | | - |
74 | | - // Setup GPU command |
75 | | - FReadSurfaceContext readSurfaceContext = { |
76 | | - renderTargetResource, |
77 | | - &(renderRequest->Image), |
78 | | - FIntRect(0, 0, renderTargetResource->GetSizeXY().X, renderTargetResource->GetSizeXY().Y), |
79 | | - FReadSurfaceDataFlags(RCM_UNorm, CubeFace_MAX)}; |
80 | | - |
81 | | - // Above 4.22 use this |
82 | | - ENQUEUE_RENDER_COMMAND(SceneDrawCompletion) |
83 | | - ( |
84 | | - [readSurfaceContext, this](FRHICommandListImmediate& RHICmdList) |
85 | | - { |
86 | | - RHICmdList.ReadSurfaceData(readSurfaceContext.SrcRenderTarget->GetRenderTargetTexture(), |
87 | | - readSurfaceContext.Rect, |
88 | | - *readSurfaceContext.OutData, |
89 | | - readSurfaceContext.Flags); |
90 | | - }); |
91 | | - |
92 | | - // Notify new task in RenderQueue |
93 | | - RenderRequestQueue.Enqueue(renderRequest); |
94 | | - if (QueueCount > QueueSize) |
95 | | - { |
96 | | - RenderRequestQueue.Pop(); |
97 | | - } |
98 | | - else |
99 | | - { |
100 | | - QueueCount++; |
101 | | - } |
102 | | - |
103 | | - // Set RenderCommandFence |
104 | | - renderRequest->RenderFence.BeginFence(); |
105 | | -} |
106 | | - |
107 | | -FROSImg URRROS2CameraComponent::GetROS2Data() |
108 | | -{ |
109 | | - if (!RenderRequestQueue.IsEmpty()) |
110 | | - { |
111 | | - // Timestamp |
112 | | - Data.Header.Stamp = URRConversionUtils::FloatToROSStamp(UGameplayStatics::GetTimeSeconds(GetWorld())); |
113 | | - |
114 | | - // Peek the next RenderRequest from queue |
115 | | - FRenderRequest* nextRenderRequest = nullptr; |
116 | | - RenderRequestQueue.Peek(nextRenderRequest); |
117 | | - if (nextRenderRequest) |
118 | | - { // nullptr check |
119 | | - if (nextRenderRequest->RenderFence.IsFenceComplete()) |
120 | | - { // Check if rendering is done, indicated by RenderFence |
121 | | - for (int I = 0; I < nextRenderRequest->Image.Num(); I++) |
122 | | - { |
123 | | - Data.Data[I * 3 + 0] = nextRenderRequest->Image[I].R; |
124 | | - Data.Data[I * 3 + 1] = nextRenderRequest->Image[I].G; |
125 | | - Data.Data[I * 3 + 2] = nextRenderRequest->Image[I].B; |
126 | | - } |
127 | | - |
128 | | - // Delete the first element from RenderQueue |
129 | | - RenderRequestQueue.Pop(); |
130 | | - QueueCount--; |
131 | | - delete nextRenderRequest; |
132 | | - } |
133 | | - } |
134 | | - } |
135 | | - |
136 | | - // SceneCaptureComponent->CaptureScene(); |
137 | | - // FTextureRenderTarget2DResource* RenderTargetResource; |
138 | | - // RenderTargetResource = (FTextureRenderTarget2DResource*)RenderTarget->GameThread_GetRenderTargetResource(); |
139 | | - // if (RenderTargetResource) { |
140 | | - // TArray<FColor> buffer; |
141 | | - // RenderTargetResource->ReadPixels(buffer); |
142 | | - // for (int I = 0; I < buffer.Num(); I++) |
143 | | - // { |
144 | | - // Data.data[I * 3 + 0] = buffer[I].R; |
145 | | - // Data.data[I * 3 + 1] = buffer[I].G; |
146 | | - // Data.data[I * 3 + 2] = buffer[I].B; |
147 | | - // } |
148 | | - // } |
149 | | - |
150 | | - return Data; |
151 | | -} |
152 | | - |
153 | | -void URRROS2CameraComponent::SetROS2Msg(UROS2GenericMsg* InMessage) |
154 | | -{ |
155 | | - CastChecked<UROS2ImgMsg>(InMessage)->SetMsg(GetROS2Data()); |
156 | | -} |
| 1 | +// Copyright 2020-2023 Rapyuta Robotics Co., Ltd. |
| 2 | + |
| 3 | +#include "Sensors/RRROS2CameraComponent.h" |
| 4 | + |
| 5 | +#include "BufferVisualizationData.h" |
| 6 | + |
| 7 | +URRROS2CameraComponent::URRROS2CameraComponent() |
| 8 | +{ |
| 9 | + // component initialization |
| 10 | + SceneCaptureComponent = CreateDefaultSubobject<USceneCaptureComponent2D>(TEXT("SceneCaptureComponent")); |
| 11 | + SceneCaptureComponent->SetupAttachment(this); |
| 12 | + |
| 13 | + CameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent")); |
| 14 | + CameraComponent->SetupAttachment(this); |
| 15 | + |
| 16 | + TopicName = TEXT("raw_image"); |
| 17 | + MsgClass = UROS2ImgMsg::StaticClass(); |
| 18 | +} |
| 19 | + |
| 20 | +void URRROS2CameraComponent::PreInitializePublisher(UROS2NodeComponent* InROS2Node, const FString& InTopicName) |
| 21 | +{ |
| 22 | + SceneCaptureComponent->FOVAngle = CameraComponent->FieldOfView; |
| 23 | + SceneCaptureComponent->OrthoWidth = CameraComponent->OrthoWidth; |
| 24 | + |
| 25 | + // Set capture source and image properties based on camera type |
| 26 | + if (CameraType == EROS2CameraType::RGB) |
| 27 | + { |
| 28 | + SceneCaptureComponent->CaptureSource = ESceneCaptureSource::SCS_FinalColorHDR; |
| 29 | + RenderTarget = NewObject<UTextureRenderTarget2D>(this, UTextureRenderTarget2D::StaticClass()); |
| 30 | + RenderTarget->InitCustomFormat(Width, Height, EPixelFormat::PF_B8G8R8A8, true); |
| 31 | + |
| 32 | + Data.Encoding = TEXT("bgr8"); |
| 33 | + Data.Step = Width * 3; |
| 34 | + } |
| 35 | + else if (CameraType == EROS2CameraType::DEPTH) |
| 36 | + { |
| 37 | + CameraComponent->PostProcessSettings.WeightedBlendables.Array.Add( |
| 38 | + FWeightedBlendable(1.0f, GetBufferVisualizationData().GetMaterial(TEXT("SceneDepth")))); |
| 39 | + SceneCaptureComponent->PostProcessSettings = CameraComponent->PostProcessSettings; |
| 40 | + SceneCaptureComponent->CaptureSource = ESceneCaptureSource::SCS_SceneDepth; |
| 41 | + |
| 42 | + RenderTarget = NewObject<UTextureRenderTarget2D>(this, UTextureRenderTarget2D::StaticClass()); |
| 43 | + RenderTarget->InitCustomFormat(Width, Height, EPixelFormat::PF_FloatRGBA, false); |
| 44 | + Data.Encoding = TEXT("32FC1"); |
| 45 | + Data.Step = Width * 4; |
| 46 | + } |
| 47 | + |
| 48 | + // Common setup |
| 49 | + SceneCaptureComponent->TextureTarget = RenderTarget; |
| 50 | + Data.Header.FrameId = FrameId; |
| 51 | + Data.Width = Width; |
| 52 | + Data.Height = Height; |
| 53 | + Data.Data.AddUninitialized(Width * Height * (CameraType == EROS2CameraType::RGB ? 3 : 4)); |
| 54 | + QueueSize = QueueSize < 1 ? 1 : QueueSize; // QueueSize should be more than 1 |
| 55 | + Super::PreInitializePublisher(InROS2Node, InTopicName); |
| 56 | +} |
| 57 | + |
| 58 | +void URRROS2CameraComponent::SensorUpdate() |
| 59 | +{ |
| 60 | + if (Render) |
| 61 | + { |
| 62 | + SceneCaptureComponent->CaptureScene(); |
| 63 | + CaptureNonBlocking(); |
| 64 | + } |
| 65 | +} |
| 66 | + |
| 67 | +// reference https://github.com/TimmHess/UnrealImageCapture |
| 68 | +void URRROS2CameraComponent::CaptureNonBlocking() |
| 69 | +{ |
| 70 | + SceneCaptureComponent->TextureTarget->TargetGamma = GEngine->GetDisplayGamma(); |
| 71 | + // Get RenderContext |
| 72 | + FTextureRenderTargetResource* renderTargetResource = SceneCaptureComponent->TextureTarget->GameThread_GetRenderTargetResource(); |
| 73 | + |
| 74 | + struct FReadSurfaceContextRGB |
| 75 | + { |
| 76 | + FRenderTarget* SrcRenderTarget; |
| 77 | + TArray<FColor>* OutData; |
| 78 | + FIntRect Rect; |
| 79 | + FReadSurfaceDataFlags Flags; |
| 80 | + }; |
| 81 | + |
| 82 | + struct FReadSurfaceContextDepth |
| 83 | + { |
| 84 | + FRenderTarget* SrcRenderTarget; |
| 85 | + TArray<FFloat16Color>* Depth; |
| 86 | + FIntRect Rect; |
| 87 | + FReadSurfaceDataFlags Flags; |
| 88 | + }; |
| 89 | + |
| 90 | + // Init new RenderRequest |
| 91 | + FRenderRequest* renderRequest = new FRenderRequest(); |
| 92 | + |
| 93 | + // Setup GPU command |
| 94 | + FIntRect rect(0, 0, renderTargetResource->GetSizeXY().X, renderTargetResource->GetSizeXY().Y); |
| 95 | + FReadSurfaceDataFlags flags(RCM_UNorm, CubeFace_MAX); |
| 96 | + |
| 97 | + if (CameraType == EROS2CameraType::RGB) |
| 98 | + { |
| 99 | + FReadSurfaceContextRGB readSurfaceContext = {renderTargetResource, &(renderRequest->Image), rect, flags}; |
| 100 | + |
| 101 | + ENQUEUE_RENDER_COMMAND(SceneDrawCompletion) |
| 102 | + ( |
| 103 | + [readSurfaceContext, this](FRHICommandListImmediate& RHICmdList) |
| 104 | + { |
| 105 | + RHICmdList.ReadSurfaceData(readSurfaceContext.SrcRenderTarget->GetRenderTargetTexture(), |
| 106 | + readSurfaceContext.Rect, |
| 107 | + *readSurfaceContext.OutData, |
| 108 | + readSurfaceContext.Flags); |
| 109 | + }); |
| 110 | + } |
| 111 | + else if (CameraType == EROS2CameraType::DEPTH) |
| 112 | + { |
| 113 | + FReadSurfaceContextDepth readSurfaceContext = {renderTargetResource, &(renderRequest->Depth), rect, flags}; |
| 114 | + |
| 115 | + ENQUEUE_RENDER_COMMAND(SceneDrawCompletion) |
| 116 | + ( |
| 117 | + [readSurfaceContext, this](FRHICommandListImmediate& RHICmdList) |
| 118 | + { |
| 119 | + RHICmdList.ReadSurfaceFloatData(readSurfaceContext.SrcRenderTarget->GetRenderTargetTexture(), |
| 120 | + readSurfaceContext.Rect, |
| 121 | + *readSurfaceContext.Depth, |
| 122 | + readSurfaceContext.Flags); |
| 123 | + }); |
| 124 | + } |
| 125 | + |
| 126 | + // Notify new task in RenderQueue |
| 127 | + RenderRequestQueue.Enqueue(renderRequest); |
| 128 | + if (QueueCount > QueueSize) |
| 129 | + { |
| 130 | + RenderRequestQueue.Pop(); |
| 131 | + } |
| 132 | + else |
| 133 | + { |
| 134 | + QueueCount++; |
| 135 | + } |
| 136 | + |
| 137 | + // Set RenderCommandFence |
| 138 | + renderRequest->RenderFence.BeginFence(); |
| 139 | +} |
| 140 | + |
| 141 | +FROSImg URRROS2CameraComponent::GetROS2Data() |
| 142 | +{ |
| 143 | + if (!RenderRequestQueue.IsEmpty()) |
| 144 | + { |
| 145 | + // Timestamp |
| 146 | + Data.Header.Stamp = URRConversionUtils::FloatToROSStamp(UGameplayStatics::GetTimeSeconds(GetWorld())); |
| 147 | + // Peek the next RenderRequest from queue |
| 148 | + FRenderRequest* nextRenderRequest = nullptr; |
| 149 | + RenderRequestQueue.Peek(nextRenderRequest); |
| 150 | + if (nextRenderRequest && nextRenderRequest->RenderFence.IsFenceComplete()) |
| 151 | + { |
| 152 | + if (CameraType == EROS2CameraType::RGB) |
| 153 | + { |
| 154 | + // Process RGB data |
| 155 | + for (int i = 0; i < nextRenderRequest->Image.Num(); i++) |
| 156 | + { |
| 157 | + Data.Data[i * 3 + 0] = nextRenderRequest->Image[i].B; |
| 158 | + Data.Data[i * 3 + 1] = nextRenderRequest->Image[i].G; |
| 159 | + Data.Data[i * 3 + 2] = nextRenderRequest->Image[i].R; |
| 160 | + } |
| 161 | + } |
| 162 | + else if (CameraType == EROS2CameraType::DEPTH) |
| 163 | + { |
| 164 | + // Process Depth data |
| 165 | + for (int i = 0; i < nextRenderRequest->Depth.Num(); i++) |
| 166 | + { |
| 167 | + float value = nextRenderRequest->Depth[i].R.GetFloat() / 100; |
| 168 | + std::memcpy(&Data.Data[i * 4], &value, sizeof(value)); |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + // Delete the first element from RenderQueue |
| 173 | + RenderRequestQueue.Pop(); |
| 174 | + QueueCount--; |
| 175 | + delete nextRenderRequest; |
| 176 | + } |
| 177 | + } |
| 178 | + return Data; |
| 179 | +} |
| 180 | + |
| 181 | +void URRROS2CameraComponent::SetROS2Msg(UROS2GenericMsg* InMessage) |
| 182 | +{ |
| 183 | + CastChecked<UROS2ImgMsg>(InMessage)->SetMsg(GetROS2Data()); |
| 184 | +} |
0 commit comments