Skip to content

Instantly share code, notes, and snippets.

@lostinplace
Last active November 14, 2024 19:43
Show Gist options
  • Save lostinplace/deae71d238948dd534e94d421cd502a2 to your computer and use it in GitHub Desktop.
Save lostinplace/deae71d238948dd534e94d421cd502a2 to your computer and use it in GitHub Desktop.
how to create a hexagon mask shader in unreal cpp
// MaterialExpressionHexagonShape.cpp
#include "HexUI_BaseEditor/Public/MaterialExpressions/MaterialExpressionHexagonShape.h"
#include "UObject/ConstructorHelpers.h"
#include "MaterialCompiler.h"
#define LOCTEXT_NAMESPACE "MaterialExpressionHexagonShape"
UMaterialExpressionHexagonShape::UMaterialExpressionHexagonShape(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
// Setup defaults
bShowOutputNameOnPin = true;
bShowMaskColorsOnPin = false;
// Setup inputs
UV.Expression = nullptr;
Color.Expression = nullptr;
MenuCategories.Add(LOCTEXT("Custom", "Custom"));
}
#if WITH_EDITOR
int32 UMaterialExpressionHexagonShape::Compile(FMaterialCompiler* Compiler, int32 OutputIndex)
{
// Get input UV coordinates and color
int32 UVIndex = UV.Expression ? UV.Compile(Compiler) : Compiler->TextureCoordinate(0, false, false);
int32 ColorIndex = Color.Expression ? Color.Compile(Compiler) : Compiler->Constant4(1.0f, 0.0f, 0.0f, 1.0f);
// Define hexagon vertices in clockwise order
float a = Radius;
float sqrt3 = FMath::Sqrt(3.0f);
// Transform UV to [-1, 1] range centered around (0, 0)
auto UV_rescaled = Compiler->Mul(UVIndex, Compiler->Constant(2.0f));
auto adjuster = Compiler->Constant2(-1, -1); // Adjust to center
auto centeredUV = Compiler->Add(UV_rescaled, adjuster);
// The domain of centeredUV is now [-1, -1] (bottom left) to [1, 1] (top right)
// Calculate distances to each line segment of the hexagon
int32 p = centeredUV; // Current point being tested
// Calculate distances to each edge
int32 d1 = DistanceToSegment(Compiler, p,
Compiler->Constant2(a, 0),
Compiler->Constant2(a/2, a*sqrt3/2));
int32 d2 = DistanceToSegment(Compiler, p,
Compiler->Constant2(a/2, a*sqrt3/2),
Compiler->Constant2(-a/2, a*sqrt3/2));
int32 d3 = DistanceToSegment(Compiler, p,
Compiler->Constant2(-a/2, a*sqrt3/2),
Compiler->Constant2(-a, 0));
int32 d4 = DistanceToSegment(Compiler, p,
Compiler->Constant2(-a, 0),
Compiler->Constant2(-a/2, -a*sqrt3/2));
int32 d5 = DistanceToSegment(Compiler, p,
Compiler->Constant2(-a/2, -a*sqrt3/2),
Compiler->Constant2(a/2, -a*sqrt3/2));
int32 d6 = DistanceToSegment(Compiler, p,
Compiler->Constant2(a/2, -a*sqrt3/2),
Compiler->Constant2(a, 0));
// Get minimum distance
int32 minDist = Compiler->Min(d1, d2);
minDist = Compiler->Min(minDist, d3);
minDist = Compiler->Min(minDist, d4);
minDist = Compiler->Min(minDist, d5);
minDist = Compiler->Min(minDist, d6);
minDist = Compiler->Sub(minDist, Compiler->Constant(BorderWidth)); // Add some padding
int32 colorFadeStart = Compiler->Mul(Compiler->Constant(1.2f), Compiler->Constant(BorderWidth));
int32 colorFadeEnd = Compiler->Mul(Compiler->Constant(0.8f), Compiler->Constant(BorderWidth));
int32 alphaFadeStart = Compiler->Mul(Compiler->Constant(1.0f), Compiler->Constant(BorderWidth));
int32 alphaFadeEnd = Compiler->Mul(Compiler->Constant(0.6f), Compiler->Constant(BorderWidth));
int32 colorFade = Compiler->SmoothStep(
colorFadeStart,
colorFadeEnd,
minDist
);
int32 alphaFade = Compiler->SmoothStep(
alphaFadeStart,
alphaFadeEnd,
minDist
);
// Rest of the color/alpha processing remains the same
int32 rgbMask = Compiler->ComponentMask(ColorIndex, true, true, true, false);
int32 alphaMask = Compiler->ComponentMask(ColorIndex, false, false, false, true);
int32 white = Compiler->Constant3(1.0f, 1.0f, 1.0f);
int32 finalRGB = Compiler->Lerp(
white,
rgbMask,
colorFade
);
int32 finalAlpha = Compiler->Mul(alphaMask, alphaFade);
int32 finalColor = Compiler->AppendVector(finalRGB, finalAlpha);
return finalColor;
}
// Helper function to calculate distance from point to line segment
int32 UMaterialExpressionHexagonShape::DistanceToSegment(FMaterialCompiler* Compiler, int32 p, int32 v1, int32 v2)
{
int32 segment = Compiler->Sub(v2, v1);
int32 p_v1 = Compiler->Sub(p, v1);
int32 t = Compiler->Saturate(
Compiler->Div(
Compiler->Dot(p_v1, segment),
Compiler->Dot(segment, segment)
)
);
int32 projection = Compiler->Add(v1, Compiler->Mul(t, segment));
int32 diff = Compiler->Sub(p, projection);
return Compiler->Length(diff);
}
void UMaterialExpressionHexagonShape::GetCaption(TArray<FString>& OutCaptions) const
{
OutCaptions.Add(TEXT("Hexagon Shape"));
}
uint32 UMaterialExpressionHexagonShape::GetInputType(int32 InputIndex)
{
switch(InputIndex)
{
case 0: return MCT_Float2; // UV coordinates
case 1: return MCT_Float4; // Color
default: return MCT_Unknown;
}
}
FName UMaterialExpressionHexagonShape::GetInputName(int32 InputIndex) const
{
switch(InputIndex)
{
case 0: return TEXT("UV");
case 1: return TEXT("Color");
default: return NAME_None;
}
}
#endif
#undef LOCTEXT_NAMESPACE
//Plugins/HexUI_Base/Source/HexUI_BaseEditor/Public/MaterialExpressions/MaterialExpressionHexagonShape.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Materials/MaterialExpression.h"
#include "MaterialExpressionHexagonShape.generated.h"
UCLASS(collapsecategories, hidecategories=Object)
class HEXUI_BASEEDITOR_API UMaterialExpressionHexagonShape : public UMaterialExpression
{
GENERATED_UCLASS_BODY()
/** Link to the UV input */
UPROPERTY()
FExpressionInput UV;
/** Link to the color input */
UPROPERTY()
FExpressionInput Color;
UPROPERTY(EditAnywhere, Category="MaterialExpressionHexagonShape", Meta = (ShowAsInputPin = "Advanced"))
float Radius = 0.8f;
UPROPERTY(EditAnywhere, Category="MaterialExpressionHexagonShape", Meta = (ShowAsInputPin = "Advanced"))
float BorderWidth = 0.05f;
static int32 DistanceToSegment(FMaterialCompiler* Compiler, int32 p, int32 v1, int32 v2);
// In MaterialExpressionHexagonShape.h
#if WITH_EDITOR
//~ Begin UMaterialExpression Interface
virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) override;
virtual void GetCaption(TArray<FString>& OutCaptions) const override;
virtual uint32 GetInputType(int32 InputIndex) override;
virtual FName GetInputName(int32 InputIndex) const override;
//~ End UMaterialExpression Interface
#endif
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment