UE5 Geometry Script — 런타임 메쉬 생성
Geometry Script는 UE5.0+에서 제공하는 프로시저럴 메쉬 생성/수정 플러그인입니다. 기존 ProceduralMeshComponent보다 훨씬 강력한 불리언 연산(CSG), UV 자동 생성, 메쉬 단순화, 콜리전 생성 기능을 Blueprint와 C++ 모두에서 사용할 수 있습니다.
1. 플러그인 활성화 및 설정
섹션 제목: “1. 플러그인 활성화 및 설정”Edit > Plugins > Geometry Script → 활성화
Build.cs:PublicDependencyModuleNames.AddRange(new[]{ "GeometryScript", "GeometryCore", "DynamicMesh",});2. 기본 메쉬 생성 — C++
섹션 제목: “2. 기본 메쉬 생성 — C++”#include "GeometryScript/MeshPrimitiveFunctions.h"#include "GeometryScript/MeshBasicEditFunctions.h"#include "GeometryScript/MeshNormalsFunctions.h"#include "GeometryScript/MeshUVFunctions.h"#include "DynamicMesh/DynamicMesh3.h"#include "Components/DynamicMeshComponent.h"
UCLASS()class AProceduralBuilding : public AActor{ GENERATED_BODY()
UPROPERTY(VisibleAnywhere) UDynamicMeshComponent* MeshComp;
public: AProceduralBuilding() { MeshComp = CreateDefaultSubobject<UDynamicMeshComponent>( TEXT("DynamicMesh")); SetRootComponent(MeshComp); }
void GenerateBuilding(float Width, float Depth, float Height) { UDynamicMesh* DynMesh = MeshComp->GetDynamicMesh(); DynMesh->Reset();
FGeometryScriptPrimitiveOptions Options;
// 기본 박스 생성 UGeometryScriptLibrary_MeshPrimitiveFunctions::AppendBox( DynMesh, Options, FTransform::Identity, Width, Depth, Height, /*WidthSubdivisions=*/ 1, /*DepthSubdivisions=*/ 1, /*HeightSubdivisions=*/ 4);
// 노멀 재계산 FGeometryScriptCalculateNormalsOptions NormalOptions; UGeometryScriptLibrary_MeshNormalsFunctions::RecomputeNormals( DynMesh, NormalOptions);
// UV 자동 생성 (박스 프로젝션) FGeometryScriptMeshBevelOptions UVOptions; UGeometryScriptLibrary_MeshUVFunctions::AutoGenerateXAtlasMeshUVs( DynMesh, 0, FGeometryScriptXAtlasOptions{});
// 콜리전 생성 MeshComp->UpdateCollision(); }};3. CSG 불리언 연산
섹션 제목: “3. CSG 불리언 연산”#include "GeometryScript/MeshBooleanFunctions.h"
void AProceduralBuilding::AddWindows(UDynamicMesh* BuildingMesh){ // 창문 커터 메쉬 생성 UDynamicMesh* CutterMesh = NewObject<UDynamicMesh>(this);
FGeometryScriptPrimitiveOptions Options;
// 각 층마다 창문 커터 박스 추가 for (int Floor = 0; Floor < 4; Floor++) for (int Side = 0; Side < 3; Side++) { float WinX = -150.f + Side * 100.f; float WinZ = 50.f + Floor * 250.f;
FTransform WinTransform( FRotator::ZeroRotator, FVector(0.f, WinX, WinZ));
UGeometryScriptLibrary_MeshPrimitiveFunctions::AppendBox( CutterMesh, Options, WinTransform, /*Width=*/ 10.f, // 관통 두께 /*Depth=*/ 60.f, /*Height=*/80.f); }
// 불리언 빼기: 건물 - 창문 커터 FGeometryScriptMeshBooleanOptions BoolOptions; UGeometryScriptLibrary_MeshBooleanFunctions::ApplyMeshBoolean( BuildingMesh, FTransform::Identity, CutterMesh, FTransform::Identity, EGeometryScriptBooleanOperation::Subtract, BoolOptions);}4. 메쉬 편집 — 버텍스 이동
섹션 제목: “4. 메쉬 편집 — 버텍스 이동”#include "GeometryScript/MeshQueryFunctions.h"#include "GeometryScript/MeshBasicEditFunctions.h"
// 높이맵 기반 지형 변형void AProceduralTerrain::ApplyHeightmap( UDynamicMesh* Mesh, UCurveFloat* HeightCurve){ // 모든 버텍스 순회 FGeometryScriptIndexList VertexIDs; UGeometryScriptLibrary_MeshQueryFunctions::GetAllVertexIDs( Mesh, VertexIDs);
bool bHasErrors = false;
for (int32 VID : VertexIDs.List.Get()) { FVector Pos; UGeometryScriptLibrary_MeshQueryFunctions::GetVertexPosition( Mesh, VID, Pos, bHasErrors);
// 높이 커브 적용 float NormX = (Pos.X + 500.f) / 1000.f; float NormY = (Pos.Y + 500.f) / 1000.f; float Height = HeightCurve->GetFloatValue( FVector2D(NormX, NormY).Size()) * 200.f;
Pos.Z = Height;
UGeometryScriptLibrary_MeshBasicEditFunctions::SetVertexPosition( Mesh, VID, Pos, bHasErrors); }
// 노멀 재계산 FGeometryScriptCalculateNormalsOptions NormalOpts; UGeometryScriptLibrary_MeshNormalsFunctions::RecomputeNormals( Mesh, NormalOpts);}5. 메쉬 단순화
섹션 제목: “5. 메쉬 단순화”#include "GeometryScript/MeshSimplifyFunctions.h"
void SimplifyForLOD(UDynamicMesh* Mesh, float TargetRatio){ FGeometryScriptSimplifyMeshOptions Options; Options.Method = EGeometryScriptRemoveMeshSimplificationType::AttributeAware; Options.TargetPercentage = TargetRatio; // 0.0 ~ 1.0 Options.bDiscardAttributes = false;
UGeometryScriptLibrary_MeshSimplifyFunctions::ApplySimplifyToTriangleCount( Mesh, Options, /*TargetTriangleCount=*/ 1000);}6. Blueprint에서 사용
섹션 제목: “6. Blueprint에서 사용”DynamicMeshActor를 씬에 배치:- DynamicMeshComponent 포함
Construction Script에서:1. Get Dynamic Mesh2. Geometry Script > Primitives > Append Box/Sphere/Cylinder3. Geometry Script > Normals > Recompute Normals4. Geometry Script > UV > Auto Generate Box UV5. Update Collision
이벤트에서 파라미터 변경 → 메쉬 재생성7. PCG(Procedural Content Generation)와 연동
섹션 제목: “7. PCG(Procedural Content Generation)와 연동”// PCG 포인트 데이터 → Geometry Script 메쉬 배치// PCG Graph에서:// - Spawn Static Mesh At Points 대신// - Execute Custom C++ (Geometry Script 메쉬 생성)// → 동적으로 변형된 메쉬를 각 지점에 배치 가능
void AProceduralProp::GenerateFromPCGPoint( const FPCGPoint& Point){ float Scale = Point.Transform.GetScale3D().X; float Height = FMath::RandRange(200.f, 500.f) * Scale;
GenerateBuilding(100.f * Scale, 100.f * Scale, Height); SetActorTransform(Point.Transform);}Geometry Script는 CSG 불리언 연산으로 복잡한 프로시저럴 건축물을, 버텍스 이동으로 지형 변형을 구현하는 데 탁월합니다. UDynamicMeshComponent를 사용하면 런타임 메쉬 업데이트가 가능하고, 완성된 메쉬는 UpdateCollision()으로 물리 콜리전을 자동 생성하세요. PCG와 결합하면 규칙 기반 월드 생성에 변형 메쉬를 대량 배치할 수 있습니다.