UE4 Capture Current Viewport

1、自定义类捕获当前窗口视图数据

 1 #pragma once
 2 
 3 // Copyright 2021 sev, All Rights Reserved.
 4 
 5 #pragma once
 6 
 7 
 8 //////////////////////////////////////////////////////////////////////////
 9 // class capture viewport
10 //////////////////////////////////////////////////////////////////////////
11 DECLARE_MULTICAST_DELEGATE_OneParam(FOnViewportToPresent, uint8*);
12 DECLARE_DELEGATE(FOnViewportToBuffer);
13 
14 class FCaptureViewport : public FRHICustomPresent
15 {
16 public:
17     FCaptureViewport(FRHIViewport* InViewport)
18         : m_ViewportRHI(nullptr)
19         , m_IsInitialized(false)
20     {
21         m_SurfaceDataWhole.Empty();
22         m_SurfaceDataStereo.Empty();
23     }
24 
25     bool InitViewport();
26     void UpdateViewport();
27     bool FinishRendering();
28 
29     FRHIViewport* GetViewportRHI();
30     FOnViewportToPresent OnViewportTOPresentEvent;
31     FOnViewportToBuffer OnViewportToBufferEvent;
32 public:
33     // Called when viewport is resized.
34     virtual void OnBackBufferResize();
35 
36     // Called from render thread to see if a native present will be requested for this frame.
37     // @return    true if native Present will be requested for this frame; false otherwise.  Must
38     // match value subsequently returned by Present for this frame.
39     virtual bool NeedsNativePresent();
40 
41     // Called from RHI thread to perform custom present.
42     // @param InOutSyncInterval - in out param, indicates if vsync is on (>0) or off (==0).
43     // @return    true if native Present should be also be performed; false otherwise. If it returns
44     // true, then InOutSyncInterval could be modified to switch between VSync/NoVSync for the normal 
45     // Present.  Must match value previously returned by NeedsNormalPresent for this frame.
46     virtual bool Present(int32& InOutSyncInterval);
47 
48 public:
49     mutable FCriticalSection    m_Sync;
50 
51     TArray<FColor>    m_SurfaceDataWhole;
52     TArray<FColor>    m_SurfaceDataStereo;
53 
54     FRHIViewport* m_ViewportRHI;
55     FTexture2DRHIRef m_SceneColor;
56     uint8* m_OutputData;
57 
58     int32            m_ViewportX;
59     int32            m_ViewportY;
60     uint32            m_LolStride;
61 
62     bool            m_IsInitialized;
63     bool            m_IsSaveImage;
64     bool            m_IsStopPreset;
65 };

 .cpp

  1 // Copyright 2021 sev, All Rights Reserved.
  2 
  3 #include "CaptureViewport.h"
  4 
  5 #include "Engine/GameEngine.h"
  6 #include "RHI\Public\DynamicRHI.h"
  7 #include "Slate\SceneViewport.h"
  8 #include "IImageWrapper.h"
  9 #include "IImageWrapperModule.h"
 10 #include "Misc\FileHelper.h"
 11 
 12 bool gIsOutImage = false;
 13 EImmediateFlushType::Type gFlushType = EImmediateFlushType::WaitForOutstandingTasksOnly;
 14 
 15 FSceneViewport* FindCurViewport()
 16 {
 17     FSceneViewport* SceneViewport = nullptr;
 18     if (!GIsEditor)
 19     {
 20         UGameEngine* GameEngine = Cast<UGameEngine>(GEngine);
 21         SceneViewport = GameEngine->SceneViewport.Get();
 22     }
 23     else
 24     {
 25         if (GEngine->GameViewport)
 26             SceneViewport = GEngine->GameViewport->GetGameViewport();
 27     }
 28 
 29     return SceneViewport;
 30 }
 31 
 32 void ReadBackbuffer(const FViewportRHIRef ViewportRHI, FIntPoint OutRect, TArray<FColor>* OutPixels, FTexture2DRHIRef& Tex2DRef)
 33 {
 34     if (!ViewportRHI)
 35         return;
 36 
 37     FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
 38 
 39     //SCOPED_DRAW_EVENT(RHICmdList, HXReadBackbuffer);
 40 
 41     {
 42         FTexture2DRHIRef pSceneColor;
 43         if (!GIsEditor)
 44         {
 45             //FViewportRHIRef ViewportRHI = pVP->GetViewportRHI();
 46             pSceneColor = RHICmdList.GetViewportBackBuffer(ViewportRHI);
 47         }
 48         else {
 49             FSceneViewport* pVP = FindCurViewport();
 50             if (pVP)
 51                 pSceneColor = pVP->GetRenderTargetTexture();
 52         }
 53 
 54         if (!IsValidRef(pSceneColor))
 55         {
 56             return;
 57         }
 58 
 59         Tex2DRef = pSceneColor;
 60 
 61         /*RHICmdList.ReadSurfaceData(
 62             pSceneColor,
 63             FIntRect(0, 0, OutRect.X, OutRect.Y),
 64             *OutPixels,
 65             FReadSurfaceDataFlags());*/
 66 
 67         QUICK_SCOPE_CYCLE_COUNTER(HXReadBackBuffer);
 68         RHICmdList.ImmediateFlush(gFlushType);
 69         GDynamicRHI->RHIReadSurfaceData(pSceneColor, FIntRect(0, 0, OutRect.X, OutRect.Y), *OutPixels, FReadSurfaceDataFlags());
 70 
 71     }
 72 }
 73 
 74 
 75 void PrintLog(FString FunName, double LastTime)
 76 {
 77     if (true)
 78         return;
 79 
 80     double CurrentTime = FPlatformTime::Seconds();
 81     CurrentTime -= LastTime;
 82 
 83     FString OutFormat = FString::Printf(TEXT("%s * * "), *FunName);
 84     OutFormat.Append(FString::SanitizeFloat(CurrentTime * 1000.0f));
 85 
 86     UE_LOG(LogTemp, Warning, TEXT("%s"), *OutFormat);
 87 }
 88 
 89 
 90 //////////////////////////////////////////////////////////////////////////
 91 // 
 92 //////////////////////////////////////////////////////////////////////////
 93 void FCaptureViewport::OnBackBufferResize()
 94 {
 95 
 96 }
 97 
 98 bool FCaptureViewport::NeedsNativePresent()
 99 {
100     return true;
101 }
102 
103 bool FCaptureViewport::Present(int32& InOutSyncInterval)
104 {
105     FString RHIName = GDynamicRHI->GetName();
106     if (RHIName == TEXT("D3D11"))
107     {
108         check(IsInRenderingThread());
109     }
110 
111     bool bNeedNativePresent = true;
112     {
113         FScopeLock lock(&m_Sync);
114         UpdateViewport();
115     }
116 
117     //FinishRendering();
118     return bNeedNativePresent;
119 }
120 
121 bool FCaptureViewport::InitViewport()
122 {
123     check(IsInGameThread());
124     if (m_IsInitialized)
125         return true;
126 
127     m_ViewportRHI = GetViewportRHI();
128     if (m_ViewportRHI == nullptr)
129         return false;
130 
131     if (m_ViewportX <= 0 || m_ViewportY <= 0)
132         return false;
133 
134     auto oldCustomPresent = m_ViewportRHI->GetCustomPresent();
135     if (oldCustomPresent != this)
136     {
137         m_ViewportRHI->SetCustomPresent(this);
138     }
139 
140     m_IsInitialized = true;
141     m_IsStopPreset = true;
142     m_OutputData = nullptr;
143     return m_IsInitialized;
144 }
145 
146 bool FCaptureViewport::FinishRendering()
147 {
148     /*if (m_SurfaceDataWhole.Num() >= m_ViewportX*m_ViewportY)
149         return true;
150 
151     return false;*/
152 
153     return true;
154 }
155 
156 void FCaptureViewport::UpdateViewport()
157 {
158     if (!m_IsStopPreset)
159         return;
160 
161     FSceneViewport* pVP = FindCurViewport();
162     if (pVP == nullptr)
163         return;
164 
165     if (m_SurfaceDataStereo.Num() > 0)
166         m_SurfaceDataStereo.Empty();
167 
168     m_ViewportX = pVP->GetSizeXY().X;
169     m_ViewportY = pVP->GetSizeXY().Y;
170 
171     double DelatTime = FPlatformTime::Seconds();
172 
173     FIntPoint OutPoint(m_ViewportX, m_ViewportY);
174     ReadBackbuffer(m_ViewportRHI, OutPoint, &m_SurfaceDataWhole, m_SceneColor);
175     OnViewportToBufferEvent.ExecuteIfBound();
176 
177     // 
178 #ifdef RHIVIEWPORT
179     FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
180 
181     /*uint8* TextureData = (uint8*)GDynamicRHI->RHILockTexture2D(m_SceneColor->GetTexture2D(), 0, EResourceLockMode::RLM_ReadOnly, m_LolStride, false);
182     OnViewportTOPresentEvent.Broadcast(TextureData);
183     GDynamicRHI->RHIUnlockTexture2D(m_SceneColor->GetTexture2D(), 0, false);*/
184 
185     uint8* TextureData = (uint8*)RHICmdList.LockTexture2D(m_SceneColor->GetTexture2D(), 0, EResourceLockMode::RLM_ReadOnly, m_LolStride, false);
186 
187     int32 SizeY = m_SceneColor->GetSizeY();
188     int32 SizeX = m_SceneColor->GetSizeX();
189     OnViewportTOPresentEvent.Broadcast(TextureData);
190 
191     RHICmdList.UnlockTexture2D(m_SceneColor->GetTexture2D(), 0, false);
192 #endif
193     // test take-time
194     PrintLog(TEXT("ReadBackBuffer"), DelatTime);
195     if (gIsOutImage && m_SurfaceDataWhole.Num() > 0)
196     {
197         DelatTime = FPlatformTime::Seconds();
198         //OnGetFrameData((const char*)m_SurfaceDataWhole.GetData(), m_ViewportX, m_ViewportY, m_ViewportX * sizeof(FColor));
199         PrintLog(TEXT("OnGetFrameData"), DelatTime);
200 
201     }
202 
203     /*m_SurfaceDataStereo.AddUninitialized(m_SurfaceDataWhole.Num() * 2);
204     FMemory::Memcpy(m_SurfaceDataStereo.GetData(), m_SurfaceDataWhole.GetData(), sizeof(FColor)*m_SurfaceDataWhole.Num());
205     FMemory::Memcpy(&m_SurfaceDataStereo[m_SurfaceDataWhole.Num()], m_SurfaceDataWhole.GetData(), sizeof(FColor)*m_SurfaceDataWhole.Num());
206 
207     if (gIsOutImage && m_SurfaceDataStereo.Num() > 0)
208     {
209         OnGetFrameData((const char*)m_SurfaceDataStereo.GetData(), m_ViewportX, m_ViewportY*2, m_ViewportX * sizeof(FColor));
210     }*/
211 
212     // save data to image
213     /*if (!m_IsSaveImage)
214         return;
215 
216     TArray<FColor> SurfaceData;
217 
218     SurfaceData.AddUninitialized(m_SurfaceDataWhole.Num());
219 
220     FMemory::Memcpy(SurfaceData.GetData(), m_SurfaceDataWhole.GetData(), sizeof(FColor)*m_SurfaceDataWhole.Num());
221 
222     for (FColor& Color : SurfaceData)
223     {
224         Color.A = 255;
225     }
226 
227     IImageWrapperModule& ImageWrapperModule = FModuleManager::LoadModuleChecked<IImageWrapperModule>(FName("ImageWrapper"));
228     TSharedPtr<IImageWrapper> ImageWrapper = ImageWrapperModule.CreateImageWrapper(EImageFormat::PNG);
229     ImageWrapper->SetRaw(SurfaceData.GetData(), SurfaceData.GetAllocatedSize(), m_ViewportX, m_ViewportY, ERGBFormat::BGRA, 8);
230     const TArray64<uint8>& PNGData = ImageWrapper->GetCompressed(100);
231     FString FileName = TEXT("D:\\CubeCapture.png");//FString::Printf(TEXT("D:\\SteroCap_%s.png"), *CaptureCounter);
232 
233     FFileHelper::SaveArrayToFile(PNGData, *FileName);
234 
235     ImageWrapper.Reset();*/
236 }
237 
238 
239 
240 FRHIViewport* FCaptureViewport::GetViewportRHI()
241 {
242     FRHIViewport* ViewportRHI = nullptr;
243     FSceneViewport* Viewport = FindCurViewport();
244 
245     if (!Viewport)
246         return nullptr;
247 
248     //m_ViewportX = Viewport->GetSizeXY().X;
249     //m_ViewportY = Viewport->GetSizeXY().Y;
250 
251     FSlateRenderer* Renderer = FSlateApplication::Get().GetRenderer();
252     TSharedPtr<SWindow> Window;
253     if (!GIsEditor)
254     {
255         UGameEngine* GameEngine = Cast<UGameEngine>(GEngine);
256         Window = FSlateApplication::Get().FindWidgetWindow(GameEngine->GameViewportWidget.ToSharedRef());
257     }
258     else
259     {
260         Window = FSlateApplication::Get().FindWidgetWindow(Viewport->GetViewportWidget().Pin().ToSharedRef());
261     }
262 
263     // If the window is not valid then we are likely in a loading movie and the viewport is not attached to the window.  
264     // We'll have to wait until safe
265     if (Window.IsValid())
266     {
267         void* ViewportResource = Renderer->GetViewportResource(*Window);
268         if (ViewportResource)
269         {
270             ViewportRHI = *((FViewportRHIRef*)ViewportResource);
271             //ViewportRHI = Viewport->GetViewportRHI().GetReference();
272         }
273     }
274 
275     return ViewportRHI;
276 }

 

可在暴露给蓝图的类中调用:

 1 {
 2         if (m_CaptureViewport == nullptr)
 3     {
 4         m_CaptureViewport = new FCaptureViewport(nullptr);
 5         m_CaptureViewport->InitViewport();
 6         m_CaptureViewport->m_IsSaveImage = false;
 7 
 8     }
 9 
10
11     m_CaptureViewport->OnViewportToBufferEvent.BindStatic(&URenderCineCameraLibrary::UpdateViewport_RenderThread);
12 }
13 
14 //
15 void URenderCineCameraLibrary::UpdateViewport_RenderThread()
16 {
17     // do something with m_CaptureViewport->m_SurfaceDataWhole
18 }

 

posted @ 2022-11-28 15:35  sev  阅读(432)  评论(0编辑  收藏  举报