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