1764 lines
		
	
	
		
			67 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			1764 lines
		
	
	
		
			67 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| 
								 | 
							
								---
							 | 
						|||
| 
								 | 
							
								title: 剖析虚幻渲染体系(08)- Shader体系
							 | 
						|||
| 
								 | 
							
								date: 2024-02-04 21:44:10
							 | 
						|||
| 
								 | 
							
								excerpt: 
							 | 
						|||
| 
								 | 
							
								tags: 
							 | 
						|||
| 
								 | 
							
								rating: ⭐
							 | 
						|||
| 
								 | 
							
								---
							 | 
						|||
| 
								 | 
							
								# 前言
							 | 
						|||
| 
								 | 
							
								原文地址:https://www.cnblogs.com/timlly/p/15092257.html
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# FShader
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								class FShader
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
									// 在编译触发之前修改编译环境参数, 可由子类覆盖.
							 | 
						|||
| 
								 | 
							
									static void ModifyCompilationEnvironment(const FShaderPermutationParameters&, FShaderCompilerEnvironment&) {}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// 是否需要编译指定的排列, 可由子类覆盖.
							 | 
						|||
| 
								 | 
							
									static bool ShouldCompilePermutation(const FShaderPermutationParameters&) { return true; }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// 检测编译结果是否有效, 可由子类覆盖.
							 | 
						|||
| 
								 | 
							
									static bool ValidateCompiledResult(EShaderPlatform InPlatform, const FShaderParameterMap& InParameterMap, TArray<FString>& OutError) { return true; }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// 取得RayTracingPayloadType
							 | 
						|||
| 
								 | 
							
									static ERayTracingPayloadType GetRayTracingPayloadType(const int32 PermutationId) { return static_cast<ERayTracingPayloadType>(0); }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// 获取各类数据的Hash的接口.
							 | 
						|||
| 
								 | 
							
									RENDERCORE_API const FSHAHash& GetHash() const;
							 | 
						|||
| 
								 | 
							
									RENDERCORE_API const FSHAHash& GetVertexFactoryHash() const;	
							 | 
						|||
| 
								 | 
							
									RENDERCORE_API const FSHAHash& GetOutputHash() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/** Returns an identifier suitable for deterministic sorting of shaders between sessions. */
							 | 
						|||
| 
								 | 
							
									uint32 GetSortKey() const { return SortKey; }
							 | 
						|||
| 
								 | 
							
									// 保存并检测shader代码的编译结果.
							 | 
						|||
| 
								 | 
							
									RENDERCORE_API void Finalize(const FShaderMapResourceCode* Code);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// 数据获取接口.
							 | 
						|||
| 
								 | 
							
									inline FShaderType* GetType(const FShaderMapPointerTable& InPointerTable) const { return Type.Get(InPointerTable.ShaderTypes); }
							 | 
						|||
| 
								 | 
							
									inline FShaderType* GetType(const FPointerTableBase* InPointerTable) const { return Type.Get(InPointerTable); }
							 | 
						|||
| 
								 | 
							
									inline FVertexFactoryType* GetVertexFactoryType(const FShaderMapPointerTable& InPointerTable) const { return VFType.Get(InPointerTable.VFTypes); }
							 | 
						|||
| 
								 | 
							
									inline FVertexFactoryType* GetVertexFactoryType(const FPointerTableBase* InPointerTable) const { return VFType.Get(InPointerTable); }
							 | 
						|||
| 
								 | 
							
									inline FShaderType* GetTypeUnfrozen() const { return Type.GetUnfrozen(); }
							 | 
						|||
| 
								 | 
							
									inline int32 GetResourceIndex() const { checkSlow(ResourceIndex != INDEX_NONE); return ResourceIndex; }
							 | 
						|||
| 
								 | 
							
									inline EShaderPlatform GetShaderPlatform() const { return Target.GetPlatform(); }
							 | 
						|||
| 
								 | 
							
									inline EShaderFrequency GetFrequency() const { return Target.GetFrequency(); }
							 | 
						|||
| 
								 | 
							
									inline const FShaderTarget GetTarget() const { return Target; }
							 | 
						|||
| 
								 | 
							
									inline bool IsFrozen() const { return Type.IsFrozen(); }
							 | 
						|||
| 
								 | 
							
									inline uint32 GetNumInstructions() const { return NumInstructions; }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if WITH_EDITORONLY_DATA
							 | 
						|||
| 
								 | 
							
									inline uint32 GetNumTextureSamplers() const { return NumTextureSamplers; }
							 | 
						|||
| 
								 | 
							
									inline uint32 GetCodeSize() const { return CodeSize; }
							 | 
						|||
| 
								 | 
							
									inline void SetNumInstructions(uint32 Value) { NumInstructions = Value; }
							 | 
						|||
| 
								 | 
							
								#else
							 | 
						|||
| 
								 | 
							
									inline uint32 GetNumTextureSamplers() const { return 0u; }
							 | 
						|||
| 
								 | 
							
									inline uint32 GetCodeSize() const { return 0u; }
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// 尝试返回匹配指定类型的自动绑定的Uniform Buffer, 如果不存在则返回未绑定的.
							 | 
						|||
| 
								 | 
							
									template<typename UniformBufferStructType>
							 | 
						|||
| 
								 | 
							
									FORCEINLINE_DEBUGGABLE const TShaderUniformBufferParameter<UniformBufferStructType>& GetUniformBufferParameter() const
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										const FShaderUniformBufferParameter& FoundParameter = GetUniformBufferParameter(UniformBufferStructType::FTypeInfo::GetStructMetadata());
							 | 
						|||
| 
								 | 
							
										return static_cast<const TShaderUniformBufferParameter<UniformBufferStructType>&>(FoundParameter);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FORCEINLINE_DEBUGGABLE const FShaderUniformBufferParameter& GetUniformBufferParameter(const FShaderParametersMetadata* SearchStruct) const
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										const FHashedName SearchName = SearchStruct->GetShaderVariableHashedName();
							 | 
						|||
| 
								 | 
							
										
							 | 
						|||
| 
								 | 
							
										return GetUniformBufferParameter(SearchName);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FORCEINLINE_DEBUGGABLE const FShaderUniformBufferParameter& GetUniformBufferParameter(const FHashedName SearchName) const
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										int32 FoundIndex = INDEX_NONE;
							 | 
						|||
| 
								 | 
							
										TArrayView<const FHashedName> UniformBufferParameterStructsView(UniformBufferParameterStructs);
							 | 
						|||
| 
								 | 
							
										for (int32 StructIndex = 0, Count = UniformBufferParameterStructsView.Num(); StructIndex < Count; StructIndex++)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											if (UniformBufferParameterStructsView[StructIndex] == SearchName)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												FoundIndex = StructIndex;
							 | 
						|||
| 
								 | 
							
												break;
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (FoundIndex != INDEX_NONE)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											const FShaderUniformBufferParameter& FoundParameter = UniformBufferParameters[FoundIndex];
							 | 
						|||
| 
								 | 
							
											return FoundParameter;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
										else
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											// This can happen if the uniform buffer was not bound
							 | 
						|||
| 
								 | 
							
											// There's no good way to distinguish not being bound due to temporary debugging / compiler optimizations or an actual code bug,
							 | 
						|||
| 
								 | 
							
											// Hence failing silently instead of an error message
							 | 
						|||
| 
								 | 
							
											static FShaderUniformBufferParameter UnboundParameter;
							 | 
						|||
| 
								 | 
							
											return UnboundParameter;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									RENDERCORE_API const FShaderParametersMetadata* FindAutomaticallyBoundUniformBufferStruct(int32 BaseIndex) const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									RENDERCORE_API void DumpDebugInfo(const FShaderMapPointerTable& InPtrTable);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if WITH_EDITOR
							 | 
						|||
| 
								 | 
							
									RENDERCORE_API void SaveShaderStableKeys(const FShaderMapPointerTable& InPtrTable, EShaderPlatform TargetShaderPlatform, int32 PermutationId, const struct FStableShaderKeyAndValue& SaveKeyVal);
							 | 
						|||
| 
								 | 
							
								#endif // WITH_EDITOR
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									/** Returns the meta data for the root shader parameter struct. */
							 | 
						|||
| 
								 | 
							
									static inline const FShaderParametersMetadata* GetRootParametersMetadata()
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return nullptr;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
									RENDERCORE_API void BuildParameterMapInfo(const TMap<FString, FParameterAllocation>& ParameterMap);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
									// 着色器参数绑定.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(FShaderParameterBindings, Bindings);
							 | 
						|||
| 
								 | 
							
									// 着色器参数绑定的映射信息.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(FShaderParameterMapInfo, ParameterMapInfo);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								protected:
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(TMemoryImageArray<FHashedName>, UniformBufferParameterStructs);
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(TMemoryImageArray<FShaderUniformBufferParameter>, UniformBufferParameters);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// 下面3个是编辑器参数. 
							 | 
						|||
| 
								 | 
							
									// 着色器的编译输出和结果参数映射的哈希值, 用于查找匹配的资源.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD_EDITORONLY(FSHAHash, OutputHash);
							 | 
						|||
| 
								 | 
							
									// 顶点工厂资源哈希值
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD_EDITORONLY(FSHAHash, VFSourceHash);
							 | 
						|||
| 
								 | 
							
									// Shader资源哈希值.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD_EDITORONLY(FSHAHash, SourceHash);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
									// 着色器类型.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(TIndexedPtr<FShaderType>, Type);
							 | 
						|||
| 
								 | 
							
									// 顶点工厂类型.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(TIndexedPtr<FVertexFactoryType>, VFType);
							 | 
						|||
| 
								 | 
							
									// 目标平台和着色频率(frequency).
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(FShaderTarget, Target);
							 | 
						|||
| 
								 | 
							
									// 在FShaderMapResource的shader索引.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(int32, ResourceIndex);
							 | 
						|||
| 
								 | 
							
									// shader指令数.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(uint32, NumInstructions);
							 | 
						|||
| 
								 | 
							
									/** Truncated version of OutputHash, intended for sorting. Not suitable for unique shader identification. */
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD(uint32, SortKey);
							 | 
						|||
| 
								 | 
							
									// 纹理采样器数量.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD_EDITORONLY(uint32, NumTextureSamplers);
							 | 
						|||
| 
								 | 
							
									// shader代码尺寸.
							 | 
						|||
| 
								 | 
							
									LAYOUT_FIELD_EDITORONLY(uint32, CodeSize);
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								以上可知,FShader存储着Shader关联的绑定参数、顶点工厂、编译后的各类资源等数据,并提供了编译器修改和检测接口,还有各类数据获取接口。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								FShader实际上是个基础父类,它的子类有:
							 | 
						|||
| 
								 | 
							
								- **FGlobalShader**:全局着色器,它的子类在内存中只有唯一的实例,常用于屏幕方块绘制、后处理等。相比父类FShader,增加了SetParameters设置视图统一缓冲的接口。FGlobalShader包含了后处理、光照、工具类、可视化、地形、虚拟纹理等方面的Shader代码,可以是VS、PS、CS,但CS必然是FGlobalShader的子类
							 | 
						|||
| 
								 | 
							
								- **FMaterialShader**:材质着色器,由FMaterialShaderType指定的材质引用的着色器,是材质蓝图在实例化后的一个shader子集。FMaterialShader主要包含了模型、专用Pass、体素化等方面的Shader代码,可以是VS、PS、GS等,但不会有CS。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## Shader Parameter
							 | 
						|||
| 
								 | 
							
								位于`Engine\Source\Runtime\RenderCore\Public\ShaderParameters.h`。
							 | 
						|||
| 
								 | 
							
								- FShaderParameter:着色器的寄存器绑定参数, 它的类型可以是float1/2/3/4,数组等。
							 | 
						|||
| 
								 | 
							
								- FShaderResourceParameter:着色器资源绑定(纹理或采样器)。
							 | 
						|||
| 
								 | 
							
								- FRWShaderParameter:绑定了UAV或SRV资源的类型。
							 | 
						|||
| 
								 | 
							
								- FShaderUniformBufferParameter:着色器统一缓冲参数。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								## Uniform Buffer
							 | 
						|||
| 
								 | 
							
								位于`Engine\Source\Runtime\RHI\Public\RHIResources.h`。
							 | 
						|||
| 
								 | 
							
								UE的Uniform Buffer涉及了几个核心的概念,最底层的是RHI层的FRHIUniformBuffer,封装了各种图形API的统一缓冲区(也叫Constant Buffer)。
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								class FRHIUniformBuffer : public FRHIResource
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    // 构造函数.
							 | 
						|||
| 
								 | 
							
								    FRHIUniformBuffer(const FRHIUniformBufferLayout& InLayout);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 引用计数操作.
							 | 
						|||
| 
								 | 
							
								    uint32 AddRef() const;
							 | 
						|||
| 
								 | 
							
								    uint32 Release() const;
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    // 数据获取接口.
							 | 
						|||
| 
								 | 
							
								    uint32 GetSize() const;
							 | 
						|||
| 
								 | 
							
								    const FRHIUniformBufferLayout& GetLayout() const;
							 | 
						|||
| 
								 | 
							
								    bool IsGlobal() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								    // RHI Uniform Buffer的布局.
							 | 
						|||
| 
								 | 
							
								    const FRHIUniformBufferLayout* Layout;
							 | 
						|||
| 
								 | 
							
								    // 缓冲区尺寸.
							 | 
						|||
| 
								 | 
							
								    uint32 LayoutConstantBufferSize;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 定义FRHIUniformBuffer的引用类型.
							 | 
						|||
| 
								 | 
							
								typedef TRefCountPtr<FRHIUniformBuffer> FUniformBufferRHIRef;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// Engine\Source\Runtime\RenderCore\Public\ShaderParameterMacros.h
							 | 
						|||
| 
								 | 
							
								// 引用了指定类型的FRHIUniformBuffer的实例资源. 注意是继承了FUniformBufferRHIRef.
							 | 
						|||
| 
								 | 
							
								template<typename TBufferStruct>
							 | 
						|||
| 
								 | 
							
								class TUniformBufferRef : public FUniformBufferRHIRef
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    TUniformBufferRef();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 根据给定的值创建Uniform Buffer, 并返回结构体引用. (模板)
							 | 
						|||
| 
								 | 
							
								    static TUniformBufferRef<TBufferStruct> CreateUniformBufferImmediate(const TBufferStruct& Value, EUniformBufferUsage Usage, EUniformBufferValidation Validation = EUniformBufferValidation::ValidateResources);
							 | 
						|||
| 
								 | 
							
								    // 根据给定的值创建[局部]的Uniform Buffer, 并返回结构体引用.
							 | 
						|||
| 
								 | 
							
								    static FLocalUniformBuffer CreateLocalUniformBuffer(FRHICommandList& RHICmdList, const TBufferStruct& Value, EUniformBufferUsage Usage);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 立即刷新缓冲区数据到RHI.
							 | 
						|||
| 
								 | 
							
								    void UpdateUniformBufferImmediate(const TBufferStruct& Value);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								    // 私有构造体, 只能给TUniformBuffer和TRDGUniformBuffer创建.
							 | 
						|||
| 
								 | 
							
								    TUniformBufferRef(FRHIUniformBuffer* InRHIRef);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    template<typename TBufferStruct2>
							 | 
						|||
| 
								 | 
							
								    friend class TUniformBuffer;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    friend class TRDGUniformBuffer<TBufferStruct>;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								最后TUniformBuffer和TRDGUniformBuffer引用了FUniformBufferRHIRef。TUniformBuffer为`TUniformBufferRef<TBufferStruct> UniformBufferRHI`成员变量;TRDGUniformBuffer为`TRefCountPtr<FRHIUniformBuffer> UniformBufferRHI`。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								![[UE_Uniform.png]]
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### 定义宏
							 | 
						|||
| 
								 | 
							
								- SHADER_PARAMETER_STRUCT_REF:引用着色器参数结构体(全局的才行)
							 | 
						|||
| 
								 | 
							
								- SHADER_PARAMETER_STRUCT_INCLUDE:包含着色器参数结构体(局部或全局都行)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# Vertex Factory
							 | 
						|||
| 
								 | 
							
								我们知道,在引擎中存在着静态网格、蒙皮骨骼、程序化网格以及地形等等类型的网格类型,而材质就是通过顶点工厂FVertexFactory来支持这些网格类型。实际上,顶点工厂要涉及各方面的数据和类型,包含但不限于:
							 | 
						|||
| 
								 | 
							
								- 顶点着色器。顶点着色器的输入输出需要顶点工厂来表明数据的布局。
							 | 
						|||
| 
								 | 
							
								- 顶点工厂的参数和RHI资源。这些数据将从C++层传入到顶点着色器中进行处理。
							 | 
						|||
| 
								 | 
							
								- 顶点缓冲和顶点布局。通过顶点布局,我们可以自定义和扩展顶点缓冲的输入,从而实现定制化的Shader代码。
							 | 
						|||
| 
								 | 
							
								- 几何预处理。顶点缓冲、网格资源、材质参数等等都可以在真正渲染前预处理它们。
							 | 
						|||
| 
								 | 
							
								![[UE_VertexFactory.png]]
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								**顶点工厂在渲染层级中的关系。由图可知,顶点工厂是渲染线程的对象,横跨于CPU和GPU两端。**
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								// Engine\Source\Runtime\RHI\Public\RHI.h
							 | 
						|||
| 
								 | 
							
								// 顶点元素.
							 | 
						|||
| 
								 | 
							
								struct FVertexElement
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    uint8 StreamIndex;      // 流索引
							 | 
						|||
| 
								 | 
							
								    uint8 Offset;          // 偏移
							 | 
						|||
| 
								 | 
							
								    TEnumAsByte<EVertexElementType> Type; // 类型
							 | 
						|||
| 
								 | 
							
								    uint8 AttributeIndex;// 属性索引
							 | 
						|||
| 
								 | 
							
								    uint16 Stride;          // 步长
							 | 
						|||
| 
								 | 
							
								    // 实例索引或顶点索引是否实例化的, 若是0, 则元素会对每个实例进行重复.
							 | 
						|||
| 
								 | 
							
								    uint16 bUseInstanceIndex;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    FVertexElement();
							 | 
						|||
| 
								 | 
							
								    FVertexElement(uint8 InStreamIndex, ...);
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    void operator=(const FVertexElement& Other);
							 | 
						|||
| 
								 | 
							
								    friend FArchive& operator<<(FArchive& Ar,FVertexElement& Element);
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    FString ToString() const;
							 | 
						|||
| 
								 | 
							
								    void FromString(const FString& Src);
							 | 
						|||
| 
								 | 
							
								    void FromString(const FStringView& Src);
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点声明元素列表的类型.
							 | 
						|||
| 
								 | 
							
								typedef TArray<FVertexElement,TFixedAllocator<MaxVertexElementCount> > FVertexDeclarationElementList;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// Engine\Source\Runtime\RHI\Public\RHIResources.h
							 | 
						|||
| 
								 | 
							
								// 顶点声明的RHI资源
							 | 
						|||
| 
								 | 
							
								class FRHIVertexDeclaration : public FRHIResource
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    virtual bool GetInitializer(FVertexDeclarationElementList& Init) { return false; }
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点缓冲区
							 | 
						|||
| 
								 | 
							
								class FRHIVertexBuffer : public FRHIResource
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    FRHIVertexBuffer(uint32 InSize,uint32 InUsage);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    uint32 GetSize() const;
							 | 
						|||
| 
								 | 
							
								    uint32 GetUsage() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								protected:
							 | 
						|||
| 
								 | 
							
								    FRHIVertexBuffer();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    void Swap(FRHIVertexBuffer& Other);
							 | 
						|||
| 
								 | 
							
								    void ReleaseUnderlyingResource();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								    // 尺寸.
							 | 
						|||
| 
								 | 
							
								    uint32 Size;
							 | 
						|||
| 
								 | 
							
								    // 缓冲区标记, 如BUF_UnorderedAccess
							 | 
						|||
| 
								 | 
							
								    uint32 Usage;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// Engine\Source\Runtime\RenderCore\Public\VertexFactory.h
							 | 
						|||
| 
								 | 
							
								// 顶点输入流.
							 | 
						|||
| 
								 | 
							
								struct FVertexInputStream
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    // 顶点流索引
							 | 
						|||
| 
								 | 
							
								    uint32 StreamIndex : 4;
							 | 
						|||
| 
								 | 
							
								    // 在VertexBuffer的偏移.
							 | 
						|||
| 
								 | 
							
								    uint32 Offset : 28;
							 | 
						|||
| 
								 | 
							
								    // 顶点缓存区
							 | 
						|||
| 
								 | 
							
								    FRHIVertexBuffer* VertexBuffer;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    FVertexInputStream();
							 | 
						|||
| 
								 | 
							
								    FVertexInputStream(uint32 InStreamIndex, uint32 InOffset, FRHIVertexBuffer* InVertexBuffer);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    inline bool operator==(const FVertexInputStream& rhs) const;
							 | 
						|||
| 
								 | 
							
								    inline bool operator!=(const FVertexInputStream& rhs) const;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点输入流数组.
							 | 
						|||
| 
								 | 
							
								typedef TArray<FVertexInputStream, TInlineAllocator<4>> FVertexInputStreamArray;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点流标记
							 | 
						|||
| 
								 | 
							
								enum class EVertexStreamUsage : uint8
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    Default            = 0 << 0, // 默认
							 | 
						|||
| 
								 | 
							
								    Instancing        = 1 << 0, // 实例化
							 | 
						|||
| 
								 | 
							
								    Overridden        = 1 << 1, // 覆盖
							 | 
						|||
| 
								 | 
							
								    ManualFetch        = 1 << 2  // 手动获取
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点输入流类型.
							 | 
						|||
| 
								 | 
							
								enum class EVertexInputStreamType : uint8
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    Default = 0,  // 默认
							 | 
						|||
| 
								 | 
							
								    PositionOnly, // 只有位置
							 | 
						|||
| 
								 | 
							
								    PositionAndNormalOnly // 只有位置和法线
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点流组件.
							 | 
						|||
| 
								 | 
							
								struct FVertexStreamComponent
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    // 流数据的顶点缓冲区, 如果为null, 则不会有数据从此顶点流被读取.
							 | 
						|||
| 
								 | 
							
								    const FVertexBuffer* VertexBuffer = nullptr;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // vertex buffer的偏移.
							 | 
						|||
| 
								 | 
							
								    uint32 StreamOffset = 0;
							 | 
						|||
| 
								 | 
							
								    // 数据的偏移, 相对于顶点缓冲区中每个元素的开头.
							 | 
						|||
| 
								 | 
							
								    uint8 Offset = 0;
							 | 
						|||
| 
								 | 
							
								    // 数据的步长.
							 | 
						|||
| 
								 | 
							
								    uint8 Stride = 0;
							 | 
						|||
| 
								 | 
							
								    // 从流读取的数据类型.
							 | 
						|||
| 
								 | 
							
								    TEnumAsByte<EVertexElementType> Type = VET_None;
							 | 
						|||
| 
								 | 
							
								    // 顶点流标记.
							 | 
						|||
| 
								 | 
							
								    EVertexStreamUsage VertexStreamUsage = EVertexStreamUsage::Default;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 着色器使用的顶点工厂的参数绑定接口.
							 | 
						|||
| 
								 | 
							
								class FVertexFactoryShaderParameters
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    // 绑定参数到ParameterMap. 具体逻辑由子类完成.
							 | 
						|||
| 
								 | 
							
								    void Bind(const class FShaderParameterMap& ParameterMap) {}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 获取顶点工厂的着色器绑定和顶点流. 具体逻辑由子类完成.
							 | 
						|||
| 
								 | 
							
								    void GetElementShaderBindings(
							 | 
						|||
| 
								 | 
							
								        const class FSceneInterface* Scene,
							 | 
						|||
| 
								 | 
							
								        const class FSceneView* View,
							 | 
						|||
| 
								 | 
							
								        const class FMeshMaterialShader* Shader,
							 | 
						|||
| 
								 | 
							
								        const EVertexInputStreamType InputStreamType,
							 | 
						|||
| 
								 | 
							
								        ERHIFeatureLevel::Type FeatureLevel,
							 | 
						|||
| 
								 | 
							
								        const class FVertexFactory* VertexFactory,
							 | 
						|||
| 
								 | 
							
								        const struct FMeshBatchElement& BatchElement,
							 | 
						|||
| 
								 | 
							
								        class FMeshDrawSingleShaderBindings& ShaderBindings,
							 | 
						|||
| 
								 | 
							
								        FVertexInputStreamArray& VertexStreams) const {}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 用来表示顶点工厂类型的类.
							 | 
						|||
| 
								 | 
							
								class FVertexFactoryType
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    // 类型定义
							 | 
						|||
| 
								 | 
							
								    typedef FVertexFactoryShaderParameters* (*ConstructParametersType)(EShaderFrequency ShaderFrequency, const class FShaderParameterMap& ParameterMap);
							 | 
						|||
| 
								 | 
							
								    typedef const FTypeLayoutDesc* (*GetParameterTypeLayoutType)(EShaderFrequency ShaderFrequency);
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 获取顶点工厂类型数量.
							 | 
						|||
| 
								 | 
							
								    static int32 GetNumVertexFactoryTypes();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 获取全局的着色器工厂列表.
							 | 
						|||
| 
								 | 
							
								    static RENDERCORE_API TLinkedList<FVertexFactoryType*>*& GetTypeList();
							 | 
						|||
| 
								 | 
							
								    // 获取已存的材质类型列表.
							 | 
						|||
| 
								 | 
							
								    static RENDERCORE_API const TArray<FVertexFactoryType*>& GetSortedMaterialTypes();
							 | 
						|||
| 
								 | 
							
								    // 通过名字查找FVertexFactoryType
							 | 
						|||
| 
								 | 
							
								    static RENDERCORE_API FVertexFactoryType* GetVFByName(const FHashedName& VFName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 初始化FVertexFactoryType静态成员, 必须在VF类型创建之前调用.
							 | 
						|||
| 
								 | 
							
								    static void Initialize(const TMap<FString, TArray<const TCHAR*> >& ShaderFileToUniformBufferVariables);
							 | 
						|||
| 
								 | 
							
								    static void Uninitialize();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 构造/析构函数.
							 | 
						|||
| 
								 | 
							
								    RENDERCORE_API FVertexFactoryType(...);
							 | 
						|||
| 
								 | 
							
								    virtual ~FVertexFactoryType();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 数据获取接口.
							 | 
						|||
| 
								 | 
							
								    const TCHAR* GetName() const;
							 | 
						|||
| 
								 | 
							
								    FName GetFName() const;
							 | 
						|||
| 
								 | 
							
								    const FHashedName& GetHashedName() const;
							 | 
						|||
| 
								 | 
							
								    const TCHAR* GetShaderFilename() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 着色器参数接口.
							 | 
						|||
| 
								 | 
							
								    FVertexFactoryShaderParameters* CreateShaderParameters(...) const;
							 | 
						|||
| 
								 | 
							
								    const FTypeLayoutDesc* GetShaderParameterLayout(...) const;
							 | 
						|||
| 
								 | 
							
								    void GetShaderParameterElementShaderBindings(...) const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 标记访问.
							 | 
						|||
| 
								 | 
							
								    bool IsUsedWithMaterials() const;
							 | 
						|||
| 
								 | 
							
								    bool SupportsStaticLighting() const;
							 | 
						|||
| 
								 | 
							
								    bool SupportsDynamicLighting() const;
							 | 
						|||
| 
								 | 
							
								    bool SupportsPrecisePrevWorldPos() const;
							 | 
						|||
| 
								 | 
							
								    bool SupportsPositionOnly() const;
							 | 
						|||
| 
								 | 
							
								    bool SupportsCachingMeshDrawCommands() const;
							 | 
						|||
| 
								 | 
							
								    bool SupportsPrimitiveIdStream() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 获取哈希.
							 | 
						|||
| 
								 | 
							
								    friend uint32 GetTypeHash(const FVertexFactoryType* Type);
							 | 
						|||
| 
								 | 
							
								    // 基于顶点工厂类型的源码和包含计算出来的哈希.
							 | 
						|||
| 
								 | 
							
								    const FSHAHash& GetSourceHash(EShaderPlatform ShaderPlatform) const;
							 | 
						|||
| 
								 | 
							
								    // 是否需要缓存材质的着色器类型.
							 | 
						|||
| 
								 | 
							
								    bool ShouldCache(const FVertexFactoryShaderPermutationParameters& Parameters) const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    void ModifyCompilationEnvironment(...);
							 | 
						|||
| 
								 | 
							
								    void ValidateCompiledResult(EShaderPlatform Platform, ...);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    bool SupportsTessellationShaders() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 增加引用的Uniform Buffer包含.
							 | 
						|||
| 
								 | 
							
								    void AddReferencedUniformBufferIncludes(...);
							 | 
						|||
| 
								 | 
							
								    void FlushShaderFileCache(...);
							 | 
						|||
| 
								 | 
							
								    const TMap<const TCHAR*, FCachedUniformBufferDeclaration>& GetReferencedUniformBufferStructsCache() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								    static uint32 NumVertexFactories;
							 | 
						|||
| 
								 | 
							
								    static bool bInitializedSerializationHistory;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 顶点工厂类型的各类数据和标记.
							 | 
						|||
| 
								 | 
							
								    const TCHAR* Name;
							 | 
						|||
| 
								 | 
							
								    const TCHAR* ShaderFilename;
							 | 
						|||
| 
								 | 
							
								    FName TypeName;
							 | 
						|||
| 
								 | 
							
								    FHashedName HashedName;
							 | 
						|||
| 
								 | 
							
								    uint32 bUsedWithMaterials : 1;
							 | 
						|||
| 
								 | 
							
								    uint32 bSupportsStaticLighting : 1;
							 | 
						|||
| 
								 | 
							
								    uint32 bSupportsDynamicLighting : 1;
							 | 
						|||
| 
								 | 
							
								    uint32 bSupportsPrecisePrevWorldPos : 1;
							 | 
						|||
| 
								 | 
							
								    uint32 bSupportsPositionOnly : 1;
							 | 
						|||
| 
								 | 
							
								    uint32 bSupportsCachingMeshDrawCommands : 1;
							 | 
						|||
| 
								 | 
							
								    uint32 bSupportsPrimitiveIdStream : 1;
							 | 
						|||
| 
								 | 
							
								    ConstructParametersType ConstructParameters;
							 | 
						|||
| 
								 | 
							
								    GetParameterTypeLayoutType GetParameterTypeLayout;
							 | 
						|||
| 
								 | 
							
								    GetParameterTypeElementShaderBindingsType GetParameterTypeElementShaderBindings;
							 | 
						|||
| 
								 | 
							
								    ShouldCacheType ShouldCacheRef;
							 | 
						|||
| 
								 | 
							
								    ModifyCompilationEnvironmentType ModifyCompilationEnvironmentRef;
							 | 
						|||
| 
								 | 
							
								    ValidateCompiledResultType ValidateCompiledResultRef;
							 | 
						|||
| 
								 | 
							
								    SupportsTessellationShadersType SupportsTessellationShadersRef;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 全局顶点工厂类型列表.
							 | 
						|||
| 
								 | 
							
								    TLinkedList<FVertexFactoryType*> GlobalListLink;
							 | 
						|||
| 
								 | 
							
								    // 缓存引用的Uniform Buffer的包含.
							 | 
						|||
| 
								 | 
							
								    TMap<const TCHAR*, FCachedUniformBufferDeclaration> ReferencedUniformBufferStructsCache;
							 | 
						|||
| 
								 | 
							
								    // 跟踪ReferencedUniformBufferStructsCache缓存了哪些平台的声明.
							 | 
						|||
| 
								 | 
							
								    bool bCachedUniformBufferStructDeclarations;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// ------顶点工厂的工具宏------
							 | 
						|||
| 
								 | 
							
								// 实现顶点工厂参数类型
							 | 
						|||
| 
								 | 
							
								#define IMPLEMENT_VERTEX_FACTORY_PARAMETER_TYPE(FactoryClass, ShaderFrequency, ParameterClass)
							 | 
						|||
| 
								 | 
							
								// 顶点工厂类型的声明
							 | 
						|||
| 
								 | 
							
								#define DECLARE_VERTEX_FACTORY_TYPE(FactoryClass)
							 | 
						|||
| 
								 | 
							
								// 顶点工厂类型的实现
							 | 
						|||
| 
								 | 
							
								#define IMPLEMENT_VERTEX_FACTORY_TYPE(FactoryClass,ShaderFilename,bUsedWithMaterials,bSupportsStaticLighting,bSupportsDynamicLighting,bPrecisePrevWorldPos,bSupportsPositionOnly)
							 | 
						|||
| 
								 | 
							
								// 顶点工厂的虚函数表实现
							 | 
						|||
| 
								 | 
							
								#define IMPLEMENT_VERTEX_FACTORY_VTABLE(FactoryClass
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点工厂
							 | 
						|||
| 
								 | 
							
								class FVertexFactory : public FRenderResource
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    FVertexFactory(ERHIFeatureLevel::Type InFeatureLevel);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    virtual FVertexFactoryType* GetType() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 获取顶点数据流.
							 | 
						|||
| 
								 | 
							
								    void GetStreams(ERHIFeatureLevel::Type InFeatureLevel, EVertexInputStreamType VertexStreamType, FVertexInputStreamArray& OutVertexStreams) const
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        // Default顶点流类型
							 | 
						|||
| 
								 | 
							
								        if (VertexStreamType == EVertexInputStreamType::Default)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            bool bSupportsVertexFetch = SupportsManualVertexFetch(InFeatureLevel);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            // 将顶点工厂的数据构造到FVertexInputStream中并添加到输出列表
							 | 
						|||
| 
								 | 
							
								            for (int32 StreamIndex = 0;StreamIndex < Streams.Num();StreamIndex++)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                const FVertexStream& Stream = Streams[StreamIndex];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                if (!(EnumHasAnyFlags(EVertexStreamUsage::ManualFetch, Stream.VertexStreamUsage) && bSupportsVertexFetch))
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    if (!Stream.VertexBuffer)
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        OutVertexStreams.Add(FVertexInputStream(StreamIndex, 0, nullptr));
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                    else
							 | 
						|||
| 
								 | 
							
								                    {
							 | 
						|||
| 
								 | 
							
								                        if (EnumHasAnyFlags(EVertexStreamUsage::Overridden, Stream.VertexStreamUsage) && !Stream.VertexBuffer->IsInitialized())
							 | 
						|||
| 
								 | 
							
								                        {
							 | 
						|||
| 
								 | 
							
								                            OutVertexStreams.Add(FVertexInputStream(StreamIndex, 0, nullptr));
							 | 
						|||
| 
								 | 
							
								                        }
							 | 
						|||
| 
								 | 
							
								                        else
							 | 
						|||
| 
								 | 
							
								                        {
							 | 
						|||
| 
								 | 
							
								                            OutVertexStreams.Add(FVertexInputStream(StreamIndex, Stream.Offset, Stream.VertexBuffer->VertexBufferRHI));
							 | 
						|||
| 
								 | 
							
								                        }
							 | 
						|||
| 
								 | 
							
								                    }
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        // 只有位置和的顶点流类型
							 | 
						|||
| 
								 | 
							
								        else if (VertexStreamType == EVertexInputStreamType::PositionOnly)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            // Set the predefined vertex streams.
							 | 
						|||
| 
								 | 
							
								            for (int32 StreamIndex = 0; StreamIndex < PositionStream.Num(); StreamIndex++)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                const FVertexStream& Stream = PositionStream[StreamIndex];
							 | 
						|||
| 
								 | 
							
								                OutVertexStreams.Add(FVertexInputStream(StreamIndex, Stream.Offset, Stream.VertexBuffer->VertexBufferRHI));
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        // 只有位置和法线的顶点流类型
							 | 
						|||
| 
								 | 
							
								        else if (VertexStreamType == EVertexInputStreamType::PositionAndNormalOnly)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            // Set the predefined vertex streams.
							 | 
						|||
| 
								 | 
							
								            for (int32 StreamIndex = 0; StreamIndex < PositionAndNormalStream.Num(); StreamIndex++)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                const FVertexStream& Stream = PositionAndNormalStream[StreamIndex];
							 | 
						|||
| 
								 | 
							
								                OutVertexStreams.Add(FVertexInputStream(StreamIndex, Stream.Offset, Stream.VertexBuffer->VertexBufferRHI));
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        else
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            // NOT_IMPLEMENTED
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    // 偏移实例的数据流.
							 | 
						|||
| 
								 | 
							
								    void OffsetInstanceStreams(uint32 InstanceOffset, EVertexInputStreamType VertexStreamType, FVertexInputStreamArray& VertexStreams) const;
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    static void ModifyCompilationEnvironment(...);
							 | 
						|||
| 
								 | 
							
								    static void ValidateCompiledResult(...);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    static bool SupportsTessellationShaders();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // FRenderResource接口, 释放RHI资源.
							 | 
						|||
| 
								 | 
							
								    virtual void ReleaseRHI();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 设置/获取顶点声明的RHI引用.
							 | 
						|||
| 
								 | 
							
								    FVertexDeclarationRHIRef& GetDeclaration();
							 | 
						|||
| 
								 | 
							
								    void SetDeclaration(FVertexDeclarationRHIRef& NewDeclaration);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 根据类型获取顶点声明的RHI引用.
							 | 
						|||
| 
								 | 
							
								    const FVertexDeclarationRHIRef& GetDeclaration(EVertexInputStreamType InputStreamType) const 
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        switch (InputStreamType)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								        case EVertexInputStreamType::Default:                return Declaration;
							 | 
						|||
| 
								 | 
							
								        case EVertexInputStreamType::PositionOnly:            return PositionDeclaration;
							 | 
						|||
| 
								 | 
							
								        case EVertexInputStreamType::PositionAndNormalOnly:    return PositionAndNormalDeclaration;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        return Declaration;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 各类标记.
							 | 
						|||
| 
								 | 
							
								    virtual bool IsGPUSkinned() const;
							 | 
						|||
| 
								 | 
							
								    virtual bool SupportsPositionOnlyStream() const;
							 | 
						|||
| 
								 | 
							
								    virtual bool SupportsPositionAndNormalOnlyStream() const;
							 | 
						|||
| 
								 | 
							
								    virtual bool SupportsNullPixelShader() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 用面向摄像机精灵的方式渲染图元.
							 | 
						|||
| 
								 | 
							
								    virtual bool RendersPrimitivesAsCameraFacingSprites() const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 是否需要顶点声明.
							 | 
						|||
| 
								 | 
							
								    bool NeedsDeclaration() const;
							 | 
						|||
| 
								 | 
							
								    // 是否支持手动的顶点获取.
							 | 
						|||
| 
								 | 
							
								    inline bool SupportsManualVertexFetch(const FStaticFeatureLevel InFeatureLevel) const;
							 | 
						|||
| 
								 | 
							
								    // 根据流类型获取索引.
							 | 
						|||
| 
								 | 
							
								    inline int32 GetPrimitiveIdStreamIndex(EVertexInputStreamType InputStreamType) const;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								protected:
							 | 
						|||
| 
								 | 
							
								    inline void SetPrimitiveIdStreamIndex(EVertexInputStreamType InputStreamType, int32 StreamIndex)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        PrimitiveIdStreamIndex[static_cast<uint8>(InputStreamType)] = StreamIndex;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 为顶点流组件创建顶点元素.
							 | 
						|||
| 
								 | 
							
								    FVertexElement AccessStreamComponent(const FVertexStreamComponent& Component,uint8 AttributeIndex);
							 | 
						|||
| 
								 | 
							
								    FVertexElement AccessStreamComponent(const FVertexStreamComponent& Component, uint8 AttributeIndex, EVertexInputStreamType InputStreamType);
							 | 
						|||
| 
								 | 
							
								    // 初始化顶点声明.
							 | 
						|||
| 
								 | 
							
								    void InitDeclaration(const FVertexDeclarationElementList& Elements, EVertexInputStreamType StreamType = EVertexInputStreamType::Default)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (StreamType == EVertexInputStreamType::PositionOnly)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            PositionDeclaration = PipelineStateCache::GetOrCreateVertexDeclaration(Elements);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        else if (StreamType == EVertexInputStreamType::PositionAndNormalOnly)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            PositionAndNormalDeclaration = PipelineStateCache::GetOrCreateVertexDeclaration(Elements);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        else // (StreamType == EVertexInputStreamType::Default)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            // Create the vertex declaration for rendering the factory normally.
							 | 
						|||
| 
								 | 
							
								            Declaration = PipelineStateCache::GetOrCreateVertexDeclaration(Elements);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 顶点流, 需要设置到顶点流的信息体.
							 | 
						|||
| 
								 | 
							
								    struct FVertexStream
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        const FVertexBuffer* VertexBuffer = nullptr;
							 | 
						|||
| 
								 | 
							
								        uint32 Offset = 0;
							 | 
						|||
| 
								 | 
							
								        uint16 Stride = 0;
							 | 
						|||
| 
								 | 
							
								        EVertexStreamUsage VertexStreamUsage = EVertexStreamUsage::Default;
							 | 
						|||
| 
								 | 
							
								        uint8 Padding = 0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        friend bool operator==(const FVertexStream& A,const FVertexStream& B);
							 | 
						|||
| 
								 | 
							
								        FVertexStream();
							 | 
						|||
| 
								 | 
							
								    };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 用于渲染顶点工厂的顶点流.
							 | 
						|||
| 
								 | 
							
								    TArray<FVertexStream,TInlineAllocator<8> > Streams;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // VF(顶点工厂)可以显式地将此设置为false,以避免在没有声明的情况下出现错误. 主要用于需要直接从缓冲区获取数据的VF(如Niagara).
							 | 
						|||
| 
								 | 
							
								    bool bNeedsDeclaration = true;
							 | 
						|||
| 
								 | 
							
								    bool bSupportsManualVertexFetch = false;
							 | 
						|||
| 
								 | 
							
								    int8 PrimitiveIdStreamIndex[3] = { -1, -1, -1 };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								    // 只有位置的顶点流, 用于渲染深度Pass的顶点工厂.
							 | 
						|||
| 
								 | 
							
								    TArray<FVertexStream,TInlineAllocator<2> > PositionStream;
							 | 
						|||
| 
								 | 
							
								    // 只有位置和法线的顶点流.
							 | 
						|||
| 
								 | 
							
								    TArray<FVertexStream, TInlineAllocator<3> > PositionAndNormalStream;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 用于常规渲染顶点工厂的RHI顶点声明.
							 | 
						|||
| 
								 | 
							
								    FVertexDeclarationRHIRef Declaration;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // PositionStream和PositionAndNormalStream对应的RHI资源.
							 | 
						|||
| 
								 | 
							
								    FVertexDeclarationRHIRef PositionDeclaration;
							 | 
						|||
| 
								 | 
							
								    FVertexDeclarationRHIRef PositionAndNormalDeclaration;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								上面展示了Vertex Factory的很多类型,有好几个是核心类,比如FVertexFactory、FVertexElement、FRHIVertexDeclaration、FRHIVertexBuffer、FVertexFactoryType、FVertexStreamComponent、FVertexInputStream、FVertexFactoryShaderParameters等。那么它们之间的关系是什么呢?
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								为了更好地说明它们之间的关系,以静态模型的FStaticMeshDataType为例:
							 | 
						|||
| 
								 | 
							
								![[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<FString>& 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<FLocalVertexFactoryUniformShaderParameters> 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<uint8>(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<uint8>(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);
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								下面进入CableComponent相关类型关于FLocalVertexFactory的使用:
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								// Engine\Plugins\Runtime\CableComponent\Source\CableComponent\Private\CableComponent.cpp
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								class FCableSceneProxy final : public FPrimitiveSceneProxy
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    FCableSceneProxy(UCableComponent* Component)
							 | 
						|||
| 
								 | 
							
								        : FPrimitiveSceneProxy(Component)
							 | 
						|||
| 
								 | 
							
								        , Material(NULL)
							 | 
						|||
| 
								 | 
							
								        // 构造顶点工厂.
							 | 
						|||
| 
								 | 
							
								        , VertexFactory(GetScene().GetFeatureLevel(), "FCableSceneProxy")
							 | 
						|||
| 
								 | 
							
								        (......)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        // 利用顶点工厂初始化缓冲区.
							 | 
						|||
| 
								 | 
							
								        VertexBuffers.InitWithDummyData(&VertexFactory, GetRequiredVertexCount());
							 | 
						|||
| 
								 | 
							
								        (......)
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    virtual ~FCableSceneProxy()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        // 释放顶点工厂.
							 | 
						|||
| 
								 | 
							
								        VertexFactory.ReleaseResource();
							 | 
						|||
| 
								 | 
							
								        (......)
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 构建Cable网格.
							 | 
						|||
| 
								 | 
							
								    void BuildCableMesh(const TArray<FVector>& InPoints, TArray<FDynamicMeshVertex>& OutVertices, TArray<int32>& OutIndices)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        (......)
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 设置动态数据(渲染线程调用)
							 | 
						|||
| 
								 | 
							
								    void SetDynamicData_RenderThread(FCableDynamicData* NewDynamicData)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        // 释放旧数据.
							 | 
						|||
| 
								 | 
							
								        if(DynamicData)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            delete DynamicData;
							 | 
						|||
| 
								 | 
							
								            DynamicData = NULL;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        DynamicData = NewDynamicData;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 从Cable点构建顶点.
							 | 
						|||
| 
								 | 
							
								        TArray<FDynamicMeshVertex> Vertices;
							 | 
						|||
| 
								 | 
							
								        TArray<int32> Indices;
							 | 
						|||
| 
								 | 
							
								        BuildCableMesh(NewDynamicData->CablePoints, Vertices, Indices);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 填充顶点缓冲区数据.
							 | 
						|||
| 
								 | 
							
								        for (int i = 0; i < Vertices.Num(); i++)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            const FDynamicMeshVertex& Vertex = Vertices[i];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            VertexBuffers.PositionVertexBuffer.VertexPosition(i) = Vertex.Position;
							 | 
						|||
| 
								 | 
							
								            VertexBuffers.StaticMeshVertexBuffer.SetVertexTangents(i, Vertex.TangentX.ToFVector(), Vertex.GetTangentY(), Vertex.TangentZ.ToFVector());
							 | 
						|||
| 
								 | 
							
								            VertexBuffers.StaticMeshVertexBuffer.SetVertexUV(i, 0, Vertex.TextureCoordinate[0]);
							 | 
						|||
| 
								 | 
							
								            VertexBuffers.ColorVertexBuffer.VertexColor(i) = Vertex.Color;
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 更新顶点缓冲区数据到RHI.
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            auto& VertexBuffer = VertexBuffers.PositionVertexBuffer;
							 | 
						|||
| 
								 | 
							
								            void* VertexBufferData = RHILockVertexBuffer(VertexBuffer.VertexBufferRHI, 0, VertexBuffer.GetNumVertices() * VertexBuffer.GetStride(), RLM_WriteOnly);
							 | 
						|||
| 
								 | 
							
								            FMemory::Memcpy(VertexBufferData, VertexBuffer.GetVertexData(), VertexBuffer.GetNumVertices() * VertexBuffer.GetStride());
							 | 
						|||
| 
								 | 
							
								            RHIUnlockVertexBuffer(VertexBuffer.VertexBufferRHI);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        (......)
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    virtual void GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const override
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        (......)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            if (VisibilityMap & (1 << ViewIndex))
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                const FSceneView* View = Views[ViewIndex];
							 | 
						|||
| 
								 | 
							
								                
							 | 
						|||
| 
								 | 
							
								                // 构造FMeshBatch实例.
							 | 
						|||
| 
								 | 
							
								                FMeshBatch& Mesh = Collector.AllocateMesh();
							 | 
						|||
| 
								 | 
							
								                // 将顶点工厂实例传给FMeshBatch实例.
							 | 
						|||
| 
								 | 
							
								                Mesh.VertexFactory = &VertexFactory;
							 | 
						|||
| 
								 | 
							
								                
							 | 
						|||
| 
								 | 
							
								                (......)
							 | 
						|||
| 
								 | 
							
								                
							 | 
						|||
| 
								 | 
							
								                Collector.AddMesh(ViewIndex, Mesh);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								    // 材质
							 | 
						|||
| 
								 | 
							
								    UMaterialInterface* Material;
							 | 
						|||
| 
								 | 
							
								    // 顶点和索引缓冲.
							 | 
						|||
| 
								 | 
							
								    FStaticMeshVertexBuffers VertexBuffers;
							 | 
						|||
| 
								 | 
							
								    FCableIndexBuffer IndexBuffer;
							 | 
						|||
| 
								 | 
							
								    // 顶点工厂.
							 | 
						|||
| 
								 | 
							
								    FLocalVertexFactory VertexFactory;
							 | 
						|||
| 
								 | 
							
								    // 动态数据.
							 | 
						|||
| 
								 | 
							
								    FCableDynamicData* DynamicData;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								主要步骤:
							 | 
						|||
| 
								 | 
							
								1. 在构造函数中初始化LocalVertexFactory成员变量。
							 | 
						|||
| 
								 | 
							
								2. SetDynamicData_RenderThread()
							 | 
						|||
| 
								 | 
							
									1. 通过控制点构建CableMesh顶点数据。
							 | 
						|||
| 
								 | 
							
									2. 填充顶点缓冲区数据。FStaticMeshVertexBuffers VertexBuffers
							 | 
						|||
| 
								 | 
							
										1. PositionVertexBuffer.VertexPosition
							 | 
						|||
| 
								 | 
							
										2. StaticMeshVertexBuffer.SetVertexTangents
							 | 
						|||
| 
								 | 
							
										3. StaticMeshVertexBuffer.SetVertexUV
							 | 
						|||
| 
								 | 
							
										4. ColorVertexBuffer.VertexColor
							 | 
						|||
| 
								 | 
							
									3. 更新IndexBufferData到RHI。
							 | 
						|||
| 
								 | 
							
								3. GetDynamicMeshElements():将顶点工厂实例传给FMeshBatch实例
							 | 
						|||
| 
								 | 
							
									1. FMeshBatch& Mesh = Collector.AllocateMesh();
							 | 
						|||
| 
								 | 
							
									2. Mesh.VertexFactory = &VertexFactory;
							 | 
						|||
| 
								 | 
							
									3. Collector.AddMesh(ViewIndex, Mesh);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								不过,无论是使用已有的还是自定义的顶点工厂,顶点工厂的顶点声明的顺序、类型、组件数量和插槽需要和HLSL层的FVertexFactoryInput保持一致。比如说FLocalVertexFactory::InitRHI的顶点声明顺序是位置、切线、颜色、纹理坐标、光照图,那么我们进入FLocalVertexFactory对应的HLSL文件(由IMPLEMENT_VERTEX_FACTORY_TYPE等宏指定)看看:
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								// Engine\Shaders\Private\LocalVertexFactory.ush
							 | 
						|||
| 
								 | 
							
								// 局部顶点工厂对应的输入结构体.
							 | 
						|||
| 
								 | 
							
								struct FVertexFactoryInput
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    // 位置
							 | 
						|||
| 
								 | 
							
								    float4    Position    : ATTRIBUTE0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 切线和颜色
							 | 
						|||
| 
								 | 
							
								#if !MANUAL_VERTEX_FETCH
							 | 
						|||
| 
								 | 
							
								    #if METAL_PROFILE
							 | 
						|||
| 
								 | 
							
								        float3    TangentX    : ATTRIBUTE1;
							 | 
						|||
| 
								 | 
							
								        // TangentZ.w contains sign of tangent basis determinant
							 | 
						|||
| 
								 | 
							
								        float4    TangentZ    : ATTRIBUTE2;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        float4    Color        : ATTRIBUTE3;
							 | 
						|||
| 
								 | 
							
								    #else
							 | 
						|||
| 
								 | 
							
								        half3    TangentX    : ATTRIBUTE1;
							 | 
						|||
| 
								 | 
							
								        // TangentZ.w contains sign of tangent basis determinant
							 | 
						|||
| 
								 | 
							
								        half4    TangentZ    : ATTRIBUTE2;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        half4    Color        : ATTRIBUTE3;
							 | 
						|||
| 
								 | 
							
								    #endif
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 纹理坐标
							 | 
						|||
| 
								 | 
							
								#if NUM_MATERIAL_TEXCOORDS_VERTEX
							 | 
						|||
| 
								 | 
							
								    #if !MANUAL_VERTEX_FETCH
							 | 
						|||
| 
								 | 
							
								        #if GPUSKIN_PASS_THROUGH
							 | 
						|||
| 
								 | 
							
								            // These must match GPUSkinVertexFactory.usf
							 | 
						|||
| 
								 | 
							
								            float2    TexCoords[NUM_MATERIAL_TEXCOORDS_VERTEX] : ATTRIBUTE4;
							 | 
						|||
| 
								 | 
							
								            #if NUM_MATERIAL_TEXCOORDS_VERTEX > 4
							 | 
						|||
| 
								 | 
							
								                #error Too many texture coordinate sets defined on GPUSkin vertex input. Max: 4.
							 | 
						|||
| 
								 | 
							
								            #endif
							 | 
						|||
| 
								 | 
							
								        #else
							 | 
						|||
| 
								 | 
							
								            #if NUM_MATERIAL_TEXCOORDS_VERTEX > 1
							 | 
						|||
| 
								 | 
							
								                float4    PackedTexCoords4[NUM_MATERIAL_TEXCOORDS_VERTEX/2] : ATTRIBUTE4;
							 | 
						|||
| 
								 | 
							
								            #endif
							 | 
						|||
| 
								 | 
							
								            #if NUM_MATERIAL_TEXCOORDS_VERTEX == 1
							 | 
						|||
| 
								 | 
							
								                float2    PackedTexCoords2 : ATTRIBUTE4;
							 | 
						|||
| 
								 | 
							
								            #elif NUM_MATERIAL_TEXCOORDS_VERTEX == 3
							 | 
						|||
| 
								 | 
							
								                float2    PackedTexCoords2 : ATTRIBUTE5;
							 | 
						|||
| 
								 | 
							
								            #elif NUM_MATERIAL_TEXCOORDS_VERTEX == 5
							 | 
						|||
| 
								 | 
							
								                float2    PackedTexCoords2 : ATTRIBUTE6;
							 | 
						|||
| 
								 | 
							
								            #elif NUM_MATERIAL_TEXCOORDS_VERTEX == 7
							 | 
						|||
| 
								 | 
							
								                float2    PackedTexCoords2 : ATTRIBUTE7;
							 | 
						|||
| 
								 | 
							
								            #endif
							 | 
						|||
| 
								 | 
							
								        #endif
							 | 
						|||
| 
								 | 
							
								    #endif
							 | 
						|||
| 
								 | 
							
								#elif USE_PARTICLE_SUBUVS && !MANUAL_VERTEX_FETCH
							 | 
						|||
| 
								 | 
							
								    float2    TexCoords[1] : ATTRIBUTE4;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								因此可知,FVertexFactoryInput结构体的数据顺序和FLocalVertexFactory的顶点声明是一一对应的。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# ShaderMap
							 | 
						|||
| 
								 | 
							
								ShaderMap的作用是**存储编译后的shader代码**,分为FGlobalShaderMap、FMaterialShaderMap、FMeshMaterialShaderMap三种类型。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								- FGlobalShaderMap:FGlobalShaderMap保存并管理着所有编译好的FGlobalShader代码。(**没有材质和顶点工程的**)
							 | 
						|||
| 
								 | 
							
								- FMaterialShaderMap:存储和管理着一组FMaterialShader实例的对象。(**额外关联一个材质和一个顶点工厂**)
							 | 
						|||
| 
								 | 
							
									- 因此可以找到,每个FMaterial都有一个FMaterialShaderMap(游戏线程一个,渲染线程一个),如果要获取FMaterial的指定类型的Shader,就需要从该FMaterial的FMaterialShaderMap实例中获取,从而完成了它们之间的链接。
							 | 
						|||
| 
								 | 
							
								- FMeshMaterialShaderMap:存储和管理FMeshMaterialShader。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								### 编译相关代码
							 | 
						|||
| 
								 | 
							
								如果需要了解编译过程可以查看`RecompileShaders`命令。
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								// Engine\Source\Runtime\Launch\Private\LaunchEngineLoop.cpp
							 | 
						|||
| 
								 | 
							
								// 引擎预初始化.
							 | 
						|||
| 
								 | 
							
								int32 FEngineLoop::PreInitPreStartupScreen(const TCHAR* CmdLine)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    // 是否开启shader编译, 一般情况下都会开启.
							 | 
						|||
| 
								 | 
							
								    bool bEnableShaderCompile = !FParse::Param(FCommandLine::Get(), TEXT("NoShaderCompile"));
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    if (bEnableShaderCompile && !IsRunningDedicatedServer() && !bIsCook)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        (......)
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        // 编译GlobalShaderMap
							 | 
						|||
| 
								 | 
							
								        CompileGlobalShaderMap(false);
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        (......)
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// Engine\Source\Runtime\Engine\Private\ShaderCompiler\ShaderCompiler.cpp
							 | 
						|||
| 
								 | 
							
								void CompileGlobalShaderMap(EShaderPlatform Platform, const ITargetPlatform* TargetPlatform, bool bRefreshShaderMap)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    (......)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 如果对应平台的GlobalShaderMap未创建, 则创建之.
							 | 
						|||
| 
								 | 
							
								    if (!GGlobalShaderMap[Platform])
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        (......)
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 创建对应平台的FGlobalShaderMap.
							 | 
						|||
| 
								 | 
							
								        GGlobalShaderMap[Platform] = new FGlobalShaderMap(Platform);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // Cooked模式.
							 | 
						|||
| 
								 | 
							
								        if (FPlatformProperties::RequiresCookedData())
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            (......)
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        // Uncooked模式
							 | 
						|||
| 
								 | 
							
								        else
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            // FGlobalShaderMap的id.
							 | 
						|||
| 
								 | 
							
								            FGlobalShaderMapId ShaderMapId(Platform);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            const int32 ShaderFilenameNum = ShaderMapId.GetShaderFilenameToDependeciesMap().Num();
							 | 
						|||
| 
								 | 
							
								            const float ProgressStep = 25.0f / ShaderFilenameNum;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            TArray<uint32> AsyncDDCRequestHandles;
							 | 
						|||
| 
								 | 
							
								            AsyncDDCRequestHandles.SetNum(ShaderFilenameNum);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            int32 HandleIndex = 0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            // 提交DDC请求.
							 | 
						|||
| 
								 | 
							
								            for (const auto& ShaderFilenameDependencies : ShaderMapId.GetShaderFilenameToDependeciesMap())
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                SlowTask.EnterProgressFrame(ProgressStep);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                const FString DataKey = GetGlobalShaderMapKeyString(ShaderMapId, Platform, TargetPlatform, ShaderFilenameDependencies.Value);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                AsyncDDCRequestHandles[HandleIndex] = GetDerivedDataCacheRef().GetAsynchronous(*DataKey, TEXT("GlobalShaderMap"_SV));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                ++HandleIndex;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            // 处理已经结束的DDC请求.
							 | 
						|||
| 
								 | 
							
								            TArray<uint8> CachedData;
							 | 
						|||
| 
								 | 
							
								            HandleIndex = 0;
							 | 
						|||
| 
								 | 
							
								            for (const auto& ShaderFilenameDependencies : ShaderMapId.GetShaderFilenameToDependeciesMap())
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                SlowTask.EnterProgressFrame(ProgressStep);
							 | 
						|||
| 
								 | 
							
								                CachedData.Reset();
							 | 
						|||
| 
								 | 
							
								                
							 | 
						|||
| 
								 | 
							
								                GetDerivedDataCacheRef().WaitAsynchronousCompletion(AsyncDDCRequestHandles[HandleIndex]);
							 | 
						|||
| 
								 | 
							
								                if (GetDerivedDataCacheRef().GetAsynchronousResults(AsyncDDCRequestHandles[HandleIndex], CachedData))
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    FMemoryReader MemoryReader(CachedData);
							 | 
						|||
| 
								 | 
							
								                    GGlobalShaderMap[Platform]->AddSection(FGlobalShaderMapSection::CreateFromArchive(MemoryReader));
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								                else
							 | 
						|||
| 
								 | 
							
								                {
							 | 
						|||
| 
								 | 
							
								                    // 没有在DDC中找到, 忽略之.
							 | 
						|||
| 
								 | 
							
								                }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                ++HandleIndex;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 如果有shader没有被加载, 编译之.
							 | 
						|||
| 
								 | 
							
								        VerifyGlobalShaders(Platform, bLoadedFromCacheFile);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 创建所有着色器.
							 | 
						|||
| 
								 | 
							
								        if (GCreateShadersOnLoad && Platform == GMaxRHIShaderPlatform)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            GGlobalShaderMap[Platform]->BeginCreateAllShaders();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# Shader调试
							 | 
						|||
| 
								 | 
							
								修改`Engine\Config\ConsoleVariables.ini`配置
							 | 
						|||
| 
								 | 
							
								- r.ShaderDevelopmentMode=1 获得关于着色器编译的详细日志和错误重试的机会。
							 | 
						|||
| 
								 | 
							
								- r.DumpShaderDebugInfo=1 将编译的所有着色器的文件保存到磁盘ProjectName/Saved/ShaderDebugInfo的目录。包含源文件、预处理后的版本、一个批处理文件(用于使用编译器等效的命令行选项来编译预处理版本)。
							 | 
						|||
| 
								 | 
							
								- r.DumpShaderDebugShortNames=1 保存的Shader路径将被精简。
							 | 
						|||
| 
								 | 
							
								- r.Shaders.Optimize=0 禁用着色器优化,使得shader的调试信息被保留。
							 | 
						|||
| 
								 | 
							
								- r.Shaders.KeepDebugInfo=1 保留调试信息,配合RenderDoc等截帧工具时特别有用。
							 | 
						|||
| 
								 | 
							
								- r.Shaders.SkipCompression=1 忽略shader压缩,可以节省调试shader的时间。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								另外,如果修改了Shader的某些文件(如BasePassPixelShader.ush),不需要重启UE编辑器,可以在控制台输入`RecompileShaders`命令重新编译指定的shader文件。其中`RecompileShaders`的具体含义如下:
							 | 
						|||
| 
								 | 
							
								- RecompileShaders all 编译源码有修改的所有shader,包含global、material、meshmaterial。
							 | 
						|||
| 
								 | 
							
								- RecompileShaders changed 编译源码有修改的shader。
							 | 
						|||
| 
								 | 
							
								- RecompileShaders global 编译源码有修改的global shader。
							 | 
						|||
| 
								 | 
							
								- RecompileShaders material 编译源码有修改的material shader。
							 | 
						|||
| 
								 | 
							
								- RecompileShaders material 编译指定名称的材质。
							 | 
						|||
| 
								 | 
							
								- RecompileShaders 编译指定路径的shader源文件。
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								# 案例
							 | 
						|||
| 
								 | 
							
								新增加FVertexFactory子类的过程如下:
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								// FMyVertexFactory.h
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 声明顶点工厂着色器参数.
							 | 
						|||
| 
								 | 
							
								BEGIN_GLOBAL_SHADER_PARAMETER_STRUCT(FMyVertexFactoryParameters, )
							 | 
						|||
| 
								 | 
							
								    SHADER_PARAMETER(FVector4, Color)
							 | 
						|||
| 
								 | 
							
								END_GLOBAL_SHADER_PARAMETER_STRUCT()
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 声明类型.
							 | 
						|||
| 
								 | 
							
								typedef TUniformBufferRef<FMyVertexFactoryParameters> FMyVertexFactoryBufferRef;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 索引缓冲.
							 | 
						|||
| 
								 | 
							
								class FMyMeshIndexBuffer : public FIndexBuffer
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    FMyMeshIndexBuffer(int32 InNumQuadsPerSide) : NumQuadsPerSide(InNumQuadsPerSide) {}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    void InitRHI() override
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        if (NumQuadsPerSide < 256)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            IndexBufferRHI = CreateIndexBuffer<uint16>();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        else
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            IndexBufferRHI = CreateIndexBuffer<uint32>();
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    int32 GetIndexCount() const { return NumIndices; };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								    template <typename IndexType>
							 | 
						|||
| 
								 | 
							
								    FIndexBufferRHIRef CreateIndexBuffer()
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        TResourceArray<IndexType, INDEXBUFFER_ALIGNMENT> Indices;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 分配顶点索引内存.
							 | 
						|||
| 
								 | 
							
								        Indices.Reserve(NumQuadsPerSide * NumQuadsPerSide * 6);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 用Morton顺序构建索引缓冲, 以更好地重用顶点.
							 | 
						|||
| 
								 | 
							
								        for (int32 Morton = 0; Morton < NumQuadsPerSide * NumQuadsPerSide; Morton++)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            int32 SquareX = FMath::ReverseMortonCode2(Morton);
							 | 
						|||
| 
								 | 
							
								            int32 SquareY = FMath::ReverseMortonCode2(Morton >> 1);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            bool ForwardDiagonal = false;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            if (SquareX % 2)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                ForwardDiagonal = !ForwardDiagonal;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            if (SquareY % 2)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                ForwardDiagonal = !ForwardDiagonal;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            int32 Index0 = SquareX + SquareY * (NumQuadsPerSide + 1);
							 | 
						|||
| 
								 | 
							
								            int32 Index1 = Index0 + 1;
							 | 
						|||
| 
								 | 
							
								            int32 Index2 = Index0 + (NumQuadsPerSide + 1);
							 | 
						|||
| 
								 | 
							
								            int32 Index3 = Index2 + 1;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            Indices.Add(Index3);
							 | 
						|||
| 
								 | 
							
								            Indices.Add(Index1);
							 | 
						|||
| 
								 | 
							
								            Indices.Add(ForwardDiagonal ? Index2 : Index0);
							 | 
						|||
| 
								 | 
							
								            Indices.Add(Index0);
							 | 
						|||
| 
								 | 
							
								            Indices.Add(Index2);
							 | 
						|||
| 
								 | 
							
								            Indices.Add(ForwardDiagonal ? Index1 : Index3);
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        NumIndices = Indices.Num();
							 | 
						|||
| 
								 | 
							
								        const uint32 Size = Indices.GetResourceDataSize();
							 | 
						|||
| 
								 | 
							
								        const uint32 Stride = sizeof(IndexType);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // Create index buffer. Fill buffer with initial data upon creation
							 | 
						|||
| 
								 | 
							
								        FRHIResourceCreateInfo CreateInfo(&Indices);
							 | 
						|||
| 
								 | 
							
								        return RHICreateIndexBuffer(Stride, Size, BUF_Static, CreateInfo);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    int32 NumIndices = 0;
							 | 
						|||
| 
								 | 
							
								    const int32 NumQuadsPerSide = 0;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点索引.
							 | 
						|||
| 
								 | 
							
								class FMyMeshVertexBuffer : public FVertexBuffer
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    FMyMeshVertexBuffer(int32 InNumQuadsPerSide) : NumQuadsPerSide(InNumQuadsPerSide) {}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    virtual void InitRHI() override
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        const uint32 NumVertsPerSide = NumQuadsPerSide + 1;
							 | 
						|||
| 
								 | 
							
								        
							 | 
						|||
| 
								 | 
							
								        NumVerts = NumVertsPerSide * NumVertsPerSide;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        FRHIResourceCreateInfo CreateInfo;
							 | 
						|||
| 
								 | 
							
								        void* BufferData = nullptr;
							 | 
						|||
| 
								 | 
							
								        VertexBufferRHI = RHICreateAndLockVertexBuffer(sizeof(FVector4) * NumVerts, BUF_Static, CreateInfo, BufferData);
							 | 
						|||
| 
								 | 
							
								        FVector4* DummyContents = (FVector4*)BufferData;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        for (uint32 VertY = 0; VertY < NumVertsPerSide; VertY++)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            FVector4 VertPos;
							 | 
						|||
| 
								 | 
							
								            VertPos.Y = (float)VertY / NumQuadsPerSide - 0.5f;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            for (uint32 VertX = 0; VertX < NumVertsPerSide; VertX++)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                VertPos.X = (float)VertX / NumQuadsPerSide - 0.5f;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                DummyContents[NumVertsPerSide * VertY + VertX] = VertPos;
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        RHIUnlockVertexBuffer(VertexBufferRHI);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    int32 GetVertexCount() const { return NumVerts; }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								    int32 NumVerts = 0;
							 | 
						|||
| 
								 | 
							
								    const int32 NumQuadsPerSide = 0;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点工厂.
							 | 
						|||
| 
								 | 
							
								class FMyVertexFactory : public FVertexFactory
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    DECLARE_VERTEX_FACTORY_TYPE(FMyVertexFactory);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    using Super = FVertexFactory;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    FMyVertexFactory(ERHIFeatureLevel::Type InFeatureLevel);
							 | 
						|||
| 
								 | 
							
								    ~FMyVertexFactory();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    virtual void InitRHI() override;
							 | 
						|||
| 
								 | 
							
								    virtual void ReleaseRHI() override;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    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<FString>& OutErrors);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    inline const FUniformBufferRHIRef GetMyVertexFactoryUniformBuffer() const { return UniformBuffer; }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
								    void SetupUniformData();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    FMyMeshVertexBuffer* VertexBuffer = nullptr;
							 | 
						|||
| 
								 | 
							
								    FMyMeshIndexBuffer* IndexBuffer = nullptr;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    FMyVertexFactoryBufferRef UniformBuffer;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// FMyVertexFactory.cpp
							 | 
						|||
| 
								 | 
							
								#include "ShaderParameterUtils.h"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 实现FMyVertexFactoryParameters, 注意在shader的名字是MyVF.
							 | 
						|||
| 
								 | 
							
								IMPLEMENT_GLOBAL_SHADER_PARAMETER_STRUCT(FMyVertexFactoryParameters, "MyVF");
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// 顶点工厂着色器参数.
							 | 
						|||
| 
								 | 
							
								class FMyVertexFactoryShaderParameters : public FVertexFactoryShaderParameters
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    DECLARE_TYPE_LAYOUT(FMyVertexFactoryShaderParameters, NonVirtual);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    void Bind(const FShaderParameterMap& ParameterMap)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    void GetElementShaderBindings(
							 | 
						|||
| 
								 | 
							
								        const class FSceneInterface* Scene,
							 | 
						|||
| 
								 | 
							
								        const class FSceneView* View,
							 | 
						|||
| 
								 | 
							
								        const class FMeshMaterialShader* Shader,
							 | 
						|||
| 
								 | 
							
								        const EVertexInputStreamType InputStreamType,
							 | 
						|||
| 
								 | 
							
								        ERHIFeatureLevel::Type FeatureLevel,
							 | 
						|||
| 
								 | 
							
								        const class FVertexFactory* InVertexFactory,
							 | 
						|||
| 
								 | 
							
								        const struct FMeshBatchElement& BatchElement,
							 | 
						|||
| 
								 | 
							
								        class FMeshDrawSingleShaderBindings& ShaderBindings,
							 | 
						|||
| 
								 | 
							
								        FVertexInputStreamArray& VertexStreams) const
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        // 强制转换成FMyVertexFactory.
							 | 
						|||
| 
								 | 
							
								        FMyVertexFactory* VertexFactory = (FMyVertexFactory*)InVertexFactory;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 增加shader帮定到表格.
							 | 
						|||
| 
								 | 
							
								        ShaderBindings.Add(Shader->GetUniformBufferParameter<FMyVertexFactoryShaderParameters>(), VertexFactory->GetMyVertexFactoryUniformBuffer());
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								        // 填充顶点流.
							 | 
						|||
| 
								 | 
							
								        if (VertexStreams.Num() > 0)
							 | 
						|||
| 
								 | 
							
								        {
							 | 
						|||
| 
								 | 
							
								            // 处理顶点流索引.
							 | 
						|||
| 
								 | 
							
								            for (int32 i = 0; i < 2; ++i)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                FVertexInputStream* InstanceInputStream = VertexStreams.FindByPredicate([i](const FVertexInputStream& InStream) { return InStream.StreamIndex == i+1; });
							 | 
						|||
| 
								 | 
							
								                // 绑定顶点流索引.
							 | 
						|||
| 
								 | 
							
								                InstanceInputStream->VertexBuffer = InstanceDataBuffers->GetBuffer(i);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								            // 处理偏移.
							 | 
						|||
| 
								 | 
							
								            if (InstanceOffsetValue > 0)
							 | 
						|||
| 
								 | 
							
								            {
							 | 
						|||
| 
								 | 
							
								                VertexFactory->OffsetInstanceStreams(InstanceOffsetValue, InputStreamType, VertexStreams);
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// ----------- 实现顶点工厂 -----------
							 | 
						|||
| 
								 | 
							
								FMyVertexFactory::FMyVertexFactory(ERHIFeatureLevel::Type InFeatureLevel)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    VertexBuffer = new FMyMeshVertexBuffer(16);
							 | 
						|||
| 
								 | 
							
								    IndexBuffer = new FMyMeshIndexBuffer(16);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								FMyVertexFactory::~FMyVertexFactory()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    delete VertexBuffer;
							 | 
						|||
| 
								 | 
							
								    delete IndexBuffer;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void FMyVertexFactory::InitRHI()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    Super::InitRHI();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 设置Uniform数据.
							 | 
						|||
| 
								 | 
							
								    SetupUniformData();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    VertexBuffer->InitResource();
							 | 
						|||
| 
								 | 
							
								    IndexBuffer->InitResource();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 顶点流: 位置
							 | 
						|||
| 
								 | 
							
								    FVertexStream PositionVertexStream;
							 | 
						|||
| 
								 | 
							
								    PositionVertexStream.VertexBuffer = VertexBuffer;
							 | 
						|||
| 
								 | 
							
								    PositionVertexStream.Stride = sizeof(FVector4);
							 | 
						|||
| 
								 | 
							
								    PositionVertexStream.Offset = 0;
							 | 
						|||
| 
								 | 
							
								    PositionVertexStream.VertexStreamUsage = EVertexStreamUsage::Default;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 简单的实例化顶点流数据 其中VertexBuffer在绑定时设置.
							 | 
						|||
| 
								 | 
							
								    FVertexStream InstanceDataVertexStream;
							 | 
						|||
| 
								 | 
							
								    InstanceDataVertexStream.VertexBuffer = nullptr;
							 | 
						|||
| 
								 | 
							
								    InstanceDataVertexStream.Stride = sizeof(FVector4);
							 | 
						|||
| 
								 | 
							
								    InstanceDataVertexStream.Offset = 0;
							 | 
						|||
| 
								 | 
							
								    InstanceDataVertexStream.VertexStreamUsage = EVertexStreamUsage::Instancing;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    FVertexElement VertexPositionElement(Streams.Add(PositionVertexStream), 0, VET_Float4, 0, PositionVertexStream.Stride, false);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 顶点声明.
							 | 
						|||
| 
								 | 
							
								    FVertexDeclarationElementList Elements;
							 | 
						|||
| 
								 | 
							
								    Elements.Add(VertexPositionElement);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 添加索引顶点流.
							 | 
						|||
| 
								 | 
							
								    for (int32 StreamIdx = 0; StreamIdx < NumAdditionalVertexStreams; ++StreamIdx)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        FVertexElement InstanceElement(Streams.Add(InstanceDataVertexStream), 0, VET_Float4, 8 + StreamIdx, InstanceDataVertexStream.Stride, true);
							 | 
						|||
| 
								 | 
							
								        Elements.Add(InstanceElement);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // 初始化声明.
							 | 
						|||
| 
								 | 
							
								    InitDeclaration(Elements);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void FMyVertexFactory::ReleaseRHI()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    UniformBuffer.SafeRelease();
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    if (VertexBuffer)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        VertexBuffer->ReleaseResource();
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    if (IndexBuffer)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        IndexBuffer->ReleaseResource();
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    Super::ReleaseRHI();
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void FMyVertexFactory::SetupUniformData()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    FMyVertexFactoryParameters UniformParams;
							 | 
						|||
| 
								 | 
							
								    UniformParams.Color = FVector4(1,0,0,1);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    UniformBuffer = FMyVertexFactoryBufferRef::CreateUniformBufferImmediate(UniformParams, UniformBuffer_MultiFrame);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void FMyVertexFactory::ShouldCompilePermutation(const FVertexFactoryShaderPermutationParameters& Parameters)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    return true;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void FMyVertexFactory::ModifyCompilationEnvironment(const FVertexFactoryShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    OutEnvironment.SetDefine(TEXT("MY_MESH_FACTORY"), 1);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void FMyVertexFactory::ValidateCompiledResult(const FVertexFactoryType* Type, EShaderPlatform Platform, const FShaderParameterMap& ParameterMap, TArray<FString>& OutErrors)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								C++层的逻辑已经完成,但HLSL层也需要编写对应的代码:
							 | 
						|||
| 
								 | 
							
								```c++
							 | 
						|||
| 
								 | 
							
								#include "/Engine/Private/VertexFactoryCommon.ush"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// VS插值到PS的结构体。
							 | 
						|||
| 
								 | 
							
								struct FVertexFactoryInterpolantsVSToPS
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								#if NUM_TEX_COORD_INTERPOLATORS
							 | 
						|||
| 
								 | 
							
								    float4    TexCoords[(NUM_TEX_COORD_INTERPOLATORS+1)/2] : TEXCOORD0;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if VF_USE_PRIMITIVE_SCENE_DATA
							 | 
						|||
| 
								 | 
							
								    nointerpolation uint PrimitiveId : PRIMITIVE_ID;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if INSTANCED_STEREO
							 | 
						|||
| 
								 | 
							
								    nointerpolation uint EyeIndex : PACKED_EYE_INDEX;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								struct FVertexFactoryInput
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    float4    Position    : ATTRIBUTE0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    float4 InstanceData0 : ATTRIBUTE8;
							 | 
						|||
| 
								 | 
							
								    float4 InstanceData1 : ATTRIBUTE9; 
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if VF_USE_PRIMITIVE_SCENE_DATA
							 | 
						|||
| 
								 | 
							
								    uint PrimitiveId : ATTRIBUTE13;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								struct FPositionOnlyVertexFactoryInput
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    float4    Position    : ATTRIBUTE0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    float4 InstanceData0 : ATTRIBUTE8;
							 | 
						|||
| 
								 | 
							
								    float4 InstanceData1 : ATTRIBUTE9; 
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if VF_USE_PRIMITIVE_SCENE_DATA
							 | 
						|||
| 
								 | 
							
								    uint PrimitiveId : ATTRIBUTE1;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								struct FPositionAndNormalOnlyVertexFactoryInput
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    float4    Position    : ATTRIBUTE0;
							 | 
						|||
| 
								 | 
							
								    float4    Normal        : ATTRIBUTE2;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    float4 InstanceData0 : ATTRIBUTE8;
							 | 
						|||
| 
								 | 
							
								    float4 InstanceData1 : ATTRIBUTE9; 
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if VF_USE_PRIMITIVE_SCENE_DATA
							 | 
						|||
| 
								 | 
							
								    uint PrimitiveId : ATTRIBUTE1;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								struct FVertexFactoryIntermediates
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    float3 OriginalWorldPos;
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    uint PrimitiveId;
							 | 
						|||
| 
								 | 
							
								};
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								uint GetPrimitiveId(FVertexFactoryInterpolantsVSToPS Interpolants)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								#if VF_USE_PRIMITIVE_SCENE_DATA
							 | 
						|||
| 
								 | 
							
								    return Interpolants.PrimitiveId;
							 | 
						|||
| 
								 | 
							
								#else
							 | 
						|||
| 
								 | 
							
								    return 0;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void SetPrimitiveId(inout FVertexFactoryInterpolantsVSToPS Interpolants, uint PrimitiveId)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								#if VF_USE_PRIMITIVE_SCENE_DATA
							 | 
						|||
| 
								 | 
							
								    Interpolants.PrimitiveId = PrimitiveId;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if NUM_TEX_COORD_INTERPOLATORS
							 | 
						|||
| 
								 | 
							
								float2 GetUV(FVertexFactoryInterpolantsVSToPS Interpolants, int UVIndex)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    float4 UVVector = Interpolants.TexCoords[UVIndex / 2];
							 | 
						|||
| 
								 | 
							
								    return UVIndex % 2 ? UVVector.zw : UVVector.xy;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void SetUV(inout FVertexFactoryInterpolantsVSToPS Interpolants, int UVIndex, float2 InValue)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    FLATTEN
							 | 
						|||
| 
								 | 
							
								    if (UVIndex % 2)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        Interpolants.TexCoords[UVIndex / 2].zw = InValue;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    else
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        Interpolants.TexCoords[UVIndex / 2].xy = InValue;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								FMaterialPixelParameters GetMaterialPixelParameters(FVertexFactoryInterpolantsVSToPS Interpolants, float4 SvPosition)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    // GetMaterialPixelParameters is responsible for fully initializing the result
							 | 
						|||
| 
								 | 
							
								    FMaterialPixelParameters Result = MakeInitializedMaterialPixelParameters();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if NUM_TEX_COORD_INTERPOLATORS
							 | 
						|||
| 
								 | 
							
								    UNROLL
							 | 
						|||
| 
								 | 
							
								    for (int CoordinateIndex = 0; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        Result.TexCoords[CoordinateIndex] = GetUV(Interpolants, CoordinateIndex);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								#endif    //NUM_MATERIAL_TEXCOORDS
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    Result.TwoSidedSign = 1;
							 | 
						|||
| 
								 | 
							
								    Result.PrimitiveId = GetPrimitiveId(Interpolants);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    return Result;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								FMaterialVertexParameters GetMaterialVertexParameters(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 WorldPosition, half3x3 TangentToLocal)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    FMaterialVertexParameters Result = (FMaterialVertexParameters)0;
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    Result.WorldPosition = WorldPosition;
							 | 
						|||
| 
								 | 
							
								    Result.TangentToWorld = float3x3(1,0,0,0,1,0,0,0,1);
							 | 
						|||
| 
								 | 
							
								    Result.PreSkinnedPosition = Input.Position.xyz;
							 | 
						|||
| 
								 | 
							
								    Result.PreSkinnedNormal = float3(0,0,1);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if NUM_MATERIAL_TEXCOORDS_VERTEX
							 | 
						|||
| 
								 | 
							
								    UNROLL
							 | 
						|||
| 
								 | 
							
								    for(int CoordinateIndex = 0; CoordinateIndex < NUM_MATERIAL_TEXCOORDS_VERTEX; CoordinateIndex++)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        Result.TexCoords[CoordinateIndex] = Intermediates.MorphedWorldPosRaw.xy;
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								#endif  //NUM_MATERIAL_TEXCOORDS_VERTEX
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    return Result;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								FVertexFactoryIntermediates GetVertexFactoryIntermediates(FVertexFactoryInput Input)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    FVertexFactoryIntermediates Intermediates;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // Get the packed instance data
							 | 
						|||
| 
								 | 
							
								    float4 Data0 = Input.InstanceData0;
							 | 
						|||
| 
								 | 
							
								    float4 Data1 = Input.InstanceData1;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    const float3 Translation = Data0.xyz;
							 | 
						|||
| 
								 | 
							
								    const float3 Scale = float3(Data1.zw, 1.0f);
							 | 
						|||
| 
								 | 
							
								    const uint PackedDataChannel = asuint(Data1.x);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // Lod level is in first 8 bits and ShouldMorph bit is in the 9th bit
							 | 
						|||
| 
								 | 
							
								    const float LODLevel = (float)(PackedDataChannel & 0xFF);
							 | 
						|||
| 
								 | 
							
								    const uint ShouldMorph = ((PackedDataChannel >> 8) & 0x1); 
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    // Calculate the world pos
							 | 
						|||
| 
								 | 
							
								    Intermediates.OriginalWorldPos = float3(Input.Position.xy, 0.0f) * Scale + Translation;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if VF_USE_PRIMITIVE_SCENE_DATA
							 | 
						|||
| 
								 | 
							
								    Intermediates.PrimitiveId = Input.PrimitiveId;
							 | 
						|||
| 
								 | 
							
								#else
							 | 
						|||
| 
								 | 
							
								    Intermediates.PrimitiveId = 0;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    return Intermediates;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								half3x3 VertexFactoryGetTangentToLocal(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    return half3x3(1,0,0,0,1,0,0,0,1);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								float4 VertexFactoryGetRasterizedWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float4 InWorldPosition)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    return InWorldPosition;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								float3 VertexFactoryGetPositionForVertexLighting(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, float3 TranslatedWorldPosition)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    return TranslatedWorldPosition;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								FVertexFactoryInterpolantsVSToPS VertexFactoryGetInterpolantsVSToPS(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates, FMaterialVertexParameters VertexParameters)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    FVertexFactoryInterpolantsVSToPS Interpolants;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    Interpolants = (FVertexFactoryInterpolantsVSToPS)0;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if NUM_TEX_COORD_INTERPOLATORS
							 | 
						|||
| 
								 | 
							
								    float2 CustomizedUVs[NUM_TEX_COORD_INTERPOLATORS];
							 | 
						|||
| 
								 | 
							
								    GetMaterialCustomizedUVs(VertexParameters, CustomizedUVs);
							 | 
						|||
| 
								 | 
							
								    GetCustomInterpolators(VertexParameters, CustomizedUVs);
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
								    UNROLL
							 | 
						|||
| 
								 | 
							
								    for (int CoordinateIndex = 0; CoordinateIndex < NUM_TEX_COORD_INTERPOLATORS; CoordinateIndex++)
							 | 
						|||
| 
								 | 
							
								    {
							 | 
						|||
| 
								 | 
							
								        SetUV(Interpolants, CoordinateIndex, CustomizedUVs[CoordinateIndex]);
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if INSTANCED_STEREO
							 | 
						|||
| 
								 | 
							
								    Interpolants.EyeIndex = 0;
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    SetPrimitiveId(Interpolants, Intermediates.PrimitiveId);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    return Interpolants;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								float4 VertexFactoryGetWorldPosition(FPositionOnlyVertexFactoryInput Input)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    return Input.Position;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								float4 VertexFactoryGetPreviousWorldPosition(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    float4x4 PreviousLocalToWorldTranslated = GetPrimitiveData(Intermediates.PrimitiveId).PreviousLocalToWorld;
							 | 
						|||
| 
								 | 
							
								    PreviousLocalToWorldTranslated[3][0] += ResolvedView.PrevPreViewTranslation.x;
							 | 
						|||
| 
								 | 
							
								    PreviousLocalToWorldTranslated[3][1] += ResolvedView.PrevPreViewTranslation.y;
							 | 
						|||
| 
								 | 
							
								    PreviousLocalToWorldTranslated[3][2] += ResolvedView.PrevPreViewTranslation.z;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    return mul(Input.Position, PreviousLocalToWorldTranslated);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								float4 VertexFactoryGetTranslatedPrimitiveVolumeBounds(FVertexFactoryInterpolantsVSToPS Interpolants)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    float4 ObjectWorldPositionAndRadius = GetPrimitiveData(GetPrimitiveId(Interpolants)).ObjectWorldPositionAndRadius;
							 | 
						|||
| 
								 | 
							
								    return float4(ObjectWorldPositionAndRadius.xyz + ResolvedView.PreViewTranslation.xyz, ObjectWorldPositionAndRadius.w);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								uint VertexFactoryGetPrimitiveId(FVertexFactoryInterpolantsVSToPS Interpolants)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    return GetPrimitiveId(Interpolants);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								float3 VertexFactoryGetWorldNormal(FPositionAndNormalOnlyVertexFactoryInput Input)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    return Input.Normal.xyz;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								float3 VertexFactoryGetWorldNormal(FVertexFactoryInput Input, FVertexFactoryIntermediates Intermediates)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								    return float3(0.0f, 0.0f, 1.0f);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								```
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								由此可见,如果新增加了FVertexFactory的自定义类型,需要在HLSL实现以下接口:
							 | 
						|||
| 
								 | 
							
								- FVertexFactoryInput 定义输入到VS的数据布局,需要匹配c++侧的FVertexFactory的类型。
							 | 
						|||
| 
								 | 
							
								- FVertexFactoryIntermediates 用于存储将在多个顶点工厂函数中使用的缓存中间数据,比如TangentToLocal。
							 | 
						|||
| 
								 | 
							
								- FVertexFactoryInterpolantsVSToPS 从VS传递到PS的顶点工厂数据。
							 | 
						|||
| 
								 | 
							
								- VertexFactoryGetWorldPosition 从顶点着色器调用来获得世界空间的顶点位置。
							 | 
						|||
| 
								 | 
							
								- VertexFactoryGetInterpolantsVSToPS 转换FVertexFactoryInput到FVertexFactoryInterpolants,在硬件光栅化插值之前计算需要插值或传递到PS的数据。
							 | 
						|||
| 
								 | 
							
								- GetMaterialPixelParameters 由PS调用,根据FVertexFactoryInterpolants计算并填充FMaterialPixelParameters结构体。
							 |