Access color and depth buffer of each frame?

In which way do you need to access it ?
If it’s for a shader purpose, you can use a SceneColor node inside your Material.
Here is an example on how to setup this kind of material : https://answers.unrealengine.com/questions/7626/question-translucent-scenecolor-black.html

Indeed, in this case you need to dig in the C++ code. Rama posted a very cool code above ! :slight_smile:

Hi guys

I am using UE4 engine to do a computer graphics research, and I need to access the color(RGB) buffer and depth buffer of each frame, in a FPS game

How could I do that? Do I need to modify source code, if so ,which class to modify?

Thanks!

#Custom Viewport Class

I am posting for you my custom viewport class

I am accessing the color buffer to save a screenshot

Even though the code says PNG I am actually saving it to a .BMP file

#config

DefaultEngine.ini

;~~~ Custom Viewport Client ~~~
GameViewportClientClassName=/Script/VictoryGame.VictoryGameViewport

#.h

// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.

#include "VictoryGameViewport.generated.h"

UCLASS()
class UVictoryGameViewport : public UGameViewportClient
{
	GENERATED_UCLASS_BODY()
	
//Utility
public:

	//Controller
	AVictoryGamePlayerController * VictoryPC;
	
	//~~~~~~~~~~~~~ Screen Shots to PNG ~~~~~~~~~~~~~~
	
	//Triggers ScreenShot
	bool VictoryDoScreenShot;
	
	//Save Screen Shot to disk as PNG
	void SaveScreenShotPNGToDisk(FString TheFileName);
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//protected because must only be run from Draw() or causes crash
protected:
	
	void VictoryTakeScreenShot();

//OVERRIDES
public:
		virtual void Draw(FViewport* Viewport,FCanvas* SceneCanvas) OVERRIDE;

};

#.cpp
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.

#include "VictoryGame.h"

//////////////////////////////////////////////////////////////////////////
// UVictoryGameViewport

UVictoryGameViewport::UVictoryGameViewport(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	
}

void UVictoryGameViewport::VictoryTakeScreenShot()
{
	if (!VictoryPC) return;
	if (!Viewport) return;
	
	//~~~~~~~~~~~~~~~~~~~~~~
	
	//get viewport size
	FVector2D viewportSize;
	GetViewportSize(viewportSize);
	
	//output viewport size, useful for debugging
	/*
	FString text = "x= ";
	text += FString::FromInt(viewportSize.X);
	text += "y= ";
	text += FString::FromInt(viewportSize.Y);
	VictoryPC->ClientMessage(text);
	*/
	
	//~~~ Invalid View Port Size ~~~
	if (viewportSize.X <= 0 || viewportSize.Y <= 0) return;
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	//Section of Viewport to capture
	//		entire buffer invalidated if going larger than viewport size
	//		during readpixels
	
	viewportSize.X--;		//actual indicies, not total size
	viewportSize.Y--;
	
	//Adjusted Image Size
	VictoryPC->BMP_Width = viewportSize.X; 
	VictoryPC->BMP_Height = viewportSize.Y; 
	
	//~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~ Empty Color Buffer ~~~
	VictoryPC->VictoryScreenShot_ColorBuffer.Empty();	
	//~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~
	
	//~~~ Reallocate Buffer ~~~
		//add uninitialized does not call constructor on the TArray type
		//do not use with non-simple data types like FColor FVector etc.
		
	//~~~ Add Zeroed To Ensure Black For No Color Data Parts ~~~
	VictoryPC->VictoryScreenShot_ColorBuffer.AddZeroed( viewportSize.X * viewportSize.Y );
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	//Get Screen Shot!
	if (!Viewport->ReadPixels(
		VictoryPC->VictoryScreenShot_ColorBuffer,
		FReadSurfaceDataFlags(),
		FIntRect(1,1,viewportSize.X,viewportSize.Y)
	)){
		VictoryPC->Optimize("Failed to ReadPixels");
		return;
		//~~~~~~~~~~~~~~~~~~~~~~~~~
	}
	
	//Start Processing Image
	VictoryPC->SaveScreenshotToDisk();
	
}


//Draw
void UVictoryGameViewport::Draw(FViewport * Viewport, FCanvas * SceneCanvas)
{
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//this line is reaaaaaaaaaaaaaalllly important
	Super::Draw(Viewport, SceneCanvas);
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	//UE_LOG(Victory,Warning,TEXT("VICTORY GAME VIEWPORT Ticking!"));
	
	//Take Screen shot?
	if (VictoryDoScreenShot)
	{
		VictoryDoScreenShot = false;
		VictoryTakeScreenShot();	
	}
}

Hi Froyok, thanks for the reply. I would like to save the color buffer and depth buffer of each frame into a BMP file and a HDR float image(e.g. PFM file), I thought I had to modify the source code of the renderer…

Dear Rama, thanks a lot for posting the code, they are very useful. Right now I am pretty sure I am able to save the RGB buffer of each frame to a BMP file; but how can I save the depth buffer? One possible solution from myself would be: modify the shader applied in the scene to display depth information on the surface and then use Viewport->ReadFloat16Pixels to save them? Is it doable? Thanks!

were you able to finally figure out how to access the depth information in the viewport?

Quick question:

Is /Script/VictoryGame.VictoryGameViewport the namespace? Where is the /script/VictoryGame part derived from?

I managed to take snapshots from the scene with Rama’s code. But it doesn’t capture the Widgets added to the viewport. Is there a way we can capture those as well as the 3D scene?

In the header, line 14:
AVictoryGamePlayerController * VictoryPC;

Where does this datatype come from ?
I want to read a buffer (motion blur in my case) as well, but do not fully comprehend this code.

I’m also looking for a way to acess the depth,so were you able to finally figure out how to access the depth information in the viewport?

Hello!!!
I saw many GBuffers who are asking to visit SceneRenderTarget.
This is another way to use SceneCapu.

Source Code:

ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
	DZRenderSutioBP_InterceptSceneBaseColor,
	UTexture2D*, vTextureAsset, TextureAsset,
	{
		/*if (!IsInRenderingThread())
			return;*/
			FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
			//计数加一避免Render完成后直接清空了GBuffer,但会慢一帧,你猜
			FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, 1);
			static const FString ScrollingMessage(TEXT("Hello World: "));
			GEngine->AddOnScreenDebugMessage(-1, 0.2f, FColor::Red, ScrollingMessage);
			FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
			if (SceneContext.GBufferA)
			{
				FTexture2DRHIRef vTextTarget = SceneContext.GetGBufferATexture();
				FString vSiceStr = FString::Printf(TEXT("FSceneRenderTargets GBufferA Size = %d*%d"), vTextTarget->GetSizeX(), vTextTarget->GetSizeY());

				GEngine->AddOnScreenDebugMessage(-1, 0.2f, FColor::Red, vSiceStr);
			}
			//移除
			FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, -1);
		}
	);

Make that a third in glorious 2020 trying to access the depth buffer with this technique.
Been looking at scene render capture source code to try and figure out how they narrow it down to just SceneDepth there but it looks like they fetch it using a material function in SceneCapturePixelShader.usf

What is going on here? What is this supposed to do exactly? How does this give us access to sampling the SceneDepth Buffer?

Hi, how are you able to get the Type FSceneRenderTargets? on the line FSceneRenderTargets::Get(RHICmdList)
i will get an error use of undefined type. I added Renderer, RenderCore and RHI to my modules and imported RendererInterface.h I think I am missing something obvious, but cant figure it out.

@Hannes_Z Can you explain what this is supposed to do? Does it grab SceneDepth from a Render Target?

As far as what you are after,IDK if much has changed but if you look into UnrealClient.cpp they have some examples there using ENQUEUE_RENDER_COMMAND.

I’d also rather use the Viewport directly rather than a Scenecapture/Render Target unless the Viewport is technically a Render Target texture anyways. IDK.

Got FSceneRenderTargets to work.

Need to add the modules to the private dependcies since SceneRenderTargets.h is in a private folder.

so in Build.cs need

PrivateDependencyModuleNames.AddRange(new string[] { “Renderer”, “RenderCore”, “RHI” });

then include

#include "Runtime/Renderer/Private/PostProcess/SceneRenderTargets.h"

you can follow this:

https://vhope.cf/zh/posts/ue/ue-depth/

But I have a problem,the depth textture I get is not the same size as my game viewport. How do I map the depth texture data from the screen coordinates?

did you manage to get correct data out of this?
I tried multiple various picture sizes and none produced a useful result.
Can you also Access custom depth or stencil buffer with this method?