- Vrealmatic
- Unreal Engine Wiki
- Material
Working with Material in Unreal Engine
How to work with materials in the Unreal Engine?

Create Material Graph with C++
Creating Material Graph with C++ instead of using Blueprint nodes make sense especially to automate processes when working with a lot of materials. C++ is a way to move material data exported from any tool to the Unreal Engine and re-create them aitomatically to materials directly by code.
C++ comes it handy as well anytime there's a need to add a functionality that is not available through the common BP nodes.
- All Material extensions
#include "MaterialEditingLibrary.h" // MaterialEditor (Editor Only)is required for working with Materials in C++ in the editor
All the code below is placed in UBlueprintFunctionLibrary inherited class.

Build Material
.h/** * Editor Only - Will not work in packaged build. * * Build a material graph with the provided values * * @param MaterialPath The path of the material: "/Game/Folder/MyMaterial" * @param TexturePath The path of the texture to add in the material: "/Game/Folder/MyTexture" * @param TexCoord Texture coordinates for the texture * @param Color Color that will be multiplied by the texture * @param Metallic Metallic value of the material * @param Specular Specular value of the material * @param Roughness Roughness value of the material * @param OutInfoMsg More information about the action's result * * @return If the action was a success or not */ UFUNCTION(BlueprintCallable, Category = "") static bool BuildMaterial(FString MaterialPath, FString TexturePath, FVector2D TexCoord, FLinearColor Color, float Metallic, float Specular, float Roughness, FString& OutInfoMsg);.cpp#include "MaterialEditingLibrary.h" // MaterialEditor (Editor Only) #include "Materials/MaterialExpressionTextureSampleParameter2D.h" // Engine #include "Materials/MaterialExpressionTextureCoordinate.h" // Engine #include "Materials/MaterialExpressionMultiply.h" // Engine #include "Materials/MaterialExpressionVectorParameter.h" // Engine bool UExampleClass::BuildMaterial(FString MaterialPath, FString TexturePath, FVector2D TexCoord, FLinearColor Color, float Metallic, float Specular, float Roughness, FString& OutInfoMsg) { // Get material and texture UMaterial* Material = Cast<UMaterial>(StaticLoadObject(UObject::StaticClass(), nullptr, *MaterialPath)); UTexture* Texture = Cast<UTexture>(StaticLoadObject(UObject::StaticClass(), nullptr, *TexturePath)); // Create material if it doesn't exist if (Material == nullptr) { Material = <a href="/unreal-engine/classes/ublueprintfunctionlibrary#CreateMaterialAsset">UExampleClass::CreateMaterialAsset</a>(MaterialPath, bOutSuccess, OutInfoMsg); if (Material == nullptr) return false; // Failed to create material } // <mark>Create nodes</mark> UMaterialExpressionTextureCoordinate* <strong>TextureCoordinateExp</strong> = <a href="#AddTexCoordExpression">AddTexCoordExpression</a>(Material, TexCoord, "MyTextureCoordinates", FIntPoint(-1000, -50)); UMaterialExpressionTextureSampleParameter2D* <strong>TextureExp</strong> = <a href="#AddTextureParameter">AddTextureParameter</a>(Material, Texture, "MyTexture", FIntPoint(-800, -50)); UMaterialExpressionVectorParameter* ColorExp = <a href="#AddVectorParameter">AddVectorParameter</a>(Material, Color, "MyColor", FIntPoint(-800, 200)); UMaterialExpressionMultiply* ColorMultiplyExp = <a href="#AddMultiplyExpression">AddMultiplyExpression</a>(Material, "MyColorMultiply", FIntPoint(-500, 0)); UMaterialExpressionScalarParameter* MetallicScalarExp = <a href="#AddScalarParameter">AddScalarParameter</a>(Material, Metallic, "MyMetallic", FIntPoint(-300, 50)); UMaterialExpressionScalarParameter* SpecularScalarExp = <a href="#AddScalarParameter">AddScalarParameter</a>(Material, Specular, "MySpecular", FIntPoint(-300, 150)); UMaterialExpressionScalarParameter* RoughnessScalarExp = <a href="#AddScalarParameter">AddScalarParameter</a>(Material, Roughness, "MyRoughness", FIntPoint(-300, 250)); // <mark>Connect nodes</mark> <strong>TextureCoordinateExp</strong>->ConnectExpression(<strong>&TextureExp</strong>->Coordinates, 0); TextureExp->ConnectExpression(&ColorMultiplyExp->A, 0); ColorExp->ConnectExpression(&ColorMultiplyExp->B, 0); // <mark>Connect to main material node</mark> Material->GetEditorOnlyData()->BaseColor.Connect(0, ColorMultiplyExp); Material->GetEditorOnlyData()->Metallic.Connect(0, MetallicScalarExp); Material->GetEditorOnlyData()->Specular.Connect(0, SpecularScalarExp); Material->GetEditorOnlyData()->Roughness.Connect(0, RoughnessScalarExp); OutInfoMsg = FString::Printf(TEXT("Build Material Succeeded - '%s'"), *MaterialPath); <strong>return true;</strong> }.Build.csPrivateDependencyModuleNames.AddRange ( new string[] { // Default Modules "Core", "CoreUObject", "Engine", // New Modules - Editor Only "AssetTools", "UnrealEd", <mark>"MaterialEditor",</mark> } );Add TextureParameter node to Material
.h/** * Editor Only - Will not work in packaged build. * * Add a texture parameter to a material graph * * @param Material The material in which to add the expression * @param Texture The texture to use * @param ParameterName The name of the expression * @param NodePos The XY coordinates of the node in the graph * * @return The expression */ UFUNCTION(BlueprintCallable, Category = "") static class UMaterialExpressionTextureSampleParameter2D* AddTextureParameter(UMaterial* Material, UTexture* Texture, FString ParameterName, FIntPoint NodePos);.cpp#include "Materials/MaterialExpressionTextureSampleParameter2D.h" // Engine UMaterialExpressionTextureSampleParameter2D* UExampleClass::AddTextureParameter(UMaterial* Material, UTexture* Texture, FString ParameterName, FIntPoint NodePos) { // Get existing parameter from material UMaterialExpressionTextureSampleParameter2D* TextureParameter = Cast<UMaterialExpressionTextureSampleParameter2D>(<a href="#GetExistingMaterialExpressionFromName">GetExistingMaterialExpressionFromName</a>(Material, ParameterName)); // Create new parameter if it doesn't exist if (TextureParameter == nullptr) { UMaterialExpression* Expression = UMaterialEditingLibrary::CreateMaterialExpression(Material, UMaterialExpressionTextureSampleParameter2D::StaticClass()); TextureParameter = Cast<UMaterialExpressionTextureSampleParameter2D>(Expression); Material->AddExpressionParameter(TextureParameter, Material->EditorParameters); } // Set name and position TextureParameter->ParameterName = *ParameterName; TextureParameter->MaterialExpressionEditorX = NodePos.X; TextureParameter->MaterialExpressionEditorY = NodePos.Y; // Set value TextureParameter->Texture = Texture; TextureParameter->SamplerType = SAMPLERTYPE_Color; // Return parameter return TextureParameter; }Add ScalarParameter node to Material
.h/** * Editor Only - Will not work in packaged build. * * Add a scalar parameter to a material graph * * @param Material The material in which to add the expression * @param Value The float value to use * @param ParameterName The name of the expression * @param NodePos The XY coordinates of the node in the graph * * @return The expression */ UFUNCTION(BlueprintCallable, Category = " ") static class UMaterialExpressionScalarParameter* AddScalarParameter(UMaterial* Material, float Value, FString ParameterName, FIntPoint NodePos);.cpp#include "Materials/MaterialExpressionScalarParameter.h" // Engine UMaterialExpressionScalarParameter* UExampleClass::AddScalarParameter(UMaterial* Material, float Value, FString ParameterName, FIntPoint NodePos) { // Get existing parameter from material UMaterialExpressionScalarParameter* ScalarParameter = Cast<UMaterialExpressionScalarParameter>(<a href="#GetExistingMaterialExpressionFromName">GetExistingMaterialExpressionFromName</a>(Material, ParameterName)); // Create new parameter if it doesn't exist if (ScalarParameter == nullptr) { UMaterialExpression* Expression = UMaterialEditingLibrary::CreateMaterialExpression(Material, UMaterialExpressionScalarParameter::StaticClass()); ScalarParameter = Cast<UMaterialExpressionScalarParameter>(Expression); Material->AddExpressionParameter(ScalarParameter, Material->EditorParameters); } // Set name and position ScalarParameter->ParameterName = *ParameterName; ScalarParameter->MaterialExpressionEditorX = NodePos.X; ScalarParameter->MaterialExpressionEditorY = NodePos.Y; // Set value ScalarParameter->DefaultValue = Value; // Return parameter return ScalarParameter; }Add VectorParameter node to Material
.h/** * Editor Only - Will not work in packaged build. * * Add a vector parameter to a material graph * * @param Material The material in which to add the expression * @param Color The color value to use * @param ParameterName The name of the expression * @param NodePos The XY coordinates of the node in the graph * * @return The expression */ UFUNCTION(BlueprintCallable, Category = "<a href="https://www.youtube.com/watch?v=Fd56hSN83mk" target="_blank">Alex Quevillon|10 - Build Material</a>") static class UMaterialExpressionVectorParameter* AddVectorParameter(UMaterial* Material, FLinearColor Color, FString ParameterName, FIntPoint NodePos);.cpp#include "Materials/MaterialExpressionVectorParameter.h" // Engine UMaterialExpressionVectorParameter* UExampleClass::AddVectorParameter(UMaterial* Material, FLinearColor Color, FString ParameterName, FIntPoint NodePos) { // Get existing parameter from material UMaterialExpressionVectorParameter* VectorParameter = Cast<UMaterialExpressionVectorParameter>(<a href="#GetExistingMaterialExpressionFromName">GetExistingMaterialExpressionFromName</a>(Material, ParameterName)); // Create new parameter if it doesn't exist if (VectorParameter == nullptr) { UMaterialExpression* Expression = UMaterialEditingLibrary::CreateMaterialExpression(Material, UMaterialExpressionVectorParameter::StaticClass()); VectorParameter = Cast<UMaterialExpressionVectorParameter>(Expression); Material->AddExpressionParameter(VectorParameter, Material->EditorParameters); } // Set name and position VectorParameter->ParameterName = *ParameterName; VectorParameter->MaterialExpressionEditorX = NodePos.X; VectorParameter->MaterialExpressionEditorY = NodePos.Y; // Set value VectorParameter->DefaultValue = Color; // Return parameter <strong>return VectorParameter;</strong> }Add MultiplyExpression node to Material
.h/** * Editor Only - Will not work in packaged build. * * Add a multiply expression to a material graph * * @param Material The material in which to add the expression * @param ExpressionDesc The description of the expression * @param NodePos The XY coordinates of the node in the graph * * @return The expression */ UFUNCTION(BlueprintCallable, Category = " ") static class UMaterialExpressionMultiply* AddMultiplyExpression(UMaterial* Material, FString ExpressionDesc, FIntPoint NodePos);.cpp#include "Materials/MaterialExpressionMultiply.h" // Engine UMaterialExpressionMultiply* UExampleClass::AddMultiplyExpression(UMaterial* Material, FString ExpressionDesc, FIntPoint NodePos) { // Get existing expression from material UMaterialExpressionMultiply* MultiplyExpression = Cast<UMaterialExpressionMultiply>(<a href="#GetExistingMaterialExpressionFromName">GetExistingMaterialExpressionFromName</a>(Material, ExpressionDesc)); // Create new expression if it doesn't exist if (MultiplyExpression == nullptr) { UMaterialExpression* Expression = UMaterialEditingLibrary::CreateMaterialExpression(Material, UMaterialExpressionMultiply::StaticClass()); MultiplyExpression = Cast<UMaterialExpressionMultiply>(Expression); Material->AddExpressionParameter(MultiplyExpression, Material->EditorParameters); } // Set name and position MultiplyExpression->Desc = ExpressionDesc; MultiplyExpression->MaterialExpressionEditorX = NodePos.X; MultiplyExpression->MaterialExpressionEditorY = NodePos.Y; // Return expression return MultiplyExpression; }Add TexCoordExpression node to Material
.h/** * Editor Only - Will not work in packaged build. * * Add a texture coordinate expression to a material graph * * @param Material The material in which to add the expression * @param Value The texture coordinates value to use * @param ExpressionDesc The description of the expression * @param NodePos The XY coordinates of the node in the graph * * @return The expression */ UFUNCTION(BlueprintCallable, Category = "<a href="https://www.youtube.com/watch?v=Fd56hSN83mk" target="_blank">Alex Quevillon|10 - Build Material</a>") static class UMaterialExpressionTextureCoordinate* AddTexCoordExpression(UMaterial* Material, FVector2D Value, FString ExpressionDesc, FIntPoint NodePos);.cpp#include "Materials/MaterialExpressionTextureCoordinate.h" // Engine UMaterialExpressionTextureCoordinate* UExampleClass::AddTexCoordExpression(UMaterial* Material, FVector2D Value, FString ExpressionDesc, FIntPoint NodePos) { // Get existing expression from material UMaterialExpressionTextureCoordinate* TextureCoordinateExpression = Cast<UMaterialExpressionTextureCoordinate>(<a href="#GetExistingMaterialExpressionFromName">GetExistingMaterialExpressionFromName</a>(Material, ExpressionDesc)); // Create new expression if it doesn't exist if (TextureCoordinateExpression == nullptr) { UMaterialExpression* Expression = UMaterialEditingLibrary::CreateMaterialExpression(Material, UMaterialExpressionTextureCoordinate::StaticClass()); TextureCoordinateExpression = Cast<UMaterialExpressionTextureCoordinate>(Expression); Material->AddExpressionParameter(TextureCoordinateExpression, Material->EditorParameters); } // Set name and position TextureCoordinateExpression->Desc = ExpressionDesc; TextureCoordinateExpression->MaterialExpressionEditorX = NodePos.X; TextureCoordinateExpression->MaterialExpressionEditorY = NodePos.Y; // Set value TextureCoordinateExpression->UTiling = Value.X; TextureCoordinateExpression->VTiling = Value.Y; // Return expression return TextureCoordinateExpression; }GetExistingMaterialExpressionFromName helpe function
.h/** * Editor Only - Will not work in packaged build. * * Retrieve an existing material expression based on the provided name or description * * @param Material The material in which the expression is * @param NameOrDescription The name or description of the expression to find * * @return The expression */ UFUNCTION(BlueprintCallable, Category = " ") static class UMaterialExpression* GetExistingMaterialExpressionFromName(UMaterial* Material, FString NameOrDescription);.cppUMaterialExpression* UExampleClass::GetExistingMaterialExpressionFromName(UMaterial* Material, FString NameOrDescription) { for (UMaterialExpression* Expression : Material->GetExpressions()) { UMaterialExpressionParameter* Parameter = Cast<UMaterialExpressionParameter>(Expression); if (Parameter != nullptr && Parameter->ParameterName.ToString() == NameOrDescription) { return Parameter; } else if (Expression->Desc == NameOrDescription) { return Expression; } } return nullptr; }
Assign Material to Mesh in C++
The code below allow to assign a material to Static Mesh as well as to Skeletal Mesh.
.h
/**
* Editor Only - Will not work in packaged build.
*
* Assign material to a mesh asset (static mesh or skeletal mesh)
*
* @param MeshPath Path of the mesh: "/Game/Folder/MyMesh"
* @param MaterialPath Path of the material: "/Game/Folder/MyMaterial"
* @param MaterialId Material slot to assign material into
* @param OutInfoMsg More information about the action's result
*
* @return If the action was a success or not
*/
UFUNCTION(BlueprintCallable, Category = "<a href="https://www.youtube.com/watch?v=u3QOZUNeJOE" target="_blank">Alex Quevillon | Assign Material To Mesh</a>")
static bool AssignMaterialToMeshAsset(FString MeshPath, FString MaterialPath, int MaterialId, FString& OutInfoMsg);.cpp
#include "Engine/StaticMesh.h" // Engine
#include "Engine/SkeletalMesh.h" // Engine
bool UExampleClass::AssignMaterialToMeshAsset(FString MeshPath, FString MaterialPath, int MaterialId, FString& OutInfoMsg)
{
// Load material
UMaterialInterface* Material = Cast<UMaterialInterface>(StaticLoadObject(UObject::StaticClass(), nullptr, *MaterialPath));
// Load mesh
UObject* PotentialMesh = StaticLoadObject(UObject::StaticClass(), nullptr, *MeshPath);
UStaticMesh* StaticMesh = Cast<<a href="/unreal-engine/static-mesh">UStaticMesh</a>>(PotentialMesh);
USkeletalMesh* SkeletalMesh = Cast<<a href="/unreal-engine/skeletal-mesh">USkeletalMesh</a>>(PotentialMesh);
if (StaticMesh != nullptr)
{
// <mark>Apply material to static mesh</mark>
int RealMaterialId = FMath::Clamp(MaterialId, 0, StaticMesh->GetStaticMaterials().Num() - 1);
StaticMesh->SetMaterial(RealMaterialId, Material);
StaticMesh->PostEditChange();
}
else if (SkeletalMesh != nullptr)
{
// <mark>Apply material to skeletal mesh</mark>
int RealMaterialId = FMath::Clamp(MaterialId, 0, SkeletalMesh->GetMaterials().Num() - 1);
SkeletalMesh->GetMaterials()[RealMaterialId] = Material;
SkeletalMesh->PostEditChange();
}
else
{
OutInfoMsg = FString::Printf(TEXT("Assign Material To Mesh Asset Failed - Mesh isn't valid. '%s'"), *MeshPath);
return false;
}
OutInfoMsg = FString::Printf(TEXT("Assign Material To Mesh Asset Succeeded - '%s'"), *MeshPath);
<strong>return true;</strong>
}

