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);  
 | 
						||
      }   
 | 
						||
	}
 | 
						||
}
 | 
						||
``` |