Phase 2A: Remove programmatic material creation — use editor-assigned materials instead

UE5.7 UMaterial API no longer exposes Expressions/EmissiveColor publicly.
FaceMaterials and InternalMaterial arrays now accept editor-assigned materials.
Default engine material used when no material is assigned.
Geometry generation remains unchanged: 26 pieces, 6 sections per piece.
This commit is contained in:
axiomlogicnexus 2026-06-10 06:00:06 +00:00
parent 6517274fc4
commit 7b3cf19181
2 changed files with 17 additions and 81 deletions

View file

@ -1,6 +1,4 @@
#include "HyperTwistSimulation/HyperTwistClassicCubeActor.h"
#include "Materials/Material.h"
#include "Materials/MaterialExpressionConstant3Vector.h"
AHyperTwistClassicCubeActor::AHyperTwistClassicCubeActor()
{
@ -40,76 +38,8 @@ void AHyperTwistClassicCubeActor::ClearPieces()
PieceMeshes.Empty();
}
void AHyperTwistClassicCubeActor::EnsureDefaultMaterials()
{
if (bDefaultMaterialsCreated)
{
return;
}
// Standard Rubik's cube colors (unlit)
const TArray<FLinearColor> Colors = {
FLinearColor(1.0f, 1.0f, 1.0f), // Up - White
FLinearColor(1.0f, 0.84f, 0.0f), // Down - Yellow
FLinearColor(0.0f, 0.62f, 0.27f), // Front - Green
FLinearColor(0.0f, 0.27f, 0.68f), // Back - Blue
FLinearColor(1.0f, 0.35f, 0.0f), // Left - Orange
FLinearColor(0.72f, 0.07f, 0.07f) // Right - Red
};
for (int32 i = 0; i < 6; ++i)
{
UMaterial* Mat = NewObject<UMaterial>(this, *FString::Printf(TEXT("FaceMat_%d"), i));
Mat->SetShadingModel(MSM_Unlit);
UMaterialExpressionConstant3Vector* ColorNode = NewObject<UMaterialExpressionConstant3Vector>(Mat);
ColorNode->Constant = Colors[i];
Mat->Expressions.Add(ColorNode);
Mat->EmissiveColor.Expression = ColorNode;
Mat->PostEditChange();
DefaultFaceMats.Add(Mat);
}
// Internal material - near-black
UMaterial* IntMat = NewObject<UMaterial>(this, TEXT("InternalMat"));
IntMat->SetShadingModel(MSM_Unlit);
UMaterialExpressionConstant3Vector* IntColorNode = NewObject<UMaterialExpressionConstant3Vector>(IntMat);
IntColorNode->Constant = FLinearColor(0.05f, 0.05f, 0.05f);
IntMat->Expressions.Add(IntColorNode);
IntMat->EmissiveColor.Expression = IntColorNode;
IntMat->PostEditChange();
DefaultInternalMat = IntMat;
bDefaultMaterialsCreated = true;
}
UMaterialInterface* AHyperTwistClassicCubeActor::GetFaceMaterial(EHyperTwistClassicCubeFace Face)
{
int32 Index = static_cast<int32>(Face);
if (FaceMaterials.IsValidIndex(Index) && FaceMaterials[Index] != nullptr)
{
return FaceMaterials[Index];
}
EnsureDefaultMaterials();
return DefaultFaceMats.IsValidIndex(Index) ? DefaultFaceMats[Index] : nullptr;
}
UMaterialInterface* AHyperTwistClassicCubeActor::GetInternalMat()
{
if (InternalMaterial != nullptr)
{
return InternalMaterial;
}
EnsureDefaultMaterials();
return DefaultInternalMat;
}
void AHyperTwistClassicCubeActor::GenerateCube()
{
EnsureDefaultMaterials();
struct FPieceDef
{
FVector GridPos;
@ -167,7 +97,20 @@ void AHyperTwistClassicCubeActor::CreatePiece(const FVector& GridPos, const TArr
for (int32 i = 0; i < 6; ++i)
{
EHyperTwistClassicCubeFace Face = static_cast<EHyperTwistClassicCubeFace>(i);
UMaterialInterface* Mat = ColoredFaces.Contains(Face) ? GetFaceMaterial(Face) : GetInternalMat();
// Look up material: use FaceMaterials if assigned, otherwise default (null)
UMaterialInterface* Mat = nullptr;
int32 FaceIndex = static_cast<int32>(Face);
if (FaceMaterials.IsValidIndex(FaceIndex) && FaceMaterials[FaceIndex] != nullptr
&& ColoredFaces.Contains(Face))
{
Mat = FaceMaterials[FaceIndex];
}
else if (InternalMaterial != nullptr && !ColoredFaces.Contains(Face))
{
Mat = InternalMaterial;
}
CreateCubeletFace(Mesh, i, Center, HalfSize, Face, Mat);
}
}

View file

@ -27,14 +27,14 @@ public:
bool bGenerateOnConstruction = true;
/**
* Override materials for each face.
* Override materials for each outward face.
* Index order matches EHyperTwistClassicCubeFace: Up, Down, Front, Back, Left, Right.
* If an entry is null, a default unlit color is generated at runtime.
* If null, the default engine material is used.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
TArray<UMaterialInterface*> FaceMaterials;
/** Material for internal (non-visible) faces. If null, a dark gray default is used. */
/** Material for internal (non-visible) faces. If null, the default engine material is used. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Cube")
UMaterialInterface* InternalMaterial;
@ -51,12 +51,5 @@ private:
const FVector& Center, float HalfSize, EHyperTwistClassicCubeFace Face,
UMaterialInterface* Material);
UMaterialInterface* GetFaceMaterial(EHyperTwistClassicCubeFace Face);
UMaterialInterface* GetInternalMat();
void EnsureDefaultMaterials();
TArray<UProceduralMeshComponent*> PieceMeshes;
TArray<UMaterialInterface*> DefaultFaceMats;
UMaterialInterface* DefaultInternalMat = nullptr;
bool bDefaultMaterialsCreated = false;
};