vault backup: 2024-09-25 17:05:44

This commit is contained in:
BlueRose 2024-09-25 17:05:44 +08:00
parent 062b7f69e4
commit df97e02338
4 changed files with 57 additions and 156 deletions

View File

@ -1 +1 @@
{"TODO清单":{"TODO清单":{"internalLink":{"count":1,"lastUpdated":1724606531953}}},"婚礼布置2W。老妈去谈。":{"婚礼布置2W。老妈去谈。":{"currentFile":{"count":1,"lastUpdated":1725803390742}}},"如下所示:":{"如下所示:":{"currentFile":{"count":1,"lastUpdated":1725940732272}}},"剩下8通道":{"剩下8通道":{"currentFile":{"count":1,"lastUpdated":1726629297275}}}}
{"婚礼布置2W。老妈去谈。":{"婚礼布置2W。老妈去谈。":{"currentFile":{"count":1,"lastUpdated":1725803390742}}},"如下所示:":{"如下所示:":{"currentFile":{"count":1,"lastUpdated":1725940732272}}},"剩下8通道":{"剩下8通道":{"currentFile":{"count":1,"lastUpdated":1726629297275}}},"根据bComputeExport分别使用RDG的ComputeShader与PixelShader输出DepthStencil。":{"根据bComputeExport分别使用RDG的ComputeShader与PixelShader输出DepthStencil。":{"currentFile":{"count":1,"lastUpdated":1727249472660}}}}

View File

@ -24,6 +24,10 @@ PS. **开启DX12后无法通过Renderdoc进行单步调试**,此时可以考
- UE5使用PIX单步调试DX12环境下的Shader https://zhuanlan.zhihu.com/p/654935138
pix的单步调试需要开启**开发者模式**具体是在window的设置 - 开发者选项 - **开发人员设置**
## 抓帧技巧
- [RenderDoc抓帧steam平台](https://zhuanlan.zhihu.com/p/721764908)
# UE相关设置
开启Renderdoc的PixelDebug功能
![](https://cdn.jsdelivr.net/gh/blueroseslol/ImageBag@latest/ImageBag/Images/20220930121129.png)

View File

@ -0,0 +1,52 @@
---
title: Untitled
date: 2024-09-25 14:59:32
excerpt:
tags:
rating: ⭐
---
# 前言
可以使用DrawDynamicMeshPass()实现在插件中使用MeshDraw绘制Pass。
参考文章:
- ***UE5为HairStrands添加自定义深度与模板***:https://zhuanlan.zhihu.com/p/689578355
# NaniteMeshDraw
`Engine\Source\Runtime\Renderer\Private\Nanite\`NaniteMaterials.h & NaniteMaterials.cpp
PS.使用的Shader必须是`FNaniteGlobalShader`的子类。
## BasePass
### DrawBasePass()
该函数在FDeferredShadingSceneRenderer::RenderBasePassInternal()中调用。
## DepthStencil
### InitCustomDepthStencilContext()
根据当前平台是否支持使用ComputeShader直接输出结果bComputeExport、以及是否写入Stencil缓存以此来创建不同的资源。最终输出FCustomDepthContext。
```c++
struct FCustomDepthContext
{
FRDGTextureRef InputDepth = nullptr;
FRDGTextureSRVRef InputStencilSRV = nullptr;
FRDGTextureRef DepthTarget = nullptr;
FRDGTextureRef StencilTarget = nullptr;
bool bComputeExport = true;
};
```
### EmitCustomDepthStencilTargets()
根据bComputeExport分别使用RDG的ComputeShader与PixelShader输出DepthStencil。
- CS使用FComputeShaderUtils::AddPass()
- PS使用NaniteExportGBuffer.usf的**EmitCustomDepthStencilPS()**FPixelShaderUtils::AddFullscreenPass()
以**FEmitCustomDepthStencilPS**(NaniteExportGBuffer.usf)为例额外输入的Nanite相关变量
- FSceneUniformParameters Scene
- StructuredBuffer`<`FPackedView`>` InViews
- ByteAddressBuffer VisibleClustersSWHW
- FIntVector4, PageConstants
- Texture2D`<`UlongType`>`, VisBuffer64
- ByteAddressBuffer MaterialSlotTable
### FinalizeCustomDepthStencil()
替换输出的Depth&Stencil。

View File

@ -1,155 +0,0 @@
# MeshDraw学习笔记
## 前言
源码版4.27.0
参考文章Yivanlee的MeshDraw系列文章。
## 图元渲染数据收集
- FDeferredShadingSceneRenderer::Render()
- InitViews()
- ComputeViewVisibility()
- GatherDynamicMeshElements()
- GetDynamicMeshElements()
InitViews():计算可见性以及初始化胶囊阴影、天空环境图、大气雾、体积雾。
GatherDynamicMeshElements():遍历场景中的所有图元类,调用`GetDynamicMeshElements()`接口函数获取渲染数据,之后调用`FMeshElementCollector``AllocateMesh()`创建一块FMeshBatch类型的内存并且使用渲染数据进行填充。
`FMeshBatch`承载`MaterialRenderProxy`以及其他渲染数据,比如:
- FVertexFactory
- FMaterialRenderProxy
- FLightCacheInterface
- uint32 CastShadow : 1; // Whether it can be used in shadow renderpasses.
- uint32 bUseForMaterial : 1; // Whether it can be used in renderpasses requiring material outputs.
- uint32 bUseForDepthPass : 1; // Whether it can be used in depth pass.
- uint32 bUseAsOccluder : 1; // Hint whether this mesh is a good occluder.
- uint32 bWireframe
`FPrimitiveSceneProxy::GetDynamicMeshElements()`
FPrimitiveSceneProxy为了解决游戏线程与渲染线程之间数据传递造成的锁死问题而诞生的方案可以理解为在渲染线程中的Scene镜像。
无论是StaticMesh还是SkeletonMesh都重写了基类的UPrimitiveComponent::CreateSceneProxy()创建对应的SceneProxy类之后再用此提交渲染数据的提交渲染信息与请求的逻辑位于GetDynamicMeshElements()。
该函数函数在渲染线程中运行根据情况使用不通的FMaterialRenderProxy子类传递给FMeshBatch与FMeshElementCollectorFMaterialRenderProxy及其子类可以看做Material信息镜像。这些情况大致包含
- DebugView
- 渲染网格模式
- Lod对应的Material
- 顶点色可视
这一步可以理解为传递Material给MeshDraw框架。
## MeshDraw渲染
`ComputeViewVisibility()`执行完`GatherDynamicMeshElements()`收集完图元渲染数据后会对每个需要渲染的View调用`SetupMeshPass()``SetupMeshPass()`会遍历`EMeshPass`中所定义的枚举再使用对应创建函数来构建FMeshPassProcessor最后执行`DispatchPassSetup()`填充所需的渲染相关信息后渲染线程中创建当前Pass的绘制任务。
EMeshPass定义了Pass:
```js
DepthPass,
BasePass,
AnisotropyPass,
SkyPass,
SingleLayerWaterPass,
CSMShadowDepth,
Distortion,
Velocity,
TranslucentVelocity,
TranslucencyStandard,
TranslucencyAfterDOF,
TranslucencyAfterDOFModulate,
TranslucencyAll, /** Drawing all translucency, regardless of separate or standard. Used when drawing translucency outside of the main renderer, eg FRendererModule::DrawTile. */
LightmapDensity,
DebugViewMode, /** Any of EDebugViewShaderMode */
CustomDepth,
MobileBasePassCSM, /** Mobile base pass with CSM shading enabled */
MobileInverseOpacity, /** Mobile specific scene capture, Non-cached */
VirtualTexture,
DitheredLODFadingOutMaskPass
```
### FMeshPassProcessor
`FMeshPassProcessor`是Mesh处理器的基类主要作用是设置渲染状态、绑定Shader与UniformStructBuffer最后生成MeshDrawCommands并且加入绘制队列。只要与模型相关的Pass都会继承该类在派生类中都会重写`AddMeshBatch()`一般会在对应的生成MeshDrawCommands函数或是`DrawDynamicMeshPass()`中的回调函数中调用。以及实现具体的处理函数`Process()`
#### DrawDynamicMeshPass
该函数中有一个回调函数,
回调函数的逻辑顺序为:
1. 使用FScene、FSceneView、FMeshPassProcessorRenderState、EDepthDrawingMode、FMeshPassDrawListContext等变量创建一个FMeshPassProcessor。
2. 之后按照有效的View使用AddMeshBatch()往FMeshPassProcessor中添加MeshBatch。
#### AddMeshBatch
其作用为往一个Pass中增加FMeshBatch。
主要逻辑:
1. 判断是否需要绘制后进行寻找FMaterial递归。
2. 从FMaterialRenderProxy中寻找FMaterial如FMaterial无效则从父类寻找直至找到为止。底层为各个材质模型的默认材质
3. 找到有效FMaterial后调用TryAddMeshBatch()。
#### TryAddMeshBatch
收集BlendMode、MeshDrawingPolic、RasterizerFillMode、RasterizerCullMode等所需变量后传递给处理函数`Process()`。在`Process()`中取得所需Shader与渲染数据后FMeshPassProcessorRenderState、FMeshDrawCommandSortKey、FMeshMaterialShaderElementData等调用`BuildMeshDrawCommands()`创建MeshDrawCommands。
以FDepthPassMeshProcessor为例`Process()`的主要逻辑顺序为取得所需的Shader包括顶点、Hull、Domain、Vertex、Pixel。初始化MeshMaterial数据BuildMeshDrawCommands构建MeshDraw命令。`Process()`同时也是个模板函数(根据不同渲染需求构建对应的MeshDrawCommand)用来切换构建的MeshDrawCommand中的EMeshPassFeatures形参用于设置顶点输入流类型Default、PositionOnly、PositionAndNormalOnly
`FMeshPassProcessorRenderState`是MeshPassProcessor的渲染状态集。存储信息如下
- FRHIBlendState* BlendState;
- FRHIDepthStencilState* DepthStencilState;
- FExclusiveDepthStencil::Type DepthStencilAccess;
- FRHIUniformBuffer* ViewUniformBuffer;
- FRHIUniformBuffer* InstancedViewUniformBuffer;
- FRHIUniformBuffer* ReflectionCaptureUniformBuffer;
- FRHIUniformBuffer* PassUniformBuffer;
- uint32 StencilRef;
### BuildMeshDrawCommands
BuildMeshDrawCommands()大致逻辑为:
1. 创建`FMeshDrawCommand`对象。以下简称为MDC。
2. 根据`FMeshPassProcessorRenderState`中的`StencilRef`来设置MDC的模板index。
3. 创建`FGraphicsMinimalPipelineStateInitializer`对象设置PrimitiveType、ImmutableSamplerState根据PassShadersType模板参数`FGraphicsMinimalPipelineStateInitializer`引用设置对应Shader的ShaderResource与ShaderIndex设置MDC的RasterizerState、BlendState、DepthStencilState、DrawShadingRate通过VertexFactory来设置MDC的PrimitiveIdStreamIndex。
4. 判断PassShadersType模板参数是那种类型的Shader之后取得对应`FMeshDrawSingleShaderBindings`,最后将`FShaderUniformBufferParameter``FViewUniformShaderParameters``FDistanceCullFadeUniformShaderParameters``FDitherUniformShaderParameters``FInstancedViewUniformShaderParameters`加入`FMeshDrawSingleShaderBindings`中。(`FShaderUniformBufferParameter`会在对应Shader类中绑定实际的UniformBuffer
5. 遍历`FMeshBatch`中存储的所有FMeshBatchElement将之前的MDC对象加入`DrawListStorage`中并取得其引用根据PassShadersType模板参数从MDC引用取得对应`FMeshDrawSingleShaderBindings`,最后将`FPrimitiveUniformShaderParameters`加入`FMeshDrawSingleShaderBindings`中。
6. 结束当前MDC构建并且将其加入`DrawListContext`的绘制列表中。
## 场景与FMeshPassProcessor的关系
在FScene::AddPrimitive(UPrimitiveComponent* Primitive)创建图元类对应的场景代理,计算矩阵、边界盒来构建`FCreateRenderThreadParameters`对象,最后向渲染线程加入图元场景信息。
在ActorComponents的UpdateAllPrimitiveSceneInfosForScenes()会在渲染线程执行UpdateAllPrimitiveSceneInfos()。UpdateAllPrimitiveSceneInfos()=》AddToScene()=>AddStaticMeshes()=>CacheMeshDrawCommands()中遍历所有类型的Pass并且创建对应的`FMeshPassProcessor`然后调用AddMeshBatch()。
## MeshDraw与RGD
MeshDraw部分不考虑Shader以SingleLayerWater为例子
- 构建FSingleLayerWaterPassMeshProcessor类
- 在构造函数中设置PassDrawRenderState。CW_RGBA, BO_Add, BF_One, BF_InverseSourceAlpha
- 重写AddMeshBatch()收集OverrideSettings、MeshFillMode、MeshCullMode、MaterialRenderProxy后传入Process().
- 实现Process(),取得Shader、初始化ShaderElementData、计算SortKey之后调用BuildMeshDrawCommands()构建MeshDrawCommands。
- 实现CreateSingleLayerWaterPassProcessor()与对应的FRegisterPassProcessorCreateFunction以用来创建FSingleLayerWaterPassMeshProcessor。
调用的逻辑位于FDeferredShadingSceneRenderer::RenderSingleLayerWaterInner
- 取得GBuffer并绑定深度模板从RTPool中取得一个纯白贴图(WhiteDummy)
- 遍历有效View开始渲染
- 使用上述2个RT与FOpaqueBasePassUniformParameters填充FSingleLayerWaterPassParameters
- 使用RDG创建一个Pass里面执行更新ViewUniformBuffer后用上述两个UniformBuffer构建FRDGParallelCommandListSet最后使用View.ParallelMeshDrawCommandPasses[EMassPass::SingleLayerWaterPass].DispatchDraw()进行绘制。
## 调整渲染方式以实现背面剔除
目标是设置为非DoubleSide以及ReverseCullMode模式一些给顶点工厂添加数据
Mesh.bDisableBackfaceCulling
Mesh.ReverseCulling
重写FSkeletalMeshSceneProxy::GetDynamicElementsSection()
```c#
ERasterizerCullMode FMeshPassProcessor::ComputeMeshCullMode(const FMeshBatch& Mesh, const FMaterial& InMaterialResource, const FMeshDrawingPolicyOverrideSettings& InOverrideSettings)
{
const bool bMaterialResourceIsTwoSided = InMaterialResource.IsTwoSided();
const bool bInTwoSidedOverride = !!(InOverrideSettings.MeshOverrideFlags & EDrawingPolicyOverrideFlags::TwoSided);
const bool bInReverseCullModeOverride = !!(InOverrideSettings.MeshOverrideFlags & EDrawingPolicyOverrideFlags::ReverseCullMode);
const bool bIsTwoSided = (bMaterialResourceIsTwoSided || bInTwoSidedOverride);
const bool bMeshRenderTwoSided = bIsTwoSided || bInTwoSidedOverride;
return bMeshRenderTwoSided ? CM_None : (bInReverseCullModeOverride ? CM_CCW : CM_CW);
}
```
## 修改ShaderModel
修改Pin
添加ShaderModel枚举
BasePassPixelShader.usf中的FPixelShaderInOut_MainPS()