2024-02-05 22:33:10 +08:00
|
|
|
|
---
|
|
|
|
|
title: 剖析虚幻渲染体系(09)- 材质体系
|
|
|
|
|
date: 2024-02-05 22:00:48
|
|
|
|
|
excerpt:
|
|
|
|
|
tags:
|
|
|
|
|
rating: ⭐
|
|
|
|
|
---
|
|
|
|
|
# 前言
|
2024-02-06 21:26:28 +08:00
|
|
|
|
https://www.cnblogs.com/timlly/p/15109132.html
|
|
|
|
|
|
2024-02-07 19:34:16 +08:00
|
|
|
|
# 概念
|
|
|
|
|
- UMaterialInterface:材质的基础接口类, 定义了大量材质相关的数据和接口, 部分接口是空实现或未实现的接口。
|
|
|
|
|
- USubsurfaceProfile* SubsurfaceProfile:次表面散射轮廓,常用于皮肤、玉石等材质。
|
|
|
|
|
- TArray<UAssetUserData*> AssetUserData:用户数据,可以存多个数据。
|
|
|
|
|
- FLightmassMaterialInterfaceSettings LightmassSettings:离线GI数据。
|
|
|
|
|
- TArray TextureStreamingData:纹理流数据。
|
|
|
|
|
- UMaterial:材质类,继承自 UMaterialInterface,对应着一个材质资源文件。定义了材质所需的所有数据和操作接口,并负责打通其它关联类型的链接。
|
|
|
|
|
- TArray<FMaterialResource*> MaterialResources:材质渲染资源,一个材质可以拥有多个渲染资源实例。
|
|
|
|
|
- FDefaultMaterialInstance* DefaultMaterialInstance:默认的材质渲染代理,继承自FMaterialRenderProxy。
|
|
|
|
|
- UPhysicalMaterial* PhysMaterial:物理材质。
|
|
|
|
|
- TArray LoadedMaterialResources:已经加载的材质资源,通常由游戏线程从磁盘加载并序列化而来。
|
|
|
|
|
- 材质的各种属性和标记。
|
|
|
|
|
- UMaterialInstance:材质实例,**不能单独存在**,而**需要依赖UMaterialInterface类型的父类**,意味着父类可以是UMaterialInterface的任意一个子类,但最上层的父类必须是UMaterial。
|
|
|
|
|
- UMaterialInstanceConstant:为了**避免运行时因修改材质参数而引起重新编译**,它内部有限的数据覆盖也是因为此。如果不重新编译,就无法支持对材质的常规修改,因此实例只能更改预定义的材质参数的值。 这里的参数就是在材质编辑器内定义的唯一的名称、类型和默认值静态定义。另外,需要明确注意的是,在运行时的代码(非编辑器代码)中,我们是无法更改UMaterialInstanceConstant实例的材质属性。UMaterialInstanceConstant还有一个专用于渲染地貌的ULandscapeMaterialInstanceConstant的子类。
|
|
|
|
|
- UMaterialInstanceDynamic:提供了可以在**运行时代码动态创建和修改材质属性的功能**,并且同样**不会引起材质重新编译**。
|
|
|
|
|
- **FMaterialRenderProxy**:FMaterialRenderProxy负责**接收游戏线程代表的数据,然后传递给渲染器去处理和渲染**。FMaterialRenderProxy是个抽象类,定义了一个静态全局的材质渲染代理映射表和获取FMaterial渲染实例的接口。具体的逻辑由子类完成。
|
|
|
|
|
- **FDefaultMaterialInstance**:渲染UMaterial的默认代表实例。
|
|
|
|
|
- **FMaterialInstanceResource**:渲染UMaterialInstance实例的代表。
|
|
|
|
|
- FColoredMaterialRenderProxy:覆盖材质颜色向量参数的材质渲染代表。
|
|
|
|
|
- FLandscapeMaskMaterialRenderProxy:地貌遮罩材质渲染代表。
|
|
|
|
|
- FLightmassMaterialProxy:Lightmass材质渲染代理。
|
|
|
|
|
- ......
|
|
|
|
|
- **FMaterial**:
|
|
|
|
|
- **描述材质的编译过程**,并提供可扩展性钩子(CompileProperty等) 。
|
|
|
|
|
- **将材质属性传递到渲染器**,并使用函数访问材质属性。
|
|
|
|
|
- 存储缓存的**ShaderMap**(GameThread & RenderingThread),和其他来自编译的瞬态输出,这对异步着色器编译是必要的。
|
|
|
|
|
- **FMaterialResource**:继承自FMaterial,实现**材质接口**。
|
|
|
|
|
- 拥有对应的UMaterial、UMaterialInstance指针。
|
|
|
|
|
|
|
|
|
|
![[UE_UMaterial.png]]
|
|
|
|
|
UE的材质为何会有如此多的概念和类型,它们的关系到底怎么样?本节尝试阐述它们的关联和作用。
|
|
|
|
|
|
|
|
|
|
首先阐述**UMaterialInterface和它的子类们,它们是引擎模块在游戏线程的代表**。UMaterialInterface继承UOjbect,提供了材质的抽象接口,为子类提供了一致的行为和规范,也好统一不同类型的子类之间的差异。子类UMaterial则对应着用材质编辑器生成的材质蓝图的资源,保存了各种表达式节点及各种参数。另一个子类UMaterialInstance则抽象了材质实例的接口,是为了支持修改材质参数后不引发材质重新编译而存在的,同时统一和规范固定实例(UMaterialInstanceConstant)和动态实例(UMaterialInstanceDynamic)两种子类的数据和行为。UMaterialInstanceConstant在编辑器期间创建和修改好材质参数,运行时不可修改,提升数据更新和渲染的性能;UMaterialInstanceDynamic则可以运行时创建实例和修改数据,提升材质的扩展性和可定制性,但性能较UMaterialInstanceConstant差一些。UMaterialInstance需要指定一个父类,最顶层的父类要求是UMaterial实例。
|
|
|
|
|
|
|
|
|
|
**FMaterialRenderProxy是UMaterialInterface的渲染线程的代表**,类似于UPrimitiveComponent和FPrimitiveSceneProxy的关系。**FMaterialRenderProxy将UMaterialInterface实例的数据搬运(拷贝)到渲染线程,但同时也会在游戏线程被访问到,是两个线程的耦合类型,需要谨慎处理它们的数据和接口调用**。**FMaterialRenderProxy的子类对应着UMaterialInterface的子类,以便将UMaterialInterface的子类数据被精准地搬运(拷贝)到渲染线程,避免游戏线程和渲染线程的竞争**。FMaterialRenderProxy及其子类都是引擎模块的类型。
|
|
|
|
|
|
|
|
|
|
既然已经有了FMaterialRenderProxy的渲染线程代表,为什么还要存在FMaterial和FMaterialResource呢?答案有两点:
|
|
|
|
|
- FMaterialRenderProxy及其子类是引擎模块的类型,是游戏线程和渲染线程的胶囊类,需要谨慎处理两个线程的数据和接口调用,渲染模块无法真正完全拥有它的管辖权。
|
|
|
|
|
- FMaterialRenderProxy的数据由UMaterialInterface传递而来,意味着FMaterialRenderProxy的信息有限,无法包含使用了材质的网格的其它信息,如顶点工厂、ShaderMap、ShaderPipelineline、FShader及各种着色器参数等。
|
|
|
|
|
|
|
|
|
|
所以,FMaterial应运而生。FMaterial同是引擎模块的类型,但存储了游戏线程和渲染线程的两个ShaderMap,意味着渲染模块可以自由地访问渲染线程的ShaderMap,而又不影响游戏线程的访问。而且FMaterial包含了渲染材质所需的所有数据,渲染器的其它地方,只要拿到网格的FMaterial,便可以正常地获取材质数据,从而提交绘制指令。比如FBasePassMeshProcessor::AddMeshBatch的代码:
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Renderer\Private\BasePassRendering.cpp
|
|
|
|
|
|
|
|
|
|
void FBasePassMeshProcessor::AddMeshBatch(const FMeshBatch& RESTRICT MeshBatch, uint64 BatchElementMask, const FPrimitiveSceneProxy* RESTRICT PrimitiveSceneProxy, int32 StaticMeshId)
|
|
|
|
|
{
|
|
|
|
|
if (MeshBatch.bUseForMaterial)
|
|
|
|
|
{
|
|
|
|
|
const FMaterialRenderProxy* FallbackMaterialRenderProxyPtr = nullptr;
|
|
|
|
|
// 获取FMaterial实例.
|
|
|
|
|
const FMaterial& Material = MeshBatch.MaterialRenderProxy->GetMaterialWithFallback(FeatureLevel, FallbackMaterialRenderProxyPtr);
|
|
|
|
|
const FMaterialRenderProxy& MaterialRenderProxy = FallbackMaterialRenderProxyPtr ? *FallbackMaterialRenderProxyPtr : *MeshBatch.MaterialRenderProxy;
|
|
|
|
|
|
|
|
|
|
// 通过FMaterial接口获取材质数据.
|
|
|
|
|
const EBlendMode BlendMode = Material.GetBlendMode();
|
|
|
|
|
const FMaterialShadingModelField ShadingModels = Material.GetShadingModels();
|
|
|
|
|
const bool bIsTranslucent = IsTranslucentBlendMode(BlendMode);
|
|
|
|
|
const FMeshDrawingPolicyOverrideSettings OverrideSettings = ComputeMeshOverrideSettings(MeshBatch);
|
|
|
|
|
const ERasterizerFillMode MeshFillMode = ComputeMeshFillMode(MeshBatch, Material, OverrideSettings);
|
|
|
|
|
const ERasterizerCullMode MeshCullMode = ComputeMeshCullMode(MeshBatch, Material, OverrideSettings);
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
>其实应该说**FMaterial**与**FMaterialResource**从FMaterialRenderProxy中将**有多线程竞争风险的渲染所需数据进行剥离**。渲染器只需要拿到FMaterial就可以获取Shader数据并进行MeshBatch提交。
|
|
|
|
|
>在FMaterialRenderProxy中通过**GetMaterialXXX()** 系列函数获取FMaterial。如果Shader没有编译好会进行等待,并在等待完之后返回。GetMaterialFallbackXXX()系列函数会不断递归获取有效的FMaterial直到默认UMaterial::GetDefaultMaterial()。
|
|
|
|
|
>从UMaterial调用GetRenderProxy()获取**FDefaultMaterialInstance DefaultMaterialInstance**,而这个变量在**UMaterial::PostInitProperties()** 通过**DefaultMaterialInstance = new FDefaultMaterialInstance(this);** 初始化。
|
2024-02-07 21:19:35 +08:00
|
|
|
|
|
|
|
|
|
MaterialTemplate.ush:
|
|
|
|
|
- **FHLSLMaterialTranslator::Translate()** 转译材质蓝图的材质节点表达式,将所有材质属性的编译结果填充到格子的FShaderCodeChunk中。
|
|
|
|
|
- **FHLSLMaterialTranslator::GetMaterialEnvironment()** 处理材质蓝图的编译环境(宏定义)。
|
|
|
|
|
- **FHLSLMaterialTranslator::GetMaterialShaderCode()**:填充MaterialTemplate.ush的空缺代码,根据Translate编译的FShaderCodeChunk对应的材质属性接口,以及其它的宏定义、结构体、工具类接口。
|
|
|
|
|
|
2024-02-07 19:34:16 +08:00
|
|
|
|
# UMaterial
|
|
|
|
|
UMaterial是属于引擎层的概念,对应着我们在材质编辑器编辑的uasset资源文件,可以被应用到网格上,以便控制它在场景中的视觉效果。它继承自UMaterialInterface。
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Engine\Classes\Materials\MaterialInterface.h
|
|
|
|
|
|
|
|
|
|
// 材质的基础接口类, 定义了大量材质相关的数据和接口, 部分接口是空实现或未实现的接口.
|
|
|
|
|
class UMaterialInterface : public UObject, public IBlendableInterface, public IInterface_AssetUserData
|
|
|
|
|
{
|
|
|
|
|
// 次表面散射轮廓(配置)
|
|
|
|
|
class USubsurfaceProfile* SubsurfaceProfile;
|
|
|
|
|
// 当图元不再被用作父元素时进行跟踪的栅栏.
|
|
|
|
|
FRenderCommandFence ParentRefFence;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
// Lightmass离线的GI设置.
|
|
|
|
|
struct FLightmassMaterialInterfaceSettings LightmassSettings;
|
|
|
|
|
// 纹理流数据.
|
|
|
|
|
TArray<FMaterialTextureInfo> TextureStreamingData;
|
|
|
|
|
// 存于此材质资源内的用户数据列表.
|
|
|
|
|
TArray<UAssetUserData*> AssetUserData;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// 强制编译的目标Feature Level.
|
|
|
|
|
uint32 FeatureLevelsToForceCompile;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
//---- IInterface_AssetUserData接口 ----
|
|
|
|
|
virtual void AddAssetUserData(UAssetUserData* InUserData) override;
|
|
|
|
|
virtual void RemoveUserDataOfClass(TSubclassOf<UAssetUserData> InUserDataClass) override;
|
|
|
|
|
virtual UAssetUserData* GetAssetUserDataOfClass(TSubclassOf<UAssetUserData> InUserDataClass) override;
|
|
|
|
|
//---- IInterface_AssetUserData接口 ----
|
|
|
|
|
|
|
|
|
|
// 为所有材质编译的Featurelevel位域.
|
|
|
|
|
static uint32 FeatureLevelsForAllMaterials;
|
|
|
|
|
void SetFeatureLevelToCompile(ERHIFeatureLevel::Type FeatureLevel, bool bShouldCompile);
|
|
|
|
|
static void SetGlobalRequiredFeatureLevel(ERHIFeatureLevel::Type FeatureLevel, bool bShouldCompile);
|
|
|
|
|
|
|
|
|
|
//---- UObject接口 ----
|
|
|
|
|
virtual void BeginDestroy() override;
|
|
|
|
|
virtual bool IsReadyForFinishDestroy() override;
|
|
|
|
|
virtual void PostLoad() override;
|
|
|
|
|
virtual void PostDuplicate(bool bDuplicateForPIE) override;
|
|
|
|
|
virtual void PostCDOContruct() override;
|
|
|
|
|
//---- UObject接口 ----
|
|
|
|
|
|
|
|
|
|
//---- IBlendableInterface接口 ----
|
|
|
|
|
virtual void OverrideBlendableSettings(class FSceneView& View, float Weight) const override;
|
|
|
|
|
//---- IBlendableInterface接口 ----
|
|
|
|
|
|
|
|
|
|
// 沿着父链查找这个实例所在的基础材质.
|
|
|
|
|
UMaterial* GetBaseMaterial();
|
|
|
|
|
// 获取正在实例化的材质
|
|
|
|
|
virtual class UMaterial* GetMaterial() PURE_VIRTUAL(UMaterialInterface::GetMaterial,return NULL;);
|
|
|
|
|
virtual const class UMaterial* GetMaterial() const PURE_VIRTUAL(UMaterialInterface::GetMaterial,return NULL;);
|
|
|
|
|
// 获取正在实例化的材质(并发模式)
|
|
|
|
|
virtual const class UMaterial* GetMaterial_Concurrent(TMicRecursionGuard RecursionGuard = TMicRecursionGuard()) const PURE_VIRTUAL(UMaterialInterface::GetMaterial_Concurrent,return NULL;);
|
|
|
|
|
|
|
|
|
|
// 测试该材质是否依赖指定的材料.
|
|
|
|
|
virtual bool IsDependent(UMaterialInterface* TestDependency);
|
|
|
|
|
virtual bool IsDependent_Concurrent(UMaterialInterface* TestDependency, TMicRecursionGuard RecursionGuard = TMicRecursionGuard());
|
|
|
|
|
|
|
|
|
|
// 获取此材质对应的用于渲染的FMaterialRenderProxy实例.
|
|
|
|
|
virtual class FMaterialRenderProxy* GetRenderProxy() const PURE_VIRTUAL(UMaterialInterface::GetRenderProxy,return NULL;);
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
// 获取用于渲染此材质的纹理列表.
|
|
|
|
|
virtual void GetUsedTextures(TArray<UTexture*>& OutTextures, EMaterialQualityLevel::Type QualityLevel, bool bAllQualityLevels, ERHIFeatureLevel::Type FeatureLevel, bool bAllFeatureLevels) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetUsedTextures,);
|
|
|
|
|
// 获取用于渲染此材质的纹理列表和索引.
|
|
|
|
|
virtual void GetUsedTexturesAndIndices(TArray<UTexture*>& OutTextures, TArray< TArray<int32> >& OutIndices, EMaterialQualityLevel::Type QualityLevel, ERHIFeatureLevel::Type FeatureLevel) const;
|
|
|
|
|
// 覆盖指定的纹理.
|
|
|
|
|
virtual void OverrideTexture(const UTexture* InTextureToOverride, UTexture* OverrideTexture, ERHIFeatureLevel::Type InFeatureLevel) PURE_VIRTUAL(UMaterialInterface::OverrideTexture, return;);
|
|
|
|
|
|
|
|
|
|
// 覆盖给定参数的默认值(短暂的)
|
|
|
|
|
virtual void OverrideVectorParameterDefault(const FHashedMaterialParameterInfo& ParameterInfo, const FLinearColor& Value, bool bOverride, ERHIFeatureLevel::Type FeatureLevel) PURE_VIRTUAL(UMaterialInterface::OverrideTexture, return;);
|
|
|
|
|
|
|
|
|
|
// 检测指定的材质标记, 如果存在就返回true.
|
|
|
|
|
virtual bool CheckMaterialUsage(const EMaterialUsage Usage) PURE_VIRTUAL(UMaterialInterface::CheckMaterialUsage,return false;);
|
|
|
|
|
virtual bool CheckMaterialUsage_Concurrent(const EMaterialUsage Usage) const PURE_VIRTUAL(UMaterialInterface::CheckMaterialUsage,return false;);
|
|
|
|
|
|
|
|
|
|
// 获取材质的渲染纹理, 需要指定FeatureLevel/QualityLevel.
|
|
|
|
|
virtual FMaterialResource* GetMaterialResource(ERHIFeatureLevel::Type InFeatureLevel, EMaterialQualityLevel::Type QualityLevel = EMaterialQualityLevel::Num);
|
|
|
|
|
|
|
|
|
|
// 获取组排序优先级.
|
|
|
|
|
virtual bool GetGroupSortPriority(const FString& InGroupName, int32& OutSortPriority) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetGroupSortPriority, return false;);
|
|
|
|
|
|
|
|
|
|
// 获取材质的各种类型的所有数据.
|
|
|
|
|
virtual void GetAllScalarParameterInfo(TArray<FMaterialParameterInfo>& OutParameterInfo, TArray<FGuid>& OutParameterIds) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetAllScalarParameterInfo,return;);
|
|
|
|
|
virtual void GetAllVectorParameterInfo(TArray<FMaterialParameterInfo>& OutParameterInfo, TArray<FGuid>& OutParameterIds) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetAllVectorParameterInfo,return;);
|
|
|
|
|
virtual void GetAllTextureParameterInfo(TArray<FMaterialParameterInfo>& OutParameterInfo, TArray<FGuid>& OutParameterIds) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetAllTextureParameterInfo,return;);
|
|
|
|
|
virtual void GetAllRuntimeVirtualTextureParameterInfo(TArray<FMaterialParameterInfo>& OutParameterInfo, TArray<FGuid>& OutParameterIds) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetAllRuntimeVirtualTextureParameterInfo, return;);
|
|
|
|
|
virtual void GetAllFontParameterInfo(TArray<FMaterialParameterInfo>& OutParameterInfo, TArray<FGuid>& OutParameterIds) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetAllFontParameterInfo,return;);
|
|
|
|
|
|
|
|
|
|
// 获取材质的各种类型的数据.
|
|
|
|
|
virtual bool GetScalarParameterDefaultValue(const FHashedMaterialParameterInfo& ParameterInfo, float& OutValue, bool bOveriddenOnly = false, bool bCheckOwnedGlobalOverrides = false) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetScalarParameterDefaultValue,return false;);
|
|
|
|
|
virtual bool GetVectorParameterDefaultValue(const FHashedMaterialParameterInfo& ParameterInfo, FLinearColor& OutValue, bool bOveriddenOnly = false, bool bCheckOwnedGlobalOverrides = false) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetVectorParameterDefaultValue,return false;);
|
|
|
|
|
virtual bool GetTextureParameterDefaultValue(const FHashedMaterialParameterInfo& ParameterInfo, class UTexture*& OutValue, bool bCheckOwnedGlobalOverrides = false) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetTextureParameterDefaultValue,return false;);
|
|
|
|
|
virtual bool GetRuntimeVirtualTextureParameterDefaultValue(const FHashedMaterialParameterInfo& ParameterInfo, class URuntimeVirtualTexture*& OutValue, bool bCheckOwnedGlobalOverrides = false) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetRuntimeVirtualTextureParameterDefaultValue, return false;);
|
|
|
|
|
virtual bool GetFontParameterDefaultValue(const FHashedMaterialParameterInfo& ParameterInfo, class UFont*& OutFontValue, int32& OutFontPage, bool bCheckOwnedGlobalOverrides = false) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetFontParameterDefaultValue,return false;);
|
|
|
|
|
|
|
|
|
|
// 获取分层数据.
|
|
|
|
|
virtual int32 GetLayerParameterIndex(EMaterialParameterAssociation Association, UMaterialFunctionInterface * LayerFunction) const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetLayerParameterIndex, return INDEX_NONE;);
|
|
|
|
|
|
|
|
|
|
// 获取由表达式引用的纹理,包括嵌套函数.
|
|
|
|
|
virtual TArrayView<UObject* const> GetReferencedTextures() const
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::GetReferencedTextures,return TArrayView<UObject* const>(););
|
|
|
|
|
|
|
|
|
|
// 保存shader稳定的键值.
|
|
|
|
|
virtual void SaveShaderStableKeysInner(const class ITargetPlatform* TP, const struct FStableShaderKeyAndValue& SaveKeyVal)
|
|
|
|
|
PURE_VIRTUAL(UMaterialInterface::SaveShaderStableKeysInner, );
|
|
|
|
|
|
|
|
|
|
// 获取材质参数信息.
|
|
|
|
|
FMaterialParameterInfo GetParameterInfo(EMaterialParameterAssociation Association, FName ParameterName, UMaterialFunctionInterface* LayerFunction) const;
|
|
|
|
|
// 获取材质关联标记.
|
|
|
|
|
ENGINE_API FMaterialRelevance GetRelevance(ERHIFeatureLevel::Type InFeatureLevel) const;
|
|
|
|
|
ENGINE_API FMaterialRelevance GetRelevance_Concurrent(ERHIFeatureLevel::Type InFeatureLevel) const;
|
|
|
|
|
|
|
|
|
|
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
|
|
|
|
|
// 记录材质和纹理.
|
|
|
|
|
ENGINE_API virtual void LogMaterialsAndTextures(FOutputDevice& Ar, int32 Indent) const {}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
int32 GetWidth() const;
|
|
|
|
|
int32 GetHeight() const;
|
|
|
|
|
|
|
|
|
|
// Lightmass接口.
|
|
|
|
|
const FGuid& GetLightingGuid() const;
|
|
|
|
|
void SetLightingGuid();
|
|
|
|
|
virtual void GetLightingGuidChain(bool bIncludeTextures, TArray<FGuid>& OutGuids) const;
|
|
|
|
|
virtual bool UpdateLightmassTextureTracking();
|
|
|
|
|
inline bool GetOverrideCastShadowAsMasked() const;
|
|
|
|
|
inline bool GetOverrideEmissiveBoost() const;
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
// 数据获取接口.
|
|
|
|
|
virtual bool GetScalarParameterValue(const FHashedMaterialParameterInfo& ParameterInfo, float& OutValue, bool bOveriddenOnly = false) const;
|
|
|
|
|
virtual bool GetScalarCurveParameterValue(const FHashedMaterialParameterInfo& ParameterInfo, FInterpCurveFloat& OutValue) const;
|
|
|
|
|
virtual bool GetVectorParameterValue(const FHashedMaterialParameterInfo& ParameterInfo, FLinearColor& OutValue, bool bOveriddenOnly = false) const;
|
|
|
|
|
virtual bool GetVectorCurveParameterValue(const FHashedMaterialParameterInfo& ParameterInfo, FInterpCurveVector& OutValue) const;
|
|
|
|
|
virtual bool GetLinearColorParameterValue(const FHashedMaterialParameterInfo& ParameterInfo, FLinearColor& OutValue) const;
|
|
|
|
|
virtual bool GetLinearColorCurveParameterValue(const FHashedMaterialParameterInfo& ParameterInfo, FInterpCurveLinearColor& OutValue) const;
|
|
|
|
|
virtual bool GetTextureParameterValue(const FHashedMaterialParameterInfo& ParameterInfo, class UTexture*& OutValue, bool bOveriddenOnly = false) const;
|
|
|
|
|
virtual bool GetRuntimeVirtualTextureParameterValue(const FHashedMaterialParameterInfo& ParameterInfo, class URuntimeVirtualTexture*& OutValue, bool bOveriddenOnly = false) const;
|
|
|
|
|
virtual bool GetFontParameterValue(const FHashedMaterialParameterInfo& ParameterInfo,class UFont*& OutFontValue, int32& OutFontPage, bool bOveriddenOnly = false) const;
|
|
|
|
|
virtual bool GetRefractionSettings(float& OutBiasValue) const;
|
|
|
|
|
|
|
|
|
|
// 访问基础材质的覆盖属性.
|
|
|
|
|
virtual float GetOpacityMaskClipValue() const;
|
|
|
|
|
virtual bool GetCastDynamicShadowAsMasked() const;
|
|
|
|
|
virtual EBlendMode GetBlendMode() const;
|
|
|
|
|
virtual FMaterialShadingModelField GetShadingModels() const;
|
|
|
|
|
virtual bool IsShadingModelFromMaterialExpression() const;
|
|
|
|
|
virtual bool IsTwoSided() const;
|
|
|
|
|
virtual bool IsDitheredLODTransition() const;
|
|
|
|
|
virtual bool IsTranslucencyWritingCustomDepth() const;
|
|
|
|
|
virtual bool IsTranslucencyWritingVelocity() const;
|
|
|
|
|
virtual bool IsMasked() const;
|
|
|
|
|
virtual bool IsDeferredDecal() const;
|
|
|
|
|
virtual USubsurfaceProfile* GetSubsurfaceProfile_Internal() const;
|
|
|
|
|
virtual bool CastsRayTracedShadows() const;
|
|
|
|
|
|
|
|
|
|
// 强制流系统忽略指定持续时间的正常逻辑,而总是加载此材质使用的所有纹理的所有mip级别.
|
|
|
|
|
virtual void SetForceMipLevelsToBeResident( bool OverrideForceMiplevelsToBeResident, bool bForceMiplevelsToBeResidentValue, float ForceDuration, int32 CinematicTextureGroups = 0, bool bFastResponse = false );
|
|
|
|
|
|
|
|
|
|
// 重新缓存所有材材质接口的统一表达式.
|
|
|
|
|
static void RecacheAllMaterialUniformExpressions(bool bRecreateUniformBuffer);
|
|
|
|
|
virtual void RecacheUniformExpressions(bool bRecreateUniformBuffer) const;
|
|
|
|
|
// 初始化所有的系统默认材质.
|
|
|
|
|
static void InitDefaultMaterials();
|
|
|
|
|
virtual bool IsPropertyActive(EMaterialProperty InProperty) const;
|
|
|
|
|
static uint32 GetFeatureLevelsToCompileForAllMaterials()
|
|
|
|
|
|
|
|
|
|
// 返回使用纹理坐标的数量,以及顶点数据是否在着色器图中使用.
|
|
|
|
|
void AnalyzeMaterialProperty(EMaterialProperty InProperty, int32& OutNumTextureCoordinates, bool& bOutRequiresVertexData);
|
|
|
|
|
|
|
|
|
|
// 遍历所有的FeatureLevel, 可以指定回调.
|
|
|
|
|
template <typename FunctionType>
|
|
|
|
|
static void IterateOverActiveFeatureLevels(FunctionType InHandler);
|
|
|
|
|
|
|
|
|
|
// 访问材质采样器类型的缓存的UEnum类型信息.
|
|
|
|
|
static UEnum* GetSamplerTypeEnum();
|
|
|
|
|
|
|
|
|
|
bool UseAnyStreamingTexture() const;
|
|
|
|
|
bool HasTextureStreamingData() const;
|
|
|
|
|
const TArray<FMaterialTextureInfo>& GetTextureStreamingData() const;
|
|
|
|
|
FORCEINLINE TArray<FMaterialTextureInfo>& GetTextureStreamingData();
|
|
|
|
|
// 纹理流接口.
|
|
|
|
|
bool FindTextureStreamingDataIndexRange(FName TextureName, int32& LowerIndex, int32& HigherIndex) const;
|
|
|
|
|
void SetTextureStreamingData(const TArray<FMaterialTextureInfo>& InTextureStreamingData);
|
|
|
|
|
// 返回纹理的比例(LocalSpace Unit / Texture), 用于纹理流矩阵.
|
|
|
|
|
virtual float GetTextureDensity(FName TextureName, const struct FMeshUVChannelInfo& UVChannelData) const;
|
|
|
|
|
// 预保存.
|
|
|
|
|
virtual void PreSave(const class ITargetPlatform* TargetPlatform) override;
|
|
|
|
|
// 按名称对纹理流数据进行排序,以加速搜索. 只在需要时排序.
|
|
|
|
|
void SortTextureStreamingData(bool bForceSort, bool bFinalSort);
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
uint32 GetFeatureLevelsToCompileForRendering() const;
|
|
|
|
|
void UpdateMaterialRenderProxy(FMaterialRenderProxy& Proxy);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
static void PostLoadDefaultMaterials();
|
|
|
|
|
// 材质采样器类型的缓存的UEnum类型信息.
|
|
|
|
|
static UEnum* SamplerTypeEnum;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Engine\Source\Runtime\Engine\Classes\Materials\Material.h
|
|
|
|
|
|
|
|
|
|
// 材质类, 对应着一个材质资源文件.
|
|
|
|
|
class UMaterial : public UMaterialInterface
|
|
|
|
|
{
|
|
|
|
|
// 物理材质.
|
|
|
|
|
class UPhysicalMaterial* PhysMaterial;
|
|
|
|
|
class UPhysicalMaterialMask* PhysMaterialMask;
|
|
|
|
|
class UPhysicalMaterial* PhysicalMaterialMap[EPhysicalMaterialMaskColor::MAX];
|
|
|
|
|
|
|
|
|
|
// 材质属性.
|
|
|
|
|
FScalarMaterialInput Metallic;
|
|
|
|
|
FScalarMaterialInput Specular;
|
|
|
|
|
FScalarMaterialInput Anisotropy;
|
|
|
|
|
FVectorMaterialInput Normal;
|
|
|
|
|
FVectorMaterialInput Tangent;
|
|
|
|
|
FColorMaterialInput EmissiveColor;
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
|
|
|
// 透射.
|
|
|
|
|
FScalarMaterialInput Opacity;
|
|
|
|
|
FScalarMaterialInput OpacityMask;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
TEnumAsByte<enum EMaterialDomain> MaterialDomain;
|
|
|
|
|
TEnumAsByte<enum EBlendMode> BlendMode;
|
|
|
|
|
TEnumAsByte<enum EDecalBlendMode> DecalBlendMode;
|
|
|
|
|
TEnumAsByte<enum EMaterialDecalResponse> MaterialDecalResponse;
|
|
|
|
|
TEnumAsByte<enum EMaterialShadingModel> ShadingModel;
|
|
|
|
|
UPROPERTY(AssetRegistrySearchable)
|
|
|
|
|
FMaterialShadingModelField ShadingModels;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// 材质属性.
|
|
|
|
|
float OpacityMaskClipValue;
|
|
|
|
|
FVectorMaterialInput WorldPositionOffset;
|
|
|
|
|
FScalarMaterialInput Refraction;
|
|
|
|
|
FMaterialAttributesInput MaterialAttributes;
|
|
|
|
|
FScalarMaterialInput PixelDepthOffset;
|
|
|
|
|
FShadingModelMaterialInput ShadingModelFromMaterialExpression;
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
|
|
|
FVectorMaterialInput WorldDisplacement;
|
|
|
|
|
FScalarMaterialInput TessellationMultiplier;
|
|
|
|
|
FColorMaterialInput SubsurfaceColor;
|
|
|
|
|
FScalarMaterialInput ClearCoat;
|
|
|
|
|
FScalarMaterialInput ClearCoatRoughness;
|
|
|
|
|
FScalarMaterialInput AmbientOcclusion;
|
|
|
|
|
FVector2MaterialInput CustomizedUVs[8];
|
|
|
|
|
#endif
|
|
|
|
|
int32 NumCustomizedUVs;
|
|
|
|
|
|
|
|
|
|
// 材质标记.
|
|
|
|
|
uint8 bCastDynamicShadowAsMasked : 1;
|
|
|
|
|
uint8 bEnableSeparateTranslucency : 1;
|
|
|
|
|
uint8 bEnableResponsiveAA : 1;
|
|
|
|
|
uint8 bScreenSpaceReflections : 1;
|
|
|
|
|
uint8 bContactShadows : 1;
|
|
|
|
|
uint8 TwoSided : 1;
|
|
|
|
|
uint8 DitheredLODTransition : 1;
|
|
|
|
|
uint8 DitherOpacityMask : 1;
|
|
|
|
|
uint8 bAllowNegativeEmissiveColor : 1;
|
|
|
|
|
|
|
|
|
|
// 透明相关.
|
|
|
|
|
TEnumAsByte<enum ETranslucencyLightingMode> TranslucencyLightingMode;
|
|
|
|
|
uint8 bEnableMobileSeparateTranslucency : 1;
|
|
|
|
|
float TranslucencyDirectionalLightingIntensity;
|
|
|
|
|
float TranslucentShadowDensityScale;
|
|
|
|
|
float TranslucentSelfShadowDensityScale;
|
|
|
|
|
float TranslucentSelfShadowSecondDensityScale;
|
|
|
|
|
float TranslucentSelfShadowSecondOpacity;
|
|
|
|
|
float TranslucentBackscatteringExponent;
|
|
|
|
|
FLinearColor TranslucentMultipleScatteringExtinction;
|
|
|
|
|
float TranslucentShadowStartOffset;
|
|
|
|
|
|
|
|
|
|
// 使用标记.
|
|
|
|
|
uint8 bDisableDepthTest : 1;
|
|
|
|
|
uint8 bWriteOnlyAlpha : 1;
|
|
|
|
|
uint8 bGenerateSphericalParticleNormals : 1;
|
|
|
|
|
uint8 bTangentSpaceNormal : 1;
|
|
|
|
|
uint8 bUseEmissiveForDynamicAreaLighting : 1;
|
|
|
|
|
uint8 bBlockGI : 1;
|
|
|
|
|
uint8 bUsedAsSpecialEngineMaterial : 1;
|
|
|
|
|
uint8 bUsedWithSkeletalMesh : 1;
|
|
|
|
|
uint8 bUsedWithEditorCompositing : 1;
|
|
|
|
|
uint8 bUsedWithParticleSprites : 1;
|
|
|
|
|
uint8 bUsedWithBeamTrails : 1;
|
|
|
|
|
uint8 bUsedWithMeshParticles : 1;
|
|
|
|
|
uint8 bUsedWithNiagaraSprites : 1;
|
|
|
|
|
uint8 bUsedWithNiagaraRibbons : 1;
|
|
|
|
|
uint8 bUsedWithNiagaraMeshParticles : 1;
|
|
|
|
|
uint8 bUsedWithGeometryCache : 1;
|
|
|
|
|
uint8 bUsedWithStaticLighting : 1;
|
|
|
|
|
uint8 bUsedWithMorphTargets : 1;
|
|
|
|
|
uint8 bUsedWithSplineMeshes : 1;
|
|
|
|
|
uint8 bUsedWithInstancedStaticMeshes : 1;
|
|
|
|
|
uint8 bUsedWithGeometryCollections : 1;
|
|
|
|
|
uint8 bUsesDistortion : 1;
|
|
|
|
|
uint8 bUsedWithClothing : 1;
|
|
|
|
|
uint32 bUsedWithWater : 1;
|
|
|
|
|
uint32 bUsedWithHairStrands : 1;
|
|
|
|
|
uint32 bUsedWithLidarPointCloud : 1;
|
|
|
|
|
uint32 bUsedWithVirtualHeightfieldMesh : 1;
|
|
|
|
|
uint8 bAutomaticallySetUsageInEditor : 1;
|
|
|
|
|
uint8 bFullyRough : 1;
|
|
|
|
|
uint8 bUseFullPrecision : 1;
|
|
|
|
|
uint8 bUseLightmapDirectionality : 1;
|
|
|
|
|
uint8 bUseAlphaToCoverage : 1;
|
|
|
|
|
uint32 bForwardRenderUsePreintegratedGFForSimpleIBL : 1;
|
|
|
|
|
uint8 bUseHQForwardReflections : 1;
|
|
|
|
|
uint8 bUsePlanarForwardReflections : 1;
|
|
|
|
|
|
|
|
|
|
// 根据屏幕空间法向变化降低粗糙度.
|
|
|
|
|
uint8 bNormalCurvatureToRoughness : 1;
|
|
|
|
|
uint8 AllowTranslucentCustomDepthWrites : 1;
|
|
|
|
|
uint8 Wireframe : 1;
|
|
|
|
|
// 着色频率.
|
|
|
|
|
TEnumAsByte<EMaterialShadingRate> ShadingRate;
|
|
|
|
|
uint8 bCanMaskedBeAssumedOpaque : 1;
|
|
|
|
|
uint8 bIsPreviewMaterial : 1;
|
|
|
|
|
uint8 bIsFunctionPreviewMaterial : 1;
|
|
|
|
|
uint8 bUseMaterialAttributes : 1;
|
|
|
|
|
uint8 bCastRayTracedShadows : 1;
|
|
|
|
|
uint8 bUseTranslucencyVertexFog : 1;
|
|
|
|
|
uint8 bApplyCloudFogging : 1;
|
|
|
|
|
uint8 bIsSky : 1;
|
|
|
|
|
uint8 bComputeFogPerPixel : 1;
|
|
|
|
|
uint8 bOutputTranslucentVelocity : 1;
|
|
|
|
|
uint8 bAllowDevelopmentShaderCompile : 1;
|
|
|
|
|
uint8 bIsMaterialEditorStatsMaterial : 1;
|
|
|
|
|
TEnumAsByte<enum EBlendableLocation> BlendableLocation;
|
|
|
|
|
uint8 BlendableOutputAlpha : 1;
|
|
|
|
|
uint8 bEnableStencilTest : 1;
|
|
|
|
|
TEnumAsByte<EMaterialStencilCompare> StencilCompare;
|
|
|
|
|
uint8 StencilRefValue = 0;
|
|
|
|
|
TEnumAsByte<enum ERefractionMode> RefractionMode;
|
|
|
|
|
int32 BlendablePriority;
|
|
|
|
|
uint8 bIsBlendable : 1;
|
|
|
|
|
uint32 UsageFlagWarnings;
|
|
|
|
|
float RefractionDepthBias;
|
|
|
|
|
FGuid StateId;
|
|
|
|
|
float MaxDisplacement;
|
|
|
|
|
|
|
|
|
|
// 当渲染器需要获取参数值时,代表这个材质到渲染器的FMaterialRenderProxy衍生物.
|
|
|
|
|
class FDefaultMaterialInstance* DefaultMaterialInstance;
|
|
|
|
|
|
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
|
|
|
// 编辑器参数.
|
|
|
|
|
TMap<FName, TArray<UMaterialExpression*> > EditorParameters;
|
|
|
|
|
// 材质图. 编辑器模型下的数据.
|
|
|
|
|
class UMaterialGraph* MaterialGraph;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// 从地盘序列化而来的内联材质资源. 由游戏线程的PostLoad处理.
|
|
|
|
|
TArray<FMaterialResource> LoadedMaterialResources;
|
|
|
|
|
// 用于渲染材质的资源列表.
|
|
|
|
|
TArray<FMaterialResource*> MaterialResources;
|
|
|
|
|
#if WITH_EDITOR
|
|
|
|
|
// 正在缓存或烘焙的材质资源.
|
|
|
|
|
TMap<const class ITargetPlatform*, TArray<FMaterialResource*>> CachedMaterialResourcesForCooking;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// 用于保证在清理之前使用此UMaterial中的各种资源完成RT的标志.
|
|
|
|
|
FThreadSafeBool ReleasedByRT;
|
|
|
|
|
FMaterialCachedExpressionData CachedExpressionData;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
//~ Begin UMaterialInterface Interface.
|
|
|
|
|
virtual UMaterial* GetMaterial() override;
|
|
|
|
|
virtual const UMaterial* GetMaterial() const override;
|
|
|
|
|
virtual const UMaterial* GetMaterial_Concurrent(TMicRecursionGuard RecursionGuard = TMicRecursionGuard()) const override;
|
|
|
|
|
virtual bool GetScalarParameterValue(...) const override;
|
|
|
|
|
(......)
|
|
|
|
|
void SetShadingModel(EMaterialShadingModel NewModel);
|
|
|
|
|
virtual bool IsPropertyActive(EMaterialProperty InProperty) const override;
|
|
|
|
|
//~ End UMaterialInterface Interface.
|
|
|
|
|
|
|
|
|
|
//~ Begin UObject Interface
|
|
|
|
|
virtual void PreSave(const class ITargetPlatform* TargetPlatform) override;
|
|
|
|
|
virtual void PostInitProperties() override;
|
|
|
|
|
virtual void Serialize(FArchive& Ar) override;
|
|
|
|
|
virtual void PostDuplicate(bool bDuplicateForPIE) override;
|
|
|
|
|
virtual void PostLoad() override;
|
|
|
|
|
virtual void BeginDestroy() override;
|
|
|
|
|
virtual bool IsReadyForFinishDestroy() override;
|
|
|
|
|
virtual void FinishDestroy() override;
|
|
|
|
|
virtual void GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize) override;
|
|
|
|
|
static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector);
|
|
|
|
|
virtual bool CanBeClusterRoot() const override;
|
|
|
|
|
virtual void GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const override;
|
|
|
|
|
//~ End UObject Interface
|
|
|
|
|
|
|
|
|
|
// 数据获取接口.
|
|
|
|
|
bool IsDefaultMaterial() const;
|
|
|
|
|
void ReleaseResources();
|
|
|
|
|
bool IsUsageFlagDirty(EMaterialUsage Usage);
|
|
|
|
|
bool IsCompilingOrHadCompileError(ERHIFeatureLevel::Type InFeatureLevel);
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// 新版的获取材质数据接口.
|
|
|
|
|
bool GetScalarParameterValue_New(...) const;
|
|
|
|
|
bool GetVectorParameterValue_New(...) const;
|
|
|
|
|
bool GetTextureParameterValue_New(...) const;
|
|
|
|
|
bool GetRuntimeVirtualTextureParameterValue_New(...) const;
|
|
|
|
|
bool GetFontParameterValue_New(...) const;
|
|
|
|
|
|
|
|
|
|
FString GetUsageName(const EMaterialUsage Usage) const;
|
|
|
|
|
bool GetUsageByFlag(const EMaterialUsage Usage) const;
|
|
|
|
|
bool SetMaterialUsage(bool &bNeedsRecompile, const EMaterialUsage Usage);
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
virtual void FlushResourceShaderMaps();
|
|
|
|
|
// 缓冲资源或数据.
|
|
|
|
|
void CacheResourceShadersForRendering(bool bRegenerateId);
|
|
|
|
|
void CacheResourceShadersForCooking(...);
|
|
|
|
|
void CacheShadersForResources(...);
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// 静态工具箱或操作接口.
|
|
|
|
|
static UMaterial* GetDefaultMaterial(EMaterialDomain Domain);
|
|
|
|
|
static void UpdateMaterialShaders(...);
|
|
|
|
|
static void BackupMaterialShadersToMemory(...);
|
|
|
|
|
static void RestoreMaterialShadersFromMemory(...);
|
|
|
|
|
static void CompileMaterialsForRemoteRecompile(...);
|
|
|
|
|
static bool GetExpressionParameterName(const UMaterialExpression* Expression, FName& OutName);
|
|
|
|
|
static bool CopyExpressionParameters(UMaterialExpression* Source, UMaterialExpression* Destination);
|
|
|
|
|
static bool IsParameter(const UMaterialExpression* Expression);
|
|
|
|
|
static bool IsDynamicParameter(const UMaterialExpression* Expression);
|
|
|
|
|
static const TCHAR* GetMaterialShadingModelString(EMaterialShadingModel InMaterialShadingModel);
|
|
|
|
|
static EMaterialShadingModel GetMaterialShadingModelFromString(const TCHAR* InMaterialShadingModelStr);
|
|
|
|
|
static const TCHAR* GetBlendModeString(EBlendMode InBlendMode);
|
|
|
|
|
static EBlendMode GetBlendModeFromString(const TCHAR* InBlendModeStr);
|
|
|
|
|
virtual TArrayView<UObject* const> GetReferencedTextures() const override final;
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
# UMaterialInstance
|
|
|
|
|
UMaterialInstance是材质实例,不能单独存在,而需要依赖UMaterialInterface类型的父类,意味着父类可以是UMaterialInterface的任意一个子类,但最上层的父类必须是UMaterial。
|
|
|
|
|
```c++
|
|
|
|
|
class UMaterialInstance : public UMaterialInterface
|
|
|
|
|
{
|
|
|
|
|
// 物理材质.
|
|
|
|
|
class UPhysicalMaterial* PhysMaterial;
|
|
|
|
|
class UPhysicalMaterial* PhysicalMaterialMap[EPhysicalMaterialMaskColor::MAX];
|
|
|
|
|
// 材质父亲.
|
|
|
|
|
class UMaterialInterface* Parent;
|
|
|
|
|
// 当渲染器需要获取参数值时,代表这个材质实例的FMaterialRenderProxy的子类.
|
|
|
|
|
class FMaterialInstanceResource* Resource;
|
|
|
|
|
|
|
|
|
|
// 可以部分覆盖Parent的属性, 和UMaterial相比, 只是一小部分.
|
|
|
|
|
uint8 bHasStaticPermutationResource:1;
|
|
|
|
|
uint8 bOverrideSubsurfaceProfile:1;
|
|
|
|
|
uint8 TwoSided : 1;
|
|
|
|
|
uint8 DitheredLODTransition : 1;
|
|
|
|
|
uint8 bCastDynamicShadowAsMasked : 1;
|
|
|
|
|
uint8 bIsShadingModelFromMaterialExpression : 1;
|
|
|
|
|
TEnumAsByte<EBlendMode> BlendMode;
|
|
|
|
|
float OpacityMaskClipValue;
|
|
|
|
|
FMaterialShadingModelField ShadingModels;
|
|
|
|
|
|
|
|
|
|
// 覆盖Parent的各种类型的数据.
|
|
|
|
|
TArray<struct FScalarParameterValue> ScalarParameterValues;
|
|
|
|
|
TArray<struct FVectorParameterValue> VectorParameterValues;
|
|
|
|
|
TArray<struct FTextureParameterValue> TextureParameterValues;
|
|
|
|
|
TArray<struct FRuntimeVirtualTextureParameterValue> RuntimeVirtualTextureParameterValues;
|
|
|
|
|
TArray<struct FFontParameterValue> FontParameterValues;
|
|
|
|
|
struct FMaterialInstanceBasePropertyOverrides BasePropertyOverrides;
|
|
|
|
|
(......)
|
|
|
|
|
private:
|
|
|
|
|
FStaticParameterSet StaticParameters;
|
|
|
|
|
FMaterialCachedParameters CachedLayerParameters;
|
|
|
|
|
TArray<UObject*> CachedReferencedTextures;
|
|
|
|
|
// 已加载的材质资源.
|
|
|
|
|
TArray<FMaterialResource> LoadedMaterialResources;
|
|
|
|
|
TArray<FMaterialResource*> StaticPermutationMaterialResources;
|
|
|
|
|
FThreadSafeBool ReleasedByRT;
|
|
|
|
|
public:
|
|
|
|
|
// Begin UMaterialInterface interface.
|
|
|
|
|
virtual ENGINE_API UMaterial* GetMaterial() override;
|
|
|
|
|
virtual ENGINE_API const UMaterial* GetMaterial() const override;
|
|
|
|
|
virtual ENGINE_API const UMaterial* GetMaterial_Concurrent(TMicRecursionGuard RecursionGuard = TMicRecursionGuard()) const override;
|
|
|
|
|
virtual ENGINE_API FMaterialResource* AllocatePermutationResource();
|
|
|
|
|
(......)
|
|
|
|
|
//~ End UMaterialInterface Interface.
|
|
|
|
|
//~ Begin UObject Interface.
|
|
|
|
|
virtual ENGINE_API void GetResourceSizeEx(FResourceSizeEx& CumulativeResourceSize) override;
|
|
|
|
|
virtual ENGINE_API void PostInitProperties() override;
|
|
|
|
|
virtual ENGINE_API void Serialize(FArchive& Ar) override;
|
|
|
|
|
virtual ENGINE_API void PostLoad() override;
|
|
|
|
|
virtual ENGINE_API void BeginDestroy() override;
|
|
|
|
|
virtual ENGINE_API bool IsReadyForFinishDestroy() override;
|
|
|
|
|
virtual ENGINE_API void FinishDestroy() override;
|
|
|
|
|
ENGINE_API static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector);
|
|
|
|
|
//~ End UObject Interface.
|
|
|
|
|
|
|
|
|
|
void GetAllShaderMaps(TArray<FMaterialShaderMap*>& OutShaderMaps);
|
|
|
|
|
void GetAllParametersOfType(EMaterialParameterType Type, TArray<FMaterialParameterInfo>& OutParameterInfo, TArray<FGuid>& OutParameterIds) const;
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
protected:
|
|
|
|
|
void CopyMaterialUniformParametersInternal(UMaterialInterface* Source);
|
|
|
|
|
bool UpdateParameters();
|
|
|
|
|
ENGINE_API void SetParentInternal(class UMaterialInterface* NewParent, bool RecacheShaders);
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
// 初始化材质实例的资源.
|
|
|
|
|
ENGINE_API void InitResources();
|
|
|
|
|
|
|
|
|
|
// 缓存资源.
|
|
|
|
|
void CacheResourceShadersForRendering();
|
|
|
|
|
void CacheResourceShadersForRendering(FMaterialResourceDeferredDeletionArray& OutResourcesToFree);
|
|
|
|
|
void CacheShadersForResources(...);
|
|
|
|
|
void DeleteDeferredResources(FMaterialResourceDeferredDeletionArray& ResourcesToFree);
|
|
|
|
|
|
|
|
|
|
ENGINE_API void CopyMaterialInstanceParameters(UMaterialInterface* Source);
|
|
|
|
|
(......)
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
UMaterialInstance和UMaterial不一样,它需要依附于父亲实例,而且最顶层的父亲必然是UMaterial实例。它**只能覆盖UMaterial的一小部分参数**,通常不会被单独创建,而是以它的两个子类**UMaterialInstanceConstant**和**UMaterialInstanceDynamic**被创建。
|
|
|
|
|
|
|
|
|
|
# FMaterialRenderProxy
|
|
|
|
|
FMaterialRenderProxy负责接收游戏线程代表的数据,然后传递给渲染器去处理和渲染。
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Engine\Public\MaterialShared.h
|
|
|
|
|
|
|
|
|
|
class FMaterialRenderProxy : public FRenderResource
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
// 缓存数据.
|
|
|
|
|
mutable FUniformExpressionCacheContainer UniformExpressionCache;
|
|
|
|
|
mutable FImmutableSamplerState ImmutableSamplerState;
|
|
|
|
|
|
|
|
|
|
// 构造/析构函数.
|
|
|
|
|
ENGINE_API FMaterialRenderProxy();
|
|
|
|
|
ENGINE_API virtual ~FMaterialRenderProxy();
|
|
|
|
|
|
|
|
|
|
// 计算表达式并存储到OutUniformExpressionCache.
|
|
|
|
|
void ENGINE_API EvaluateUniformExpressions(FUniformExpressionCache& OutUniformExpressionCache, const FMaterialRenderContext& Context, class FRHICommandList* CommandListIfLocalMode = nullptr) const;
|
|
|
|
|
|
|
|
|
|
// UniformExpression接口.
|
|
|
|
|
void ENGINE_API CacheUniformExpressions(bool bRecreateUniformBuffer);
|
|
|
|
|
void ENGINE_API CacheUniformExpressions_GameThread(bool bRecreateUniformBuffer);
|
|
|
|
|
void ENGINE_API InvalidateUniformExpressionCache(bool bRecreateUniformBuffer);
|
|
|
|
|
void ENGINE_API UpdateUniformExpressionCacheIfNeeded(ERHIFeatureLevel::Type InFeatureLevel) const;
|
|
|
|
|
|
|
|
|
|
// 返回有效的FMaterial实例.
|
|
|
|
|
const class FMaterial* GetMaterial(ERHIFeatureLevel::Type InFeatureLevel) const;
|
|
|
|
|
// 查找用于渲染此FMaterialRenderProxy的FMaterial实例.
|
|
|
|
|
virtual const FMaterial& GetMaterialWithFallback(ERHIFeatureLevel::Type InFeatureLevel, const FMaterialRenderProxy*& OutFallbackMaterialRenderProxy) const = 0;
|
|
|
|
|
virtual FMaterial* GetMaterialNoFallback(ERHIFeatureLevel::Type InFeatureLevel) const { return NULL; }
|
|
|
|
|
// 获取对应的UMaterialInterface实例.
|
|
|
|
|
virtual UMaterialInterface* GetMaterialInterface() const { return NULL; }
|
|
|
|
|
|
|
|
|
|
// 获取材质属性的值.
|
|
|
|
|
virtual bool GetVectorValue(const FHashedMaterialParameterInfo& ParameterInfo, FLinearColor* OutValue, const FMaterialRenderContext& Context) const = 0;
|
|
|
|
|
virtual bool GetScalarValue(const FHashedMaterialParameterInfo& ParameterInfo, float* OutValue, const FMaterialRenderContext& Context) const = 0;
|
|
|
|
|
virtual bool GetTextureValue(const FHashedMaterialParameterInfo& ParameterInfo,const UTexture** OutValue, const FMaterialRenderContext& Context) const = 0;
|
|
|
|
|
virtual bool GetTextureValue(const FHashedMaterialParameterInfo& ParameterInfo, const URuntimeVirtualTexture** OutValue, const FMaterialRenderContext& Context) const = 0;
|
|
|
|
|
|
|
|
|
|
bool IsDeleted() const;
|
|
|
|
|
void MarkForGarbageCollection();
|
|
|
|
|
bool IsMarkedForGarbageCollection() const;
|
|
|
|
|
|
|
|
|
|
// FRenderResource interface.
|
|
|
|
|
ENGINE_API virtual void InitDynamicRHI() override;
|
|
|
|
|
ENGINE_API virtual void ReleaseDynamicRHI() override;
|
|
|
|
|
ENGINE_API virtual void ReleaseResource() override;
|
|
|
|
|
|
|
|
|
|
// 获取静态的材质渲染代表的映射表.
|
|
|
|
|
ENGINE_API static const TSet<FMaterialRenderProxy*>& GetMaterialRenderProxyMap();
|
|
|
|
|
|
|
|
|
|
void SetSubsurfaceProfileRT(const USubsurfaceProfile* Ptr);
|
|
|
|
|
const USubsurfaceProfile* GetSubsurfaceProfileRT() const;
|
|
|
|
|
|
|
|
|
|
ENGINE_API static void UpdateDeferredCachedUniformExpressions();
|
|
|
|
|
static inline bool HasDeferredUniformExpressionCacheRequests();
|
|
|
|
|
|
|
|
|
|
int32 GetExpressionCacheSerialNumber() const { return UniformExpressionCacheSerialNumber; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const USubsurfaceProfile* SubsurfaceProfileRT;
|
|
|
|
|
mutable int32 UniformExpressionCacheSerialNumber = 0;
|
|
|
|
|
|
|
|
|
|
// 材质标记.
|
|
|
|
|
mutable int8 MarkedForGarbageCollection : 1;
|
|
|
|
|
mutable int8 DeletedFlag : 1;
|
|
|
|
|
mutable int8 ReleaseResourceFlag : 1;
|
|
|
|
|
mutable int8 HasVirtualTextureCallbacks : 1;
|
|
|
|
|
|
|
|
|
|
// 追踪在所有场景的所有材质渲染代表. 只可在渲染线程访问. 用来传播新的着色器映射到渲染所用的材质.
|
|
|
|
|
ENGINE_API static TSet<FMaterialRenderProxy*> MaterialRenderProxyMap;
|
|
|
|
|
ENGINE_API static TSet<FMaterialRenderProxy*> DeferredUniformExpressionCacheRequests;
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
我们将注意力放到两个重要的子类:FDefaultMaterialInstance和FMaterialInstanceResource,它们的定义如下:
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Engine\Private\Materials\Material.cpp
|
|
|
|
|
|
|
|
|
|
// 用于渲染UMaterial的默认渲染代表, 默认的参数值已经存储于FMaterialUniformExpressionXxxParameter对象, 此资源值用来存储选中的颜色.
|
|
|
|
|
class FDefaultMaterialInstance : public FMaterialRenderProxy
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
// 游戏线程销毁接口.
|
|
|
|
|
void GameThread_Destroy()
|
|
|
|
|
{
|
|
|
|
|
FDefaultMaterialInstance* Resource = this;
|
|
|
|
|
ENQUEUE_RENDER_COMMAND(FDestroyDefaultMaterialInstanceCommand)(
|
|
|
|
|
[Resource](FRHICommandList& RHICmdList)
|
|
|
|
|
{
|
|
|
|
|
delete Resource;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FMaterialRenderProxy interface.
|
|
|
|
|
// 获取材质接口.
|
|
|
|
|
virtual const FMaterial& GetMaterialWithFallback(ERHIFeatureLevel::Type InFeatureLevel, const FMaterialRenderProxy*& OutFallbackMaterialRenderProxy) const
|
|
|
|
|
{
|
|
|
|
|
const FMaterialResource* MaterialResource = Material->GetMaterialResource(InFeatureLevel);
|
|
|
|
|
if (MaterialResource && MaterialResource->GetRenderingThreadShaderMap())
|
|
|
|
|
{
|
|
|
|
|
return *MaterialResource;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
OutFallbackMaterialRenderProxy = &GetFallbackRenderProxy();
|
|
|
|
|
return OutFallbackMaterialRenderProxy->GetMaterialWithFallback(InFeatureLevel, OutFallbackMaterialRenderProxy);
|
|
|
|
|
}
|
|
|
|
|
virtual FMaterial* GetMaterialNoFallback(ERHIFeatureLevel::Type InFeatureLevel) const
|
|
|
|
|
{
|
|
|
|
|
return Material->GetMaterialResource(InFeatureLevel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取对应的UMaterialInterface接口.
|
|
|
|
|
virtual UMaterialInterface* GetMaterialInterface() const override
|
|
|
|
|
{
|
|
|
|
|
return Material;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取向量的参数值.
|
|
|
|
|
virtual bool GetVectorValue(const FHashedMaterialParameterInfo& ParameterInfo, FLinearColor* OutValue, const FMaterialRenderContext& Context) const
|
|
|
|
|
{
|
|
|
|
|
const FMaterialResource* MaterialResource = Material->GetMaterialResource(Context.Material.GetFeatureLevel());
|
|
|
|
|
if(MaterialResource && MaterialResource->GetRenderingThreadShaderMap())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return GetFallbackRenderProxy().GetVectorValue(ParameterInfo, OutValue, Context);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 获取标量的参数值.
|
|
|
|
|
virtual bool GetScalarValue(const FHashedMaterialParameterInfo& ParameterInfo, float* OutValue, const FMaterialRenderContext& Context) const
|
|
|
|
|
{
|
|
|
|
|
const FMaterialResource* MaterialResource = Material->GetMaterialResource(Context.Material.GetFeatureLevel());
|
|
|
|
|
if(MaterialResource && MaterialResource->GetRenderingThreadShaderMap())
|
|
|
|
|
{
|
|
|
|
|
static FName NameSubsurfaceProfile(TEXT("__SubsurfaceProfile"));
|
|
|
|
|
if (ParameterInfo.Name == NameSubsurfaceProfile)
|
|
|
|
|
{
|
|
|
|
|
const USubsurfaceProfile* MySubsurfaceProfileRT = GetSubsurfaceProfileRT();
|
|
|
|
|
|
|
|
|
|
int32 AllocationId = 0;
|
|
|
|
|
if(MySubsurfaceProfileRT)
|
|
|
|
|
{
|
|
|
|
|
// can be optimized (cached)
|
|
|
|
|
AllocationId = GSubsurfaceProfileTextureObject.FindAllocationId(MySubsurfaceProfileRT);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// no profile specified means we use the default one stored at [0] which is human skin
|
|
|
|
|
AllocationId = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*OutValue = AllocationId / 255.0f;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return GetFallbackRenderProxy().GetScalarValue(ParameterInfo, OutValue, Context);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 获取纹理的参数值.
|
|
|
|
|
virtual bool GetTextureValue(const FHashedMaterialParameterInfo& ParameterInfo,const UTexture** OutValue, const FMaterialRenderContext& Context) const
|
|
|
|
|
{
|
|
|
|
|
const FMaterialResource* MaterialResource = Material->GetMaterialResource(Context.Material.GetFeatureLevel());
|
|
|
|
|
if(MaterialResource && MaterialResource->GetRenderingThreadShaderMap())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return GetFallbackRenderProxy().GetTextureValue(ParameterInfo,OutValue,Context);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual bool GetTextureValue(const FHashedMaterialParameterInfo& ParameterInfo, const URuntimeVirtualTexture** OutValue, const FMaterialRenderContext& Context) const
|
|
|
|
|
{
|
|
|
|
|
const FMaterialResource* MaterialResource = Material->GetMaterialResource(Context.Material.GetFeatureLevel());
|
|
|
|
|
if (MaterialResource && MaterialResource->GetRenderingThreadShaderMap())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return GetFallbackRenderProxy().GetTextureValue(ParameterInfo, OutValue, Context);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FRenderResource interface.
|
|
|
|
|
virtual FString GetFriendlyName() const { return Material->GetName(); }
|
|
|
|
|
|
|
|
|
|
// Constructor.
|
|
|
|
|
FDefaultMaterialInstance(UMaterial* InMaterial);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// 获取备份的材质渲染代理.
|
|
|
|
|
FMaterialRenderProxy& GetFallbackRenderProxy() const
|
|
|
|
|
{
|
|
|
|
|
return *(UMaterial::GetDefaultMaterial(Material->MaterialDomain)->GetRenderProxy());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 对应的材质实例.
|
|
|
|
|
UMaterial* Material;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Engine\Source\Runtime\Engine\Private\Materials\MaterialInstanceSupport.h
|
|
|
|
|
// 渲染UMaterialInstance的材质资源.
|
|
|
|
|
class FMaterialInstanceResource: public FMaterialRenderProxy
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
// 存储材质实例的名称和值的配对.
|
|
|
|
|
template <typename ValueType>
|
|
|
|
|
struct TNamedParameter
|
|
|
|
|
{
|
|
|
|
|
FHashedMaterialParameterInfo Info;
|
|
|
|
|
ValueType Value;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FMaterialInstanceResource(UMaterialInstance* InOwner);
|
|
|
|
|
|
|
|
|
|
void GameThread_Destroy()
|
|
|
|
|
{
|
|
|
|
|
FMaterialInstanceResource* Resource = this;
|
|
|
|
|
ENQUEUE_RENDER_COMMAND(FDestroyMaterialInstanceResourceCommand)(
|
|
|
|
|
[Resource](FRHICommandList& RHICmdList)
|
|
|
|
|
{
|
|
|
|
|
delete Resource;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FRenderResource interface.
|
|
|
|
|
virtual FString GetFriendlyName() const override { return Owner->GetName(); }
|
|
|
|
|
|
|
|
|
|
// FMaterialRenderProxy interface.
|
|
|
|
|
// 获取材质渲染资源.
|
|
|
|
|
virtual const FMaterial& GetMaterialWithFallback(ERHIFeatureLevel::Type FeatureLevel, const FMaterialRenderProxy*& OutFallbackMaterialRenderProxy) const override;
|
|
|
|
|
virtual FMaterial* GetMaterialNoFallback(ERHIFeatureLevel::Type FeatureLevel) const override;
|
|
|
|
|
virtual UMaterialInterface* GetMaterialInterface() const override;
|
|
|
|
|
|
|
|
|
|
// 获取材质的值.
|
|
|
|
|
virtual bool GetVectorValue(const FHashedMaterialParameterInfo& ParameterInfo, FLinearColor* OutValue, const FMaterialRenderContext& Context) const override;
|
|
|
|
|
virtual bool GetScalarValue(const FHashedMaterialParameterInfo& ParameterInfo, float* OutValue, const FMaterialRenderContext& Context) const override;
|
|
|
|
|
virtual bool GetTextureValue(const FHashedMaterialParameterInfo& ParameterInfo, const UTexture** OutValue, const FMaterialRenderContext& Context) const override;
|
|
|
|
|
virtual bool GetTextureValue(const FHashedMaterialParameterInfo& ParameterInfo, const URuntimeVirtualTexture** OutValue, const FMaterialRenderContext& Context) const override;
|
|
|
|
|
|
|
|
|
|
void GameThread_SetParent(UMaterialInterface* ParentMaterialInterface);
|
|
|
|
|
void InitMIParameters(struct FMaterialInstanceParameterSet& ParameterSet);
|
|
|
|
|
void RenderThread_ClearParameters()
|
|
|
|
|
{
|
|
|
|
|
VectorParameterArray.Empty();
|
|
|
|
|
ScalarParameterArray.Empty();
|
|
|
|
|
TextureParameterArray.Empty();
|
|
|
|
|
RuntimeVirtualTextureParameterArray.Empty();
|
|
|
|
|
InvalidateUniformExpressionCache(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新参数.
|
|
|
|
|
template <typename ValueType>
|
|
|
|
|
void RenderThread_UpdateParameter(const FHashedMaterialParameterInfo& ParameterInfo, const ValueType& Value )
|
|
|
|
|
{
|
|
|
|
|
LLM_SCOPE(ELLMTag::MaterialInstance);
|
|
|
|
|
|
|
|
|
|
InvalidateUniformExpressionCache(false);
|
|
|
|
|
TArray<TNamedParameter<ValueType> >& ValueArray = GetValueArray<ValueType>();
|
|
|
|
|
const int32 ParameterCount = ValueArray.Num();
|
|
|
|
|
for (int32 ParameterIndex = 0; ParameterIndex < ParameterCount; ++ParameterIndex)
|
|
|
|
|
{
|
|
|
|
|
TNamedParameter<ValueType>& Parameter = ValueArray[ParameterIndex];
|
|
|
|
|
if (Parameter.Info == ParameterInfo)
|
|
|
|
|
{
|
|
|
|
|
Parameter.Value = Value;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TNamedParameter<ValueType> NewParameter;
|
|
|
|
|
NewParameter.Info = ParameterInfo;
|
|
|
|
|
NewParameter.Value = Value;
|
|
|
|
|
ValueArray.Add(NewParameter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查找指定名字的参数值.
|
|
|
|
|
template <typename ValueType>
|
|
|
|
|
const ValueType* RenderThread_FindParameterByName(const FHashedMaterialParameterInfo& ParameterInfo) const
|
|
|
|
|
{
|
|
|
|
|
const TArray<TNamedParameter<ValueType> >& ValueArray = GetValueArray<ValueType>();
|
|
|
|
|
const int32 ParameterCount = ValueArray.Num();
|
|
|
|
|
for (int32 ParameterIndex = 0; ParameterIndex < ParameterCount; ++ParameterIndex)
|
|
|
|
|
{
|
|
|
|
|
const TNamedParameter<ValueType>& Parameter = ValueArray[ParameterIndex];
|
|
|
|
|
if (Parameter.Info == ParameterInfo)
|
|
|
|
|
{
|
|
|
|
|
return &Parameter.Value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
template <typename ValueType> TArray<TNamedParameter<ValueType> >& GetValueArray();
|
|
|
|
|
|
|
|
|
|
// 材质实例的父亲.
|
|
|
|
|
UMaterialInterface* Parent;
|
|
|
|
|
// 游戏线程的父亲.
|
|
|
|
|
UMaterialInterface* GameThreadParent;
|
|
|
|
|
// 所属的材质实例.
|
|
|
|
|
UMaterialInstance* Owner;
|
|
|
|
|
|
|
|
|
|
// 各种类型的参数值列表.
|
|
|
|
|
TArray<TNamedParameter<FLinearColor> > VectorParameterArray;
|
|
|
|
|
TArray<TNamedParameter<float> > ScalarParameterArray;
|
|
|
|
|
TArray<TNamedParameter<const UTexture*> > TextureParameterArray;
|
|
|
|
|
TArray<TNamedParameter<const URuntimeVirtualTexture*> > RuntimeVirtualTextureParameterArray;
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
需要格外注意的是,FMaterialRenderProxy既会被游戏线程处理,又会被渲染线程处理,需要小心注意它们之间的数据访问和接口调用。带有GameThread的是专用于游戏线程,带有RenderThread的专用于渲染线程,如果没有特别说明,一般(非绝对)用于渲染线程。
|
|
|
|
|
|
|
|
|
|
# FMaterial & FMaterialResource
|
|
|
|
|
FMaterial有3个功能:
|
|
|
|
|
- 表示材质到材质的编译过程,并提供可扩展性钩子(CompileProperty等) 。
|
|
|
|
|
- 将材质数据传递到渲染器,并使用函数访问材质属性。
|
|
|
|
|
- 存储缓存的shader map和其他来自编译的瞬态输出,这对异步着色器编译是必要的。
|
|
|
|
|
|
|
|
|
|
下面是FMaterial的定义:
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Engine\Public\MaterialShared.h
|
|
|
|
|
|
|
|
|
|
class FMaterial
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
#if UE_CHECK_FMATERIAL_LIFETIME
|
|
|
|
|
uint32 AddRef() const;
|
|
|
|
|
uint32 Release() const;
|
|
|
|
|
inline uint32 GetRefCount() const { return uint32(NumDebugRefs.GetValue()); }
|
|
|
|
|
|
|
|
|
|
mutable FThreadSafeCounter NumDebugRefs;
|
|
|
|
|
#else
|
|
|
|
|
FORCEINLINE uint32 AddRef() const { return 0u; }
|
|
|
|
|
FORCEINLINE uint32 Release() const { return 0u; }
|
|
|
|
|
FORCEINLINE uint32 GetRefCount() const { return 0u; }
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
FMaterial();
|
|
|
|
|
ENGINE_API virtual ~FMaterial();
|
|
|
|
|
|
|
|
|
|
// 缓存shader.
|
|
|
|
|
ENGINE_API bool CacheShaders(EShaderPlatform Platform, const ITargetPlatform* TargetPlatform = nullptr);
|
|
|
|
|
ENGINE_API bool CacheShaders(const FMaterialShaderMapId& ShaderMapId, EShaderPlatform Platform, const ITargetPlatform* TargetPlatform = nullptr);
|
|
|
|
|
|
|
|
|
|
// 是否需要缓存指定shader type的数据.
|
|
|
|
|
ENGINE_API virtual bool ShouldCache(EShaderPlatform Platform, const FShaderType* ShaderType, const FVertexFactoryType* VertexFactoryType) const;
|
|
|
|
|
ENGINE_API bool ShouldCachePipeline(EShaderPlatform Platform, const FShaderPipelineType* PipelineType, const FVertexFactoryType* VertexFactoryType) const;
|
|
|
|
|
|
|
|
|
|
// 序列化.
|
|
|
|
|
ENGINE_API virtual void LegacySerialize(FArchive& Ar);
|
|
|
|
|
void SerializeInlineShaderMap(FArchive& Ar);
|
|
|
|
|
|
|
|
|
|
// ShaderMap接口.
|
|
|
|
|
void RegisterInlineShaderMap(bool bLoadedByCookedMaterial);
|
|
|
|
|
void ReleaseShaderMap();
|
|
|
|
|
void DiscardShaderMap();
|
|
|
|
|
|
|
|
|
|
// 材质属性.
|
|
|
|
|
ENGINE_API virtual void GetShaderMapId(EShaderPlatform Platform, const ITargetPlatform* TargetPlatform, FMaterialShaderMapId& OutId) const;
|
|
|
|
|
virtual EMaterialDomain GetMaterialDomain() const = 0; // See EMaterialDomain.
|
|
|
|
|
virtual bool IsTwoSided() const = 0;
|
|
|
|
|
virtual bool IsDitheredLODTransition() const = 0;
|
|
|
|
|
virtual bool IsTranslucencyWritingCustomDepth() const { return false; }
|
|
|
|
|
virtual bool IsTranslucencyWritingVelocity() const { return false; }
|
|
|
|
|
virtual bool IsTangentSpaceNormal() const { return false; }
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
// 是否需要保存到磁盘.
|
|
|
|
|
virtual bool IsPersistent() const = 0;
|
|
|
|
|
// 获取材质实例.
|
|
|
|
|
virtual UMaterialInterface* GetMaterialInterface() const { return NULL; }
|
|
|
|
|
|
|
|
|
|
ENGINE_API bool HasValidGameThreadShaderMap() const;
|
|
|
|
|
inline bool ShouldCastDynamicShadows() const;
|
|
|
|
|
EMaterialQualityLevel::Type GetQualityLevel() const
|
|
|
|
|
|
|
|
|
|
// 数据访问接口.
|
|
|
|
|
ENGINE_API const FUniformExpressionSet& GetUniformExpressions() const;
|
|
|
|
|
ENGINE_API TArrayView<const FMaterialTextureParameterInfo> GetUniformTextureExpressions(EMaterialTextureParameterType Type) const;
|
|
|
|
|
ENGINE_API TArrayView<const FMaterialVectorParameterInfo> GetUniformVectorParameterExpressions() const;
|
|
|
|
|
ENGINE_API TArrayView<const FMaterialScalarParameterInfo> GetUniformScalarParameterExpressions() const;
|
|
|
|
|
inline TArrayView<const FMaterialTextureParameterInfo> GetUniform2DTextureExpressions() const { return GetUniformTextureExpressions(EMaterialTextureParameterType::Standard2D); }
|
|
|
|
|
inline TArrayView<const FMaterialTextureParameterInfo> GetUniformCubeTextureExpressions() const { return GetUniformTextureExpressions(EMaterialTextureParameterType::Cube); }
|
|
|
|
|
inline TArrayView<const FMaterialTextureParameterInfo> GetUniform2DArrayTextureExpressions() const { return GetUniformTextureExpressions(EMaterialTextureParameterType::Array2D); }
|
|
|
|
|
inline TArrayView<const FMaterialTextureParameterInfo> GetUniformVolumeTextureExpressions() const { return GetUniformTextureExpressions(EMaterialTextureParameterType::Volume); }
|
|
|
|
|
inline TArrayView<const FMaterialTextureParameterInfo> GetUniformVirtualTextureExpressions() const { return GetUniformTextureExpressions(EMaterialTextureParameterType::Virtual); }
|
|
|
|
|
|
|
|
|
|
const FStaticFeatureLevel GetFeatureLevel() const { return FeatureLevel; }
|
|
|
|
|
bool GetUsesDynamicParameter() const;
|
|
|
|
|
ENGINE_API bool RequiresSceneColorCopy_GameThread() const;
|
|
|
|
|
ENGINE_API bool RequiresSceneColorCopy_RenderThread() const;
|
|
|
|
|
ENGINE_API bool NeedsSceneTextures() const;
|
|
|
|
|
ENGINE_API bool NeedsGBuffer() const;
|
|
|
|
|
ENGINE_API bool UsesEyeAdaptation() const;
|
|
|
|
|
ENGINE_API bool UsesGlobalDistanceField_GameThread() const;
|
|
|
|
|
ENGINE_API bool UsesWorldPositionOffset_GameThread() const;
|
|
|
|
|
|
|
|
|
|
// 材质标记.
|
|
|
|
|
ENGINE_API bool MaterialModifiesMeshPosition_RenderThread() const;
|
|
|
|
|
ENGINE_API bool MaterialModifiesMeshPosition_GameThread() const;
|
|
|
|
|
ENGINE_API bool MaterialUsesPixelDepthOffset() const;
|
|
|
|
|
ENGINE_API bool MaterialUsesDistanceCullFade_GameThread() const;
|
|
|
|
|
ENGINE_API bool MaterialUsesSceneDepthLookup_RenderThread() const;
|
|
|
|
|
ENGINE_API bool MaterialUsesSceneDepthLookup_GameThread() const;
|
|
|
|
|
ENGINE_API bool UsesCustomDepthStencil_GameThread() const;
|
|
|
|
|
ENGINE_API bool MaterialMayModifyMeshPosition() const;
|
|
|
|
|
ENGINE_API bool MaterialUsesAnisotropy_GameThread() const;
|
|
|
|
|
ENGINE_API bool MaterialUsesAnisotropy_RenderThread() const;
|
|
|
|
|
|
|
|
|
|
// shader map接口.
|
|
|
|
|
class FMaterialShaderMap* GetGameThreadShaderMap() const
|
|
|
|
|
{
|
|
|
|
|
return GameThreadShaderMap;
|
|
|
|
|
}
|
|
|
|
|
void SetGameThreadShaderMap(FMaterialShaderMap* InMaterialShaderMap)
|
|
|
|
|
{
|
|
|
|
|
GameThreadShaderMap = InMaterialShaderMap;
|
|
|
|
|
|
|
|
|
|
TRefCountPtr<FMaterialShaderMap> ShaderMap = GameThreadShaderMap;
|
|
|
|
|
TRefCountPtr<FMaterial> Material = this;
|
|
|
|
|
|
|
|
|
|
// 将游戏线程的shader map设置到渲染线程.
|
|
|
|
|
ENQUEUE_RENDER_COMMAND(SetGameThreadShaderMap)([Material = MoveTemp(Material), ShaderMap = MoveTemp(ShaderMap)](FRHICommandListImmediate& RHICmdList) mutable
|
|
|
|
|
{
|
|
|
|
|
Material->RenderingThreadShaderMap = MoveTemp(ShaderMap);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
void SetInlineShaderMap(FMaterialShaderMap* InMaterialShaderMap);
|
|
|
|
|
ENGINE_API class FMaterialShaderMap* GetRenderingThreadShaderMap() const;
|
|
|
|
|
ENGINE_API void SetRenderingThreadShaderMap(const TRefCountPtr<FMaterialShaderMap>& InMaterialShaderMap);
|
|
|
|
|
|
|
|
|
|
ENGINE_API virtual void AddReferencedObjects(FReferenceCollector& Collector);
|
|
|
|
|
|
|
|
|
|
virtual TArrayView<UObject* const> GetReferencedTextures() const = 0;
|
|
|
|
|
|
|
|
|
|
// 获取shader/shader pipeline.
|
|
|
|
|
template<typename ShaderType>
|
|
|
|
|
TShaderRef<ShaderType> GetShader(FVertexFactoryType* VertexFactoryType, const typename ShaderType::FPermutationDomain& PermutationVector, bool bFatalIfMissing = true) const;
|
|
|
|
|
template <typename ShaderType>
|
|
|
|
|
TShaderRef<ShaderType> GetShader(FVertexFactoryType* VertexFactoryType, int32 PermutationId = 0, bool bFatalIfMissing = true) const;
|
|
|
|
|
ENGINE_API FShaderPipelineRef GetShaderPipeline(class FShaderPipelineType* ShaderPipelineType, FVertexFactoryType* VertexFactoryType, bool bFatalIfNotFound = true) const;
|
|
|
|
|
|
|
|
|
|
// 材质接口.
|
|
|
|
|
virtual FString GetMaterialUsageDescription() const = 0;
|
|
|
|
|
virtual bool GetAllowDevelopmentShaderCompile()const{ return true; }
|
|
|
|
|
virtual EMaterialShaderMapUsage::Type GetMaterialShaderMapUsage() const { return EMaterialShaderMapUsage::Default; }
|
|
|
|
|
ENGINE_API bool GetMaterialExpressionSource(FString& OutSource);
|
|
|
|
|
ENGINE_API bool WritesEveryPixel(bool bShadowPass = false) const;
|
|
|
|
|
virtual void SetupExtaCompilationSettings(const EShaderPlatform Platform, FExtraShaderCompilerSettings& Settings) const;
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
const FMaterialShaderMap* GetShaderMapToUse() const;
|
|
|
|
|
|
|
|
|
|
virtual int32 CompilePropertyAndSetMaterialProperty(EMaterialProperty Property, class FMaterialCompiler* Compiler, EShaderFrequency OverrideShaderFrequency = SF_NumFrequencies, bool bUsePreviousFrameTime = false) const = 0;
|
|
|
|
|
|
|
|
|
|
void SetQualityLevelProperties(ERHIFeatureLevel::Type InFeatureLevel, EMaterialQualityLevel::Type InQualityLevel = EMaterialQualityLevel::Num);
|
|
|
|
|
virtual EMaterialShaderMapUsage::Type GetShaderMapUsage() const;
|
|
|
|
|
virtual FGuid GetMaterialId() const = 0;
|
|
|
|
|
ENGINE_API void GetDependentShaderAndVFTypes(EShaderPlatform Platform, TArray<FShaderType*>& OutShaderTypes, TArray<const FShaderPipelineType*>& OutShaderPipelineTypes, TArray<FVertexFactoryType*>& OutVFTypes) const;
|
|
|
|
|
bool GetLoadedCookedShaderMapId() const;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// 游戏线程和渲染线程的shader map.
|
|
|
|
|
TRefCountPtr<FMaterialShaderMap> GameThreadShaderMap;
|
|
|
|
|
TRefCountPtr<FMaterialShaderMap> RenderingThreadShaderMap;
|
|
|
|
|
|
|
|
|
|
// 质量等级.
|
|
|
|
|
EMaterialQualityLevel::Type QualityLevel;
|
|
|
|
|
ERHIFeatureLevel::Type FeatureLevel;
|
|
|
|
|
|
|
|
|
|
// 特殊标记.
|
|
|
|
|
uint32 bStencilDitheredLOD : 1;
|
|
|
|
|
uint32 bContainsInlineShaders : 1;
|
|
|
|
|
uint32 bLoadedCookedShaderMapId : 1;
|
|
|
|
|
|
|
|
|
|
bool BeginCompileShaderMap(
|
|
|
|
|
const FMaterialShaderMapId& ShaderMapId,
|
|
|
|
|
const FStaticParameterSet &StaticParameterSet,
|
|
|
|
|
EShaderPlatform Platform,
|
|
|
|
|
TRefCountPtr<class FMaterialShaderMap>& OutShaderMap,
|
|
|
|
|
const ITargetPlatform* TargetPlatform = nullptr);
|
|
|
|
|
void SetupMaterialEnvironment(
|
|
|
|
|
EShaderPlatform Platform,
|
|
|
|
|
const FShaderParametersMetadata& InUniformBufferStruct,
|
|
|
|
|
const FUniformExpressionSet& InUniformExpressionSet,
|
|
|
|
|
FShaderCompilerEnvironment& OutEnvironment
|
|
|
|
|
) const;
|
|
|
|
|
|
|
|
|
|
ENGINE_API TShaderRef<FShader> GetShader(class FMeshMaterialShaderType* ShaderType, FVertexFactoryType* VertexFactoryType, int32 PermutationId, bool bFatalIfMissing = true) const;
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
由上面可知,FMaterial集大之所成,囊括了材质、Shader、VertexFactory、ShaderPipeline、ShaderMap等各种数据和操作接口,是这些数据的集散地。不过,它只是个抽象的父类,具体的功能需要由子类实现。它的子类只有FMaterialResource:
|
|
|
|
|
```c++
|
|
|
|
|
// 实现FMaterial的接口, 用于渲染UMaterial或UMaterialInstance.
|
|
|
|
|
class FMaterialResource : public FMaterial
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ENGINE_API FMaterialResource();
|
|
|
|
|
ENGINE_API virtual ~FMaterialResource();
|
|
|
|
|
|
|
|
|
|
// 设置材质.
|
|
|
|
|
void SetMaterial(UMaterial* InMaterial, UMaterialInstance* InInstance, ERHIFeatureLevel::Type InFeatureLevel, EMaterialQualityLevel::Type InQualityLevel = EMaterialQualityLevel::Num)
|
|
|
|
|
{
|
|
|
|
|
Material = InMaterial;
|
|
|
|
|
MaterialInstance = InInstance;
|
|
|
|
|
SetQualityLevelProperties(InFeatureLevel, InQualityLevel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ENGINE_API uint32 GetNumVirtualTextureStacks() const;
|
|
|
|
|
ENGINE_API virtual FString GetMaterialUsageDescription() const override;
|
|
|
|
|
|
|
|
|
|
// FMaterial interface.
|
|
|
|
|
ENGINE_API virtual void GetShaderMapId(EShaderPlatform Platform, const ITargetPlatform* TargetPlatform, FMaterialShaderMapId& OutId) const override;
|
|
|
|
|
ENGINE_API virtual EMaterialDomain GetMaterialDomain() const override;
|
|
|
|
|
ENGINE_API virtual bool IsTwoSided() const override;
|
|
|
|
|
ENGINE_API virtual bool IsDitheredLODTransition() const override;
|
|
|
|
|
ENGINE_API virtual bool IsTranslucencyWritingCustomDepth() const override;
|
|
|
|
|
ENGINE_API virtual bool IsTranslucencyWritingVelocity() const override;
|
|
|
|
|
ENGINE_API virtual bool IsTangentSpaceNormal() const override;
|
|
|
|
|
ENGINE_API virtual EMaterialShadingRate GetShadingRate() const override;
|
|
|
|
|
(......)
|
|
|
|
|
// 材质接口.
|
|
|
|
|
inline const UMaterial* GetMaterial() const { return Material; }
|
|
|
|
|
inline const UMaterialInstance* GetMaterialInstance() const { return MaterialInstance; }
|
|
|
|
|
inline void SetMaterial(UMaterial* InMaterial) { Material = InMaterial; }
|
|
|
|
|
inline void SetMaterialInstance(UMaterialInstance* InMaterialInstance) { MaterialInstance = InMaterialInstance; }
|
|
|
|
|
protected:
|
|
|
|
|
// 对应的材质.
|
|
|
|
|
UMaterial* Material;
|
|
|
|
|
// 对应的材质实例.
|
|
|
|
|
UMaterialInstance* MaterialInstance;
|
|
|
|
|
|
|
|
|
|
// 编译指定材质属性的入口, 须有SetMaterialProperty调用.
|
|
|
|
|
ENGINE_API virtual int32 CompilePropertyAndSetMaterialProperty(EMaterialProperty Property, class FMaterialCompiler* Compiler, EShaderFrequency OverrideShaderFrequency, bool bUsePreviousFrameTime) const override;
|
|
|
|
|
|
|
|
|
|
ENGINE_API virtual bool HasVertexPositionOffsetConnected() const override;
|
|
|
|
|
ENGINE_API virtual bool HasPixelDepthOffsetConnected() const override;
|
|
|
|
|
ENGINE_API virtual bool HasMaterialAttributesConnected() const override;
|
|
|
|
|
(......)
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
FMaterialResource只是实现了FMaterial未实现的接口,并且存储了UMaterial或UMaterialInstance的实例。如果UMaterialInstance和UMaterial的实例都有效的情况下,那么它们重叠的数据会优先取UMaterialInstance的数据,比如:
|
|
|
|
|
```c++
|
|
|
|
|
// 获取着色模型域
|
|
|
|
|
FMaterialShadingModelField FMaterialResource::GetShadingModels() const
|
|
|
|
|
{
|
|
|
|
|
// 优先选用MaterialInstance的数据.
|
|
|
|
|
return MaterialInstance ? MaterialInstance->GetShadingModels() : Material->GetShadingModels();
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
渲染资源除了FMaterial之外,还有个比较核心的概念就是**FMaterialRenderContext**,它保存了**FMaterialRenderProxy和FMaterial**之间的关联配对:
|
|
|
|
|
```c++
|
|
|
|
|
struct ENGINE_API FMaterialRenderContext
|
|
|
|
|
{
|
|
|
|
|
// 用于材质shader的材质渲染代表.
|
|
|
|
|
const FMaterialRenderProxy* MaterialRenderProxy;
|
|
|
|
|
// 材质渲染资源.
|
|
|
|
|
const FMaterial& Material;
|
|
|
|
|
|
|
|
|
|
// 是否显示选中时的颜色.
|
|
|
|
|
bool bShowSelection;
|
|
|
|
|
|
|
|
|
|
// 构造函数.
|
|
|
|
|
FMaterialRenderContext(const FMaterialRenderProxy* InMaterialRenderProxy, const FMaterial& InMaterial, const FSceneView* InView);
|
|
|
|
|
};
|
|
|
|
|
```
|
|
|
|
|
FMaterialRenderContext较多地用于材质各种类型的接口的形参,比如:
|
|
|
|
|
```c++
|
|
|
|
|
// FDefaultMaterialInstance中的获取向量参数值, 用到了FMaterialRenderContext参数.
|
|
|
|
|
virtual bool FDefaultMaterialInstance::GetVectorValue(const FHashedMaterialParameterInfo& ParameterInfo, FLinearColor* OutValue, const FMaterialRenderContext& Context) const
|
|
|
|
|
{
|
|
|
|
|
const FMaterialResource* MaterialResource = Material->GetMaterialResource(Context.Material.GetFeatureLevel());
|
|
|
|
|
|
|
|
|
|
if(MaterialResource && MaterialResource->GetRenderingThreadShaderMap())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return GetFallbackRenderProxy().GetVectorValue(ParameterInfo, OutValue, Context);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
# 材质渲染
|
|
|
|
|
材质数据的发起者依然是游戏线程侧的资源,一般是从磁盘加载的二进制资源,然后序列化成UMaterialInterface实例,或者由运行时动态创建并设置材质数据。不过绝大多数是由磁盘加载而来。
|
|
|
|
|
当使用了材质的图元组件在被要求**收集MeshBatch**的时候,可以将其使用的UMaterialInterface对应的**FMaterialRenderProxy传递到FMeshBatchElement**中。下面以StaticMesh为例:
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Engine\Private\StaticMeshRender.cpp
|
|
|
|
|
|
|
|
|
|
bool FStaticMeshSceneProxy::GetMeshElement(
|
|
|
|
|
int32 LODIndex,
|
|
|
|
|
int32 BatchIndex,
|
|
|
|
|
int32 SectionIndex,
|
|
|
|
|
uint8 InDepthPriorityGroup,
|
|
|
|
|
bool bUseSelectionOutline,
|
|
|
|
|
bool bAllowPreCulledIndices,
|
|
|
|
|
FMeshBatch& OutMeshBatch) const
|
|
|
|
|
{
|
|
|
|
|
const ERHIFeatureLevel::Type FeatureLevel = GetScene().GetFeatureLevel();
|
|
|
|
|
const FStaticMeshLODResources& LOD = RenderData->LODResources[LODIndex];
|
|
|
|
|
const FStaticMeshVertexFactories& VFs = RenderData->LODVertexFactories[LODIndex];
|
|
|
|
|
const FStaticMeshSection& Section = LOD.Sections[SectionIndex];
|
|
|
|
|
const FLODInfo& ProxyLODInfo = LODs[LODIndex];
|
|
|
|
|
|
|
|
|
|
// 获取材质的各种实例(包含UMaterialInterface, FMaterialRenderProxy和FMaterial)
|
|
|
|
|
UMaterialInterface* MaterialInterface = ProxyLODInfo.Sections[SectionIndex].Material;
|
|
|
|
|
FMaterialRenderProxy* MaterialRenderProxy = MaterialInterface->GetRenderProxy();
|
|
|
|
|
const FMaterial* Material = MaterialRenderProxy->GetMaterial(FeatureLevel);
|
|
|
|
|
|
|
|
|
|
FMeshBatchElement& OutMeshBatchElement = OutMeshBatch.Elements[0];
|
|
|
|
|
|
|
|
|
|
// 处理顶点工厂
|
|
|
|
|
const FVertexFactory* VertexFactory = nullptr;
|
|
|
|
|
if (ProxyLODInfo.OverrideColorVertexBuffer)
|
|
|
|
|
{
|
|
|
|
|
(......)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
if(NumPrimitives > 0)
|
|
|
|
|
{
|
|
|
|
|
OutMeshBatch.SegmentIndex = SectionIndex;
|
|
|
|
|
OutMeshBatch.LODIndex = LODIndex;
|
|
|
|
|
|
|
|
|
|
// 赋值材质和渲染代表.
|
|
|
|
|
OutMeshBatch.MaterialRenderProxy = MaterialRenderProxy;
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
因此,可以知道,在组件收集网格元素的时候,材质的所有类型的数据已经准备好,并且可以被访问了。说明在游戏线程阶段,材质的各种类型的实例已经被加载、设置和创建。我们继续深究到底是什么时候创建的。首先看FMaterialRenderProxy,不同的UMaterialInterface的子类稍有不一样,具体如下代码所示:
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Engine\Private\Materials\MaterialInstance.cpp
|
|
|
|
|
void UMaterialInstance::PostInitProperties()
|
|
|
|
|
{
|
|
|
|
|
Super::PostInitProperties();
|
|
|
|
|
|
|
|
|
|
if(!HasAnyFlags(RF_ClassDefaultObject))
|
|
|
|
|
{
|
|
|
|
|
// 创建FMaterialRenderProxy.
|
|
|
|
|
Resource = new FMaterialInstanceResource(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FMaterialRenderProxy* UMaterialInstance::GetRenderProxy() const
|
|
|
|
|
{
|
|
|
|
|
return Resource;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Engine\Source\Runtime\Engine\Private\Materials\Material.cpp
|
|
|
|
|
|
|
|
|
|
void UMaterial::PostInitProperties()
|
|
|
|
|
{
|
|
|
|
|
Super::PostInitProperties();
|
|
|
|
|
if(!HasAnyFlags(RF_ClassDefaultObject))
|
|
|
|
|
{
|
|
|
|
|
// 创建FMaterialRenderProxy.
|
|
|
|
|
DefaultMaterialInstance = new FDefaultMaterialInstance(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FPlatformMisc::CreateGuid(StateId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FMaterialRenderProxy* UMaterial::GetRenderProxy() const
|
|
|
|
|
{
|
|
|
|
|
return DefaultMaterialInstance;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
由此可推断,UMaterialInstance对应的FMaterialRenderProxy是在子类的PostInitProperties阶段被创建的。
|
|
|
|
|
我们继续查明UMaterialInterface获取对应的FMaterial实例是哪个接口哪个成员:
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Engine\Private\Materials\Material.cpp
|
|
|
|
|
// 获取UMaterial对应的FMaterialResource(FMaterial的子类)实例.
|
|
|
|
|
FMaterialResource* UMaterial::GetMaterialResource(ERHIFeatureLevel::Type InFeatureLevel, EMaterialQualityLevel::Type QualityLevel)
|
|
|
|
|
{
|
|
|
|
|
if (QualityLevel == EMaterialQualityLevel::Num)
|
|
|
|
|
{
|
|
|
|
|
QualityLevel = GetCachedScalabilityCVars().MaterialQualityLevel;
|
|
|
|
|
}
|
|
|
|
|
return FindMaterialResource(MaterialResources, InFeatureLevel, QualityLevel, true);
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
以上可以知道,是查找UMaterial::MaterialResources,那么继续深究其何时被创建:
|
|
|
|
|
```c++
|
|
|
|
|
FMaterialResource* FindOrCreateMaterialResource(TArray<FMaterialResource*>& MaterialResources,
|
|
|
|
|
UMaterial* OwnerMaterial,
|
|
|
|
|
UMaterialInstance* OwnerMaterialInstance,
|
|
|
|
|
ERHIFeatureLevel::Type InFeatureLevel,
|
|
|
|
|
EMaterialQualityLevel::Type InQualityLevel)
|
|
|
|
|
{
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
FMaterialResource* CurrentResource = FindMaterialResource(MaterialResources, InFeatureLevel, QualityLevelForResource, false);
|
|
|
|
|
|
|
|
|
|
// 如果当前资源列表不存在就创建新的FMaterialResource实例.
|
|
|
|
|
if (!CurrentResource)
|
|
|
|
|
{
|
|
|
|
|
// 优先使用材质实例的的接口来创建.
|
|
|
|
|
CurrentResource = OwnerMaterialInstance ? OwnerMaterialInstance->AllocatePermutationResource() : OwnerMaterial->AllocateResource();
|
|
|
|
|
CurrentResource->SetMaterial(OwnerMaterial, OwnerMaterialInstance, InFeatureLevel, QualityLevelForResource);
|
|
|
|
|
// 添加到FMaterialResource实例列表.
|
|
|
|
|
MaterialResources.Add(CurrentResource);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
return CurrentResource;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
以上创建FMaterialResource实例时会优先使用有效的OwnerMaterialInstance,然后才使用UMaterial的接口,下面进入它们创建FMaterialResource实例的接口:
|
|
|
|
|
```c++
|
|
|
|
|
FMaterialResource* UMaterialInstance::AllocatePermutationResource()
|
|
|
|
|
{
|
|
|
|
|
return new FMaterialResource();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FMaterialResource* UMaterial::AllocateResource()
|
|
|
|
|
{
|
|
|
|
|
return new FMaterialResource();
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
好家伙,逻辑一样的,都是直接new一个FMaterialResource对象并返回。下面继续追踪有哪些接口会调用FindOrCreateMaterialResource:
|
|
|
|
|
- ProcessSerializedInlineShaderMaps
|
|
|
|
|
- UMaterial::PostLoad
|
|
|
|
|
- UMaterial::CacheResourceShadersForRendering
|
|
|
|
|
- UMaterial::AllMaterialsCacheResourceShadersForRendering
|
|
|
|
|
- UMaterial::ForceRecompileForRendering
|
|
|
|
|
- UMaterial::PostEditChangePropertyInternal
|
|
|
|
|
- UMaterial::SetMaterialUsage
|
|
|
|
|
- UMaterial::UpdateMaterialShaders
|
|
|
|
|
- UMaterial::UpdateMaterialShaderCacheAndTextureReferences
|
|
|
|
|
|
|
|
|
|
以上接口都会直接或间接调用到FindOrCreateMaterialResource接口,从而触发FMaterialResource对象的创建。但在运行时的版本中,通常由UMaterial::PostLoad触发,调用堆栈如下所示:
|
|
|
|
|
- UMaterial::PostLoad
|
|
|
|
|
- ProcessSerializedInlineShaderMaps
|
|
|
|
|
- FindOrCreateMaterialResource
|
|
|
|
|
|
|
|
|
|
此外,UMaterialInstance的部分接口也会触发FMaterialResource实例的创建,此文不继续追踪了。
|
|
|
|
|
|
|
|
|
|
我们继续研究FMaterial的GameThreadShaderMap和RenderingThreadShaderMap是在何处何时被设置和传递的:
|
|
|
|
|
```c++
|
|
|
|
|
// 直接设置RenderingThreadShaderMap
|
|
|
|
|
void FMaterial::SetRenderingThreadShaderMap(const TRefCountPtr<FMaterialShaderMap>& InMaterialShaderMap)
|
|
|
|
|
{
|
|
|
|
|
RenderingThreadShaderMap = InMaterialShaderMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置游戏线程ShaderMap.
|
|
|
|
|
void FMaterial::SetGameThreadShaderMap(FMaterialShaderMap* InMaterialShaderMap)
|
|
|
|
|
{
|
|
|
|
|
GameThreadShaderMap = InMaterialShaderMap;
|
|
|
|
|
|
|
|
|
|
TRefCountPtr<FMaterialShaderMap> ShaderMap = GameThreadShaderMap;
|
|
|
|
|
TRefCountPtr<FMaterial> Material = this;
|
|
|
|
|
// 向渲染线程推送设置ShaderMap的指令.
|
|
|
|
|
ENQUEUE_RENDER_COMMAND(SetGameThreadShaderMap)([Material = MoveTemp(Material), ShaderMap = MoveTemp(ShaderMap)](FRHICommandListImmediate& RHICmdList) mutable
|
|
|
|
|
{
|
|
|
|
|
Material->RenderingThreadShaderMap = MoveTemp(ShaderMap);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置内联ShaderMap
|
|
|
|
|
void FMaterial::SetInlineShaderMap(FMaterialShaderMap* InMaterialShaderMap)
|
|
|
|
|
{
|
|
|
|
|
GameThreadShaderMap = InMaterialShaderMap;
|
|
|
|
|
bContainsInlineShaders = true;
|
|
|
|
|
bLoadedCookedShaderMapId = true;
|
|
|
|
|
|
|
|
|
|
TRefCountPtr<FMaterialShaderMap> ShaderMap = GameThreadShaderMap;
|
|
|
|
|
TRefCountPtr<FMaterial> Material = this;
|
|
|
|
|
// 向渲染线程推送设置ShaderMap的指令.
|
|
|
|
|
ENQUEUE_RENDER_COMMAND(SetInlineShaderMap)([Material = MoveTemp(Material), ShaderMap = MoveTemp(ShaderMap)](FRHICommandListImmediate& RHICmdList) mutable
|
|
|
|
|
{
|
|
|
|
|
Material->RenderingThreadShaderMap = MoveTemp(ShaderMap);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
以上可以设置FMaterial的RenderingThreadShaderMap有3个接口,继续追踪有哪些接口会调用到它们:
|
|
|
|
|
- FMaterial::CacheShaders
|
|
|
|
|
- FMaterial::SetGameThreadShaderMap
|
|
|
|
|
- FMaterialShaderMap::LoadForRemoteRecompile
|
|
|
|
|
- FMaterial::SetGameThreadShaderMap
|
|
|
|
|
- ProcessSerializedInlineShaderMaps
|
|
|
|
|
- FMaterial::SetInlineShaderMap
|
|
|
|
|
- SetShaderMapsOnMaterialResources_RenderThread
|
|
|
|
|
- FMaterial::SetRenderingThreadShaderMap
|
|
|
|
|
|
|
|
|
|
虽然上面有很多接口最终会设置到FMaterial的RenderingThreadShaderMap,不过多数情况下,运行时RenderingThreadShaderMap被设置的调用堆栈如下:
|
|
|
|
|
- UMaterial::PostLoad
|
|
|
|
|
- ProcessSerializedInlineShaderMaps
|
|
|
|
|
- FMaterial::SetInlineShaderMap
|
|
|
|
|
|
|
|
|
|
一旦FMaterial的RenderingThreadShaderMap被正确设置,材质相关的其它众多数据将被渲染线程和渲染器自由地读取,如同鱼儿无忧无虑地遨游在湛蓝的大海之中。
|
|
|
|
|
|
|
|
|
|
# 材质编译
|
|
|
|
|
UMaterialExpression就是表达式,每个材质节点UMaterialGraphNode都有一个UMaterialExpression实例。下面进入FMaterialCompiler(是抽象类,由子类FHLSLMaterialTranslator实现)的这两个接口的实现:
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Engine\Private\Materials\HLSLMaterialTranslator.cpp
|
|
|
|
|
|
|
|
|
|
int32 FHLSLMaterialTranslator::Add(int32 A,int32 B)
|
|
|
|
|
{
|
|
|
|
|
if(A == INDEX_NONE || B == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
return INDEX_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const uint64 Hash = CityHash128to64({ GetParameterHash(A), GetParameterHash(B) });
|
|
|
|
|
if(GetParameterUniformExpression(A) && GetParameterUniformExpression(B))
|
|
|
|
|
{
|
|
|
|
|
return AddUniformExpressionWithHash(Hash, new FMaterialUniformExpressionFoldedMath(GetParameterUniformExpression(A),GetParameterUniformExpression(B),FMO_Add),GetArithmeticResultType(A,B),TEXT("(%s + %s)"),*GetParameterCode(A),*GetParameterCode(B));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return AddCodeChunkWithHash(Hash, GetArithmeticResultType(A,B),TEXT("(%s + %s)"),*GetParameterCode(A),*GetParameterCode(B));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32 FHLSLMaterialTranslator::DDX( int32 X )
|
|
|
|
|
{
|
|
|
|
|
if (X == INDEX_NONE)
|
|
|
|
|
{
|
|
|
|
|
return INDEX_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ShaderFrequency == SF_Compute)
|
|
|
|
|
{
|
|
|
|
|
// running a material in a compute shader pass (e.g. when using SVOGI)
|
|
|
|
|
return AddInlinedCodeChunk(MCT_Float, TEXT("0"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ShaderFrequency != SF_Pixel)
|
|
|
|
|
{
|
|
|
|
|
return NonPixelShaderExpressionError();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return AddCodeChunk(GetParameterType(X),TEXT("DDX(%s)"),*GetParameterCode(X));
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**UMaterialGraphNode即我们在材质编辑器创建的材质节点**,继承的父类依次是UMaterialGraphNode_Base、UEdGraphNode。
|
|
|
|
|
|
|
|
|
|
## FHLSLMaterialTranslator
|
|
|
|
|
FHLSLMaterialTranslator继承自FMaterialCompiler,作用就是将材质的表达式转译成HLSL代码,填充到MaterialTemplate.ush的宏和空缺代码段。
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Source\Runtime\Engine\Public\MaterialCompiler.h
|
|
|
|
|
class FMaterialCompiler
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual ~FMaterialCompiler() { }
|
|
|
|
|
// 材质属性接口.
|
|
|
|
|
virtual void SetMaterialProperty(EMaterialProperty InProperty, EShaderFrequency OverrideShaderFrequency = SF_NumFrequencies, bool bUsePreviousFrameTime = false) = 0;
|
|
|
|
|
virtual void PushMaterialAttribute(const FGuid& InAttributeID) = 0;
|
|
|
|
|
virtual FGuid PopMaterialAttribute() = 0;
|
|
|
|
|
virtual const FGuid GetMaterialAttribute() = 0;
|
|
|
|
|
virtual void SetBaseMaterialAttribute(const FGuid& InAttributeID) = 0;
|
|
|
|
|
virtual void PushParameterOwner(const FMaterialParameterInfo& InOwnerInfo) = 0;
|
|
|
|
|
virtual FMaterialParameterInfo PopParameterOwner() = 0;
|
|
|
|
|
|
|
|
|
|
// 调用材质表达式.
|
|
|
|
|
virtual int32 CallExpression(FMaterialExpressionKey ExpressionKey,FMaterialCompiler* InCompiler) = 0;
|
|
|
|
|
|
|
|
|
|
// 平台和着色模型相关.
|
|
|
|
|
virtual EShaderFrequency GetCurrentShaderFrequency() const = 0;
|
|
|
|
|
virtual EMaterialCompilerType GetCompilerType() const;
|
|
|
|
|
inline bool IsVertexInterpolatorBypass() const;
|
|
|
|
|
virtual EMaterialValueType GetType(int32 Code) = 0;
|
|
|
|
|
virtual EMaterialQualityLevel::Type GetQualityLevel() = 0;
|
|
|
|
|
virtual ERHIFeatureLevel::Type GetFeatureLevel() = 0;
|
|
|
|
|
virtual EShaderPlatform GetShaderPlatform() = 0;
|
|
|
|
|
virtual const ITargetPlatform* GetTargetPlatform() const = 0;
|
|
|
|
|
virtual FMaterialShadingModelField GetMaterialShadingModels() const = 0;
|
|
|
|
|
(......)
|
|
|
|
|
// 材质表达式对应的接口.
|
|
|
|
|
virtual int32 AccessCollectionParameter(UMaterialParameterCollection* ParameterCollection, int32 ParameterIndex, int32 ComponentIndex) = 0;
|
|
|
|
|
virtual int32 ScalarParameter(FName ParameterName, float DefaultValue) = 0;
|
|
|
|
|
virtual int32 VectorParameter(FName ParameterName, const FLinearColor& DefaultValue) = 0;
|
|
|
|
|
virtual int32 Constant(float X) = 0;
|
|
|
|
|
virtual int32 Constant2(float X,float Y) = 0;
|
|
|
|
|
virtual int32 Sine(int32 X) = 0;
|
|
|
|
|
virtual int32 Cosine(int32 X) = 0;
|
|
|
|
|
virtual int32 Tangent(int32 X) = 0;
|
|
|
|
|
virtual int32 ReflectionVector() = 0;
|
|
|
|
|
|
|
|
|
|
virtual int32 If(int32 A,int32 B,int32 AGreaterThanB,int32 AEqualsB,int32 ALessThanB,int32 Threshold) = 0;
|
|
|
|
|
virtual int32 VertexInterpolator(uint32 InterpolatorIndex) = 0;
|
|
|
|
|
|
|
|
|
|
virtual int32 Add(int32 A,int32 B) = 0;
|
|
|
|
|
virtual int32 Sub(int32 A,int32 B) = 0;
|
|
|
|
|
virtual int32 Mul(int32 A,int32 B) = 0;
|
|
|
|
|
virtual int32 Div(int32 A,int32 B) = 0;
|
|
|
|
|
virtual int32 Dot(int32 A,int32 B) = 0;
|
|
|
|
|
virtual int32 Cross(int32 A,int32 B) = 0;
|
|
|
|
|
|
|
|
|
|
virtual int32 DDX(int32 X) = 0;
|
|
|
|
|
virtual int32 DDY(int32 X) = 0;
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Engine\Source\Runtime\Engine\Private\Materials\HLSLMaterialTranslator.h
|
|
|
|
|
class FHLSLMaterialTranslator : public FMaterialCompiler
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
// 编译的材质.
|
|
|
|
|
FMaterial* Material;
|
|
|
|
|
// 编译输出结果, 会被存储到DDC.
|
|
|
|
|
FMaterialCompilationOutput& MaterialCompilationOutput;
|
|
|
|
|
|
|
|
|
|
// 资源字符串.
|
|
|
|
|
FString ResourcesString;
|
|
|
|
|
// MaterialTemplate.usf字符串内容.
|
|
|
|
|
FString MaterialTemplate;
|
|
|
|
|
|
|
|
|
|
// 平台相关.
|
|
|
|
|
EShaderFrequency ShaderFrequency;
|
|
|
|
|
EShaderPlatform Platform;
|
|
|
|
|
EMaterialQualityLevel::Type QualityLevel;
|
|
|
|
|
ERHIFeatureLevel::Type FeatureLevel;
|
|
|
|
|
FMaterialShadingModelField ShadingModelsFromCompilation;
|
|
|
|
|
const ITargetPlatform* TargetPlatform;
|
|
|
|
|
|
|
|
|
|
// 编译的中间数据.
|
|
|
|
|
EMaterialProperty MaterialProperty;
|
|
|
|
|
TArray<FGuid> MaterialAttributesStack;
|
|
|
|
|
TArray<FMaterialParameterInfo> ParameterOwnerStack;
|
|
|
|
|
TArray<FShaderCodeChunk>* CurrentScopeChunks;
|
|
|
|
|
bool SharedPixelProperties[CompiledMP_MAX];
|
|
|
|
|
TArray<FMaterialFunctionCompileState*> FunctionStacks[SF_NumFrequencies];
|
|
|
|
|
FStaticParameterSet StaticParameters;
|
|
|
|
|
|
|
|
|
|
TArray<FShaderCodeChunk> SharedPropertyCodeChunks[SF_NumFrequencies];
|
|
|
|
|
TArray<FShaderCodeChunk> UniformExpressions;
|
|
|
|
|
TArray<TRefCountPtr<FMaterialUniformExpression> > UniformVectorExpressions;
|
|
|
|
|
TArray<TRefCountPtr<FMaterialUniformExpression> > UniformScalarExpressions;
|
|
|
|
|
TArray<TRefCountPtr<FMaterialUniformExpressionTexture> > UniformTextureExpressions[NumMaterialTextureParameterTypes];
|
|
|
|
|
TArray<TRefCountPtr<FMaterialUniformExpressionExternalTexture>> UniformExternalTextureExpressions;
|
|
|
|
|
|
|
|
|
|
TArray<UMaterialParameterCollection*> ParameterCollections;
|
|
|
|
|
TArray<FMaterialCustomExpressionEntry> CustomExpressions;
|
|
|
|
|
TArray<FString> CustomOutputImplementations;
|
|
|
|
|
TArray<UMaterialExpressionVertexInterpolator*> CustomVertexInterpolators;
|
|
|
|
|
|
|
|
|
|
// 顶点工厂栈入口.
|
|
|
|
|
TArray<FMaterialVTStackEntry> VTStacks;
|
|
|
|
|
FHashTable VTStackHash;
|
|
|
|
|
|
|
|
|
|
TBitArray<> AllocatedUserTexCoords;
|
|
|
|
|
TBitArray<> AllocatedUserVertexTexCoords;
|
|
|
|
|
(.....)
|
|
|
|
|
public:
|
|
|
|
|
// 执行HLSL转译.
|
|
|
|
|
bool Translate();
|
|
|
|
|
// 获取材质环境.
|
|
|
|
|
void GetMaterialEnvironment(EShaderPlatform InPlatform, FShaderCompilerEnvironment& OutEnvironment);
|
|
|
|
|
void GetSharedInputsMaterialCode(FString& PixelMembersDeclaration, FString& NormalAssignment, FString& PixelMembersInitializationEpilog);
|
|
|
|
|
// 获取材质着色器代码.
|
|
|
|
|
FString GetMaterialShaderCode();
|
|
|
|
|
protected:
|
|
|
|
|
// 获取所有定义.
|
|
|
|
|
FString GetDefinitions(TArray<FShaderCodeChunk>& CodeChunks, int32 StartChunk, int32 EndChunk) const;
|
|
|
|
|
|
|
|
|
|
// 代码块.
|
|
|
|
|
int32 AddCodeChunkInner(uint64 Hash, const TCHAR* FormattedCode, EMaterialValueType Type, bool bInlined);
|
|
|
|
|
int32 AddCodeChunk(EMaterialValueType Type, const TCHAR* Format, ...);
|
|
|
|
|
int32 AddCodeChunkWithHash(uint64 BaseHash, EMaterialValueType Type, const TCHAR* Format, ...);
|
|
|
|
|
int32 AddInlinedCodeChunk(EMaterialValueType Type, const TCHAR* Format, ...);
|
|
|
|
|
int32 AddInlinedCodeChunkWithHash(uint64 BaseHash, EMaterialValueType Type, const TCHAR* Format, ...);
|
|
|
|
|
|
|
|
|
|
int32 AddUniformExpressionInner(uint64 Hash, FMaterialUniformExpression* UniformExpression, EMaterialValueType Type, const TCHAR* FormattedCode);
|
|
|
|
|
int32 AddUniformExpression(FMaterialUniformExpression* UniformExpression, EMaterialValueType Type, const TCHAR* Format, ...);
|
|
|
|
|
int32 AddUniformExpressionWithHash(uint64 BaseHash, FMaterialUniformExpression* UniformExpression, EMaterialValueType Type, const TCHAR* Format, ...);
|
|
|
|
|
|
|
|
|
|
// 材质表达式.
|
|
|
|
|
virtual int32 Sine(int32 X) override;
|
|
|
|
|
virtual int32 Cosine(int32 X) override;
|
|
|
|
|
virtual int32 Tangent(int32 X) override;
|
|
|
|
|
virtual int32 Arcsine(int32 X) override;
|
|
|
|
|
virtual int32 ArcsineFast(int32 X) override;
|
|
|
|
|
virtual int32 Arccosine(int32 X) override;
|
|
|
|
|
virtual int32 Floor(int32 X) override;
|
|
|
|
|
virtual int32 Ceil(int32 X) override;
|
|
|
|
|
virtual int32 Round(int32 X) override;
|
|
|
|
|
virtual int32 Truncate(int32 X) override;
|
|
|
|
|
virtual int32 Sign(int32 X) override;
|
|
|
|
|
virtual int32 Frac(int32 X) override;
|
|
|
|
|
virtual int32 Fmod(int32 A, int32 B) override;
|
|
|
|
|
(......)
|
|
|
|
|
};
|
2024-02-07 21:19:35 +08:00
|
|
|
|
```
|
|
|
|
|
FHLSLMaterialTranslator实现了FMaterialCompiler的所有抽象接口,它的核心核心成员和接口如下:
|
|
|
|
|
- FMaterial* Material:编译的目标材质。
|
|
|
|
|
- FMaterialCompilationOutput& MaterialCompilationOutput:编译后的结果。
|
|
|
|
|
- FString MaterialTemplate:待填充或填充后的MaterialTemplate.ush字符串。
|
|
|
|
|
- Translate():执行HLSL转译,将表达式转译成代码块保存到对应的属性槽中。
|
|
|
|
|
- GetMaterialShaderCode():将材质的宏、属性、表达式等数据填充到MaterialTemplate.ush并返回结果。
|
|
|
|
|
|
|
|
|
|
## MaterialTemplate.ush
|
|
|
|
|
MaterialTemplate.usf是材质shader模板,内涵大量%s的空缺和待替换的宏,它们由FHLSLMaterialTranslator::GetMaterialShaderCode负责填充。
|
|
|
|
|
```c++
|
|
|
|
|
// Engine\Shaders\Private\MaterialTemplate.ush
|
|
|
|
|
|
|
|
|
|
#include "/Engine/Private/SceneTexturesCommon.ush"
|
|
|
|
|
#include "/Engine/Private/EyeAdaptationCommon.ush"
|
|
|
|
|
#include "/Engine/Private/Random.ush"
|
|
|
|
|
#include "/Engine/Private/SobolRandom.ush"
|
|
|
|
|
#include "/Engine/Private/MonteCarlo.ush"
|
|
|
|
|
#include "/Engine/Generated/UniformBuffers/Material.ush"
|
|
|
|
|
#include "/Engine/Private/DepthOfFieldCommon.ush"
|
|
|
|
|
#include "/Engine/Private/CircleDOFCommon.ush"
|
|
|
|
|
#include "/Engine/Private/GlobalDistanceFieldShared.ush"
|
|
|
|
|
#include "/Engine/Private/SceneData.ush"
|
|
|
|
|
#include "/Engine/Private/HairShadingCommon.ush"
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//! Must match ESceneTextureId
|
|
|
|
|
|
|
|
|
|
// 后处理属性宏.
|
|
|
|
|
#define PPI_SceneColor 0
|
|
|
|
|
#define PPI_SceneDepth 1
|
|
|
|
|
#define PPI_DiffuseColor 2
|
|
|
|
|
#define PPI_SpecularColor 3
|
|
|
|
|
#define PPI_SubsurfaceColor 4
|
|
|
|
|
#define PPI_BaseColor 5
|
|
|
|
|
#define PPI_Specular 6
|
|
|
|
|
#define PPI_Metallic 7
|
|
|
|
|
#define PPI_WorldNormal 8
|
|
|
|
|
#define PPI_SeparateTranslucency 9
|
|
|
|
|
#define PPI_Opacity 10
|
|
|
|
|
#define PPI_Roughness 11
|
|
|
|
|
#define PPI_MaterialAO 12
|
|
|
|
|
#define PPI_CustomDepth 13
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
// 待填充的宏定义.
|
|
|
|
|
#define NUM_MATERIAL_TEXCOORDS_VERTEX %s
|
|
|
|
|
#define NUM_MATERIAL_TEXCOORDS %s
|
|
|
|
|
#define NUM_CUSTOM_VERTEX_INTERPOLATORS %s
|
|
|
|
|
#define NUM_TEX_COORD_INTERPOLATORS %s
|
|
|
|
|
|
|
|
|
|
// 顶点插值位置定义.
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
// 文件引用和宏定义.
|
|
|
|
|
|
|
|
|
|
#include "/Engine/Private/PaniniProjection.ush"
|
|
|
|
|
|
|
|
|
|
#ifndef USE_DITHERED_LOD_TRANSITION
|
|
|
|
|
#if USE_INSTANCING
|
|
|
|
|
#ifndef USE_DITHERED_LOD_TRANSITION_FOR_INSTANCED
|
|
|
|
|
#error "USE_DITHERED_LOD_TRANSITION_FOR_INSTANCED should have been defined"
|
|
|
|
|
#endif
|
|
|
|
|
#define USE_DITHERED_LOD_TRANSITION USE_DITHERED_LOD_TRANSITION_FOR_INSTANCED
|
|
|
|
|
#else
|
|
|
|
|
#ifndef USE_DITHERED_LOD_TRANSITION_FROM_MATERIAL
|
|
|
|
|
#error "USE_DITHERED_LOD_TRANSITION_FROM_MATERIAL should have been defined"
|
|
|
|
|
#endif
|
|
|
|
|
#define USE_DITHERED_LOD_TRANSITION USE_DITHERED_LOD_TRANSITION_FROM_MATERIAL
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef USE_STENCIL_LOD_DITHER
|
|
|
|
|
#define USE_STENCIL_LOD_DITHER USE_STENCIL_LOD_DITHER_DEFAULT
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#define MATERIALBLENDING_ANY_TRANSLUCENT (MATERIALBLENDING_TRANSLUCENT || MATERIALBLENDING_ADDITIVE || MATERIALBLENDING_MODULATE)
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
// 材质的各类结构体.
|
|
|
|
|
struct FMaterialAttributes
|
|
|
|
|
{
|
|
|
|
|
%s
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct FPixelMaterialInputs
|
|
|
|
|
{
|
|
|
|
|
%s
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 像素参数.
|
|
|
|
|
struct FMaterialPixelParameters
|
|
|
|
|
{
|
|
|
|
|
#if NUM_TEX_COORD_INTERPOLATORS
|
|
|
|
|
float2 TexCoords[NUM_TEX_COORD_INTERPOLATORS];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
half4 VertexColor;
|
|
|
|
|
half3 WorldNormal;
|
|
|
|
|
half3 WorldTangent;
|
|
|
|
|
half3 ReflectionVector;
|
|
|
|
|
half3 CameraVector;
|
|
|
|
|
half3 LightVector;
|
|
|
|
|
float4 SvPosition;
|
|
|
|
|
float4 ScreenPosition;
|
|
|
|
|
half UnMirrored;
|
|
|
|
|
half TwoSidedSign;
|
|
|
|
|
half3x3 TangentToWorld;
|
|
|
|
|
|
|
|
|
|
#if USE_WORLDVERTEXNORMAL_CENTER_INTERPOLATION
|
|
|
|
|
half3 WorldVertexNormal_Center;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
float3 AbsoluteWorldPosition;
|
|
|
|
|
float3 WorldPosition_CamRelative;
|
|
|
|
|
float3 WorldPosition_NoOffsets;
|
|
|
|
|
float3 WorldPosition_NoOffsets_CamRelative;
|
|
|
|
|
half3 LightingPositionOffset;
|
|
|
|
|
float AOMaterialMask;
|
|
|
|
|
|
|
|
|
|
#if LIGHTMAP_UV_ACCESS
|
|
|
|
|
float2 LightmapUVs;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if USE_INSTANCING
|
|
|
|
|
half4 PerInstanceParams;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
uint PrimitiveId;
|
|
|
|
|
|
|
|
|
|
#if TEX_COORD_SCALE_ANALYSIS
|
|
|
|
|
FTexCoordScalesParams TexCoordScalesParams;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
(.....)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 顶点参数.
|
|
|
|
|
struct FMaterialVertexParameters
|
|
|
|
|
{
|
|
|
|
|
float3 WorldPosition;
|
|
|
|
|
half3x3 TangentToWorld;
|
|
|
|
|
#if USE_INSTANCING
|
|
|
|
|
float4x4 InstanceLocalToWorld;
|
|
|
|
|
float3 InstanceLocalPosition;
|
|
|
|
|
float4 PerInstanceParams;
|
|
|
|
|
uint InstanceId;
|
|
|
|
|
uint InstanceOffset;
|
|
|
|
|
|
|
|
|
|
#elif IS_MESHPARTICLE_FACTORY
|
|
|
|
|
float4x4 InstanceLocalToWorld;
|
|
|
|
|
#endif
|
|
|
|
|
float4x4 PrevFrameLocalToWorld;
|
|
|
|
|
|
|
|
|
|
float3 PreSkinnedPosition;
|
|
|
|
|
float3 PreSkinnedNormal;
|
|
|
|
|
|
|
|
|
|
#if GPU_SKINNED_MESH_FACTORY
|
|
|
|
|
float3 PreSkinOffset;
|
|
|
|
|
float3 PostSkinOffset;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
half4 VertexColor;
|
|
|
|
|
#if NUM_MATERIAL_TEXCOORDS_VERTEX
|
|
|
|
|
float2 TexCoords[NUM_MATERIAL_TEXCOORDS_VERTEX];
|
|
|
|
|
#if ES3_1_PROFILE
|
|
|
|
|
float2 TexCoordOffset;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
FMaterialParticleParameters Particle;
|
|
|
|
|
uint PrimitiveId;
|
|
|
|
|
|
|
|
|
|
(......)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 数据操作接口.
|
|
|
|
|
MaterialFloat3x3 GetLocalToWorld3x3(uint PrimitiveId);
|
|
|
|
|
MaterialFloat3x3 GetLocalToWorld3x3();
|
|
|
|
|
float3 GetObjectWorldPosition(FMaterialPixelParameters Parameters);
|
|
|
|
|
float3 GetObjectWorldPosition(FMaterialTessellationParameters Parameters);
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
// 材质表达式接口.
|
|
|
|
|
float MaterialExpressionDepthOfFieldFunction(float SceneDepth, int FunctionValueIndex);
|
|
|
|
|
float2 MaterialExpressionGetAtlasUVs(FMaterialPixelParameters Parameters);
|
|
|
|
|
float4 MaterialExpressionGetHairAuxilaryData(FMaterialPixelParameters Parameters);
|
|
|
|
|
float3 MaterialExpressionGetHairColorFromMelanin(float Melanin, float Redness, float3 DyeColor);
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
// 材质属性查找.
|
|
|
|
|
MaterialFloat4 ProcessMaterialColorTextureLookup(MaterialFloat4 TextureValue);
|
|
|
|
|
MaterialFloat4 ProcessMaterialVirtualColorTextureLookup(MaterialFloat4 TextureValue);
|
|
|
|
|
MaterialFloat4 ProcessMaterialExternalTextureLookup(MaterialFloat4 TextureValue);
|
|
|
|
|
MaterialFloat4 ProcessMaterialLinearColorTextureLookup(MaterialFloat4 TextureValue);
|
|
|
|
|
MaterialFloat ProcessMaterialGreyscaleTextureLookup(MaterialFloat TextureValue);
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
// 统一材质表达式.
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
// 材质属性获取接口.
|
|
|
|
|
half3 GetMaterialNormalRaw(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half3 GetMaterialNormal(FMaterialPixelParameters Parameters, FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half3 GetMaterialTangentRaw(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half3 GetMaterialTangent(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half3 GetMaterialEmissiveRaw(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half3 GetMaterialEmissive(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half3 GetMaterialEmissiveForCS(FMaterialPixelParameters Parameters);
|
|
|
|
|
{
|
|
|
|
|
%s;
|
|
|
|
|
}
|
|
|
|
|
uint GetMaterialShadingModel(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half3 GetMaterialBaseColorRaw(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half3 GetMaterialBaseColor(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half GetMaterialCustomData0(FMaterialPixelParameters Parameters)
|
|
|
|
|
{
|
|
|
|
|
%s;
|
|
|
|
|
}
|
|
|
|
|
half GetMaterialCustomData1(FMaterialPixelParameters Parameters)
|
|
|
|
|
{
|
|
|
|
|
%s;
|
|
|
|
|
}
|
|
|
|
|
half GetMaterialAmbientOcclusionRaw(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half GetMaterialAmbientOcclusion(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
half2 GetMaterialRefraction(FPixelMaterialInputs PixelMaterialInputs);
|
|
|
|
|
(......)
|
|
|
|
|
|
|
|
|
|
// 计算材质参数接口.
|
|
|
|
|
void CalcMaterialParametersEx(
|
|
|
|
|
in out FMaterialPixelParameters Parameters,
|
|
|
|
|
in out FPixelMaterialInputs PixelMaterialInputs,
|
|
|
|
|
float4 SvPosition,
|
|
|
|
|
float4 ScreenPosition,
|
|
|
|
|
FIsFrontFace bIsFrontFace,
|
|
|
|
|
float3 TranslatedWorldPosition,
|
|
|
|
|
float3 TranslatedWorldPositionExcludingShaderOffsets);
|
|
|
|
|
void CalcMaterialParameters(
|
|
|
|
|
in out FMaterialPixelParameters Parameters,
|
|
|
|
|
in out FPixelMaterialInputs PixelMaterialInputs,
|
|
|
|
|
float4 SvPosition,
|
|
|
|
|
FIsFrontFace bIsFrontFace);
|
|
|
|
|
void CalcMaterialParametersPost(
|
|
|
|
|
in out FMaterialPixelParameters Parameters,
|
|
|
|
|
in out FPixelMaterialInputs PixelMaterialInputs,
|
|
|
|
|
float4 SvPosition,
|
|
|
|
|
FIsFrontFace bIsFrontFace);
|
|
|
|
|
float ApplyPixelDepthOffsetToMaterialParameters(inout FMaterialPixelParameters MaterialParameters, FPixelMaterialInputs PixelMaterialInputs, out float OutDepth);
|
|
|
|
|
(......)
|
|
|
|
|
```
|
|
|
|
|
MaterialTemplate.ush包含了大量的数据和接口,主要有几类:
|
|
|
|
|
- 基础shader模块引用。
|
|
|
|
|
- 待填充的宏定义。
|
|
|
|
|
- 待填充的接口实现。
|
|
|
|
|
- 顶点、像素、材质属性等结构体定义。部分结构体待填充。
|
|
|
|
|
- 材质属性、数据处理、表达式、工具类接口定义。部分接口待填充。
|
|
|
|
|
|
|
|
|
|
# 材质编译流程
|
|
|
|
|
材质ShaderMap的编译入口在FMaterial的以下两个接口:
|
|
|
|
|
- FMaterial::BeginCompileShaderMap
|
|
|
|
|
- FMaterial::GetMaterialExpressionSource
|
|
|
|
|
|
|
|
|
|
**编译不同类型的shader时,需要的数据不完全一样**:
|
|
|
|
|
- GlobalShader:Shader_x.usf
|
|
|
|
|
- MaterialShader:Shader_x.usf + MaterialTemplate_x.usf
|
|
|
|
|
- MeshMaterialShader:Shader_x.usf + MaterialTemplate_x.usf + VertexFactory_x.usf
|