175 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			175 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								---
							 | 
						|||
| 
								 | 
							
								title: UE的透明渲染功能笔记
							 | 
						|||
| 
								 | 
							
								date: 2022-10-30 21:36:08
							 | 
						|||
| 
								 | 
							
								excerpt: 
							 | 
						|||
| 
								 | 
							
								tags: Rendering
							 | 
						|||
| 
								 | 
							
								rating: ⭐
							 | 
						|||
| 
								 | 
							
								---
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								其主函数为FDeferredShadingSceneRenderer::RenderTranslucency(),位于FXSystem与头发合成之后,渲染Distortion、速度之前。
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								// Draw translucency.  
							 | 
						|||
| 
								 | 
							
								   if (bCanOverlayRayTracingOutput && TranslucencyViewsToRender != ETranslucencyView::None)  
							 | 
						|||
| 
								 | 
							
								   {      RDG_CSV_STAT_EXCLUSIVE_SCOPE(GraphBuilder, RenderTranslucency);  
							 | 
						|||
| 
								 | 
							
								      SCOPE_CYCLE_COUNTER(STAT_TranslucencyDrawTime);  
							 | 
						|||
| 
								 | 
							
								  
							 | 
						|||
| 
								 | 
							
								      // Raytracing doesn't need the distortion effect.  
							 | 
						|||
| 
								 | 
							
								      const bool bShouldRenderDistortion = TranslucencyViewsToRender != ETranslucencyView::RayTracing;  
							 | 
						|||
| 
								 | 
							
								  
							 | 
						|||
| 
								 | 
							
								#if RHI_RAYTRACING  
							 | 
						|||
| 
								 | 
							
								      if (EnumHasAnyFlags(TranslucencyViewsToRender, ETranslucencyView::RayTracing))  
							 | 
						|||
| 
								 | 
							
								      {         RenderRayTracingTranslucency(GraphBuilder, SceneColorTexture);  
							 | 
						|||
| 
								 | 
							
								         EnumRemoveFlags(TranslucencyViewsToRender, ETranslucencyView::RayTracing);  
							 | 
						|||
| 
								 | 
							
								      }#endif  
							 | 
						|||
| 
								 | 
							
								  
							 | 
						|||
| 
								 | 
							
								      // Render all remaining translucency views.  
							 | 
						|||
| 
								 | 
							
								      AddSetCurrentStatPass(GraphBuilder, GET_STATID(STAT_CLM_Translucency));  
							 | 
						|||
| 
								 | 
							
								      RenderTranslucency(GraphBuilder, SceneColorTexture, SceneDepthTexture, HairDatas, &SeparateTranslucencyTextures, TranslucencyViewsToRender);  
							 | 
						|||
| 
								 | 
							
								      AddServiceLocalQueuePass(GraphBuilder);  
							 | 
						|||
| 
								 | 
							
								      TranslucencyViewsToRender = ETranslucencyView::None;
							 | 
						|||
| 
								 | 
							
									...
							 | 
						|||
| 
								 | 
							
								   }
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## Pass Event String
							 | 
						|||
| 
								 | 
							
								static const TCHAR* TranslucencyPassToString(ETranslucencyPass::Type TranslucencyPass)  
							 | 
						|||
| 
								 | 
							
								{  
							 | 
						|||
| 
								 | 
							
								   switch (TranslucencyPass)  
							 | 
						|||
| 
								 | 
							
								   {   case ETranslucencyPass::TPT_StandardTranslucency:  
							 | 
						|||
| 
								 | 
							
								      return TEXT("Standard");  
							 | 
						|||
| 
								 | 
							
								   case ETranslucencyPass::TPT_TranslucencyAfterDOF:  
							 | 
						|||
| 
								 | 
							
								      return TEXT("AfterDOF");  
							 | 
						|||
| 
								 | 
							
								   case ETranslucencyPass::TPT_TranslucencyAfterDOFModulate:  
							 | 
						|||
| 
								 | 
							
								      return TEXT("AfterDOFModulate");  
							 | 
						|||
| 
								 | 
							
								   case ETranslucencyPass::TPT_AllTranslucency:  
							 | 
						|||
| 
								 | 
							
								      return TEXT("All");  
							 | 
						|||
| 
								 | 
							
								   }   checkNoEntry();  
							 | 
						|||
| 
								 | 
							
								   return TEXT("");  
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 
							 | 
						|||
| 
								 | 
							
								半透明渲染分为可分离与单Pass渲染。
							 | 
						|||
| 
								 | 
							
								- 可分离渲染调用RenderViewTranslucencyInner()渲染内部,之后调用AddEndSeparateTranslucencyTimerPass()完成渲染。
							 | 
						|||
| 
								 | 
							
								- 单Pass渲染完所有物体。调用RenderViewTranslucencyInner()渲染内部,之后调用AddEndSeparateTranslucencyTimerPass()完成渲染。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								Shader变量使用FTranslucentBasePassParameters。
							 | 
						|||
| 
								 | 
							
								MeshDrawPass名为。
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								EMeshPass::TranslucencyStandard
							 | 
						|||
| 
								 | 
							
								EMeshPass::TranslucencyAfterDOF
							 | 
						|||
| 
								 | 
							
								EMeshPass::TranslucencyAfterDOFModulate
							 | 
						|||
| 
								 | 
							
								EMeshPass::TranslucencyAfterMotionBlur
							 | 
						|||
| 
								 | 
							
								EMeshPass::TranslucencyAll
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								最后在AddPass()调用RenderViewTranslucencyInner()进行实际MeshDraw渲染:
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
									if (bRenderInParallel)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										GraphBuilder.AddPass(
							 | 
						|||
| 
								 | 
							
											RDG_EVENT_NAME("Translucency(%s Parallel) %dx%d",
							 | 
						|||
| 
								 | 
							
												TranslucencyPassToString(TranslucencyPass),
							 | 
						|||
| 
								 | 
							
												int32(View.ViewRect.Width() * ViewportScale),
							 | 
						|||
| 
								 | 
							
												int32(View.ViewRect.Height() * ViewportScale)),
							 | 
						|||
| 
								 | 
							
											PassParameters,
							 | 
						|||
| 
								 | 
							
											ERDGPassFlags::Raster | ERDGPassFlags::SkipRenderPass,
							 | 
						|||
| 
								 | 
							
											[&SceneRenderer, &View, PassParameters, ViewportScale, Viewport, TranslucencyPass](FRHICommandListImmediate& RHICmdList)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											FRDGParallelCommandListSet ParallelCommandListSet(RHICmdList, GET_STATID(STAT_CLP_Translucency), SceneRenderer, View, FParallelCommandListBindings(PassParameters), ViewportScale);
							 | 
						|||
| 
								 | 
							
											RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, &ParallelCommandListSet, PassParameters->InstanceCullingDrawParams);
							 | 
						|||
| 
								 | 
							
										});
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									else
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										GraphBuilder.AddPass(
							 | 
						|||
| 
								 | 
							
											RDG_EVENT_NAME("Translucency(%s) %dx%d",
							 | 
						|||
| 
								 | 
							
												TranslucencyPassToString(TranslucencyPass),
							 | 
						|||
| 
								 | 
							
												int32(View.ViewRect.Width() * ViewportScale),
							 | 
						|||
| 
								 | 
							
												int32(View.ViewRect.Height() * ViewportScale)),
							 | 
						|||
| 
								 | 
							
											PassParameters,
							 | 
						|||
| 
								 | 
							
											ERDGPassFlags::Raster,
							 | 
						|||
| 
								 | 
							
											[&SceneRenderer, &View, ViewportScale, Viewport, TranslucencyPass, PassParameters](FRHICommandListImmediate& RHICmdList)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											RenderViewTranslucencyInner(RHICmdList, SceneRenderer, View, Viewport, ViewportScale, TranslucencyPass, nullptr, PassParameters->InstanceCullingDrawParams);
							 | 
						|||
| 
								 | 
							
										});
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								最后使用FBasePassMeshProcessor。
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								DrawDynamicMeshPass(View, RHICmdList,  
							 | 
						|||
| 
								 | 
							
								   [&View, &DrawRenderState, TranslucencyPass](FDynamicPassMeshDrawListContext* DynamicMeshPassContext)  
							 | 
						|||
| 
								 | 
							
								{  
							 | 
						|||
| 
								 | 
							
								   FBasePassMeshProcessor PassMeshProcessor(  
							 | 
						|||
| 
								 | 
							
								      View.Family->Scene->GetRenderScene(),  
							 | 
						|||
| 
								 | 
							
								      View.GetFeatureLevel(),  
							 | 
						|||
| 
								 | 
							
								      &View,  
							 | 
						|||
| 
								 | 
							
								      DrawRenderState,  
							 | 
						|||
| 
								 | 
							
								      DynamicMeshPassContext,  
							 | 
						|||
| 
								 | 
							
								      FBasePassMeshProcessor::EFlags::CanUseDepthStencil,  
							 | 
						|||
| 
								 | 
							
								      TranslucencyPass);  
							 | 
						|||
| 
								 | 
							
								  
							 | 
						|||
| 
								 | 
							
								   const uint64 DefaultBatchElementMask = ~0ull;  
							 | 
						|||
| 
								 | 
							
								  
							 | 
						|||
| 
								 | 
							
								   for (int32 MeshIndex = 0; MeshIndex < View.ViewMeshElements.Num(); MeshIndex++)  
							 | 
						|||
| 
								 | 
							
								   {      const FMeshBatch& MeshBatch = View.ViewMeshElements[MeshIndex];  
							 | 
						|||
| 
								 | 
							
								      PassMeshProcessor.AddMeshBatch(MeshBatch, DefaultBatchElementMask, nullptr);  
							 | 
						|||
| 
								 | 
							
								   }});
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 透明物体判断
							 | 
						|||
| 
								 | 
							
								IsTranslucentBlendMode()位于MaterialShared.h:
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								inline bool IsTranslucentBlendMode(enum EBlendMode BlendMode)  
							 | 
						|||
| 
								 | 
							
								{  
							 | 
						|||
| 
								 | 
							
								   return BlendMode != BLEND_Opaque && BlendMode != BLEND_Masked;  
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								位于`bool FBasePassMeshProcessor::ShouldDraw(const FMaterial& Material)`
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								const bool bIsTranslucent = IsTranslucentBlendMode(BlendMode);
							 | 
						|||
| 
								 | 
							
								if (bTranslucentBasePass)  
							 | 
						|||
| 
								 | 
							
								{  
							 | 
						|||
| 
								 | 
							
								   if (bIsTranslucent && !Material.IsDeferredDecal())  
							 | 
						|||
| 
								 | 
							
								   {      
							 | 
						|||
| 
								 | 
							
									  switch (TranslucencyPassType)  
							 | 
						|||
| 
								 | 
							
								      {      
							 | 
						|||
| 
								 | 
							
								      case ETranslucencyPass::TPT_StandardTranslucency:  
							 | 
						|||
| 
								 | 
							
								         bShouldDraw = !Material.IsTranslucencyAfterDOFEnabled();  
							 | 
						|||
| 
								 | 
							
								         break;  
							 | 
						|||
| 
								 | 
							
								  
							 | 
						|||
| 
								 | 
							
								      case ETranslucencyPass::TPT_TranslucencyAfterDOF:  
							 | 
						|||
| 
								 | 
							
								         bShouldDraw = Material.IsTranslucencyAfterDOFEnabled();  
							 | 
						|||
| 
								 | 
							
								         break;  
							 | 
						|||
| 
								 | 
							
								  
							 | 
						|||
| 
								 | 
							
								      // only dual blended or modulate surfaces need background modulation  
							 | 
						|||
| 
								 | 
							
								      case ETranslucencyPass::TPT_TranslucencyAfterDOFModulate:  
							 | 
						|||
| 
								 | 
							
								         bShouldDraw = Material.IsTranslucencyAfterDOFEnabled() && (Material.IsDualBlendingEnabled(GetFeatureLevelShaderPlatform(FeatureLevel)) || BlendMode == BLEND_Modulate);  
							 | 
						|||
| 
								 | 
							
								         break;  
							 | 
						|||
| 
								 | 
							
								  
							 | 
						|||
| 
								 | 
							
								      case ETranslucencyPass::TPT_AllTranslucency:  
							 | 
						|||
| 
								 | 
							
								         bShouldDraw = true;  
							 | 
						|||
| 
								 | 
							
								         break;  
							 | 
						|||
| 
								 | 
							
								      }        
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## 为什么MultiDraw无法同时渲染透明与不透明材质
							 | 
						|||
| 
								 | 
							
								首先透明会使用FBasePassMeshProcessor进行渲染(不同BasePass会有不同的设置),针对图元创建MeshProcessor时是以每个图元为单位进行的。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								void FMaterialRenderProxy::UpdateUniformExpressionCacheIfNeeded(ERHIFeatureLevel::Type InFeatureLevel) const  
							 | 
						|||
| 
								 | 
							
								{  
							 | 
						|||
| 
								 | 
							
								   if (!UniformExpressionCache[InFeatureLevel].bUpToDate)  
							 | 
						|||
| 
								 | 
							
								   {      // Don't cache uniform expressions if an entirely different FMaterialRenderProxy is going to be used for rendering  
							 | 
						|||
| 
								 | 
							
								      const FMaterial* Material = GetMaterialNoFallback(InFeatureLevel);  
							 | 
						|||
| 
								 | 
							
								      if (Material)  
							 | 
						|||
| 
								 | 
							
								      {         FMaterialRenderContext MaterialRenderContext(this, *Material, nullptr);  
							 | 
						|||
| 
								 | 
							
								         MaterialRenderContext.bShowSelection = GIsEditor;  
							 | 
						|||
| 
								 | 
							
								         EvaluateUniformExpressions(UniformExpressionCache[InFeatureLevel], MaterialRenderContext);  
							 | 
						|||
| 
								 | 
							
								      }   
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 |