|
发表于 2023-1-18 13:43:43
|
显示全部楼层
前言
——本篇针对的是静态材质实例(MIC)的操作,动态材质实例(MID)可以看上一篇。
UE蓝图
——现成的蓝图节点里没有创建也没有Set参数,只有GetXXXParameterValue系列,就是下面这种同名但是写了“MIC”的。


——需要注意的是,Target输入接口的对象类型需要是MaterialInstanceConstant,即MIC,这也是它们与MID相关节点的唯一区别。
UE C++
——先保证你在.h中引了下面两个头文件
#include "Materials/MaterialInstanceConstant.h"
#include "AssetRegistry/AssetRegistryModule.h"
1、创建MIC文件
——其实资产操作相关的API有很多效果相似的,我现在也不是很清楚他们之间的区别,目前姑且先按下面套路来做,至少可以保证是有效的。不久之后的StaticMesh读写与创建也会用到相同的套路。
//路径拼装
FString Path = TEXT(文件保存路径);
FString OutName = TEXT(文件名);
FString PackageName = TEXT("/Game/") + Path + OutName;//"/Game/"效果等同于项目的Content目录,一般不要改
//拷贝输入的MIC相关数据到新的MIC中
UPackage* Package = CreatePackage(*PackageName);
UMaterialInstanceConstant* OutMIC = NewObject<UMaterialInstanceConstant>(Package, *OutName, RF_Public | RF_Standalone);
OutMIC->Parent = MI;//指定新创建的OutMIC的父材质,对应材质实例面板的Parent。可以是材质也可以是材质实例,即UMaterialInterface
//这里可以配置一些其他的参数设置
//创建文件
FAssetRegistryModule::AssetCreated(OutSM);
//保存更改
Package->SetDirtyFlag(true);//如果没有这行,虽然跑完上面的代码就可以看到生成的文件,但关掉再开UE后会发现文件消失
//U3D中也有一些类似的Dirty的概念和API
——如果要更保险一些,其实还需要加一些类型判断,路径检查之类的代码,这里只是提取了必要的步骤来做。
——除了Parent材质外,也可以代码配置一些其他的材质实例面板中的参数,用MIC->的代码提示猜一猜试一试即可,这里不再赘述。
2、参数读写
//以四维向量的配置为例
FLinearColor ColorOUT;
MIC->GetVectorParameterValue(TEXT(&#34;参数名&#34;), ColorOUT);
MIC->SetVectorParameterValueEditorOnly(TEXT(&#34;参数名&#34;), ColorOUT);
——看名字都知道,Set方法只能在Editor模式下用。而且如果你在运行时用这个方法,停止运行后,其对MIC做出的修改是不会重置的,这点和U3D不同。
3、案例
——这里临时补充一个知识点,就是UE中的PostEditChangeProperty方法。
void AActor::PostEditChangeProperty(FPropertyChangedEvent& e)
{
Super::PostEditChangeProperty(e);
}
——它的作用相当于U3D里的OnValidate,即每当参数发生改变就会调用一次这个方法。UE里能起到相同效果的做法还有一个,就是在蓝图的构造函数(Construction Script)里去连一些节点。
——这种方法的好处就是能让美术,策划等在非运行模式下就能实时的看到调参带来的效果改变。
——然后我们这次利用PostEditChangeProperty方法来做一个给2Dfbm材质批量调参的功能,最终效果是下面这样。

https://www.zhihu.com/video/1594666183537655809
——因为我还不知道UE怎么给材质传数组(如果不用一些像是纹理存数组这种骚操作的话),所以这次姑且给定一个4阶的fbm。参数名匹配的方式也因此比较蠢,见谅- -
——材质大概是下面这样。

——这里图方便连了个自定义节点MF_FbmSampler去算UV和采样。

——然后代码都是在PostEditChangeProperty里的。因为参数名和循环上限是死的,所以代码仅针对本文案例。
——简单说一下案例结构:
1、ScaleVelocity参数中,R=混合权重、G=纹理缩放、BA=速度向量
2、下面的代码基本思路是,Step控制fbm阶数、RG通道按等比数列缩放、BA通道的向量长度和方向角按等差数列累加
//头文件的参数定义部分
UPROPERTY(EditAnywhere)
UMaterialInstanceConstant* MIC;
UPROPERTY(EditAnywhere, meta = (ClampMin = 1, ClampMax = 4, UIMin = 1, UIMax = 4))
int8 Step = 2;
UPROPERTY(EditAnywhere, meta = (ClampMin = 0, ClampMax = 1, UIMin = 0, UIMax = 1))
float AttenRatio = 0.5f;
UPROPERTY(EditAnywhere, meta = (ClampMin = 0, ClampMax = 2, UIMin = 0, UIMax = 2))
float ScaleRatio = 2;
UPROPERTY(EditAnywhere, meta = (ClampMin = 0, ClampMax = 1, UIMin = 0, UIMax = 1))
float VelocityDelta = 0.5f;
UPROPERTY(EditAnywhere, meta = (ClampMin = 0, ClampMax = 10, UIMin = 0, UIMax = 10))
float Scale0 = 1;
UPROPERTY(EditAnywhere, meta = (ClampMin = 0, ClampMax = 1, UIMin = 0, UIMax = 1))
float Velocity0 = 1;
//cpp的PostEditChangeProperty
void AFbmManager::PostEditChangeProperty(FPropertyChangedEvent& e)
{
Super::PostEditChangeProperty(e);
if (MIC)
{
float Sigma = (1 - pow(AttenRatio, Step)) / (1 - AttenRatio);
float DeltaAngle = 2 * PI / Step;
for (int8 i = 0; i < 4; i++)
{
FName CurrentName = FName(*FString::Printf(TEXT(&#34;ScaleVelocity_%d&#34;), i));
if (i < Step)
{
FLinearColor CurrentCol = FLinearColor(
pow(AttenRatio, i) / Sigma,
Scale0 * pow(ScaleRatio, i),
(Velocity0 + VelocityDelta * i) * cos(DeltaAngle * i),
(Velocity0 + VelocityDelta * i) * sin(DeltaAngle * i)
);
MIC->SetVectorParameterValueEditorOnly(CurrentName, CurrentCol);
}
else
{
MIC->SetVectorParameterValueEditorOnly(CurrentName, FLinearColor::Transparent);
}
}
}
}
U3D
——U3D的静态动态材质的API没有区别,直接看上一篇即可。
——关于U3D的资产创建可以提一嘴,简单来说就是AssetDatabase.CreateAsset。
Material matDst = new Material(matSrc);
AssetDatabase.CreateAsset(matDst, &#34;Assets/TEST.mat&#34;);//一般打头都是Assets,后面可以自己改
AssetDatabase.Refresh();
——CreateAsset的第一个参数是祖类Object类型,所以这个API不光能生成材质球,很多U3D类对象都可以用这个创建出资产文件。一般创建完了之后可以来一发AssetDatabase.Refresh来刷新一下Project目录,省的手动Ctrl+R才能在Project中看到生成的资产。 |
|