27 KiB
Raw Blame History

title, date, excerpt, tags, rating
title date excerpt tags rating
剖析虚幻渲染体系08- Shader体系 2024-02-04 21:44:10

前言

原文地址:https://www.cnblogs.com/timlly/p/15092257.html

FShader

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

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两端。

// 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