Hey everyone,
i am using cosys-airsim in UE5.4 to capture images from multiple UAVs in real time. However, the current process for capturing a single image is taking too long. I need suggestions for improving this process or a different approach to capture images faster.
My PC is equipped with a powerful Core i9-13Gen processor and A6000 GPU, so it should be capable of running my environment in real time and quickly capturing images.
The current capturing method involves calling the getSceneCaptureImage
function and carrying out some post-pre processing. However, the bottleneck appears to be the function getScreenshot
. I’ve heard about using Vulkan instead of the default Unreal rendering functions to speed up image capturing. I tried changing the editor’s base RHI to Vulkan, but it caused my FPS to drop from 120 to 60. Can anyone help me with this?
void RenderRequest::getScreenshot(std::shared_ptr<RenderParams> params[], std::vector<std::shared_ptr<RenderResult>>& results, unsigned int req_size, bool use_safe_method)
{
for (unsigned int i = 0; i < req_size; ++i) {
results.push_back(std::make_shared<RenderResult>());
if (!params[i]->pixels_as_float)
results[i]->bmp.Reset();
else
results[i]->bmp_float.Reset();
results[i]->time_stamp = 0;
}
CheckNotBlockedOnRenderThread();
params_ = params;
results_ = results.data();
req_size_ = req_size;
// Queue up the task of querying camera pose in the game thread and synchronizing render thread with camera pose
AsyncTask(ENamedThreads::GameThread, [this]() {
check(IsInGameThread());
saved_DisableWorldRendering_ = game_viewport_->bDisableWorldRendering;
game_viewport_->bDisableWorldRendering = 0;
end_draw_handle_ = game_viewport_->OnEndDraw().AddLambda([this] {
check(IsInGameThread());
// capture CameraPose for this frame
query_camera_pose_cb_();
// The completion is called immeidately after GameThread sends the
// rendering commands to RenderThread. Hence, our ExecuteTask will
// execute *immediately* after RenderThread renders the scene!
RenderRequest* This = this;
ENQUEUE_RENDER_COMMAND(SceneDrawCompletion)
(
[This](FRHICommandListImmediate& RHICmdList) {
This->ExecuteTask();
});
game_viewport_->bDisableWorldRendering = saved_DisableWorldRendering_;
assert(end_draw_handle_.IsValid());
game_viewport_->OnEndDraw().Remove(end_draw_handle_);
});
// while we're still on GameThread, enqueue request for capture the scene!
for (unsigned int i = 0; i < req_size_; ++i) {
if (params_[i]->render_target != nullptr && params_[i]->render_component != nullptr) {
params_[i]->render_component->CaptureSceneDeferred();
}
}
});
// wait for this task to complete
while (!wait_signal_->waitFor(5)) {
// log a message and continue wait
// lamda function still references a few objects for which there is no refcount.
// Walking away will cause memory corruption, which is much more difficult to debug.
UE_LOG(LogTemp, Warning, TEXT("Failed: timeout waiting for screenshot"));
}
}
for (unsigned int i = 0; i < req_size; ++i) {
if (params[i]->render_target != nullptr && params[i]->render_component != nullptr) {
if (!params[i]->pixels_as_float) {
if (results[i]->width != 0 && results[i]->height != 0) {
results[i]->image_data_uint8.SetNumUninitialized(results[i]->width * results[i]->height * 3, false);
if (params[i]->compress)
UAirBlueprintLib::CompressImageArray(results[i]->width, results[i]->height, results[i]->bmp, results[i]->image_data_uint8);
else {
uint8* ptr = results[i]->image_data_uint8.GetData();
for (const auto& item : results[i]->bmp) {
*ptr++ = item.R;
*ptr++ = item.G;
*ptr++ = item.B;
}
}
}
}
else {
results[i]->image_data_float.SetNumUninitialized(results[i]->width * results[i]->height);
float* ptr = results[i]->image_data_float.GetData();
for (const auto& item : results[i]->bmp_float) {
*ptr++ = item.R.GetFloat();
}
}
}
}