[UE] StaticMesh

플러그인 시스템을 통해 개발자는 Unreal Editor 내에서 StaticMesh에 적용할 수 있는 새로운 도구, 수정자 및 렌더링 옵션을 생성할 수 있으며 이러한 새로운 기능을 다른 개발자 또는 더 넓은 커뮤니티와 쉽게 공유할 수 있다. StaticMesh 플러그인을 만들려면 개발자는 먼저 Unreal의 Asset Editor를 사용하여 수행할 수 있는 새 자산 유형을 정의해야 한다. 이 새로운 자산 유형은 새로운 재료 또는 충돌 모양과 같은 사용자 정의 속성 및 기능으로 확장될 수 있다. 플러그인이 생성되면 다른 프로젝트에서 사용할 수 있도록 패키징 및 배포할 수 있으며, 개발자는 언리얼 에디터의 사용자 인터페이스를 통해 자신의 StaticMesh에 새 기능을 쉽게 추가할 수 있다. 전반적으로 Unreal Engine의 StaticMesh 플러그인 시스템은 개발자가 엔진의 핵심 기능을 커스터마이즈하여 특정 요구 사항을 충족하고 사용자를 위해 보다 매력적이고 몰입감 있는 경험을 생성할 수 있는 강력하고 유연한 방법을 제공한다.
목차
Plugins | ||
Example | ||
Example.Build.cs ExampleConsoleCommand.h .cpp ExampleDebuggerCategory.h .cpp ExampleModule.h .cpp StaticMesh_Detail.h .cpp 생성 |
||
Source | ||
Utilities | ||
CHelper.h 추가 CLog.h .cpp 추가 |
||
Global.h 추가 CStaticMesh.h .cpp 생성 .Build.cs |
||
.uproject | ||
Source에 Global.h와 Utilities(CHelper, CLog)폴더 추가하기
Global.h 가져오기
이전에 만들었던 Global.h를 가져와서 추가한다.
Global.h
#pragma once #include "DrawDebugHelpers.h" #include "Kismet/KismetSystemLibrary.h" #include "Kismet/KismetMathLibrary.h" #include "Kismet/GameplayStatics.h" #include "Utilities/CHelpers.h" #include "Utilities/CLog.h"
Utilities 폴더 가져오기 - CHelpers.h, CLog.h .cpp

이전에 만들었던 Utilites 폴더를 가져와서 추가한다.
Utilities 폴더 안에는 CHelpers.h, CLog.h .cpp가 있다.
해당 코드들의 변경사항은 없다.
CHelpers.h
#pragma once #include "CoreMinimal.h" #define CheckTrue(x) { if(x == true) return; } #define CheckTrueResult(x, y) { if(x == true) return y; } #define CheckFalse(x) { if(x == false) return;} #define CheckFalseResult(x, y) { if(x == false) return y;} #define CheckNull(x) { if(x == nullptr) return;} #define CheckNullResult(x, y) { if(x == nullptr) return y;} #define CreateTextRender()\ {\ CHelpers::CreateComponent<UTextRenderComponent>(this, &Text, "Tex", Root);\ Text->SetRelativeLocation(FVector(0, 0, 100));\ Text->SetRelativeRotation(FRotator(0, 180, 0));\ Text->SetRelativeScale3D(FVector(2));\ Text->TextRenderColor = FColor::Red;\ Text->HorizontalAlignment = EHorizTextAligment::EHTA_Center;\ Text->Text = FText::FromString(GetName().Replace(L"Default__", L""));\ } class U2212_05_API CHelpers { public: template<typename T> static void CreateComponent(AActor* InActor, T** OutComponent, FName InName, USceneComponent* InParent = nullptr, FName InSocketName = NAME_None) { *OutComponent = InActor->CreateDefaultSubobject<T>(InName); if (!!InParent) { (*OutComponent)->SetupAttachment(InParent, InSocketName); //이렇게 사용하면 Socket Name에 _를 사용하면 안 된다. return; } InActor->SetRootComponent(*OutComponent); } //CreateActorComponent 추가 template<typename T> static void CreateActorComponent(AActor* InActor, T** OutComponent, FName InName) { *OutComponent = InActor->CreateDefaultSubobject<T>(InName); } template<typename T> static void GetAsset(T** OutObject, FString InPath) { ConstructorHelpers::FObjectFinder<T> asset(*InPath); *OutObject = asset.Object; } template<typename T> static void GetAssetDynamic(T** OutObject, FString InPath) { *OutObject = Cast<T>(StaticLoadObject(T::StaticClass(), nullptr, *InPath)); } template<typename T> static void GetClass(TSubclassOf<T>* OutClass, FString InPath) { ConstructorHelpers::FClassFinder<T> asset(*InPath); *OutClass = asset.Class; } template<typename T> static T* FindActor(UWorld* InWorld) { for (AActor* actor : InWorld->GetCurrentLevel()->Actors) { if (!!actor && actor->IsA<T>()) return Cast<T>(actor); } return nullptr; } template<typename T> static void FindActors(UWorld* InWorld, TArray<T*>& OutActors) { for (AActor* actor : InWorld->GetCurrentLevel()->Actors) { if (!!actor && actor->IsA<T>()) OutActors.Add(Cast<T>(actor)); } } template<typename T> static T* GetComponent(AActor* InActor) { return Cast<T>(InActor->GetComponentByClass(T::StaticClass())); } template<typename T> static T* GetComponent(AActor* InActor, const FString& InName) { TArray<T*> components; InActor->GetComponents<T>(components); for (T* component : components) { if (component->GetName() == InName) return component; } return nullptr; } static void AttachTo(AActor* InActor, USceneComponent* InParent, FName InSocketName) { InActor->AttachToComponent(InParent, FAttachmentTransformRules(EAttachmentRule::KeepRelative, true), InSocketName); } };
CLog.h
#pragma once #include "CoreMinimal.h" #define LogLine(){ CLog::Log(__FILE__, __FUNCTION__, __LINE__); } #define PrintLine(){ CLog::Print(__FILE__, __FUNCTION__, __LINE__); } class U2212_05_API CLog { public: static void Log(int32 InValue); static void Log(float InValue); static void Log(const FString& InValue); static void Log(const FVector& InValue); static void Log(const FRotator& InValue); static void Log(const UObject* InValue); static void Log(const FString& InFileName, const FString& InFuncName, int32 InLineNumber); static void Print(int32 InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue); static void Print(float InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue); static void Print(const FString& InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue); static void Print(const FVector& InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue); static void Print(const FRotator& InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue); static void Print(const UObject* InValue, int32 InKey = -1, float InDuration = 10, FColor InColor = FColor::Blue); static void Print(const FString& InFileName, const FString& InFuncName, int32 InLineNumber); };
CLog.cpp
#include "Utilities/CLog.h" #include "Engine.h" DEFINE_LOG_CATEGORY_STATIC(GP, Display, All) void CLog::Log(int32 InValue) { //GLog->Log("GP", ELogVerbosity::Display, FString::FromInt(InValue)); UE_LOG(GP, Display, L"%d", InValue); } void CLog::Log(float InValue) { UE_LOG(GP, Display, L"%f", InValue); } void CLog::Log(const FString & InValue) { UE_LOG(GP, Display, L"%s", *InValue); } void CLog::Log(const FVector & InValue) { UE_LOG(GP, Display, L"%s", *InValue.ToString()); } void CLog::Log(const FRotator & InValue) { UE_LOG(GP, Display, L"%s", *InValue.ToString()); } void CLog::Log(const UObject * InValue) { FString str; if (!!InValue) str.Append(InValue->GetName()); str.Append(!!InValue ? " Not Null" : "Null"); UE_LOG(GP, Display, L"%s", *str); } void CLog::Log(const FString & InFileName, const FString & InFuncName, int32 InLineNumber) { //C:\\Test\\Test.cpp int32 index = 0, length = 0; InFileName.FindLastChar(L'\\', index); length = InFileName.Len() - 1; FString fileName = InFileName.Right(length - index); UE_LOG(GP, Display, L"%s, %s, %d", *fileName, *InFuncName, InLineNumber); } void CLog::Print(int32 InValue, int32 InKey, float InDuration, FColor InColor) { GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, FString::FromInt(InValue)); } void CLog::Print(float InValue, int32 InKey, float InDuration, FColor InColor) { GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, FString::SanitizeFloat(InValue)); } void CLog::Print(const FString & InValue, int32 InKey, float InDuration, FColor InColor) { GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, InValue); } void CLog::Print(const FVector & InValue, int32 InKey, float InDuration, FColor InColor) { GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, InValue.ToString()); } void CLog::Print(const FRotator & InValue, int32 InKey, float InDuration, FColor InColor) { GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, InValue.ToString()); } void CLog::Print(const UObject * InValue, int32 InKey, float InDuration, FColor InColor) { FString str; if (!!InValue) str.Append(InValue->GetName()); str.Append(!!InValue ? " Not Null" : "Null"); GEngine->AddOnScreenDebugMessage(InKey, InDuration, InColor, str); } void CLog::Print(const FString& InFileName, const FString& InFuncName, int32 InLineNumber) { int32 index = 0, length = 0; InFileName.FindLastChar(L'\\', index); length = InFileName.Len() - 1; FString fileName = InFileName.Right(length - index); FString str = FString::Printf(L"%s, %s, %d", *fileName, *InFuncName, InLineNumber); GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Blue, str); }
U2212_05 수정하기
2212_05.uproject

U2212_05.Build.cs
U2212_05.Build.cs
// Copyright Epic Games, Inc. All Rights Reserved. using UnrealBuildTool; public class U2212_05 : ModuleRules { public U2212_05(ReadOnlyTargetRules Target) : base(Target) { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; PrivateIncludePaths.Add(ModuleDirectory); PublicDependencyModuleNames.Add("Core"); PrivateDependencyModuleNames.Add("CoreUObject"); PrivateDependencyModuleNames.Add("Engine"); PrivateDependencyModuleNames.Add("InputCore"); PrivateDependencyModuleNames.Add("HeadMountedDisplay"); PrivateDependencyModuleNames.Add("NavigationSystem"); PrivateDependencyModuleNames.Add("AIModule"); } }
Plugin -> Game의 private Module은 인식이 안 된다.
U22212_05/CstaticMesh
Source/U2212_05는 ModuleDirectory
보통 private으로 만들고 필요한것만 public으로 연다.
Plugins - Example - Source - Example - Example.Build.cs
플러그인쪽에 있는 아래의 코드와 U2212_05쪽에 있는 위의 코드의 차이를 비교해보자.
Example.Build.cs
Example.Build.cs
using UnrealBuildTool; public class Example : ModuleRules { public Example(ReadOnlyTargetRules Target) : base(Target) //public은 외부에 공개 { PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; PublicIncludePaths.Add(ModuleDirectory); PublicDependencyModuleNames.Add("Core"); PrivateDependencyModuleNames.Add("U2212_05"); //본인 모델은 private PrivateDependencyModuleNames.Add("CoreUObject"); PrivateDependencyModuleNames.Add("Engine"); PrivateDependencyModuleNames.Add("Slate"); PrivateDependencyModuleNames.Add("SlateCore"); PrivateDependencyModuleNames.Add("GameplayDebugger"); } }
CStaticMesh 생성
새 C++ 클래스 - Actor - CStaticMes 생성 (직렬화 될 것이기 때문에 게임쪽에서 만든다)

CStaticMesh.h
#pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "CStaticMesh.generated.h" UCLASS() class U2212_05_API ACStaticMesh : public AActor { GENERATED_BODY() private: UPROPERTY(VisibleAnywhere, Category = "Material") class UMaterialInstanceConstant* Material; private: UPROPERTY(VisibleAnywhere) class UStaticMeshComponent* Mesh; public: ACStaticMesh(); protected: virtual void BeginPlay() override; };
변수 생성
- class UMaterialInstanceConstant* Material;
- class UStaticMeshComponent* Mesh;
CStaticMesh.cpp
#include "CStaticMesh.h" #include "Global.h" #include "Components/StaticMeshComponent.h" #include "Materials/MaterialInstanceConstant.h" ACStaticMesh::ACStaticMesh() { CHelpers::CreateComponent<UStaticMeshComponent>(this, &Mesh, "Mesh"); UStaticMesh* mesh; CHelpers::GetAsset<UStaticMesh>(&mesh, "StaticMesh'/Game/MatineeCam_SM.MatineeCam_SM'"); Mesh->SetStaticMesh(mesh); CHelpers::GetAsset<UMaterialInstanceConstant>(&Material, "MaterialInstanceConstant'/Game/M_StaticMesh_Inst.M_StaticMesh_Inst'"); Mesh->SetMaterial(0, Material); } void ACStaticMesh::BeginPlay() { Super::BeginPlay(); }
Matinee Camera 생성
- CHelpers::GetAsset<UStaticMesh>(&mesh, "StaticMesh'/Game/MatineeCam_SM.MatineeCam_SM'");
Matinee Camera 머테리얼 지정
- CHelpers::GetAsset<UMaterialInstanceConstant>(&Material, "MaterialInstanceConstant'/Game /M_StaticMesh_Inst.M_StaticMesh_Inst'");
Matinee Camera로 사용할 StaticMesh를 복사하여 생성 후 콘텐츠 폴더로 이동

Matinee Camera에 사용할 머테리얼 생성

CStaticMesh 기반 블루프린트 생성 - BP_CStaticMesh 생성

Plugin 부분
StaticMesh_Detail 생성
새 C++ 클래스 - 없음 - StaticMesh_Detail 생성

StaticMesh_Detail.h
#pragma once #include "CoreMinimal.h" #include "IDetailCustomization.h" class EXAMPLE_API FStaticMesh_Detail : public IDetailCustomization //IDetailCustomization로부터 상속받는다. { public: static TSharedRef<IDetailCustomization> MakeInstance(); public: void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override; private: FReply OnClicked_Paint(); };
StaticMesh_Detail.cpp
#include "StaticMesh_Detail.h" #include "DetailLayoutBuilder.h" #include "DetailCategoryBuilder.h" #include "DetailWidgetRow.h" TSharedRef<IDetailCustomization> FStaticMesh_Detail::MakeInstance() { return MakeShareable(new FStaticMesh_Detail()); } void FStaticMesh_Detail::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { IDetailCategoryBuilder& actor = DetailBuilder.EditCategory("Actor"); actor.SetCategoryVisibility(false); //actor 카테고리를 숨긴다. IDetailCategoryBuilder& lighting = DetailBuilder.EditCategory("Lighting"); IDetailCategoryBuilder& mesh = DetailBuilder.EditCategory("Mesh"); mesh.AddCustomRow(FText::FromString("Mesh")) .NameContent() [ SNew(STextBlock) //SNew는 Slate UI들을 동적할당 한다. .Text(FText::FromString("Color")) ]; }
"AddCustomRow"는 개발자가 주어진 위젯에 커스텀 행을 추가할 수 있게 해주는 언리얼 엔진의 기능이다. 이 기능은 엔진의 기본 위젯에서 제공하는 것 이상의 추가 기능이 필요한 사용자 정의 편집기 패널 또는 사용자 인터페이스 요소를 생성하는 데 자주 사용된다.
"AddCustomRow"를 사용하려면 먼저 행을 추가할 위젯 컨테이너의 새 인스턴스를 생성해야 한다. 컨테이너가 있으면 "AddCustomRow" 함수를 호출하고 컨테이너에 대한 참조와 새 행을 생성하는 데 사용할 위임 함수를 전달할 수 있다.
대리자 함수는 행의 실제 콘텐츠를 생성하는 역할을 담당하며 여기에는 필요한 위젯 또는 사용자 지정 논리의 조합이 포함될 수 있다. 행이 생성되면 컨테이너에 추가되고 화면에 표시된다.


StaticMesh_Detail.cpp
#include "StaticMesh_Detail.h" #include "DetailLayoutBuilder.h" #include "DetailCategoryBuilder.h" #include "DetailWidgetRow.h" TSharedRef<IDetailCustomization> FStaticMesh_Detail::MakeInstance() { return MakeShareable(new FStaticMesh_Detail()); } void FStaticMesh_Detail::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) { IDetailCategoryBuilder& actor = DetailBuilder.EditCategory("Actor"); //actor.SetCategoryVisibility(false); //actor 카테고리를 숨긴다. TArray<TSharedRef<IPropertyHandle>> handles; actor.GetDefaultProperties(handles); for(TSharedRef<IPropertyHandle> handle : handles) { // GLog->Log(handle->GetProperty()->GetName()); // GLog->Log(handle->GetProperty()->GetPathName()); // GLog->Log(handle->GetProperty()->GetFullName()); if (handle->GetProperty()->GetName().Compare("bCanBeDamaged") == 0) DetailBuilder.HideProperty(handle); //해당 조건이면 handle를 숨겨준다.(=actor에 있는 bCanBeDamaged를 숨겨준다. } IDetailCategoryBuilder& mesh = DetailBuilder.EditCategory("Mesh"); mesh.AddCustomRow(FText::FromString("Mesh")) .NameContent() [ SNew(STextBlock) //SNew는 Slate UI들을 동적할당 한다. .Text(FText::FromString("Color")) ] .ValueContent() [ SNew(SButton) .VAlign(VAlign_Center) .HAlign(HAlign_Fill) .OnClicked(this, &FStaticMesh_Detail::OnClicked_Paint) //.Content() [ SNew(STextBlock) .Text(FText::FromString("Paint")) ] ]; } FReply FStaticMesh_Detail::OnClicked_Paint() { return FReply::Handled(); }






'⭐ Unreal Engine > UE Plugin - Basic' 카테고리의 다른 글
[UE] Plugin (Save StaticMesh & RenderData, LOD) (0) | 2023.04.12 |
---|---|
[UE] Plugin (StaticMesh Detail) (0) | 2023.04.07 |
[UE] Console Command (0) | 2023.04.05 |
[UE] Console, DrawDebugLine (0) | 2023.04.04 |
[UE] Plugin, Slate UI (0) | 2023.04.03 |
댓글
이 글 공유하기
다른 글
-
[UE] Plugin (Save StaticMesh & RenderData, LOD)
[UE] Plugin (Save StaticMesh & RenderData, LOD)
2023.04.12 -
[UE] Plugin (StaticMesh Detail)
[UE] Plugin (StaticMesh Detail)
2023.04.07 -
[UE] Console Command
[UE] Console Command
2023.04.05 -
[UE] Console, DrawDebugLine
[UE] Console, DrawDebugLine
2023.04.04
댓글을 사용할 수 없습니다.