27 KiB
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
。
定义宏
- SHADER_PARAMETER_STRUCT_REF:引用着色器参数结构体(全局的才行)
- SHADER_PARAMETER_STRUCT_INCLUDE:包含着色器参数结构体(局部或全局都行)
Vertex Factory
我们知道,在引擎中存在着静态网格、蒙皮骨骼、程序化网格以及地形等等类型的网格类型,而材质就是通过顶点工厂FVertexFactory来支持这些网格类型。实际上,顶点工厂要涉及各方面的数据和类型,包含但不限于:
- 顶点着色器。顶点着色器的输入输出需要顶点工厂来表明数据的布局。
- 顶点工厂的参数和RHI资源。这些数据将从C++层传入到顶点着色器中进行处理。
- 顶点缓冲和顶点布局。通过顶点布局,我们可以自定义和扩展顶点缓冲的输入,从而实现定制化的Shader代码。
- 几何预处理。顶点缓冲、网格资源、材质参数等等都可以在真正渲染前预处理它们。
!
顶点工厂在渲染层级中的关系。由图可知,顶点工厂是渲染线程的对象,横跨于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等。那么它们之间的关系是什么呢?