星鸿阁

 找回密码
 立即注册
搜索
热搜: 活动 交友 动画
查看: 3851|回复: 1

UE4 – 以编程方式创建新材质和内部节点

[复制链接]

2254

主题

2764

帖子

9644

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9644
发表于 2021-9-29 10:28:57 | 显示全部楼层 |阅读模式
UE4 – 以编程方式创建新材质和内部节点


在这篇文章中,我们将学习如何从 Cpp 代码创建新材料、创建节点和创建链接。
您可以将此代码添加到自定义插件中,以便在用户单击编辑器按钮时神奇地创建新材料。
请记住,此代码旨在在编辑器中执行。您的插件必须是编辑器插件。此代码在运行时无法工作...
创建一个新资产:材料
首先,我们必须以编程方式创建一个新资产,例如,让我们在根目录文件夹“/Game/”中创建一个名为“M_Material”的新材质。
为此,我们需要创建一个UPackage(这是我们资产的存储对象)。然后,我们使用一个材料工厂来创建我们的UMaterial。
FString MaterialBaseName = "M_Material";FString PackageName = "/Game/"ackageName += MaterialBaseName;UPackage* Package = CreatePackage(NULL, *PackageName);// Create an unreal material assetauto MaterialFactory = NewObject<UMaterialFactoryNew>();UMaterial* UnrealMaterial = (UMaterial*)MaterialFactory->FactoryCreateNew(UMaterial::StaticClass(), Package, *MaterialBaseName, RF_Standalone | RF_Public, NULL, GWarn);[size=0.8em][url=]复制[/url]



然后,我们必须让 Unreal 做一些关于资产创建的后台处理,并加载/设置我们刚刚创建的包。如果没有这个代码,资产创建就无法完成,并且可能会在以后带来一些问题……
FAssetRegistryModule::AssetCreated(UnrealMaterial)ackage->FullyLoad()ackage->SetDirtyFlag(true);[size=0.8em][url=]复制[/url]


现在,我们的资产已创建但为空。
最后,一旦我们创建了材质并且——也许——添加了节点,让材质自行更新:
// Let the material update itself if necessaryUnrealMaterial->PreEditChange(NULL);UnrealMaterial->PostEditChange();// make sure that any static meshes, etc using this material will stop using the FMaterialResource of the original// material, and will use the new FMaterialResource created when we make a new UMaterial in placeFGlobalComponentReregisterContext RecreateComponents;[size=0.8em][url=]复制[/url]


您可以测试此代码以检查新的空材质创建。

UMaterialExpression
我们将添加的每个节点都是 UMaterialExpression 的子对象。查看虚幻引擎文档以查看可能的节点。
创建节点后,将其添加到材质表达式中。
基本上,必须将表达式分配给要链接到材料的节点。
我们将使用相同的方式在节点之间创建链接:如果我们要将乘法节点的结果设置为材质的基色,则将乘法节点分配给Material->BaseColor.Expression
这里有些例子:

用节点填充材料资产将“0”常量分配给镜面反射
让我们创建最简单的节点:常量节点。
创建一个新的 UMaterialExpressionConstant 节点,然后将其添加到材质表达式中,将其赋值为 0,最后将其分配给镜面反射表达式。
UMaterialExpressionConstant* ZeroExpression = NewObject<UMaterialExpressionConstant>(UnrealMaterial);ZeroExpression->R = 0.0f;UnrealMaterial->Expressions.Add(ZeroExpression);UnrealMaterial->Specular.Expression = ZeroExpression;[size=0.8em][url=]复制[/url]


我们的第一个节点已创建并分配!
将纹理与材质基色链接起来
我们假设您已经将纹理资产放入您的内容文件夹中。
我们需要获取UTexture引用来创建节点。所以我们需要通过路径获取这个资产:
FStringAssetReference DiffuseAssetPath("/Game/T_Texture");UTexture* DiffuseTexture = Cast(DiffuseAssetPath.TryLoad());if (DiffuseTexture){...}[size=0.8em][url=]复制[/url]

然后,创建一个新的 TextureSample 材质表达式,为其指定我们的纹理并将其与材质基色链接。
// Make texture samplerUMaterialExpressionTextureSample* TextureExpression = NewObject(UnrealMaterial);TextureExpression->Texture = DiffuseTexture;TextureExpression->SamplerType = SAMPLERTYPE_Color;UnrealMaterial->Expressions.Add(TextureExpression);UnrealMaterial->BaseColor.Expression = TextureExpression;[size=0.8em][url=]复制[/url]

使用乘法节点
如果我们想创建一个纹理平铺系统,我们需要将纹理坐标与一些标量参数相乘。
让我们创建一个乘法节点并将其分配给我们的纹理坐标。
// Tiling systemUMaterialExpressionMultiply* Multiply = NewObject<UMaterialExpressionMultiply>(UnrealMaterial);UnrealMaterial->Expressions.Add(Multiply);TextureExpression->Coordinates.Expression = Multiply;[size=0.8em][url=]复制[/url]

将纹理坐标节点分配给乘法节点的 A 参数:
UMaterialExpressionTextureCoordinate* TexCoords = NewObject<UMaterialExpressionTextureCoordinate>(UnrealMaterial);UnrealMaterial->Expressions.Add(TexCoords);Multiply->A.Expression = TexCoords;[size=0.8em][url=]复制[/url]

如您所想,您可以使用相同的方式将其他节点分配给 B 参数。

平铺系统
现在,通过创建 2 个包含 X 和 Y 纹理重复的标量参数来完成平铺系统:
// TilingUMaterialExpressionAppendVector* Append = NewObject<UMaterialExpressionAppendVector>(UnrealMaterial);UnrealMaterial->Expressions.Add(Append);Multiply->B.Expression = Append;UMaterialExpressionScalarParameter* XParam = NewObject<UMaterialExpressionScalarParameter>(UnrealMaterial);UMaterialExpressionScalarParameter* YParam = NewObject<UMaterialExpressionScalarParameter>(UnrealMaterial);UnrealMaterial->Expressions.Add(XParam);UnrealMaterial->Expressions.Add(YParam);XParam->ParameterName = "TextureRepeatX";XParam->DefaultValue = 1;YParam->ParameterName = "TextureRepeatY";YParam->DefaultValue = 1;Append->A.Expression = XParam;Append->B.Expression = YParam;[size=0.8em][url=]复制[/url]


完整代码FString MaterialBaseName = "M_Material";FString PackageName = "/Game/"ackageName += MaterialBaseName;UPackage* Package = CreatePackage(NULL, *PackageName);// create an unreal material assetauto MaterialFactory = NewObject<UMaterialFactoryNew>();UMaterial* UnrealMaterial = (UMaterial*)MaterialFactory->FactoryCreateNew(UMaterial::StaticClass(), Package, *MaterialBaseName, RF_Standalone | RF_Public, NULL, GWarn);FAssetRegistryModule::AssetCreated(UnrealMaterial)ackage->FullyLoad()ackage->SetDirtyFlag(true);// Tiling systemUMaterialExpressionMultiply* Multiply = NewObject<UMaterialExpressionMultiply>(UnrealMaterial);UnrealMaterial->Expressions.Add(Multiply);// DiffuseFStringAssetReference DiffuseAssetPath("/Game/T_Texture");UTexture* DiffuseTexture = Cast<UTexture>(DiffuseAssetPath.TryLoad());if (DiffuseTexture){        // make texture sampler        UMaterialExpressionTextureSample* TextureExpression = NewObject<UMaterialExpressionTextureSample>(UnrealMaterial);        TextureExpression->Texture = DiffuseTexture;        TextureExpression->SamplerType = SAMPLERTYPE_Color;        UnrealMaterial->Expressions.Add(TextureExpression);        UnrealMaterial->BaseColor.Expression = TextureExpression;        // Tiling        TextureExpression->Coordinates.Expression = Multiply;}// TilingUMaterialExpressionAppendVector* Append = NewObject<UMaterialExpressionAppendVector>(UnrealMaterial);UnrealMaterial->Expressions.Add(Append);Multiply->B.Expression = Append;UMaterialExpressionTextureCoordinate* TexCoords = NewObject<UMaterialExpressionTextureCoordinate>(UnrealMaterial);UnrealMaterial->Expressions.Add(TexCoords);Multiply->A.Expression = TexCoords;UMaterialExpressionScalarParameter* XParam = NewObject<UMaterialExpressionScalarParameter>(UnrealMaterial);UMaterialExpressionScalarParameter* YParam = NewObject<UMaterialExpressionScalarParameter>(UnrealMaterial);UnrealMaterial->Expressions.Add(XParam);UnrealMaterial->Expressions.Add(YParam);XParam->ParameterName = "TextureRepeatX";XParam->DefaultValue = 1;YParam->ParameterName = "TextureRepeatY";YParam->DefaultValue = 1;Append->A.Expression = XParam;Append->B.Expression = YParam;// let the material update itself if necessaryUnrealMaterial->PreEditChange(NULL);UnrealMaterial->PostEditChange();// make sure that any static meshes, etc using this material will stop using the FMaterialResource of the original// material, and will use the new FMaterialResource created when we make a new UMaterial in placeFGlobalComponentReregisterContext RecreateComponents;[size=0.8em][url=]复制[/url]


结果














回复

使用道具 举报

2254

主题

2764

帖子

9644

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9644
 楼主| 发表于 2021-9-29 10:31:44 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|starfluidga

GMT+8, 2025-3-10 05:03 , Processed in 0.020251 second(s), 20 queries .

Made by Liga 星鸿阁

Copyright © 2020-2048, LigaStudio.

快速回复 返回顶部 返回列表