延迟渲染到最终结果------1,2,分配渲染目标和初始化窗口(大象无形11.3.1)

 

版本不同,我这里延迟渲染是FDeferredShadingSceneRenderer类

即函数

void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList);

逐渐填充大象无形中的注释

 

一,按需要重新分配渲染目标

void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)
{

.............

//获得渲染目标单例

    FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);
    ......

    //分配渲染目标
    SceneContext.AllocDummyGBufferTargets(RHICmdList);
....

}

查看其实现

static TGlobalResource<FSceneRenderTargets> SceneRenderTargetsSingleton;

FSceneRenderTargets& FSceneRenderTargets::Get(FRHICommandListImmediate& RHICmdList)
{
.......
    return SceneRenderTargetsSingleton;
}


void FSceneRenderTargets::AllocDummyGBufferTargets(FRHICommandList& RHICmdList)
{
    if (GBufferDummyResourcesUniformBuffer)
    {
        return;
    }

    FTextureRHIRef BlackDummy = GSystemTextures.BlackDummy->GetRenderTargetItem().ShaderResourceTexture;    

    FGBufferResourceStruct GBufferResourceStruct;

    GBufferResourceStruct.GBufferATexture = BlackDummy;

........

    GBufferResourceStruct.GBufferATextureSampler = TStaticSamplerState<>::GetRHI();

.......

    GBufferDummyResourcesUniformBuffer = FGBufferResourceStruct::CreateUniformBuffer(GBufferResourceStruct, UniformBuffer_SingleFrame);
}
 

二,初始化视口(可以多个),包括确定可见性与设置阴影相关参数


void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)

{

.......
    FGraphEventArray SortEvents;
    FILCUpdatePrimTaskData ILCTaskData;
    bool bDoInitViewAftersPrepass = InitViews(RHICmdList, ILCTaskData, SortEvents);

.........

}

现在看下initViews函数
bool FDeferredShadingSceneRenderer::InitViews(FRHICommandListImmediate& RHICmdList, struct FILCUpdatePrimTaskData& ILCTaskData, FGraphEventArray& SortEvents)
{    
........

   //预设置可见性

    PreVisibilityFrameSetup(RHICmdList);

    //可见性计算
    ComputeViewVisibility(RHICmdList);

.....

//完成可见性计算

    PostVisibilityFrameSetup(ILCTaskData);

.......
}
1, //预设置可见性
void FSceneRenderer::PreVisibilityFrameSetup(FRHICommandListImmediate& RHICmdList)

{

      //告诉RHI命令队列,开始渲染
        RHICmdList.BeginScene();

......

       //根据当前画质设置,设置TemporalAA的采样方式,同时确定采样位置,

       //这个采样位置用于微调接下来的矩阵,进行像素偏移,混合前面几帧的渲染结果,提高精度

      
    for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
    {
        FViewInfo& View = Views[ViewIndex];
        FSceneViewState* ViewState = View.ViewState;

......
        FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);


        // set up the screen area for occlusion
        float NumPossiblePixels = SceneContext.UseDownsizedOcclusionQueries() && IsValidRef(SceneContext.GetSmallDepthSurface()) ? 
            (float)View.ViewRect.Width() / SceneContext.GetSmallColorDepthDownsampleFactor() * (float)View.ViewRect.Height() / SceneContext.GetSmallColorDepthDownsampleFactor() :
            View.ViewRect.Width() * View.ViewRect.Height();
        View.OneOverNumPossiblePixels = NumPossiblePixels > 0.0 ? 1.0f / NumPossiblePixels : 0.0f;

        // Still need no jitter to be set for temporal feedback on SSR (it is enabled even when temporal AA is off).
        View.TemporalJitterPixelsX = 0.0f;
        View.TemporalJitterPixelsY = 0.0f;

        if (ViewState)
        {
            ViewState->SetupDistanceFieldTemporalOffset(ViewFamily);
        }

        if( View.AntiAliasingMethod == AAM_TemporalAA && ViewState )
        {
            // Subpixel jitter for temporal AA
            int32 TemporalAASamples = CVarTemporalAASamples.GetValueOnRenderThread();
        
            if( TemporalAASamples > 1 && View.bAllowTemporalJitter )
            {
                float SampleX, SampleY;

                if (Scene->GetFeatureLevel() < ERHIFeatureLevel::SM4)
                {
                    // Only support 2 samples for mobile temporal AA.
                    TemporalAASamples = 2;
                }

                if( TemporalAASamples == 2 )
                {
                    #if 0
                        // 2xMSAA
                        // Pattern docs: http://msdn.microsoft.com/en-us/library/windows/desktop/ff476218(v=vs.85).aspx
                        //   N.
                        //   .S
                        float SamplesX[] = { -4.0f/16.0f, 4.0/16.0f };
                        float SamplesY[] = { -4.0f/16.0f, 4.0/16.0f };
                    #else
                        // This pattern is only used for mobile.
                        // Shift to reduce blur.
                        float SamplesX[] = { -8.0f/16.0f, 0.0/16.0f };
                        float SamplesY[] = { /* - */ 0.0f/16.0f, 8.0/16.0f };
                    #endif
                    ViewState->OnFrameRenderingSetup(ARRAY_COUNT(SamplesX), ViewFamily);
                    uint32 Index = ViewState->GetCurrentTemporalAASampleIndex();
                    SampleX = SamplesX[ Index ];
                    SampleY = SamplesY[ Index ];
                }
                else if( TemporalAASamples == 3 )
                {
                    // 3xMSAA
                    //   A..
                    //   ..B
                    //   .C.
                    // Rolling circle pattern (A,B,C).
                    float SamplesX[] = { -2.0f/3.0f,  2.0/3.0f,  0.0/3.0f };
                    float SamplesY[] = { -2.0f/3.0f,  0.0/3.0f,  2.0/3.0f };
                    ViewState->OnFrameRenderingSetup(ARRAY_COUNT(SamplesX), ViewFamily);
                    uint32 Index = ViewState->GetCurrentTemporalAASampleIndex();
                    SampleX = SamplesX[ Index ];
                    SampleY = SamplesY[ Index ];
                }
                else if( TemporalAASamples == 4 )
                {
                    // 4xMSAA
                    // Pattern docs: http://msdn.microsoft.com/en-us/library/windows/desktop/ff476218(v=vs.85).aspx
                    //   .N..
                    //   ...E
                    //   W...
                    //   ..S.
                    // Rolling circle pattern (N,E,S,W).
                    float SamplesX[] = { -2.0f/16.0f,  6.0/16.0f, 2.0/16.0f, -6.0/16.0f };
                    float SamplesY[] = { -6.0f/16.0f, -2.0/16.0f, 6.0/16.0f,  2.0/16.0f };
                    ViewState->OnFrameRenderingSetup(ARRAY_COUNT(SamplesX), ViewFamily);
                    uint32 Index = ViewState->GetCurrentTemporalAASampleIndex();
                    SampleX = SamplesX[ Index ];
                    SampleY = SamplesY[ Index ];
                }
                else if( TemporalAASamples == 5 )
                {
                    // Compressed 4 sample pattern on same vertical and horizontal line (less temporal flicker).
                    // Compressed 1/2 works better than correct 2/3 (reduced temporal flicker).
                    //   . N .
                    //   W . E
                    //   . S .
                    // Rolling circle pattern (N,E,S,W).
                    float SamplesX[] = {  0.0f/2.0f,  1.0/2.0f,  0.0/2.0f, -1.0/2.0f };
                    float SamplesY[] = { -1.0f/2.0f,  0.0/2.0f,  1.0/2.0f,  0.0/2.0f };
                    ViewState->OnFrameRenderingSetup(ARRAY_COUNT(SamplesX), ViewFamily);
                    uint32 Index = ViewState->GetCurrentTemporalAASampleIndex();
                    SampleX = SamplesX[ Index ];
                    SampleY = SamplesY[ Index ];
                }
                else
                {
                    ViewState->OnFrameRenderingSetup(TemporalAASamples, ViewFamily);
                    uint32 Index = ViewState->GetCurrentTemporalAASampleIndex();

                    float u1 = Halton( Index + 1, 2 );
                    float u2 = Halton( Index + 1, 3 );

                    // Generates samples in normal distribution
                    // exp( x^2 / Sigma^2 )
                    
                    static auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("r.TemporalAAFilterSize"));
                    float FilterSize = CVar->GetFloat();

                    // Scale distribution to set non-unit variance
                    // Variance = Sigma^2
                    float Sigma = 0.47f * FilterSize;

                    // Window to [-0.5, 0.5] output
                    // Without windowing we could generate samples far away on the infinite tails.
                    float OutWindow = 0.5f;
                    float InWindow = FMath::Exp( -0.5 * FMath::Square( OutWindow / Sigma ) );
                    
                    // Box-Muller transform
                    float Theta = 2.0f * PI * u2;
                    float r = Sigma * FMath::Sqrt( -2.0f * FMath::Loge( (1.0f - u1) * InWindow + u1 ) );
                    
                    SampleX = r * FMath::Cos( Theta );
                    SampleY = r * FMath::Sin( Theta );
                }

                View.TemporalJitterPixelsX = SampleX;
                View.TemporalJitterPixelsY = SampleY;

                View.ViewMatrices.HackAddTemporalAAProjectionJitter(FVector2D(SampleX * 2.0f / View.ViewRect.Width(), SampleY * -2.0f / View.ViewRect.Height()));
            }

.....

     //设置视口矩阵,包括视口投影矩阵和转换矩阵


                ViewState->PrevViewMatrices.ApplyWorldOffset(View.OriginOffsetThisFrame);
                ViewState->PendingPrevViewMatrices.ApplyWorldOffset(View.OriginOffsetThisFrame);

......

 

}

 

2,可见性计算

void FSceneRenderer::ComputeViewVisibility(FRHICommandListImmediate& RHICmdList)

{

。。。。。。

//(1)初始化一系列用于可视化检测的缓冲区,(位数组,0和1代表是否可见
    int32 NumPrimitives = Scene->Primitives.Num();

    FPrimitiveViewMasks HasDynamicMeshElementsMasks;
    HasDynamicMeshElementsMasks.AddZeroed(NumPrimitives);

    FPrimitiveViewMasks HasDynamicEditorMeshElementsMasks;
        HasDynamicEditorMeshElementsMasks.AddZeroed(NumPrimitives);

    uint8 ViewBit = 0x1;
    for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex, ViewBit <<= 1)
    {
        FViewInfo& View = Views[ViewIndex];

......
        View.PrimitiveVisibilityMap.Init(false,Scene->Primitives.Num());
。。。。。。

//(2)先用六棱锥进行筛选(a,b代表true或者false),不可见的对象的可视化检测缓冲区对应的比特位设置为0

int32  NumCulledPrimitivesForView = FrustumCull<true, false>(Scene, View);

........

//(3)对过小的线框直接剔除

//线框模式下,剔除所有的非线框

        if (View.Family->EngineShowFlags.Wireframe)
        {
            float ScreenSizeScale = FMath::Max(View.ViewMatrices.GetProjectionMatrix().M[0][0] * View.ViewRect.Width(), View.ViewMatrices.GetProjectionMatrix().M[1][1] * View.ViewRect.Height());
            for (FSceneSetBitIterator BitIt(View.PrimitiveVisibilityMap); BitIt; ++BitIt)
            {
                if (ScreenSizeScale * Scene->PrimitiveBounds[BitIt.GetIndex()].BoxSphereBounds.SphereRadius <= GWireframeCullThreshold)
                {
                    View.PrimitiveVisibilityMap.AccessCorrespondingBit(BitIt) = false;
                }
            }
        }

//(4)在非线框模式下,对于处于视口范围内,但是被其他对象遮挡的对象进行一次剔除

        if (!View.Family->EngineShowFlags.Wireframe)
        {
            int32 NumOccludedPrimitivesInView = OcclusionCull(RHICmdList, Scene, View);
            STAT(NumOccludedPrimitives += NumOccludedPrimitivesInView);
        }

//(5)根据所有的可见性位图,设置每个需要渲染的对象的可见性状况,即Hiddenflags


        FLODSceneTree& HLODTree = Scene->SceneLODHierarchy;

        if (HLODTree.IsActive())
        {
            QUICK_SCOPE_CYCLE_COUNTER(STAT_ViewVisibilityTime_HLOD);
            HLODTree.UpdateAndApplyVisibilityStates(View);
        }

。。。。

//(6)给每个对象返回自己是否可见的机会
        if (FPlatformProperties::SupportsWindowedMode() && ViewState && ViewState->IsViewParent())
        {
            for (FSceneDualSetBitIterator BitIt(View.PrimitiveVisibilityMap, View.PrimitiveDefinitelyUnoccludedMap); BitIt; ++BitIt)
            {
                ViewState->ParentPrimitives.Add(Scene->PrimitiveComponentIds[BitIt.GetIndex()]);
            }
        }

。。。。。。

//(7)获取所有动态对象的渲染信息
    GatherDynamicMeshElements(Views, Scene, ViewFamily, HasDynamicMeshElementsMasks, HasDynamicEditorMeshElementsMasks, MeshCollector);

.......

}

2.1对于第(2)步,剔除方式是Parrallefor线性剔除,而不是八叉树等树状结构


template<bool UseCustomCulling, bool bAlsoUseSphereTest>
static int32 FrustumCull(const FScene* Scene, FViewInfo& View)
{
.....

    ParallelFor(NumTasks, 
        [&NumCulledPrimitives, Scene, &View, MaxDrawDistanceScale](int32 TaskIndex)
        {

...
            for (int32 WordIndex = TaskWordOffset; WordIndex < TaskWordOffset + FrustumCullNumWordsPerTask && WordIndex * NumBitsPerDWORD < BitArrayNumInner; WordIndex++)
            {

.....


                for (int32 BitSubIndex = 0; BitSubIndex < NumBitsPerDWORD && WordIndex * NumBitsPerDWORD + BitSubIndex < BitArrayNumInner; BitSubIndex++, Mask <<= 1)
                {

....


                    if (DistanceSquared > FMath::Square(MaxDrawDistance + FadeRadius) ||
                        (DistanceSquared < Bounds.MinDrawDistanceSq) ||
                        (UseCustomCulling && !View.CustomVisibilityQuery->IsVisible(VisibilityId, FBoxSphereBounds(Bounds.BoxSphereBounds.Origin, Bounds.BoxSphereBounds.BoxExtent, Bounds.BoxSphereBounds.SphereRadius))) ||
                        (bAlsoUseSphereTest && View.ViewFrustum.IntersectSphere(Bounds.BoxSphereBounds.Origin, Bounds.BoxSphereBounds.SphereRadius) == false) ||
                        View.ViewFrustum.IntersectBox(Bounds.BoxSphereBounds.Origin, Bounds.BoxSphereBounds.BoxExtent) == false ||
                        (UseMonoCulling && Scene->Primitives[Index]->Proxy->RenderInMono()))
                    {
                        STAT(NumCulledPrimitives.Increment());
                    }

....


    return NumCulledPrimitives.GetValue();
 

}

3,完成可见性计算
void FSceneRenderer::PostVisibilityFrameSetup(FILCUpdatePrimTaskData& OutILCTaskData)

{

.......

//(1)对半透明对象进行排序,半透明对象的渲染由于涉及到互相遮挡,则必须按照从后往前的顺序来渲染,才能保证渲染结果的正确性,因此,必须在此时完成排序
        for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
        {        
            FViewInfo& View = Views[ViewIndex];

            View.TranslucentPrimSet.SortPrimitives();
            View.MeshDecalPrimSet.SortPrimitives();

            if (View.State)
            {
                ((FSceneViewState*)View.State)->TrimHistoryRenderTargets(Scene);
            }
        }

.....

//(2)对每个光照确定当前光照可见的对象列表,这里也是使用平截头体剔除,只需要测点光源和聚光灯,而平行光始终可见
    
        for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
        {        
            const FLightSceneProxy* Proxy = LightSceneInfo->Proxy;
            FViewInfo& View = Views[ViewIndex];
            FVisibleLightViewInfo& VisibleLightViewInfo = View.VisibleLightInfos[LightIt.GetIndex()];
            if (Proxy->GetLightType() == LightType_Point  
                || Proxy->GetLightType() == LightType_Spot)
            {
                const float Radius = Proxy->GetRadius();

                if (View.ViewFrustum.IntersectSphere(Proxy->GetOrigin(), Radius))
                {
                    if (View.IsPerspectiveProjection())
                    {
                        FSphere Bounds = Proxy->GetBoundingSphere();
                        float DistanceSquared = (Bounds.Center - View.ViewMatrices.GetViewOrigin()).SizeSquared();
                        float MaxDistSquared = Proxy->GetMaxDrawDistance() * Proxy->GetMaxDrawDistance() * GLightMaxDrawDistanceScale * GLightMaxDrawDistanceScale;
                        const bool bDrawLight = (FMath::Square(FMath::Min(0.0002f, GMinScreenRadiusForLights / Bounds.W) * View.LODDistanceFactor) * DistanceSquared < 1.0f)
                                                    && (MaxDistSquared == 0 || DistanceSquared < MaxDistSquared);
                            
                        VisibleLightViewInfo.bInViewFrustum = bDrawLight;
                    }
                    else
                    {
                        VisibleLightViewInfo.bInViewFrustum = true;
                    }
                }
            }
            else
            {
                VisibleLightViewInfo.bInViewFrustum = true;

....

//(3)初始化雾与大气的常量值
        InitFogConstants();

具体实现
void FSceneRenderer::InitFogConstants()
{
    float FogDensityOverride = -1.0f;
    float FogStartDistanceOverride = -1.

    for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++)
    {
        FViewInfo& View = Views[ViewIndex];
        InitAtmosphereConstantsInView(View);
        // set fog consts based on height fog components
        if(ShouldRenderFog(*View.Family))
        {

...

 

到这里为止,进行了重分配渲染目标和初始化视口两部分。估计看到这里,自己都要迷糊了。

总结下;

延迟渲染

void FDeferredShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList)

一,按需要重新分配渲染目标
 1,void FSceneRenderTargets::AllocDummyGBufferTargets(FRHICommandList& RHICmdList)

    1.1, template<typename InitializerType,typename RHIRefType,typename RHIParamRefType> static RHIParamRefType TStaticStateRHI<typename InitializerType,typename RHIRefType,typename RHIParamRefType>::GetRHI();

    1.2,FGBufferResourceStruct::CreateUniformBuffer(GBufferResourceStruct, UniformBuffer_SingleFrame);

二,初始化视口(可以多个),包括确定可见性与设置阴影相关参数
1,bool FDeferredShadingSceneRenderer::InitViews(FRHICommandListImmediate& RHICmdList, struct FILCUpdatePrimTaskData& ILCTaskData, FGraphEventArray& SortEvents)

   1.1,预设置可见性
           void FSceneRenderer::PreVisibilityFrameSetup(FRHICommandListImmediate& RHICmdList)

       1.1.1,根据当前画质设置,设置TemporalAA的采样方式,同时确定采样位置,
                  1.1.1.1, uint32 FSceneViewState::GetCurrentTemporalAASampleIndex() const

                  1.1.1.2,void  FViewMatrices::HackAddTemporalAAProjectionJitter(const FVector2D& InTemporalAAProjectionJitter)  

        1.1.2,设置视口矩阵,包括视口投影矩阵和转换矩阵
                   void FViewMatrices::ApplyWorldOffset(const FVector& InOffset)

    1.2,可见性计算
           void FSceneRenderer::ComputeViewVisibility(FRHICommandListImmediate& RHICmdList)

          1.2.1,初始化一系列用于可视化检测的缓冲区,(位数组,0和1代表是否可见)

          1.2.2,用六棱锥进行筛选(a,b代表true或者false),不可见的对象的可视化检测缓冲区对应的比特位设置为0
         template<bool UseCustomCulling, bool bAlsoUseSphereTest>
         static int32 FrustumCull(const FScene* Scene, FViewInfo& View)

         1.2.3,线框模式下,对直接剔除,剔除所有的非线框和过小的线框

         1.2.4,在非线框模式下,对于处于视口范围内,但是被其他对象遮挡的对象进行一次剔除
               static int32 OcclusionCull(FRHICommandListImmediate& RHICmdList, const FScene* Scene, FViewInfo& View)

         1.2.5,根据所有的可见性位图,设置每个需要渲染的对象的可见性状况,即Hiddenflags
                     void FLODSceneTree::UpdateAndApplyVisibilityStates(FViewInfo& View)

         1.2.6,给每个对象返回自己是否可见的机会

         1.2.7,获取所有动态对象的渲染信息

              void FSceneRenderer::GatherDynamicMeshElements(
                         TArray<FViewInfo>& InViews, 
                          const FScene* InScene, 
                          const FSceneViewFamily& InViewFamily, 
                          const FPrimitiveViewMasks& HasDynamicMeshElementsMasks, 
                          const FPrimitiveViewMasks& HasDynamicEditorMeshElementsMasks, 
                          FMeshElementCollector& Collector)

        1.3,完成可见性计算
            void FSceneRenderer::PostVisibilityFrameSetup(FILCUpdatePrimTaskData& OutILCTaskData)

               1.3.1,对半透明对象进行排序,半透明对象的渲染由于涉及到互相遮挡,则必须按照从后往前的顺序来渲染,才能保                                   证渲染结果的正确性,因此,必须在此时完成排序
                          1.3.1.1,void FTranslucentPrimSet::SortPrimitives()
                          1.3.1.2,void FSceneViewState::TrimHistoryRenderTargets(const FScene* Scene)

               1.3.2,对每个光照确定当前光照可见的对象列表,这里也是使用平截头体剔除,只需要测点光源和聚光灯,而平行光始                          终可见
                     bool FConvexVolume::IntersectSphere(const FVector& Origin,const float& Radius) const

               1.3.3,初始化雾与大气的常量值
                      void FSceneRenderer::InitFogConstants()

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值