BlueRoseNote/03-UnrealEngine/Rendering/Shader/UE的透明渲染功能笔记.md
2023-06-29 11:55:02 +08:00

175 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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