// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. /*============================================================================= ForwardTranslucentRendering.cpp: translucent rendering implementation. =============================================================================*/ #include "RendererPrivate.h" #include "ScenePrivate.h" #include "ScreenRendering.h" #include "SceneFilterRendering.h" #include "SceneUtils.h" /** Pixel shader used to copy scene color into another texture so that materials can read from scene color with a node. */ class FForwardCopySceneAlphaPS : public FGlobalShader { DECLARE_SHADER_TYPE(FForwardCopySceneAlphaPS,Global); public: static bool ShouldCache(EShaderPlatform Platform) { return true; } FForwardCopySceneAlphaPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer): FGlobalShader(Initializer) { SceneTextureParameters.Bind(Initializer.ParameterMap); } FForwardCopySceneAlphaPS() {} void SetParameters(FRHICommandList& RHICmdList, const FSceneView& View) { SceneTextureParameters.Set(RHICmdList, GetPixelShader(), View); } virtual bool Serialize(FArchive& Ar) override { bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar); Ar << SceneTextureParameters; return bShaderHasOutdatedParameters; } private: FSceneTextureShaderParameters SceneTextureParameters; }; IMPLEMENT_SHADER_TYPE(,FForwardCopySceneAlphaPS,TEXT("TranslucentLightingShaders"),TEXT("CopySceneAlphaMain"),SF_Pixel); FGlobalBoundShaderState ForwardCopySceneAlphaBoundShaderState; void FForwardShadingSceneRenderer::CopySceneAlpha(FRHICommandListImmediate& RHICmdList, const FViewInfo& View) { SCOPED_DRAW_EVENTF(RHICmdList, EventCopy, TEXT("CopySceneAlpha")); RHICmdList.SetRasterizerState(TStaticRasterizerState::GetRHI()); RHICmdList.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI()); GSceneRenderTargets.ResolveSceneColor(RHICmdList); GSceneRenderTargets.BeginRenderingSceneAlphaCopy(RHICmdList); int X = GSceneRenderTargets.GetBufferSizeXY().X; int Y = GSceneRenderTargets.GetBufferSizeXY().Y; RHICmdList.SetViewport(0, 0, 0.0f, X, Y, 1.0f); TShaderMapRef ScreenVertexShader(View.ShaderMap); TShaderMapRef PixelShader(View.ShaderMap); SetGlobalBoundShaderState(RHICmdList, FeatureLevel, ForwardCopySceneAlphaBoundShaderState, GFilterVertexDeclaration.VertexDeclarationRHI, *ScreenVertexShader, *PixelShader); PixelShader->SetParameters(RHICmdList, View); DrawRectangle( RHICmdList, 0, 0, X, Y, 0, 0, X, Y, FIntPoint(X, Y), GSceneRenderTargets.GetBufferSizeXY(), *ScreenVertexShader, EDRF_UseTriangleOptimization); GSceneRenderTargets.FinishRenderingSceneAlphaCopy(RHICmdList); } /** The parameters used to draw a translucent mesh. */ class FDrawTranslucentMeshForwardShadingAction { public: const FViewInfo& View; bool bBackFace; float DitheredLODTransitionValue; FHitProxyId HitProxyId; /** Initialization constructor. */ FDrawTranslucentMeshForwardShadingAction( const FViewInfo& InView, bool bInBackFace, float InDitheredLODTransitionValue, FHitProxyId InHitProxyId ): View(InView), bBackFace(bInBackFace), DitheredLODTransitionValue(InDitheredLODTransitionValue), HitProxyId(InHitProxyId) {} inline bool ShouldPackAmbientSH() const { // So shader code can read a single constant to get the ambient term return true; } const FLightSceneInfo* GetSimpleDirectionalLight() const { return ((FScene*)View.Family->Scene)->SimpleDirectionalLight; } /** Draws the translucent mesh with a specific light-map type, and fog volume type */ template void Process( FRHICommandList& RHICmdList, const FProcessBasePassMeshParameters& Parameters, const LightMapPolicyType& LightMapPolicy, const typename LightMapPolicyType::ElementDataType& LightMapElementData ) const { const bool bIsLitMaterial = Parameters.ShadingModel != MSM_Unlit; const FScene* Scene = Parameters.PrimitiveSceneProxy ? Parameters.PrimitiveSceneProxy->GetPrimitiveSceneInfo()->Scene : NULL; TBasePassForForwardShadingDrawingPolicy DrawingPolicy( Parameters.Mesh.VertexFactory, Parameters.Mesh.MaterialRenderProxy, *Parameters.Material, LightMapPolicy, Parameters.BlendMode, Parameters.TextureMode, Parameters.ShadingModel != MSM_Unlit && Scene && Scene->ShouldRenderSkylight(), View.Family->EngineShowFlags.ShaderComplexity, View.GetFeatureLevel() ); RHICmdList.BuildAndSetLocalBoundShaderState(DrawingPolicy.GetBoundShaderStateInput(View.GetFeatureLevel())); DrawingPolicy.SetSharedState(RHICmdList, &View, typename TBasePassForForwardShadingDrawingPolicy::ContextDataType()); for (int32 BatchElementIndex = 0; BatchElementIndex::ElementDataType(LightMapElementData), typename TBasePassForForwardShadingDrawingPolicy::ContextDataType() ); DrawingPolicy.DrawMesh(RHICmdList, Parameters.Mesh, BatchElementIndex); } } }; /** * Render a dynamic mesh using a translucent draw policy * @return true if the mesh rendered */ bool FTranslucencyForwardShadingDrawingPolicyFactory::DrawDynamicMesh( FRHICommandList& RHICmdList, const FViewInfo& View, ContextType DrawingContext, const FMeshBatch& Mesh, bool bBackFace, bool bPreFog, const FPrimitiveSceneProxy* PrimitiveSceneProxy, FHitProxyId HitProxyId ) { bool bDirty = false; // Determine the mesh's material and blend mode. const auto FeatureLevel = View.GetFeatureLevel(); const auto ShaderPlatform = View.GetShaderPlatform(); const FMaterial* Material = Mesh.MaterialRenderProxy->GetMaterial(FeatureLevel); const EBlendMode BlendMode = Material->GetBlendMode(); // Only render translucent materials. if (IsTranslucentBlendMode(BlendMode)) { const bool bDisableDepthTest = Material->ShouldDisableDepthTest(); if (bDisableDepthTest) { RHICmdList.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); } ProcessBasePassMeshForForwardShading( RHICmdList, FProcessBasePassMeshParameters( Mesh, Material, PrimitiveSceneProxy, true, false, ESceneRenderTargetsMode::SetTextures, FeatureLevel ), FDrawTranslucentMeshForwardShadingAction( View, bBackFace, Mesh.DitheredLODTransitionAlpha, HitProxyId ) ); if (bDisableDepthTest) { // Restore default depth state RHICmdList.SetDepthStencilState(TStaticDepthStencilState::GetRHI()); } bDirty = true; } return bDirty; } /** * Render a static mesh using a translucent draw policy * @return true if the mesh rendered */ bool FTranslucencyForwardShadingDrawingPolicyFactory::DrawStaticMesh( FRHICommandList& RHICmdList, const FViewInfo& View, ContextType DrawingContext, const FStaticMesh& StaticMesh, bool bPreFog, const FPrimitiveSceneProxy* PrimitiveSceneProxy, FHitProxyId HitProxyId ) { bool bDirty = false; const FMaterial* Material = StaticMesh.MaterialRenderProxy->GetMaterial(View.GetFeatureLevel()); bDirty |= DrawDynamicMesh( RHICmdList, View, DrawingContext, StaticMesh, false, bPreFog, PrimitiveSceneProxy, HitProxyId ); return bDirty; } /*----------------------------------------------------------------------------- FTranslucentPrimSet -----------------------------------------------------------------------------*/ void FTranslucentPrimSet::DrawPrimitivesForForwardShading(FRHICommandListImmediate& RHICmdList, const FViewInfo& View, FSceneRenderer& Renderer) const { // Draw sorted scene prims for (int32 PrimIdx = 0; PrimIdx < SortedPrims.Num(); PrimIdx++) { FPrimitiveSceneInfo* PrimitiveSceneInfo = SortedPrims[PrimIdx].PrimitiveSceneInfo; int32 PrimitiveId = PrimitiveSceneInfo->GetIndex(); const FPrimitiveViewRelevance& ViewRelevance = View.PrimitiveViewRelevanceMap[PrimitiveId]; checkSlow(ViewRelevance.HasTranslucency()); if(ViewRelevance.bDrawRelevance) { FTranslucencyForwardShadingDrawingPolicyFactory::ContextType Context; //@todo parallelrendering - come up with a better way to filter these by primitive for (int32 MeshBatchIndex = 0; MeshBatchIndex < View.DynamicMeshElements.Num(); MeshBatchIndex++) { const FMeshBatchAndRelevance& MeshBatchAndRelevance = View.DynamicMeshElements[MeshBatchIndex]; if (MeshBatchAndRelevance.PrimitiveSceneProxy == PrimitiveSceneInfo->Proxy) { const FMeshBatch& MeshBatch = *MeshBatchAndRelevance.Mesh; FTranslucencyForwardShadingDrawingPolicyFactory::DrawDynamicMesh(RHICmdList, View, Context, MeshBatch, false, false, MeshBatchAndRelevance.PrimitiveSceneProxy, MeshBatch.BatchHitProxyId); } } // Render static scene prim if( ViewRelevance.bStaticRelevance ) { // Render static meshes from static scene prim for( int32 StaticMeshIdx=0; StaticMeshIdx < PrimitiveSceneInfo->StaticMeshes.Num(); StaticMeshIdx++ ) { FStaticMesh& StaticMesh = PrimitiveSceneInfo->StaticMeshes[StaticMeshIdx]; if (View.StaticMeshVisibilityMap[StaticMesh.Id] // Only render static mesh elements using translucent materials && StaticMesh.IsTranslucent(View.GetFeatureLevel()) ) { FTranslucencyForwardShadingDrawingPolicyFactory::DrawStaticMesh( RHICmdList, View, FTranslucencyForwardShadingDrawingPolicyFactory::ContextType(), StaticMesh, false, PrimitiveSceneInfo->Proxy, StaticMesh.BatchHitProxyId ); } } } } } View.SimpleElementCollector.DrawBatchedElements(RHICmdList, View, FTexture2DRHIRef(), EBlendModeFilter::Translucent); } 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. RHICmdList.SetDepthStencilState(TStaticDepthStencilState::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(RHICmdList, View, FTranslucencyForwardShadingDrawingPolicyFactory::ContextType(), SDPG_World, false); // Draw the view's mesh elements with the translucent drawing policy. DrawViewElements(RHICmdList, View, FTranslucencyForwardShadingDrawingPolicyFactory::ContextType(), SDPG_Foreground, false); } } }