Creating Custom Material Expression in C++

Hello friends,

I’m trying to create a new custom material expression that acts as switch node but lerps between colors/values and the node can take as many inputs as I need by adding + Add button that adds inputs in an array.


image

The class in C++ inherits from UMaterialExpression same as switch node and I saw I should override compile function. I did that but I saw there is no change in the material output and I just get 0 for no reason I tried to copy paste the switch node compile function into Palette compile function but same no change I don’t understand why and how.

// MaterialExpression.h
USTRUCT()
struct FPaletteCustomInput {
	GENERATED_USTRUCT_BODY()
	UPROPERTY(EditAnywhere, Category = CustomInput)
		FName InputName;
	UPROPERTY()
		FExpressionInput Input;
};

/**
 *
 */
UCLASS(collapsecategories, hidecategories = Object, MinimalAPI)
class UMaterialExpressionPalette : public UMaterialExpression {
	GENERATED_UCLASS_BODY()
	UPROPERTY(EditAnywhere, Category = UMaterialExpressionPalette)
		FString Description;
	UPROPERTY(meta = (RequiredInput = "false", ToolTip = "Defaults to 'ConstAlpha' if not specified"))
		FExpressionInput Alpha;
	UPROPERTY(EditAnywhere, Category = UMaterialExpressionPalette, meta = (OverridingInputProperty = "Alpha"))
		float ConstAlpha;
	UPROPERTY(EditAnywhere, Category = UMaterialExpressionPalette)
		TArray<struct FPaletteCustomInput> Inputs;
	#if WITH_EDITOR
		virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
		void RebuildOutputs();
	#endif // WITH_EDITOR
		virtual void Serialize(FStructuredArchive::FRecord Record) override;
	////~ End UObject Interface.

	//~ Begin UMaterialExpression Interface
	#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("Palette")); }
		virtual TArrayView<FExpressionInput*> GetInputsView() override;
		virtual FExpressionInput* GetInput(int32 InputIndex) override;
		virtual FName GetInputName(int32 InputIndex) const override;
		virtual uint32 GetInputType(int32 InputIndex) override { return MCT_Float3; }
	#endif // WITH_EDITOR
	//~ End UMaterialExpression Interface
};
// UMaterialExpression.cpp
int32 UMaterialExpressionPalette::Compile(FMaterialCompiler* Compiler, int32 OutputIndex) {
        TArray<int32> CompiledInputs;
uint32 Value = this->Alpha.Compile(Compiler), Default = Compiler->Constant(0.0);
for (int32 i = 0; i < Inputs.Num(); i++)
{
	if (!Inputs[i].Input.GetTracedInput().Expression)
	{
		return Compiler->Errorf(TEXT("Texture Multiplexer missing input %d (%s)"), i + 1, *Inputs[i].InputName.ToString());
	}
	int32 InputCode = Inputs[i].Input.Compile(Compiler);
	if (InputCode < 0)
	{
		return InputCode;
	}
	CompiledInputs.Add(InputCode);
}
return Compiler->Switch(Value, Default, CompiledInputs);

for now I tried to use switch node logic but still no change, and even though I can’t implement the lerping logic here because in the code below it shows that I need to get alpha value as floating point and the only way I can is overriding the value of alpha variable through UPROPERTY which is not ideal because I can’t use a texture to use it as alpha and I want the expression to work with textures as well as the switch node does so I can have an output like this.

// Native C++
struct Color {
	float R, G, B;
	Color operator+(Color Other) {
		return Color(R + Other.R, G + Other.G, B + Other.B);
	}
	Color operator-(Color Other) {
		return Color(R - Other.R, G - Other.G, B - Other.B);
	}
	Color operator*(float Alpha) {
		return Color(R * Alpha, G * Alpha, B * Alpha);
	}
};
Color Lerp(Color A, Color B, float Alpha) {
	return Color(A + ((B - A) * Alpha));
}
Color ColorPalette(const std::vector<Color>& Colors, float Alpha) {
	if (Colors.size() == 1 || Alpha <= 0) {
		return Colors.front();
	}
	if (Alpha >= 1) {
		return Colors.back();
	}
	float ScaledAlpha = Alpha * (Colors.size() - 1);
	int Index = ScaledAlpha;
	float A = ScaledAlpha - Index;
	return Lerp(Colors[Index], Colors[Index + 1], A);
}

I want to know if I’m missing something i tried even to modify the source code in the following files:
MaterialCompiler.h
HLSLMaterialTranslator.h/.cpp

but still nothing seems to work.

Thanks

1 Like

Hi did you found a solution , it’s interresting?
I am doing something similar

Have nice day

Sorry I’m busy nowadays with collage so I ignored it, it needs time to solve it and searching in the source code for this takes a lot of time.

1 Like