UE4:材质实例有关的编辑器方法

  1. 确认材质实例的动态参数是否被引用和覆盖
    1. 问题
    2. 实现
      1. 函数声明
      2. 实现思路
  2. 获取材质实例编辑面板显示的参数名称
    1. 问题
    2. 实现
      1. 函数声明
      2. 实现思路
  3. 材质实例的引用关系中有母材质已经不存在的材质参数
    1. 问题
    2. 实现
      1. 函数声明
      2. 实现思路
  4. 源码

确认材质实例的动态参数是否被引用和覆盖

问题

在材质中使用了DynamicParameter节点,通过该节点获得的值参与了部分计算

在级联粒子中,给发射器添加了Dynamic Parameter,引用了材质,并输出动态参数的值给材质

或者是在Niagara粒子中覆盖了引用的材质的动态参数,两者存在实际的引用关系

TA大佬有发现可能部分材质中的某些动态参数节点其实已经在多次修改后完全没有被任何粒子或特效输入,已经退化成一个默认值,此处的计算可以被优化,删除DynamicParameter节点

所以,需要一个工具来确认,给定一个材质实例,确认是否有存在动态参数节点,该节点有没有被任何一个其他资产使用,如果有的话需要返回每个参数对应的值

实现

函数声明

1
2
3
4
5
6
7
/**
* @brief 获取指定材质实例有被特效等覆盖的动态参数的列表,如果是级联粒子可以获取到对应的值
* @param MaterialInstance 材质实例
* @param UseDynamicParameters key为参数名, value是该参数的index和值
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | MaterialInstance")
static void GetFxInvolvedDynamicParameter(const UMaterialInstance* MaterialInstance, TMap<FName, FMTIDynamicParamFloatValueSet>& UseDynamicParameters);

实现思路

通过MaterialInstance->GetMaterial()可以获取到母材质,Material->GetCachedExpressionData().DynamicParameterNames可以获取到母材质的所有动态参数名。

MaterialInstance->GetPackage()->GetName()可以获取到材质实例的Package的名字,在通过IAssetRegistry的GetReferencers可以获取到所有的ReferencerPackages的名字。

对所有的有引用关系的Package遍历,IsChildOf()和IsChildOf()分别获取他们的发射器进行保存。

接下来分别对两种粒子的发射器进行遍历,级联粒子的UParticleModuleParameterDynamic中有DynamicParams,Niagara略微麻烦一点,这里具体的可以去看源码,不多赘述。

获取材质实例编辑面板显示的参数名称

问题

TA大佬希望能够获取到某一个材质或材质实例中没有被使用到的参数节点,针对情况进行一些优化。

设想是使用UE本身的接口获取了某种类型的所有Parameter,然后和默认值对比,如果一直说明该Parameter可能是没有用到的。

但是,在材质实例的使用过程中存在这样一种情况:
假设我们有材质M_A,从它创建了一个材质实例MI_A,材质有一个Switch节点,默认值是false,美术同学在开发过程中覆盖了这个材质节点,改成了true,那么材质实例就是true那个分支了,如果在true的这个分支里有别的参数,比如贴图什么的,美术同学又在MI_A中覆盖掉了这个参数,没有用M_A中的默认值,然后看了一下效果感觉不太行,又把Switch改回了false使用原来的节点,这个时候,仅通过参数默认值对比这个方式,就无法确认这个材质是不是可能没有被使用。

之后TA大佬发现,材质实例的编辑器面板显示的材质参数,和通过MaterialInstance的接口获取到的参数列表是不一致的。材质面板显示出来的能确定是有在使用,没有显示的就可能是没有使用的(针对Switch节点)。TA通过接口拿到了没有在编辑器面板上显示的参数名,TA大佬不想要这个美术其实没用到的参数名,希望可以有一个蓝图接口直接拿到和编辑器面板显示相同的参数名。

实现

函数声明

1
2
3
4
5
6
7
/**
* @brief 获取指定材质实例的一个参数名的列表,该列表和编辑器下打开材质实例编辑器显示的参数名相同,与是否启用和是否override不相同
* @param MaterialInstance 材质实例
* @param ParameterName 参数名的列表
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | MaterialInstance")
static void GetMaterialInstanceParametersEditorDisplayed(UMaterialInstance* MaterialInstance, TArray<FString>& ParameterName);

实现思路

直接创建了一个UMaterialEditorInstanceConstant对象,并将UMaterialInstance的对象Cast为一个UMaterialInstanceConstant,然后对创建的UMaterialEditorInstanceConstant对象进行SetSourceInstance,这样就相当于创建了一个编辑器面板的C++对象。

MaterialEditorInstance->VisibleExpressions之中是所有的面板上会看到的参数名。

材质实例的引用关系中有母材质已经不存在的材质参数

问题

TA大佬有发现存在如下情况:
有一个母材质MA,该母材质有一个材质实例MIA,又从MIA创建了一个材质实例MIAA
MA中之前有一个Texture的参数,引用了一个贴图TexA,后来删掉了这个节点
保存并应用MA之后,发现MIA的引用关系里没有TexA,但是在MIAA的引用关系中有TexA,十分奇怪。

这里写了一个方法去对比材质实例和母材质的参数列表来进行清理。

实现

函数声明

1
2
3
4
5
6
7
/**
* @brief 对指定的材质实例进行参数检查,检查指定的参数类型,如果存在该材质实例拥有但是母材质不存在的参数,则会remove掉
* @param MaterialInstance 材质实例
* @param MIParameterType 材质实例的参数类型
*/
UFUNCTION(BlueprintCallable, Category = "Editor Scripting | MaterialInstance")
static void ClearMaterialInstanceNonexistentParameters(UMaterialInstance* MaterialInstance, EMaterialInstanceParameterType MIParameterType);

实现思路

从材质实例获取到母材质之后,可以分别通过GetAllScalarParameterInfo,GetAllTextureParameterInfo等函数获取到对应类型的材质参数。

材质实例的参数直接是成员变量,直接访问,比如MaterialInstance->TextureParameterValues

将两者进行对比,视情况Remove即可。

源码

MuBlueprintLibrary


UE4:材质实例有关的编辑器方法
http://muchenhen.com/posts/54813/
作者
木尘痕
发布于
2022年9月5日
许可协议