@authot: 白袍小道
- 轉載說明那啥即可。
-
( 圖片和本文無關,嘿嘿,坑一下)
- 以下為Unreal4.18版本中對GPUBuffer部分的分析結果
-
(插入:比之夠着,知至目的)
-
Memo of GBuffer (UE4.18)
-
GBufferA : Normal(rgb), PerObjectGBufferData(a)
-
GBufferB : Metallic(r), Specular(g), Roughness(b), ShadingModelID(a&0xF),
-
SelectiveOutputMask(a&0xF0)
-
GBufferC : BaseColor(rgb), IndirectIrradiance(a)
-
GBufferD : CustomData(rgba)
-
GBufferE : PrecomputedShadowFactors(rgba)
-
SceneDepth
-
CustomNativeDepth : depth®
-
CustomStencilTexture
-
GBufferVelocity : rgba
補充說明:注意源碼中對這一塊的對齊處理,線程,訪問方式的處理
-
-
Dbuffer
-
DBufferA : PreMultColor(rgb), ColorOpacity(a)
-
DBufferB : PreMulWorldNormal(rgb), NormalOpacity(a)
- DBufferC : PreMulRoughness(r ), RoughnessOpacity(g)
(一)、DeferredShadingRender中對Buffer的處理
從調式和RenderDoc可以詳細看到過程,這里就不做詳細說明
結果:
(二),代碼抓取
結局:
https://twitter.com/i/status/1096091562642001920
這里主要用兩種方式去獲取,一種是通過Fmemory,一種直接用Unreal提供CopyShareMip
具體如下:
以下為全部代碼:
DynamicAccessGBufferRenderTarget.h:
//////////////////這里就沒有按照Buff處理做分裝了,直接懟的(嘿嘿)
#pragma once
#include <memory>
#include "Engine/Texture2D.h"
#include "Object.h"
#include "DynamicAccessGBufferRenderTarget.generated.h"
UENUM(BlueprintType) //"BlueprintType" is essential to include
enum class EDZShowGbuffer : uint8
{
VE_GDZSHOWBUFFERA UMETA(DisplayName = "ShowGBuffA"),
VE_GDZSHOWBUFFERB UMETA(DisplayName = "ShowGBuffB"),
VE_GDZSHOWBUFFERC UMETA(DisplayName = "ShowGBuffC"),
VE_GDZSHOWBUFFERD UMETA(DisplayName = "ShowGBuffD"),
VE_GDZSHOWBUFFERE UMETA(DisplayName = "ShowGBuffE"),
};
UENUM(BlueprintType) //"BlueprintType" is essential to include
enum class EDZCOPYGbufferType : uint8
{
VE_GDZSHOWGBUFFER_COPYMIP UMETA(DisplayName = "COPY_Mip"),
VE_GDZSHOWBUFFERR_COPYMEMO UMETA(DisplayName = "COPY_Memory"),
VE_GDZSHOWBUFFERC_CPUARRAY UMETA(DisplayName = "COPY_MemoryForWhile"),
};
USTRUCT()
struct FCommitRenderData
{
GENERATED_BODY()
public:
EDZCOPYGbufferType ECOPYBuffType;
EDZShowGbuffer EShowBuff;
UTextureRenderTarget2D* mTextureTarget;
EPixelFormat format;
int32 canvasWidth = 512;
int32 canvasHeight = 512;
bool isGetGBufferData = false;
};
UCLASS(Blueprintable, BlueprintType)
class DZRENDERSTUDIOPLUGIN_API UDynamicAccessGBufferRenderTarget : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DynamicAccessGBufferRenderTarget)
EDZCOPYGbufferType ECOPYBuffType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DynamicAccessGBufferRenderTarget)
EDZShowGbuffer EShowBuff;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DynamicAccessGBufferRenderTarget)
UTextureRenderTarget2D* mTextureTarget;
UFUNCTION(BlueprintCallable, Category = DynamicAccessGBufferRenderTarget)
void InitializeTexture(UTextureRenderTarget2D* pTextureTarget,EDZShowGbuffer pEShowBuff, EDZCOPYGbufferType pECOPYBuffType);
UFUNCTION(BlueprintCallable, Category = DynamicAccessGBufferRenderTarget)
void CaputerGBuffer();
UFUNCTION(BlueprintCallable, Category = DynamicAccessGBufferRenderTarget)
void ClearTexture();
UDynamicAccessGBufferRenderTarget();
~UDynamicAccessGBufferRenderTarget();
static void CaputerGBufer_Rebuild_RenderThread(FCommitRenderData* pRenderData);
static void CaputerGBuffer_RenderThread(FCommitRenderData* pRenderData);
static void Copy_TextureRHI(FRHICommandListImmediate& RHICmdList, FRHITexture2D* pDesc, FRHITexture2D* pSrc);
static void Copy_MemoryRHI(FRHICommandListImmediate& RHICmdList, FRHITexture2D* pDesc, FRHITexture2D* pSrc);
static void Copy_CPUArrayRHI();
private:
EPixelFormat format;
UPROPERTY()
FCommitRenderData CatchRenderData;
UPROPERTY()
bool isRebulidRenderTargetSuccess = false;
};
DynamicAccessGBufferRenderTarget.cpp
/**
* 1、這里步驟基本為先得到當前Buffer的大小,刷新RT目標的數據。並在基礎屬性變化時* 候再次刷新
* 2、抓取數據(由於BUFF在Render管線處理時候有獲取和釋放的處理也是為了能及時釋* 放,所以手動加1,
* 當然成對的寫法在DepthRender, Slate等都可以看到,這非常好。
* 3、CopyShare或者利用FMemory::Memcpy(但拷貝前需要加鎖,完成后還需要解鎖,所* * 以你懂的
**/
#include "DynamicAccessGBufferRenderTarget.h"
#include "private/PostProcess/SceneRenderTargets.h"
#include "Engine.h"
#include "RHICommandList.h"
UDynamicAccessGBufferRenderTarget::UDynamicAccessGBufferRenderTarget()
{
}
UDynamicAccessGBufferRenderTarget::~UDynamicAccessGBufferRenderTarget()
{
}
void UDynamicAccessGBufferRenderTarget::InitializeTexture(UTextureRenderTarget2D* pTextureTarget
, EDZShowGbuffer pEShowBuff, EDZCOPYGbufferType pECOPYBuffType)
{
if (mTextureTarget != pTextureTarget || EShowBuff != pEShowBuff || ECOPYBuffType != pECOPYBuffType)
{
mTextureTarget = pTextureTarget;
EShowBuff = pEShowBuff;
ECOPYBuffType = pECOPYBuffType;
isRebulidRenderTargetSuccess = false;
}
}
void UDynamicAccessGBufferRenderTarget::ClearTexture()
{
}
void UDynamicAccessGBufferRenderTarget::CaputerGBuffer()
{
if (!CatchRenderData.isGetGBufferData)
{
isRebulidRenderTargetSuccess = false;
CatchRenderData.EShowBuff = EShowBuff;
CatchRenderData.ECOPYBuffType = ECOPYBuffType;
CatchRenderData.mTextureTarget = mTextureTarget;
ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
DZRenderSutioBP_AccessGBufferRenderTarget_init,
FCommitRenderData*, RenderData, &CatchRenderData,
{
UDynamicAccessGBufferRenderTarget::CaputerGBufer_Rebuild_RenderThread(RenderData);
}
);
}
else
{
if (!isRebulidRenderTargetSuccess)
{
if (IsInGameThread())
{
mTextureTarget->InitCustomFormat(CatchRenderData.canvasWidth, CatchRenderData.canvasHeight, CatchRenderData.format, false);
mTextureTarget->ForceRebuildPlatformData();
}
isRebulidRenderTargetSuccess = true;
}
else
{
CatchRenderData.EShowBuff = EShowBuff;
CatchRenderData.ECOPYBuffType = ECOPYBuffType;
CatchRenderData.mTextureTarget = mTextureTarget;
ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(
DZRenderSutioBP_InterceptSceneGBufferToRenderTarget,
FCommitRenderData*, RenderData, &CatchRenderData,
{
UDynamicAccessGBufferRenderTarget::CaputerGBuffer_RenderThread(RenderData);
}
);
}
}
}
void UDynamicAccessGBufferRenderTarget::CaputerGBufer_Rebuild_RenderThread(FCommitRenderData* pRenderData)
{
FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
//計數加一避免Render完成后直接清空了GBuffer,但會慢一幀,你猜
FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, 1);
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
if (SceneContext.GBufferA)
{
FTexture2DRHIRef vTextTarget;
switch (pRenderData->EShowBuff)
{
case EDZShowGbuffer::VE_GDZSHOWBUFFERA:
vTextTarget = SceneContext.GetGBufferATexture();
break;
case EDZShowGbuffer::VE_GDZSHOWBUFFERB:
vTextTarget = SceneContext.GetGBufferBTexture();
break;
case EDZShowGbuffer::VE_GDZSHOWBUFFERC:
vTextTarget = SceneContext.GetGBufferCTexture();
break;
case EDZShowGbuffer::VE_GDZSHOWBUFFERD:
vTextTarget = SceneContext.GetGBufferDTexture();
break;
case EDZShowGbuffer::VE_GDZSHOWBUFFERE:
vTextTarget = SceneContext.GetGBufferETexture();
break;
default:
vTextTarget = SceneContext.GetGBufferATexture();
break;
}
pRenderData->format = vTextTarget->GetFormat();
pRenderData->canvasWidth = vTextTarget->GetSizeX();
pRenderData->canvasHeight = vTextTarget->GetSizeY();
pRenderData->isGetGBufferData = true;
}
FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, -1);
}
void UDynamicAccessGBufferRenderTarget::CaputerGBuffer_RenderThread(FCommitRenderData* pRenderData)
{
FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();
//計數加一避免Render完成后直接清空了GBuffer,但會慢一幀,你猜
FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, 1);
FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
if (SceneContext.GBufferA && pRenderData->mTextureTarget != nullptr)
{
FTexture2DRHIRef vTextTarget;
switch (pRenderData->EShowBuff)
{
case EDZShowGbuffer::VE_GDZSHOWBUFFERA:
vTextTarget = SceneContext.GetGBufferATexture();
break;
case EDZShowGbuffer::VE_GDZSHOWBUFFERB:
vTextTarget = SceneContext.GetGBufferBTexture();
break;
case EDZShowGbuffer::VE_GDZSHOWBUFFERC:
vTextTarget = SceneContext.GetGBufferCTexture();
break;
case EDZShowGbuffer::VE_GDZSHOWBUFFERD:
vTextTarget = SceneContext.GetGBufferDTexture();
break;
case EDZShowGbuffer::VE_GDZSHOWBUFFERE:
vTextTarget = SceneContext.GetGBufferETexture();
break;
break;
default:
vTextTarget = SceneContext.GetGBufferATexture();
break;
}
pRenderData->format = vTextTarget->GetFormat();
if (pRenderData->canvasWidth != vTextTarget->GetSizeX())
{
pRenderData->isGetGBufferData = false;
return;
}
FTextureReferenceRHIRef vTexRHIRef = pRenderData->mTextureTarget->TextureReference.TextureReferenceRHI;
FRHITexture* vRTTexture = vTexRHIRef->GetTextureReference()->GetReferencedTexture();
FRHITexture2D* vtex = (FRHITexture2D*)vRTTexture;
if (vtex == nullptr)
{
return;
}
switch (pRenderData->ECOPYBuffType)
{
case EDZCOPYGbufferType::VE_GDZSHOWGBUFFER_COPYMIP:
UDynamicAccessGBufferRenderTarget::Copy_TextureRHI(RHICmdList,vtex, vTextTarget);
break;
case EDZCOPYGbufferType::VE_GDZSHOWBUFFERR_COPYMEMO:
UDynamicAccessGBufferRenderTarget::Copy_MemoryRHI(RHICmdList, vtex, vTextTarget);
break;
case EDZCOPYGbufferType::VE_GDZSHOWBUFFERC_CPUARRAY:
UDynamicAccessGBufferRenderTarget::Copy_CPUArrayRHI();
break;
default:
break;
}
RHICmdList.CopySharedMips(vtex, vTextTarget);
}
//移除
FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, -1);
}
//利用SharedMip的共享方式在這里會快一些
//擴展方式
void UDynamicAccessGBufferRenderTarget::Copy_TextureRHI(FRHICommandListImmediate& RHICmdList,FRHITexture2D* pDesc,FRHITexture2D* pSrc)
{
RHICmdList.CopySharedMips(pDesc, pSrc);
}
//內存CPY,但需要鎖住,這樣就會讓另外的渲染不能訪問,會造成掉幀率。
void UDynamicAccessGBufferRenderTarget::Copy_MemoryRHI(FRHICommandListImmediate& RHICmdList, FRHITexture2D* pDesc, FRHITexture2D* pSrc)
{
uint32 Lolstrid = 0;
void * UAVRenderTargetData = RHILockTexture2D(pDesc, 0, RLM_WriteOnly, Lolstrid, true);
void * UAVCSData = RHILockTexture2D(pSrc, 0, RLM_ReadOnly, Lolstrid, true);
FMemory::Memcpy(UAVRenderTargetData, UAVCSData, GPixelFormats[pSrc->GetFormat()].BlockBytes * pSrc->GetSizeX() * pSrc->GetSizeY());
RHICmdList.UnlockTexture2D(pDesc, 0, false);
RHICmdList.UnlockTexture2D(pSrc, 0, false);
}
void UDynamicAccessGBufferRenderTarget::Copy_CPUArrayRHI()
{
}
藍圖和資源部分
1、RT (1個對應一個結果)
2、一個UI材質(用於做一些額外效果)
3、一個UI藍圖(就是調用代碼和綁定資源,用C++也可以,偷懶下)
RT賦予
BP部分
UI_ShowCapResul_Child:
除了一些我們自己做的方式和LitMode中調試方式
還以通過像素檢查器進行分析和查看
題外:
1、Create Custom GBUFFER :http://www.catalinzima.com/xna/tutorials/deferred-rendering-in-xna/creating-the-g-buffer/
2、Buffer,RT ,Pipeline
3、https://en.wikipedia.org/wiki/Deferred_shading
4、高效的GPU GBUFFER管理:http://www.klayge.org/2015/05/25/%E9%AB%98%E6%95%88gpu-buffer%E7%AE%A1%E7%90%86%E4%B9%8Btransient-buffer/
-