void FForwardShadingSceneRenderer::RenderTranslucency(FRHICommandListImmediate& RHICmdList) { if (ShouldRenderTranslucency()) { const bool bGammaSpace = !IsMobileHDR(); const bool bLinearHDR64 = !bGammaSpace && !IsMobileHDR32bpp(); SCOPED_DRAW_EVENT(RHICmdList, Translucency); for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex); const FViewInfo& View = Views[ViewIndex]; #if PLATFORM_HTML5 // Copy the view so emulation of framebuffer fetch works for alpha=depth. // Possible optimization: this copy shouldn't be needed unless something uses fetch of depth. if(bLinearHDR64 && GSupportsRenderTargetFormat_PF_FloatRGBA && (GSupportsShaderFramebufferFetch == false) && (!IsPCPlatform(View.GetShaderPlatform()))) { CopySceneAlpha(RHICmdList, View); } #endif if (!bGammaSpace) { GSceneRenderTargets.BeginRenderingTranslucency(RHICmdList, View); } else { RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0.0f, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1.0f); } // Enable depth test, disable depth writes. // Note, this is a reversed Z depth surface, using CF_GreaterEqual. RHICmdList.SetDepthStencilState(TStaticDepthStencilState<false,CF_GreaterEqual>::GetRHI()); // Draw only translucent prims that don't read from scene color View.TranslucentPrimSet.DrawPrimitivesForForwardShading(RHICmdList, View, *this); // Draw the view's mesh elements with the translucent drawing policy. DrawViewElements<FTranslucencyForwardShadingDrawingPolicyFactory>(RHICmdList, View, FTranslucencyForwardShadingDrawingPolicyFactory::ContextType(), SDPG_World, false); // Draw the view's mesh elements with the translucent drawing policy. DrawViewElements<FTranslucencyForwardShadingDrawingPolicyFactory>(RHICmdList, View, FTranslucencyForwardShadingDrawingPolicyFactory::ContextType(), SDPG_Foreground, false); } } }
/** * Renders the scene's base pass * @return true if anything was rendered */ bool FDeferredShadingSceneRenderer::RenderBasePass() { bool bDirty = false; if(ViewFamily.EngineShowFlags.LightMapDensity && AllowDebugViewmodes()) { // Override the base pass with the lightmap density pass if the viewmode is enabled. bDirty = RenderLightMapDensities(); } else { SCOPED_DRAW_EVENT(BasePass, DEC_SCENE_ITEMS); SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime); // Draw the scene's emissive and light-map color. for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(EventView, Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex); FViewInfo& View = Views[ViewIndex]; if (ViewFamily.EngineShowFlags.ShaderComplexity) { // Additive blending when shader complexity viewmode is enabled. RHISetBlendState(TStaticBlendState<CW_RGBA,BO_Add,BF_One,BF_One,BO_Add,BF_Zero,BF_One>::GetRHI()); // Disable depth writes as we have a full depth prepass. RHISetDepthStencilState(TStaticDepthStencilState<false,CF_GreaterEqual>::GetRHI()); } else { // Opaque blending for all G buffer targets, depth tests and writes. RHISetBlendState(TStaticBlendStateWriteMask<CW_RGBA, CW_RGBA, CW_RGBA, CW_RGBA>::GetRHI()); // Note, this is a reversed Z depth surface, using CF_GreaterEqual. RHISetDepthStencilState(TStaticDepthStencilState<true,CF_GreaterEqual>::GetRHI()); } RHISetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1); bDirty |= RenderBasePass(View); } } return bDirty; }
bool FDeferredShadingSceneRenderer::RenderLightMapDensities(FRHICommandListImmediate& RHICmdList) { bool bDirty=0; if (Scene->GetFeatureLevel() >= ERHIFeatureLevel::SM4) { SCOPED_DRAW_EVENT(RHICmdList, LightMapDensity); // Draw the scene's emissive and light-map color. for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex); FViewInfo& View = Views[ViewIndex]; // Opaque blending, depth tests and writes. RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); RHICmdList.SetDepthStencilState(TStaticDepthStencilState<true,CF_DepthNearOrEqual>::GetRHI()); RHICmdList.SetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1); { SCOPED_DRAW_EVENT(RHICmdList, Dynamic); FLightMapDensityDrawingPolicyFactory::ContextType Context; for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicMeshElements.Num(); MeshBatchIndex++) { const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicMeshElements[MeshBatchIndex]; if (MeshBatchAndRelevance.bHasOpaqueOrMaskedMaterial || ViewFamily.EngineShowFlags.Wireframe) { const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh; FLightMapDensityDrawingPolicyFactory::DrawDynamicMesh(RHICmdList, View, Context, MeshBatch, false, true, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId); } } } } } return bDirty; }
/** Renders the scene's prepass and occlusion queries */ bool FDeferredShadingSceneRenderer::RenderPrePass() { SCOPED_DRAW_EVENT(PrePass, DEC_SCENE_ITEMS); SCOPE_CYCLE_COUNTER(STAT_DepthDrawTime); bool bDirty = false; GSceneRenderTargets.BeginRenderingPrePass(); // Clear the depth buffer. // Note, this is a reversed Z depth surface, so 0.0f is the far plane. RHIClear(false,FLinearColor::Black,true,0.0f,true,0, FIntRect()); // Draw a depth pass to avoid overdraw in the other passes. if(EarlyZPassMode != DDM_None) { for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(EventView, Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex); const FViewInfo& View = Views[ViewIndex]; // Disable color writes, enable depth tests and writes. RHISetBlendState(TStaticBlendState<CW_NONE>::GetRHI()); // Note, this is a reversed Z depth surface, using CF_GreaterEqual. RHISetDepthStencilState(TStaticDepthStencilState<true,CF_GreaterEqual>::GetRHI()); RHISetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1); // Draw the static occluder primitives using a depth drawing policy. { // Draw opaque occluders which support a separate position-only // vertex buffer to minimize vertex fetch bandwidth, which is // often the bottleneck during the depth only pass. SCOPED_DRAW_EVENT(PosOnlyOpaque, DEC_SCENE_ITEMS); bDirty |= Scene->PositionOnlyDepthDrawList.DrawVisible(View,View.StaticMeshOccluderMap,View.StaticMeshBatchVisibility); } { // Draw opaque occluders, using double speed z where supported. SCOPED_DRAW_EVENT(Opaque, DEC_SCENE_ITEMS); bDirty |= Scene->DepthDrawList.DrawVisible(View,View.StaticMeshOccluderMap,View.StaticMeshBatchVisibility); } if(EarlyZPassMode >= DDM_AllOccluders) { // Draw opaque occluders with masked materials SCOPED_DRAW_EVENT(Opaque, DEC_SCENE_ITEMS); bDirty |= Scene->MaskedDepthDrawList.DrawVisible(View,View.StaticMeshOccluderMap,View.StaticMeshBatchVisibility); } // Draw the dynamic occluder primitives using a depth drawing policy. TDynamicPrimitiveDrawer<FDepthDrawingPolicyFactory> Drawer(&View,FDepthDrawingPolicyFactory::ContextType(EarlyZPassMode),true); { SCOPED_DRAW_EVENT(Dynamic, DEC_SCENE_ITEMS); for(int32 PrimitiveIndex = 0;PrimitiveIndex < View.VisibleDynamicPrimitives.Num();PrimitiveIndex++) { const FPrimitiveSceneInfo* PrimitiveSceneInfo = View.VisibleDynamicPrimitives[PrimitiveIndex]; int32 PrimitiveId = PrimitiveSceneInfo->GetIndex(); const FPrimitiveViewRelevance& PrimitiveViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId]; bool bShouldUseAsOccluder = true; if(EarlyZPassMode != DDM_AllOccluders) { extern float GMinScreenRadiusForDepthPrepass; const float LODFactorDistanceSquared = (PrimitiveSceneInfo->Proxy->GetBounds().Origin - View.ViewMatrices.ViewOrigin).SizeSquared() * FMath::Square(View.LODDistanceFactor); // Only render primitives marked as occluders bShouldUseAsOccluder = PrimitiveSceneInfo->Proxy->ShouldUseAsOccluder() // Only render static objects unless movable are requested && (!PrimitiveSceneInfo->Proxy->IsMovable() || GEarlyZPassMovable) && (FMath::Square(PrimitiveSceneInfo->Proxy->GetBounds().SphereRadius) > GMinScreenRadiusForDepthPrepass * GMinScreenRadiusForDepthPrepass * LODFactorDistanceSquared); } // Only render opaque primitives marked as occluders if (bShouldUseAsOccluder && PrimitiveViewRelevance.bOpaqueRelevance && PrimitiveViewRelevance.bRenderInMainPass) { FScopeCycleCounter Context(PrimitiveSceneInfo->Proxy->GetStatId()); Drawer.SetPrimitive(PrimitiveSceneInfo->Proxy); PrimitiveSceneInfo->Proxy->DrawDynamicElements( &Drawer, &View ); } } } bDirty |= Drawer.IsDirty(); } } GSceneRenderTargets.FinishRenderingPrePass(); return bDirty; }
/** * Renders the view family. */ void FDeferredShadingSceneRenderer::Render() { if(!ViewFamily.EngineShowFlags.Rendering) { return; } SCOPED_DRAW_EVENT(Scene,DEC_SCENE_ITEMS); // Initialize global system textures (pass-through if already initialized). GSystemTextures.InitializeTextures(); // Allocate the maximum scene render target space for the current view family. GSceneRenderTargets.Allocate(ViewFamily); // Find the visible primitives. InitViews(); const bool bIsWireframe = ViewFamily.EngineShowFlags.Wireframe; static const auto ClearMethodCVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.ClearSceneMethod")); bool bRequiresRHIClear = true; bool bRequiresFarZQuadClear = false; if (ClearMethodCVar) { switch (ClearMethodCVar->GetValueOnRenderThread()) { case 0: // No clear { bRequiresRHIClear = false; bRequiresFarZQuadClear = false; break; } case 1: // RHIClear { bRequiresRHIClear = true; bRequiresFarZQuadClear = false; break; } case 2: // Clear using far-z quad { bRequiresFarZQuadClear = true; bRequiresRHIClear = false; break; } } } // Always perform a full buffer clear for wireframe, shader complexity view mode, and stationary light overlap viewmode. if (bIsWireframe || ViewFamily.EngineShowFlags.ShaderComplexity || ViewFamily.EngineShowFlags.StationaryLightOverlap) { bRequiresRHIClear = true; } // force using occ queries for wireframe if rendering is parented or frozen in the first view check(Views.Num()); #if (UE_BUILD_SHIPPING || UE_BUILD_TEST) const bool bIsViewFrozen = false; const bool bHasViewParent = false; #else const bool bIsViewFrozen = Views[0].State && ((FSceneViewState*)Views[0].State)->bIsFrozen; const bool bHasViewParent = Views[0].State && ((FSceneViewState*)Views[0].State)->HasViewParent(); #endif const bool bIsOcclusionTesting = DoOcclusionQueries() && (!bIsWireframe || bIsViewFrozen || bHasViewParent); // Dynamic vertex and index buffers need to be committed before rendering. FGlobalDynamicVertexBuffer::Get().Commit(); FGlobalDynamicIndexBuffer::Get().Commit(); // Notify the FX system that the scene is about to be rendered. if (Scene->FXSystem) { Scene->FXSystem->PreRender(); } // Draw the scene pre-pass / early z pass, populating the scene depth buffer and HiZ RenderPrePass(); // Clear scene color buffer if necessary. if ( bRequiresRHIClear ) { ClearView(); // Only clear once. bRequiresRHIClear = false; } // Clear LPVs for all views if ( IsFeatureLevelSupported(GRHIShaderPlatform, ERHIFeatureLevel::SM5) ) { ClearLPVs(); } // only temporarily available after early z pass and until base pass check(!GSceneRenderTargets.DBufferA); check(!GSceneRenderTargets.DBufferB); check(!GSceneRenderTargets.DBufferC); if(IsDBufferEnabled()) { GSceneRenderTargets.ResolveSceneDepthTexture(); // Resolve the scene depth to an auxiliary texture when SM3/SM4 is in use. This needs to happen so the auxiliary texture can be bound as a shader parameter // while the primary scene depth texture can be bound as the target. Simultaneously binding a single DepthStencil resource as a parameter and target // is unsupported in d3d feature level 10. if(!(GRHIFeatureLevel >= ERHIFeatureLevel::SM5) && GRHIFeatureLevel >= ERHIFeatureLevel::SM4) { GSceneRenderTargets.ResolveSceneDepthToAuxiliaryTexture(); } // e.g. ambient cubemaps, ambient occlusion, deferred decals for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(EventView,Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex); GCompositionLighting.ProcessBeforeBasePass(Views[ViewIndex]); } } if(bIsWireframe && FDeferredShadingSceneRenderer::ShouldCompositeEditorPrimitives(Views[0])) { // In Editor we want wire frame view modes to be MSAA for better quality. Resolve will be done with EditorPrimitives RHISetRenderTarget(GSceneRenderTargets.GetEditorPrimitivesColor(), GSceneRenderTargets.GetEditorPrimitivesDepth()); RHIClear(true, FLinearColor(0, 0, 0, 0), true, 0.0f, false, 0, FIntRect()); } else { // Begin rendering to scene color GSceneRenderTargets.BeginRenderingSceneColor(true); } RenderBasePass(); if(ViewFamily.EngineShowFlags.VisualizeLightCulling) { // clear out emissive and baked lighting (not too efficient but simple and only needed for this debug view) GSceneRenderTargets.BeginRenderingSceneColor(false); RHIClear(true, FLinearColor(0, 0, 0, 0), false, 0, false, 0, FIntRect()); } GSceneRenderTargets.DBufferA.SafeRelease(); GSceneRenderTargets.DBufferB.SafeRelease(); GSceneRenderTargets.DBufferC.SafeRelease(); // only temporarily available after early z pass and until base pass check(!GSceneRenderTargets.DBufferA); check(!GSceneRenderTargets.DBufferB); check(!GSceneRenderTargets.DBufferC); if (bRequiresFarZQuadClear) { // Clears view by drawing quad at maximum Z // TODO: if all the platforms have fast color clears, we can replace this with an RHIClear. ClearGBufferAtMaxZ(); bRequiresFarZQuadClear = false; } GSceneRenderTargets.ResolveSceneColor(FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY)); GSceneRenderTargets.ResolveSceneDepthTexture(); // Resolve the scene depth to an auxiliary texture when SM3/SM4 is in use. This needs to happen so the auxiliary texture can be bound as a shader parameter // while the primary scene depth texture can be bound as the target. Simultaneously binding a single DepthStencil resource as a parameter and target // is unsupported in d3d feature level 10. if(!GSupportsDepthFetchDuringDepthTest) { GSceneRenderTargets.ResolveSceneDepthToAuxiliaryTexture(); } RenderCustomDepthPass(); // Notify the FX system that opaque primitives have been rendered and we now have a valid depth buffer. if (Scene->FXSystem && Views.IsValidIndex(0)) { Scene->FXSystem->PostRenderOpaque( Views.GetTypedData(), GSceneRenderTargets.GetSceneDepthTexture(), GSceneRenderTargets.GetGBufferATexture() ); } // Update the quarter-sized depth buffer with the current contents of the scene depth texture. // This needs to happen before occlusion tests, which makes use of the small depth buffer. UpdateDownsampledDepthSurface(); // Issue occlusion queries // This is done after the downsampled depth buffer is created so that it can be used for issuing queries if ( bIsOcclusionTesting ) { BeginOcclusionTests(); } // Render lighting. if (ViewFamily.EngineShowFlags.Lighting && GRHIFeatureLevel >= ERHIFeatureLevel::SM4 && ViewFamily.EngineShowFlags.DeferredLighting ) { // Pre-lighting composition lighting stage // e.g. deferred decals, blurred GBuffer for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(EventView,Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex); GCompositionLighting.ProcessAfterBasePass(Views[ViewIndex]); } // Clear the translucent lighting volumes before we accumulate ClearTranslucentVolumeLighting(); RenderLights(); InjectAmbientCubemapTranslucentVolumeLighting(); CompositeIndirectTranslucentVolumeLighting(); // Filter the translucency lighting volume now that it is complete FilterTranslucentVolumeLighting(); // Clear LPVs for all views if ( IsFeatureLevelSupported(GRHIShaderPlatform, ERHIFeatureLevel::SM5) ) { PropagateLPVs(); } // Render reflections that only operate on opaque pixels RenderDeferredReflections(); // Post-lighting composition lighting stage // e.g. ambient cubemaps, ambient occlusion, LPV indirect for(int32 ViewIndex = 0; ViewIndex < Views.Num(); ++ViewIndex) { SCOPED_CONDITIONAL_DRAW_EVENTF(EventView,Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex); GCompositionLighting.ProcessLighting(Views[ViewIndex]); } } if( ViewFamily.EngineShowFlags.StationaryLightOverlap && GRHIFeatureLevel >= ERHIFeatureLevel::SM4) { RenderStationaryLightOverlap(); } FLightShaftsOutput LightShaftOutput; // Draw Lightshafts if (ViewFamily.EngineShowFlags.LightShafts) { LightShaftOutput = RenderLightShaftOcclusion(); } // Draw atmosphere if(ShouldRenderAtmosphere(ViewFamily)) { if (Scene->AtmosphericFog) { // Update RenderFlag based on LightShaftTexture is valid or not if (LightShaftOutput.bRendered) { Scene->AtmosphericFog->RenderFlag &= EAtmosphereRenderFlag::E_LightShaftMask; } else { Scene->AtmosphericFog->RenderFlag |= EAtmosphereRenderFlag::E_DisableLightShaft; } #if WITH_EDITOR if (Scene->bIsEditorScene) { // Precompute Atmospheric Textures Scene->AtmosphericFog->PrecomputeTextures(Views.GetTypedData(), &ViewFamily); } #endif RenderAtmosphere(LightShaftOutput); } } // Draw fog. if(ShouldRenderFog(ViewFamily)) { RenderFog(LightShaftOutput); } // No longer needed, release LightShaftOutput.LightShaftOcclusion = NULL; // Draw translucency. if(ViewFamily.EngineShowFlags.Translucency) { SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime); if(ViewFamily.EngineShowFlags.Refraction) { // to apply refraction effect by distorting the scene color RenderDistortion(); } RenderTranslucency(); } if (ViewFamily.EngineShowFlags.LightShafts) { RenderLightShaftBloom(); } // Resolve the scene color for post processing. GSceneRenderTargets.ResolveSceneColor(FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY)); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if(CVarTestUIBlur.GetValueOnRenderThread() > 0) { Views[0].UIBlurOverrideRectangles.Add(FIntRect(20, 20, 400, 400)); } #endif // Finish rendering for each view. if(ViewFamily.bResolveScene) { SCOPED_DRAW_EVENT(FinishRendering, DEC_SCENE_ITEMS); SCOPE_CYCLE_COUNTER(STAT_FinishRenderViewTargetTime); for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(EventView, Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex); FinishRenderViewTarget(&Views[ViewIndex], ViewIndex == (Views.Num() - 1)); } } RenderFinish(); }
/** * Clears view where Z is still at the maximum value (ie no geometry rendered) */ void FDeferredShadingSceneRenderer::ClearGBufferAtMaxZ() { // Assumes BeginRenderingSceneColor() has been called before this function SCOPED_DRAW_EVENT(ClearGBufferAtMaxZ, DEC_SCENE_ITEMS); // Clear the G Buffer render targets const bool bClearBlack = Views[0].Family->EngineShowFlags.ShaderComplexity || Views[0].Family->EngineShowFlags.StationaryLightOverlap; // Same clear color from RHIClearMRT FLinearColor ClearColors[6] = {bClearBlack ? FLinearColor(0,0,0,0) : Views[0].BackgroundColor, FLinearColor(0.5f,0.5f,0.5f,0), FLinearColor(0,0,0,1), FLinearColor(0,0,0,0), FLinearColor(0,1,1,1), FLinearColor(1,1,1,1)}; uint32 NumActiveRenderTargets = GSceneRenderTargets.GetNumGBufferTargets(); TShaderMapRef<FOneColorVS> VertexShader(GetGlobalShaderMap()); FOneColorPS* PixelShader = NULL; // Assume for now all code path supports SM4, otherwise render target numbers are changed switch(NumActiveRenderTargets) { case 5: { TShaderMapRef<TOneColorPixelShaderMRT<5> > MRTPixelShader(GetGlobalShaderMap()); PixelShader = *MRTPixelShader; } break; case 6: { TShaderMapRef<TOneColorPixelShaderMRT<6> > MRTPixelShader(GetGlobalShaderMap()); PixelShader = *MRTPixelShader; } break; default: case 1: { TShaderMapRef<TOneColorPixelShaderMRT<1> > MRTPixelShader(GetGlobalShaderMap()); PixelShader = *MRTPixelShader; } break; } SetGlobalBoundShaderState(GClearMRTBoundShaderState[NumActiveRenderTargets - 1], GetVertexDeclarationFVector4(), *VertexShader, PixelShader); // Opaque rendering, depth test but no depth writes RHISetRasterizerState( TStaticRasterizerState<FM_Solid,CM_None>::GetRHI() ); RHISetBlendState(TStaticBlendStateWriteMask<>::GetRHI()); // Note, this is a reversed Z depth surface, using CF_GreaterEqual. RHISetDepthStencilState(TStaticDepthStencilState<false,CF_GreaterEqual>::GetRHI()); // Clear each viewport by drawing background color at MaxZ depth for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(EventView, Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("ClearView%d"), ViewIndex); FViewInfo& View = Views[ViewIndex]; // Set viewport for this view RHISetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1); // Setup PS SetShaderValueArray(PixelShader->GetPixelShader(),PixelShader->ColorParameter, ClearColors, NumActiveRenderTargets); // Render quad RHIDrawPrimitiveUP(PT_TriangleStrip, 2, ClearQuadVertices, sizeof(ClearQuadVertices[0]) ); } }
void FForwardShadingSceneRenderer::RenderForwardShadingBasePass() { SCOPED_DRAW_EVENT(BasePass, DEC_SCENE_ITEMS); SCOPE_CYCLE_COUNTER(STAT_BasePassDrawTime); EBasePassSort::Type SortMode = GetSortMode(); int32 MaxDraws = GMaxBasePassDraws.GetValueOnRenderThread(); if (MaxDraws <= 0) { MaxDraws = MAX_int32; } if (SortMode == EBasePassSort::SortStateBuckets) { SCOPE_CYCLE_COUNTER(STAT_SortStaticDrawLists); for (int32 DrawType = 0; DrawType < FScene::EBasePass_MAX; DrawType++) { Scene->BasePassForForwardShadingLowQualityLightMapDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); Scene->BasePassForForwardShadingNoLightMapDrawList[DrawType].SortFrontToBack(Views[0].ViewLocation); } } // Draw the scene's emissive and light-map color. for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(EventView, Views.Num() > 1, DEC_SCENE_ITEMS, TEXT("View%d"), ViewIndex); FViewInfo& View = Views[ViewIndex]; // Opaque blending RHISetBlendState(TStaticBlendStateWriteMask<CW_RGBA>::GetRHI()); // Note, this is a reversed Z depth surface, using CF_GreaterEqual. RHISetDepthStencilState(TStaticDepthStencilState<true, CF_GreaterEqual>::GetRHI()); RHISetViewport(View.ViewRect.Min.X, View.ViewRect.Min.Y, 0, View.ViewRect.Max.X, View.ViewRect.Max.Y, 1); // Render the base pass static data if (SortMode == EBasePassSort::SortPerMesh) { SCOPE_CYCLE_COUNTER(STAT_StaticDrawListDrawTime); MaxDraws -= Scene->BasePassForForwardShadingLowQualityLightMapDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingNoLightMapDrawList[FScene::EBasePass_Default].DrawVisibleFrontToBack(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); } else { SCOPE_CYCLE_COUNTER(STAT_StaticDrawListDrawTime); Scene->BasePassForForwardShadingLowQualityLightMapDrawList[FScene::EBasePass_Default].DrawVisible(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[FScene::EBasePass_Default].DrawVisible(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[FScene::EBasePass_Default].DrawVisible(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingNoLightMapDrawList[FScene::EBasePass_Default].DrawVisible(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); } { SCOPE_CYCLE_COUNTER(STAT_DynamicPrimitiveDrawTime); SCOPED_DRAW_EVENT(Dynamic, DEC_SCENE_ITEMS); if (View.VisibleDynamicPrimitives.Num() > 0) { // Draw the dynamic non-occluded primitives using a base pass drawing policy. TDynamicPrimitiveDrawer<FBasePassForwardOpaqueDrawingPolicyFactory> Drawer(&View, FBasePassForwardOpaqueDrawingPolicyFactory::ContextType(ESceneRenderTargetsMode::DontSet), true); for (int32 PrimitiveIndex = 0; PrimitiveIndex < View.VisibleDynamicPrimitives.Num(); PrimitiveIndex++) { const FPrimitiveSceneInfo* PrimitiveSceneInfo = View.VisibleDynamicPrimitives[PrimitiveIndex]; int32 PrimitiveId = PrimitiveSceneInfo->GetIndex(); const FPrimitiveViewRelevance& PrimitiveViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId]; const bool bVisible = View.PrimitiveVisibilityMap[PrimitiveId]; // Only draw the primitive if it's visible if (bVisible && // only draw opaque and masked primitives if wireframe is disabled (PrimitiveViewRelevance.bOpaqueRelevance || ViewFamily.EngineShowFlags.Wireframe)) { FScopeCycleCounter Context(PrimitiveSceneInfo->Proxy->GetStatId()); Drawer.SetPrimitive(PrimitiveSceneInfo->Proxy); PrimitiveSceneInfo->Proxy->DrawDynamicElements(&Drawer, &View); } } } const bool bNeedToSwitchVerticalAxis = IsES2Platform(GRHIShaderPlatform) && !IsPCPlatform(GRHIShaderPlatform); // Draw the base pass for the view's batched mesh elements. DrawViewElements<FBasePassForwardOpaqueDrawingPolicyFactory>(View,FBasePassForwardOpaqueDrawingPolicyFactory::ContextType(ESceneRenderTargetsMode::DontSet), SDPG_World, true); // Draw the view's batched simple elements(lines, sprites, etc). View.BatchedViewElements.Draw(bNeedToSwitchVerticalAxis, View.ViewProjectionMatrix, View.ViewRect.Width(), View.ViewRect.Height(), false); // Draw foreground objects last DrawViewElements<FBasePassForwardOpaqueDrawingPolicyFactory>(View,FBasePassForwardOpaqueDrawingPolicyFactory::ContextType(ESceneRenderTargetsMode::DontSet), SDPG_Foreground, true); // Draw the view's batched simple elements(lines, sprites, etc). View.TopBatchedViewElements.Draw(bNeedToSwitchVerticalAxis, View.ViewProjectionMatrix, View.ViewRect.Width(), View.ViewRect.Height(), false); } // Issue static draw list masked draw calls last, as PVR wants it if (SortMode == EBasePassSort::SortPerMesh) { SCOPE_CYCLE_COUNTER(STAT_StaticDrawListDrawTime); MaxDraws -= Scene->BasePassForForwardShadingNoLightMapDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingLowQualityLightMapDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); MaxDraws -= Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[FScene::EBasePass_Masked].DrawVisibleFrontToBack(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility,MaxDraws); } else { SCOPE_CYCLE_COUNTER(STAT_StaticDrawListDrawTime); Scene->BasePassForForwardShadingNoLightMapDrawList[FScene::EBasePass_Masked].DrawVisible(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingLowQualityLightMapDrawList[FScene::EBasePass_Masked].DrawVisible(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingDistanceFieldShadowMapLightMapDrawList[FScene::EBasePass_Masked].DrawVisible(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); Scene->BasePassForForwardShadingDirectionalLightAndSHIndirectDrawList[FScene::EBasePass_Masked].DrawVisible(View,View.StaticMeshVisibilityMap,View.StaticMeshBatchVisibility); } } }
/** * Renders the view family. */ void FForwardShadingSceneRenderer::Render(FRHICommandListImmediate& RHICmdList) { if(!ViewFamily.EngineShowFlags.Rendering) { return; } auto FeatureLevel = ViewFamily.GetFeatureLevel(); // Initialize global system textures (pass-through if already initialized). GSystemTextures.InitializeTextures(RHICmdList, FeatureLevel); // Allocate the maximum scene render target space for the current view family. GSceneRenderTargets.Allocate(ViewFamily); // Find the visible primitives. InitViews(RHICmdList); RenderShadowDepthMaps(RHICmdList); // Notify the FX system that the scene is about to be rendered. if (Scene->FXSystem) { Scene->FXSystem->PreRender(RHICmdList); } GRenderTargetPool.VisualizeTexture.OnStartFrame(Views[0]); // Dynamic vertex and index buffers need to be committed before rendering. FGlobalDynamicVertexBuffer::Get().Commit(); FGlobalDynamicIndexBuffer::Get().Commit(); // This might eventually be a problem with multiple views. // Using only view 0 to check to do on-chip transform of alpha. FViewInfo& View = Views[0]; const bool bGammaSpace = !IsMobileHDR(); const bool bRequiresUpscale = ((uint32)ViewFamily.RenderTarget->GetSizeXY().X > ViewFamily.FamilySizeX || (uint32)ViewFamily.RenderTarget->GetSizeXY().Y > ViewFamily.FamilySizeY); const bool bRenderToScene = bRequiresUpscale || FSceneRenderer::ShouldCompositeEditorPrimitives(View); if (bGammaSpace && !bRenderToScene) { SetRenderTarget(RHICmdList, ViewFamily.RenderTarget->GetRenderTargetTexture(), GSceneRenderTargets.GetSceneDepthTexture(), ESimpleRenderTargetMode::EClearToDefault); } else { // Begin rendering to scene color GSceneRenderTargets.BeginRenderingSceneColor(RHICmdList, ESimpleRenderTargetMode::EClearToDefault); } if (GIsEditor) { RHICmdList.Clear(true, Views[0].BackgroundColor, false, 0, false, 0, FIntRect()); } RenderForwardShadingBasePass(RHICmdList); // Make a copy of the scene depth if the current hardware doesn't support reading and writing to the same depth buffer GSceneRenderTargets.ResolveSceneDepthToAuxiliaryTexture(RHICmdList); // Notify the FX system that opaque primitives have been rendered. if (Scene->FXSystem) { Scene->FXSystem->PostRenderOpaque(RHICmdList); } // Draw translucency. if (ViewFamily.EngineShowFlags.Translucency) { SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime); // Note: Forward pass has no SeparateTranslucency, so refraction effect order with Transluency is different. // Having the distortion applied between two different translucency passes would make it consistent with the deferred pass. // This is not done yet. if (ViewFamily.EngineShowFlags.Refraction) { // to apply refraction effect by distorting the scene color RenderDistortion(RHICmdList); } RenderTranslucency(RHICmdList); } static const auto CVarMobileMSAA = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileMSAA")); bool bOnChipSunMask = GSupportsRenderTargetFormat_PF_FloatRGBA && GSupportsShaderFramebufferFetch && ViewFamily.EngineShowFlags.PostProcessing && ((View.bLightShaftUse) || (View.FinalPostProcessSettings.DepthOfFieldScale > 0.0) || ((ViewFamily.GetShaderPlatform() == SP_METAL) && (CVarMobileMSAA ? CVarMobileMSAA->GetValueOnAnyThread() > 1 : false)) ); if (!bGammaSpace && bOnChipSunMask) { // Convert alpha from depth to circle of confusion with sunshaft intensity. // This is done before resolve on hardware with framebuffer fetch. // This will break when PrePostSourceViewportSize is not full size. FIntPoint PrePostSourceViewportSize = GSceneRenderTargets.GetBufferSizeXY(); FMemMark Mark(FMemStack::Get()); FRenderingCompositePassContext CompositeContext(RHICmdList, View); FRenderingCompositePass* PostProcessSunMask = CompositeContext.Graph.RegisterPass(new(FMemStack::Get()) FRCPassPostProcessSunMaskES2(PrePostSourceViewportSize, true)); CompositeContext.Root->AddDependency(FRenderingCompositeOutputRef(PostProcessSunMask)); CompositeContext.Process(TEXT("OnChipAlphaTransform")); } if (!bGammaSpace || bRenderToScene) { // Resolve the scene color for post processing. GSceneRenderTargets.ResolveSceneColor(RHICmdList, FResolveRect(0, 0, ViewFamily.FamilySizeX, ViewFamily.FamilySizeY)); // Drop depth and stencil before post processing to avoid export. RHICmdList.DiscardRenderTargets(true, true, 0); } if (!bGammaSpace) { // Finish rendering for each view, or the full stereo buffer if enabled if (ViewFamily.bResolveScene) { if (ViewFamily.EngineShowFlags.StereoRendering) { check(Views.Num() > 1); //@todo ES2 stereo post: until we get proper stereo postprocessing for ES2, process the stereo buffer as one view FIntPoint OriginalMax0 = Views[0].ViewRect.Max; Views[0].ViewRect.Max = Views[1].ViewRect.Max; GPostProcessing.ProcessES2(RHICmdList, Views[0], bOnChipSunMask); Views[0].ViewRect.Max = OriginalMax0; } else { SCOPED_DRAW_EVENT(RHICmdList, PostProcessing); SCOPE_CYCLE_COUNTER(STAT_FinishRenderViewTargetTime); for(int32 ViewIndex = 0;ViewIndex < Views.Num();ViewIndex++) { SCOPED_CONDITIONAL_DRAW_EVENTF(RHICmdList, EventView, Views.Num() > 1, TEXT("View%d"), ViewIndex); GPostProcessing.ProcessES2(RHICmdList, Views[ViewIndex], bOnChipSunMask); } } } } else if (bRenderToScene) { BasicPostProcess(RHICmdList, View, bRequiresUpscale, FSceneRenderer::ShouldCompositeEditorPrimitives(View)); } RenderFinish(RHICmdList); }