diff --git a/03-UnrealEngine/Rendering/RenderingPipeline/向往渲染系列文章阅读笔记/剖析虚幻渲染体系(08)- Shader体系.md b/03-UnrealEngine/Rendering/RenderingPipeline/向往渲染系列文章阅读笔记/剖析虚幻渲染体系(08)- Shader体系.md index ffc72f9..bea883d 100644 --- a/03-UnrealEngine/Rendering/RenderingPipeline/向往渲染系列文章阅读笔记/剖析虚幻渲染体系(08)- Shader体系.md +++ b/03-UnrealEngine/Rendering/RenderingPipeline/向往渲染系列文章阅读笔记/剖析虚幻渲染体系(08)- Shader体系.md @@ -661,4 +661,236 @@ private: 上面展示了Vertex Factory的很多类型,有好几个是核心类,比如FVertexFactory、FVertexElement、FRHIVertexDeclaration、FRHIVertexBuffer、FVertexFactoryType、FVertexStreamComponent、FVertexInputStream、FVertexFactoryShaderParameters等。那么它们之间的关系是什么呢? 为了更好地说明它们之间的关系,以静态模型的FStaticMeshDataType为例: -![[UE_VertexFactory_FStaticMeshDataType.jpg]] \ No newline at end of file +![[UE_VertexFactory_FStaticMeshDataType.jpg]] +FStaticMeshDataType会包含若干个FVertexStreamComponent实例,每个FVertexStreamComponent包含了一个在**FVertexDeclarationElementList**的**FVertexElement实例索引**和一个在**FVertexInputStreamArray**列表的**FVertexStream实例索引**。 +此外,FVertexFactory是个基类,内置的子类主要有: +- FGeometryCacheVertexVertexFactory:几何缓存顶点的顶点工厂,常用于预生成的布料、动作等网格类型。 +- FGPUBaseSkinVertexFactory:GPU蒙皮骨骼网格的父类,它的子类有: + - TGPUSkinVertexFactory:可指定骨骼权重方式的GPU蒙皮的顶点工厂。 +- FLocalVertexFactory:局部顶点工厂,常用于**静态网格**,它拥有**数量较多的子类**: + - FInstancedStaticMeshVertexFactory:实例化的静态网格顶点工厂。 + - FSplineMeshVertexFactory:样条曲线网格顶点工厂。 + - FGeometryCollectionVertexFactory:几何收集顶点工厂。 + - FGPUSkinPassthroughVertexFactory:启用了Skin Cache模式的蒙皮骨骼顶点工厂。 + - FSingleTriangleMeshVertexFactory:单个三角形网格的顶点工厂,用于体积云渲染。 + - ...... +- FParticleVertexFactoryBase:用于粒子渲染的顶点工厂基类。 +- FLandscapeVertexFactory:用于渲染地形的顶点工厂。 + +除了以上继承自FVertexFactory,还有一些不是继承自FVertexFactory的类型,如: +- FGPUBaseSkinAPEXClothVertexFactory:布料顶点工厂。 + - TGPUSkinAPEXClothVertexFactory:可带骨骼权重模式的布料顶点工厂。 + +除了FVertexFactory,相应的其它核心类也有继承体系。比如FVertexFactoryShaderParameters的子类有: +- FGeometryCacheVertexFactoryShaderParameters +- FGPUSkinVertexFactoryShaderParameters +- FMeshParticleVertexFactoryShaderParameters +- FParticleSpriteVertexFactoryShaderParameters +- FGPUSpriteVertexFactoryShaderParametersVS +- FGPUSpriteVertexFactoryShaderParametersPS +- FSplineMeshVertexFactoryShaderParameters +- FLocalVertexFactoryShaderParametersBase +- FLandscapeVertexFactoryVertexShaderParameters +- FLandscapeVertexFactoryPixelShaderParameters +- ...... + +另外,有部分顶点工厂还会在内部派生FStaticMeshDataType的类型,以复用静态网格相关的数据成员。为了更好地说明顶点工厂的使用方式,下面就以最常见的FLocalVertexFactory和使用了FLocalVertexFactory的CableComponent为例: +```c++ + +class ENGINE_API FLocalVertexFactory : public FVertexFactory +{ +public: + FLocalVertexFactory(ERHIFeatureLevel::Type InFeatureLevel, const char* InDebugName); + + // 派生自FStaticMeshDataType的数据类型. + struct FDataType : public FStaticMeshDataType + { + FRHIShaderResourceView* PreSkinPositionComponentSRV = nullptr; + }; + + // 环境变量更改和校验. + static bool ShouldCompilePermutation(const FVertexFactoryShaderPermutationParameters& Parameters); + static void ModifyCompilationEnvironment(const FVertexFactoryShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment); + static void ValidateCompiledResult(const FVertexFactoryType* Type, EShaderPlatform Platform, const FShaderParameterMap& ParameterMap, TArray& OutErrors); + + // 由TSynchronizedResource从游戏线程更新而来的数据. + void SetData(const FDataType& InData); + // 从其它顶点工厂复制数据. + void Copy(const FLocalVertexFactory& Other); + + // FRenderResource接口. + virtual void InitRHI() override; + virtual void ReleaseRHI() override + { + UniformBuffer.SafeRelease(); + FVertexFactory::ReleaseRHI(); + } + + // 顶点颜色接口. + void SetColorOverrideStream(FRHICommandList& RHICmdList, const FVertexBuffer* ColorVertexBuffer) const; + void GetColorOverrideStream(const FVertexBuffer* ColorVertexBuffer, FVertexInputStreamArray& VertexStreams) const; + + // 着色器参数和其它数据接口. + inline FRHIShaderResourceView* GetPositionsSRV() const; + inline FRHIShaderResourceView* GetPreSkinPositionSRV() const; + inline FRHIShaderResourceView* GetTangentsSRV() const; + inline FRHIShaderResourceView* GetTextureCoordinatesSRV() const; + inline FRHIShaderResourceView* GetColorComponentsSRV() const; + inline const uint32 GetColorIndexMask() const; + inline const int GetLightMapCoordinateIndex() const; + inline const int GetNumTexcoords() const; + FRHIUniformBuffer* GetUniformBuffer() const; + + (......) + +protected: + // 从游戏线程传入的数据. FDataType是FStaticMeshDataType的子类. + FDataType Data; + // 局部顶点工厂的着色器参数. + TUniformBufferRef UniformBuffer; + // 顶点颜色流索引. + int32 ColorStreamIndex; + + (......) +}; + +// Engine\Source\Runtime\Engine\Public\LocalVertexFactory.cpp +void FLocalVertexFactory::InitRHI() +{ + // 是否使用gpu场景. + const bool bCanUseGPUScene = UseGPUScene(GMaxRHIShaderPlatform, GMaxRHIFeatureLevel); + + // 初始化位置流和位置声明. + if (Data.PositionComponent.VertexBuffer != Data.TangentBasisComponents[0].VertexBuffer) + { + // 增加顶点声明. + auto AddDeclaration = [this, bCanUseGPUScene](EVertexInputStreamType InputStreamType, bool bAddNormal) + { + // 顶点流元素. + FVertexDeclarationElementList StreamElements; + StreamElements.Add(AccessStreamComponent(Data.PositionComponent, 0, InputStreamType)); + + bAddNormal = bAddNormal && Data.TangentBasisComponents[1].VertexBuffer != NULL; + if (bAddNormal) + { + StreamElements.Add(AccessStreamComponent(Data.TangentBasisComponents[1], 2, InputStreamType)); + } + + const uint8 TypeIndex = static_cast(InputStreamType); + PrimitiveIdStreamIndex[TypeIndex] = -1; + if (GetType()->SupportsPrimitiveIdStream() && bCanUseGPUScene) + { + // When the VF is used for rendering in normal mesh passes, this vertex buffer and offset will be overridden + StreamElements.Add(AccessStreamComponent(FVertexStreamComponent(&GPrimitiveIdDummy, 0, 0, sizeof(uint32), VET_UInt, EVertexStreamUsage::Instancing), 1, InputStreamType)); + PrimitiveIdStreamIndex[TypeIndex] = StreamElements.Last().StreamIndex; + } + + // 初始化声明. + InitDeclaration(StreamElements, InputStreamType); + }; + + // 增加PositionOnly和PositionAndNormalOnly两种顶点声明, 其中前者不需要法线. + AddDeclaration(EVertexInputStreamType::PositionOnly, false); + AddDeclaration(EVertexInputStreamType::PositionAndNormalOnly, true); + } + + // 顶点声明元素列表. + FVertexDeclarationElementList Elements; + + // 顶点位置 + if(Data.PositionComponent.VertexBuffer != NULL) + { + Elements.Add(AccessStreamComponent(Data.PositionComponent,0)); + } + + // 图元id + { + const uint8 Index = static_cast(EVertexInputStreamType::Default); + PrimitiveIdStreamIndex[Index] = -1; + if (GetType()->SupportsPrimitiveIdStream() && bCanUseGPUScene) + { + // When the VF is used for rendering in normal mesh passes, this vertex buffer and offset will be overridden + Elements.Add(AccessStreamComponent(FVertexStreamComponent(&GPrimitiveIdDummy, 0, 0, sizeof(uint32), VET_UInt, EVertexStreamUsage::Instancing), 13)); + PrimitiveIdStreamIndex[Index] = Elements.Last().StreamIndex; + } + } + + // 切线和法线, 切线法线才需要被顶点流使用, 副法线由shader生成. + uint8 TangentBasisAttributes[2] = { 1, 2 }; + for(int32 AxisIndex = 0;AxisIndex < 2;AxisIndex++) + { + if(Data.TangentBasisComponents[AxisIndex].VertexBuffer != NULL) + { + Elements.Add(AccessStreamComponent(Data.TangentBasisComponents[AxisIndex],TangentBasisAttributes[AxisIndex])); + } + } + + if (Data.ColorComponentsSRV == nullptr) + { + Data.ColorComponentsSRV = GNullColorVertexBuffer.VertexBufferSRV; + Data.ColorIndexMask = 0; + } + + // 顶点颜色 + ColorStreamIndex = -1; + if(Data.ColorComponent.VertexBuffer) + { + Elements.Add(AccessStreamComponent(Data.ColorComponent,3)); + ColorStreamIndex = Elements.Last().StreamIndex; + } + else + { + FVertexStreamComponent NullColorComponent(&GNullColorVertexBuffer, 0, 0, VET_Color, EVertexStreamUsage::ManualFetch); + Elements.Add(AccessStreamComponent(NullColorComponent, 3)); + ColorStreamIndex = Elements.Last().StreamIndex; + } + + // 纹理坐标 + if(Data.TextureCoordinates.Num()) + { + const int32 BaseTexCoordAttribute = 4; + for(int32 CoordinateIndex = 0;CoordinateIndex < Data.TextureCoordinates.Num();CoordinateIndex++) + { + Elements.Add(AccessStreamComponent( + Data.TextureCoordinates[CoordinateIndex], + BaseTexCoordAttribute + CoordinateIndex + )); + } + + for (int32 CoordinateIndex = Data.TextureCoordinates.Num(); CoordinateIndex < MAX_STATIC_TEXCOORDS / 2; CoordinateIndex++) + { + Elements.Add(AccessStreamComponent( + Data.TextureCoordinates[Data.TextureCoordinates.Num() - 1], + BaseTexCoordAttribute + CoordinateIndex + )); + } + } + + // 光照图 + if(Data.LightMapCoordinateComponent.VertexBuffer) + { + Elements.Add(AccessStreamComponent(Data.LightMapCoordinateComponent,15)); + } + else if(Data.TextureCoordinates.Num()) + { + Elements.Add(AccessStreamComponent(Data.TextureCoordinates[0],15)); + } + + // 初始化顶点声明 + InitDeclaration(Elements); + + const int32 DefaultBaseVertexIndex = 0; + const int32 DefaultPreSkinBaseVertexIndex = 0; + if (RHISupportsManualVertexFetch(GMaxRHIShaderPlatform) || bCanUseGPUScene) + { + SCOPED_LOADTIMER(FLocalVertexFactory_InitRHI_CreateLocalVFUniformBuffer); + UniformBuffer = CreateLocalVFUniformBuffer(this, Data.LODLightmapDataIndex, nullptr, DefaultBaseVertexIndex, DefaultPreSkinBaseVertexIndex); + } +} + +// 实现FLocalVertexFactory的参数类型. +IMPLEMENT_VERTEX_FACTORY_PARAMETER_TYPE(FLocalVertexFactory, SF_Vertex, FLocalVertexFactoryShaderParameters); + +// 实现FLocalVertexFactory. +IMPLEMENT_VERTEX_FACTORY_TYPE_EX(FLocalVertexFactory,"/Engine/Private/LocalVertexFactory.ush",true,true,true,true,true,true,true); +``` \ No newline at end of file