(原)Unreal渲染相關的緩沖區 及其 自定義代碼幾種抓取


@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/

       

    2Buffer,RT ,Pipeline

    https://medium.com/@lordned/unreal-engine-4-rendering-part-4-the-deferred-shading-pipeline-389fc0175789

       

    3https://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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM