@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

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

     
     

    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/

(原)Unreal渲染相关的缓冲区 及其 自定义代码几种抓取的更多相关文章

  1. (原)Unreal 渲染模块引言Temp

            @author:白袍小道     引言 本文只在对Unreal渲染模块做一些详细的理解,务求能分析出个大概. 其中框架的思想和实现的过程,是非常值得学习和推敲一二的. 涉及资源系统,材 ...

  2. (原)Unreal 渲染模块 渲染流程

    @author:白袍小道 浏览分享随缘,评论不喷亦可.     扯淡部分: 在temp中,乱七八糟的说了下大致的UE过程.下面我们还是稍微别那么任性,一步步来吧.     UE渲染模块牵扯到场景遍历. ...

  3. 扩展阿里p3c实现自定义代码规范检查

     前段时间fastjson报出了漏洞,只要打开setAutoType特性就会存在风险,自己测试环境的一个项目被揪出来了-_-!.虽然改动很小,但就是觉得憋屈.fastjson还是挺好的,想着禁用的话太 ...

  4. Java抓取网页数据(原网页+Javascript返回数据)

    有时候由于种种原因,我们需要采集某个网站的数据,但由于不同网站对数据的显示方式略有不同! 本文就用Java给大家演示如何抓取网站的数据:(1)抓取原网页数据:(2)抓取网页Javascript返回的数 ...

  5. 遇到Audio/Speech相关问题,如何抓取log

      [DESCRIPTION] 遇到Audio/Speech相关问题时,经常需要抓取相关log信息,总结抓取方法如下 [SOLUTION] 1.    通话声音相关的问题: Case 1: 通话中某一 ...

  6. IDE MAC下的快捷键,自定义代码块。

    快捷键 参考博客:http://blog.csdn.net/iguiyi/article/details/51853728 alt+f7查找在哪里使用 相当于eclipse的ctrl+shift+G ...

  7. pycharm自定义代码片段

    pycharm自定义代码片段 目录 (一)通用阶段 0 .新建.py文件模板:2 0 .pycharm中添加自定义代码片段:一图全知道:3 1 .定义类:classin              描述 ...

  8. vsCode与Hubilder中自定义代码块

    平常测试vue的一些属性时总要新增代码,引入文件,麻烦,顾自定义代码块来实现快速新增测试 一.打开设置 1.1 vsCode设置 点击后选择代码块所属的文件类型,比如在html中则选择html类型配置 ...

  9. Joomla - 优化(时区、google字体、压缩图片、压缩自定义代码)

    Joomla - 优化(时区.google字体.压缩图片.压缩自定义代码) 一.时区 发布文章是往往会发现发布时间和当前时间对不上,原因是 Joomla 用的是国际标准时间,和中国时区大约相差8小时, ...

随机推荐

  1. leetcode_No.1 Two Sum

    原题: Given an array of integers, return indices of the two numbers such that they add up to a specifi ...

  2. @NotEmpty、@NotNull、@NotBlank 的区别

    @NotEmpty 用在集合上面(不能注释枚举) @NotBlank用在String上面 @NotNull用在所有类型上面 1. @NotEmpty Asserts that the annotate ...

  3. python中的反斜杠问题

    python本身使用 \ 来转义一些特殊字符,比如在字符串中加入引号的时候 s = 'i\'m superman' print(s) # i'm superman 为了防止和字符串本身的引号冲突,使用 ...

  4. JT796、JT1077部标平台检测报名须知

    检测报名须知 申请道路运输车辆卫星定位系统平台标准符合性检测时,请先将1检测意向单(只针对企业监控平台).2符合性检测申请材料(基本材料包括:申请函.授权人身份证复印件.检测登记表.运输企业信息表.平 ...

  5. Oracle字符集的查看查询和Oracle字符集的设置修改(转载)

    本文主要讨论以下几个部分:如何查看查询oracle字符集. 修改设置字符集以及常见的Oracle UTF8字符集和Oracle exp 字符集问题. 一.什么是Oracle字符集 Oracle字符集是 ...

  6. 基于mybatis设计简单OA系统问题2

    1.<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <fm ...

  7. 一、小程序连接MySql数据库

    前言:我用的是wafer2 node.解决方案 下面连接有环境配置及搭建流程(https://github.com/tencentyun/wafer2-quickstart-nodejs) ,连接是官 ...

  8. mysql,oracle表数据相互导入

    mysql导入oracle: 例如mysql中有ts_user_info表,现在要导入到oracle中的user_info表 1:导出mysql表数据到data.txt文件 mysql> sel ...

  9. java8之list集合中取出某一属性的方法

    上代码 List<User> list = new ArrayList<User>(); User user1 = new User("第一位"," ...

  10. Mybatis中updateByPrimaryKeySelective和updateByPrimaryKey区别

    int updateByPrimaryKeySelective(TbItem record); int updateByPrimaryKey(TbItem record); 上面的是逆转工程生成的Ma ...