Hello
I am trying to add new types of material node in a blank plugin template, such as an new “add” node.
Here is how it looks like:
However, when I try to build the project, Error LNK2019 occurs.
Error LNK2019 unresolved external symbol "public: class UE::HLSLTree::FExpression const * __cdecl UE::HLSLTree::FTree::NewBinaryOp(enum UE::HLSLTree::EOperation,class UE::HLSLTree::FExpression const *,class UE::HLSLTree::FExpression const *)" (?NewBinaryOp@FTree@HLSLTree@UE@@QEAAPEBVFExpression@23@W4EOperation@23@PEBV423@1@Z) referenced in function "private: virtual bool __cdecl UUMaterialExpressionAddCustom::GenerateHLSLExpression(class FMaterialHLSLGenerator &,class UE::HLSLTree::FScope &,int,class UE::HLSLTree::FExpression const * &)const " (?GenerateHLSLExpression@UUMaterialExpressionAddCustom@@EEBA_NAEAVFMaterialHLSLGenerator@@AEAVFScope@HLSLTree@UE@@HAEAPEBVFExpression@45@@Z) WorkPlace E:\UnrealProjects\WorkPlace\Intermediate\ProjectFiles\Module.CustomMaterialNode.cpp.obj 1
Error LNK2019 unresolved external symbol "public: class UE::HLSLTree::FTree & __cdecl FMaterialHLSLGenerator::GetTree(void)const " (?GetTree@FMaterialHLSLGenerator@@QEBAAEAVFTree@HLSLTree@UE@@XZ) referenced in function "private: virtual bool __cdecl UUMaterialExpressionAddCustom::GenerateHLSLExpression(class FMaterialHLSLGenerator &,class UE::HLSLTree::FScope &,int,class UE::HLSLTree::FExpression const * &)const " (?GenerateHLSLExpression@UUMaterialExpressionAddCustom@@EEBA_NAEAVFMaterialHLSLGenerator@@AEAVFScope@HLSLTree@UE@@HAEAPEBVFExpression@45@@Z) WorkPlace E:\UnrealProjects\WorkPlace\Intermediate\ProjectFiles\Module.CustomMaterialNode.cpp.obj 1
The code of the new type of material node is almost same to the original UMaterialExpressionAdd
. Here is my code of UMaterialExpressionAddCustom.h
and UMaterialExpressionAddCustom.cpp
.
#pragma once
#include "CoreMinimal.h"
#include "MaterialExpressionIO.h"
#include "Materials/MaterialExpression.h"
#include "UMaterialExpressionAddCustom.generated.h"
UCLASS()
class CUSTOMMATERIALNODE_API UUMaterialExpressionAddCustom : public UMaterialExpression
{
GENERATED_BODY()
UUMaterialExpressionAddCustom(const FObjectInitializer& ObjectInitializer);
UPROPERTY(meta = (RequiredInput = "false", ToolTip = "Defaults to 'ConstA' if not specified"))
FExpressionInput A;
UPROPERTY(meta = (RequiredInput = "false", ToolTip = "Defaults to 'ConstB' if not specified"))
FExpressionInput B;
UPROPERTY(EditAnywhere, Category=MaterialExpressionAdd, meta=(OverridingInputProperty = "A"))
float ConstA;
UPROPERTY(EditAnywhere, Category=MaterialExpressionAdd, meta=(OverridingInputProperty = "B"))
float ConstB;
#if WITH_EDITOR
virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) override;
virtual void GetCaption(TArray<FString>& OutCaptions) const override;
virtual FText GetCreationName() const override { return FText::FromString(TEXT("AddCustom")); }
virtual bool GenerateHLSLExpression(FMaterialHLSLGenerator& Generator, UE::HLSLTree::FScope& Scope, int32 OutputIndex, UE::HLSLTree::FExpression const*& OutExpression) const override;
#endif // WITH_EDITOR
};
#include "UMaterialExpressionAddCustom.h"
#include "MaterialCompiler.h"
#include "MaterialHLSLGenerator.h"
#include "HLSLTree/HLSLTree.h"
#define LOCTEXT_NAMESPACE "MaterialExpression2"
UUMaterialExpressionAddCustom::UUMaterialExpressionAddCustom(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
// Structure to hold one-time initialization
struct FConstructorStatics
{
FText NAME_Math;
FConstructorStatics()
: NAME_Math(LOCTEXT( "Math", "Math" ))
{
}
};
static FConstructorStatics ConstructorStatics;
ConstA = 0.0f;
ConstB = 1.0f;
#if WITH_EDITORONLY_DATA
MenuCategories.Add(ConstructorStatics.NAME_Math);
#endif
}
#undef LOCTEXT_NAMESPACE
#if WITH_EDITOR
int32 UUMaterialExpressionAddCustom::Compile(FMaterialCompiler* Compiler, int32 OutputIndex)
{
// if the input is hooked up, use it, otherwise use the internal constant
int32 Arg1 = A.GetTracedInput().Expression ? A.Compile(Compiler) : Compiler->Constant(ConstA);
// if the input is hooked up, use it, otherwise use the internal constant
int32 Arg2 = B.GetTracedInput().Expression ? B.Compile(Compiler) : Compiler->Constant(ConstB);
return Compiler->Add(Arg1, Arg2);
}
void UUMaterialExpressionAddCustom::GetCaption(TArray<FString>& OutCaptions) const
{
FString ret = TEXT("AddCustom");
FExpressionInput ATraced = A.GetTracedInput();
FExpressionInput BTraced = B.GetTracedInput();
if(!ATraced.Expression || !BTraced.Expression)
{
ret += TEXT("(");
ret += ATraced.Expression ? TEXT(",") : FString::Printf( TEXT("%.4g,"), ConstA);
ret += BTraced.Expression ? TEXT(")") : FString::Printf( TEXT("%.4g)"), ConstB);
}
OutCaptions.Add(ret);
}
bool UUMaterialExpressionAddCustom::GenerateHLSLExpression(FMaterialHLSLGenerator& Generator,
UE::HLSLTree::FScope& Scope, int32 OutputIndex, UE::HLSLTree::FExpression const*& OutExpression) const
{
const UE::HLSLTree::FExpression* Lhs = A.AcquireHLSLExpressionOrConstant(Generator, Scope, ConstA);
const UE::HLSLTree::FExpression* Rhs = B.AcquireHLSLExpressionOrConstant(Generator, Scope, ConstB);
if (!Lhs || !Rhs)
{
return false;
}
///////////////!!!!!!!!!!!!!!!!!!!!!!
OutExpression = Generator.GetTree().NewAdd(Lhs, Rhs); // Something Wrong Here
///////////////!!!!!!!!!!!!!!!!!!!!!!
return true;
}
#endif
After some tests, I find the error comes from OutExpression = Generator.GetTree().NewAdd(Lhs, Rhs);
.
Every time I try to use the method of FMaterialHLSLGenerator
,the error will appear.
But if I delete this line, the project can be built successfully.
I guess it is not the problem about Module Dependency, because I have add Engine
module to the build.cs
file, which include the classes of Materials
. Here is the content of build.cs
file.
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class CustomMaterialNode : ModuleRules
{
public CustomMaterialNode(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"Engine",
"CoreUObject",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
// ... add private dependencies that you statically link with here ...
}
);
}
}
Any help will be greatly appreciated