2017-04-04 1 views
2

첨부 된 카메라에서 이미지를 캡처하고 저장하려고하는 Unreal 기반 오픈 소스 UAV 시뮬레이션 (Microsoft AirSim)을 작업 중입니다. 무인 항공기. 아래 이미지는 게임이 어떻게 보이는지에 대한 아이디어를 제공합니다. 아래쪽의 가장 오른쪽 뷰는 카메라의 실제 뷰이며 다른 두 개는 동일한 이미지의 방금 처리 된 버전입니다. 지금Unreal Engine : 게임 스레드를 차단하지 않고 게임 이미지를 디스크에 액세스/저장

UAV simulation

는 IT가 이런 식으로 설정하는 것 방법 : 캡처 구성 요소와 코드를 읽을 수있는 카메라 자산이있다. 스크린 샷의 세 가지보기는이 캡처 구성 요소에 연결됩니다. 드론이 게임 내에서 비행 할 때 아무런 문제없이 뷰가 스트리밍됩니다. 그러나 스크린 샷을 녹화 할 때 현재 코드는이 캡처 구성 요소에서 TextureRenderTargetResource를 설정하고 ReadPixels를 호출하고 해당 데이터를 이미지로 저장합니다 (코드 흐름은 아래 참조). ReadPixels()을 그대로 사용하면 게임 스레드를 직접 차단하고 게임 전체를 느리게 처리합니다. 녹화를 시작할 때 ~ 120FPS에서 10FPS 미만으로 떨어집니다. this article에서

bool saveImage() { 
    USceneCaptureComponent2D* capture = getCaptureComponent(camera_type, true); 
    FTextureRenderTargetResource* RenderResource = capture->TextureTarget->GameThread_GetRenderTargetResource(); 
    width = capture->TextureTarget->GetSurfaceWidth(); 
    height = capture->TextureTarget->GetSurfaceHeight(); 

    TArray<FColor> imageColor; 
    imageColor.AddUninitialized(width * height); 
    RenderResource->ReadPixels(bmp); 
} 

보면, ReadPixels는() "렌더링 스레드가 잡았 때까지 게임 스레드를 차단합니다"고 분명하게 보인다. 이 기사에는 FlushRenderingCommands()를 제거하고 RenderCommandFence 플래그를 사용하여 작업 완료 시점을 결정하는 픽셀을 읽는 '비 차단'방법에 대한 샘플 코드가 포함되어 있지만 성능이 크게 향상되지는 않습니다. 이미지가 저장되는 위치는 약간 높지만 게임 스레드는 여전히 약 20FPS에서 실행되므로 UAV를 제어하기가 정말 어렵습니다. 별도의 스레드에서 내가하려고하는 것을 달성 할 수있는 더 효율적인 비동기 메서드가 있습니까? 또한 코드가 가능한 빨리 이미지를 스트리밍하는 데 문제가없는 이유에 대해 조금 혼란 스럽지만 이미지를 저장하는 것이 더 복잡해 보입니다. 게임의 기본 FPS를 너무 많이 방해하지 않는 한 이미지가 디스크에 15 Hz 정도만 저장되는 경우에도 문제가 없습니다.

답변

0

"게임"이 완료 될 때까지 스크린 샷을 TArray에 저장 한 다음 저장된 모든 데이터를 처리해야합니까?

또는 픽셀 데이터를 조작하는 대신 드론 카메라에서 스크린 샷을 찍는 것이 좋을까요? 왼쪽과 가운데 무인 항공기 카메라 이미지는 기본 카메라 이미지의 재질이 수정 된 버전이라고 가정합니다.

이미지를 저장할 때 이미지 형식 파일이나 .uasset을 쓰고 있습니까?

마지막으로, 이것은 완벽한 어둠의 섬광입니다. 커스텀 UActorComponent를 만들어 무인 항공기에 추가하고 게임의 일부 지시 사항을 지켜 봅니다. 이미지를 작성하려면 RenderTarget 데이터를 사용자 정의 UActorComponent로 푸시합니다. 액터 구성 요소는 모든 스레드에서 틱 할 수 있으므로 (BCanTickOnAnyThread = true를 사용하여 생성자에서 변수 이름이라고 생각합니다) 액터 구성 요소의 틱은 들어오는 이미지 데이터를보고 처리합니다. 나는 한번도 해본 적이 없지만 모든 스레드에서 액터 구성 요소 틱을 만들었습니다 (내 물리학 검사).

+0

"픽셀 데이터를 조작하는 대신 드론 카메라에서 스크린 샷을 찍는 모습을 보겠습니다."에 대해 더 자세히 설명해주십시오. 캡처 한 이미지 데이터를 끌어낼 수있는 유일한 방법은 ReadPixels() 명령을 사용하는 것입니다. 그리고 지금은 압축 된 PNG 파일을 작성하고 있습니다. 만약 내가 TArray에 그것들을 저장한다면, 나는 그것을 분리 된 실에서 제안 할 것이라고 추측하고 있나? – HighVoltage

+0

방금 ​​내 생각에 내 게시물에 다른 아이디어를 추가했습니다 :) 플레이어 카메라에서 스크린 샷을 찍으려면 콘솔 명령을 호출 할 수 있습니다. 아마도 당신은 그 명령의 근원을 발견 할 수 있었고, 다른 소스 카메라를주는 방법을 발견했을 것입니다. screenshot 명령은 파일을 저장한다고 생각합니다. 죄송합니다, 렌더링은 내 전문 분야가 아닙니다. 여기서 문제는 개별 이미지를 찍는 것이 아니라 비디오를 녹화한다는 것입니다. 제 3 자 미디어 라이브러리를 추가하는 방법을 살펴보십시오. – JonS

+0

나는 또한 게임이 끝난 후에도 이미지를 저장하면 아무런 fps도 떨어지지 않을 것이라고 생각합니다. 원하는 게 있다면, 언리얼의 캡처 기능을 시도해보십시오. https://docs.unrealengine.com/latest/INT/ Engine/Basics/Screenshots /를 사용하면 그림 자체를 저장하고 이미 수행 한 것보다 빠릅니다. – LumbusterTick

1

(...) ReadPixels는() "렌더링 스레드가 잡았 때까지 게임 스레드를 차단합니다"것이 분명 보인다 액세스하려고 GPU 텍스처 데이터가 복사 기능을 사용

항상 고통. 나는이 기능의 완료 시간이 하드웨어 나 드라이버 버전에 달려 있다는 것을 발견했다. 당신은 다른 (prefferably 빠른 또는 최신) GPU 플랫폼에서 코드를 실행하려고 할 수 있습니다.

코드로 돌아 가기 : 단일 스레드 문제를 우회하려면 UTextureRenderTarget2D을 으로 복사하려고합니다. TextureRenderTarget2D::ConstructTexture2D 메서드를 사용합니다. 이미지를 복사 할 때 (훨씬 빨라 졌으면 좋겠다) 15 FPS 비율로 소비자 스레드로 푸시 할 수 있습니다. 스레드는 FRunnable 또는 비동기 엔진 모듈 (작업 그래프 사용)을 사용하여 생성 할 수 있습니다. 소비자 스레드는 텍스처의 PlatformData->Mips[0]->BulkData을 사용하여 복제 된 텍스처에 액세스 할 수 있습니다. BulkData->Lock(...)BulkData->Unlock() 사이에서 텍스처 데이터를 읽어야합니다.

잘 모르겠지만 복사 된 텍스처가 렌더링 스레드에서 사용되지 않아 렌더링 스레드에서 차단없이 데이터를 잠글 수 있기 때문에 도움이 될 수 있습니다. 엔진 RHI 호출이 없으면 잠금 및 잠금 해제 작업 (실마리를 찾지 못함)의 스레드 안전성에 대해서만 걱정됩니다.

Here은 도움이 될만한 관련 코드입니다.

+0

자세한 설명을 주셔서 감사합니다 : 불행히도이 방법은 또한 내 게임 FPS 약 10, 그리고 이것은 ConstructTexture2D() 함수 그냥 있습니다. 아마도 별도의 스레드에서 전체 작업을 수행 할 수 있습니까? ConstructTexture2D() 함수는 내부적으로 게임 스레드에서 호출되고 있는지를 확인하기 위해 내부적으로 호출을합니다. – HighVoltage

1

게임 저장 스레드에서 다른 스레드로 디스크 저장 작업을 이동할 수 있습니다.
스레드에 대한 제한이 추가/수정/다른 스레드에서/uactor을 UObject에서 삭제할 수 없습니다 것입니다 세부

에 대한 에게 Async.h을 확인하시기 바랍니다. Multi-thread for UE4

관련 문제