목차

     

     


     

     

     

     
    Plugins
      Example
        ButtonCommand.h .cpp
    Example.Build.cs

    ExampleConsoleCommand.h .cpp 
    ExampleDebuggerCategory.h .cpp
    ExampleModule.h .cpp
    ExampleStyle.h.cpp

    StaticMesh_Detail.h .cpp
    Source
        Utilities
        CHelper.h
    CLog.h .cpp
        Global.h
    CStaticMesh.h .cpp
    CStaticMesh_Copied.h .cpp 생성
    .Build.cs
        .uproject
     

     

     

     

    Plugin

     


     

    ButtonCommand

     

    ButtonCommand.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Framework/Commands/Commands.h"
    
    class EXAMPLE_API FButtonCommand
     : public TCommands<FButtonCommand>
    {
    public:
     FButtonCommand();
     ~FButtonCommand();
    
    public:
     void RegisterCommands() override;
    
    public:
     TSharedPtr<FUICommandList> Command;
    
    public:
     TSharedPtr<FUICommandInfo> LoadMesh;
    
    private:
     void OnClicked_LoadMesh();
    };

    변경사항 없음

     

     

    ButtonCommand.cpp

    더보기
    #include "ButtonCommand.h"
    #include "Misc/MessageDialog.h"
    #include "Misc/FileHelper.h"
    #include "Serialization/BufferArchive.h" //행렬화 관련 헤더. Buffer를 활용하여 내보내는데 필요하다.
    #include "DesktopPlatformModule.h"
    #include "Interfaces/IMainFrameModule.h"
    #include "StaticMesh_Detail.h"
    #include "Editor.h"
    #include "LevelEditorViewport.h"
    #include "U2212_05/CStaticMesh_Copied.h"
    
    FButtonCommand::FButtonCommand()
    	: TCommands("ToolBar_Buttons", FText(), NAME_None,FEditorStyle::GetStyleSetName())//ToolBar_Buttons는 총괄 객체의 이름
    {
    	Command = MakeShareable(new FUICommandList());
    }
    
    FButtonCommand::~FButtonCommand()
    {
    	if (Command.IsValid())
    		Command.Reset();
    }
    
    void FButtonCommand::RegisterCommands()
    {
    #define LOCTEXT_NAMESPACE ""
        UI_COMMAND(LoadMesh, "LoadMesh", "", EUserInterfaceActionType::Button, FInputChord());//q버튼, 체크박스, 라디오버튼 등 원는 방식으로 버튼을 만들어준다.
    #undef LOCTEXT_NAMESPACE
    
        Command->MapAction(LoadMesh, FExecuteAction::CreateRaw(this, &FButtonCommand::OnClicked_LoadMesh));//LoadMesh실행을 위해 OnClicked_LoadMesh를ExecuteAction::CreateRaw으로 연결해준다.
    }
    
    void FButtonCommand::OnClicked_LoadMesh()
    {
    	IMainFrameModule& mainFrame = FModuleManager::LoadModuleChecked<IMainFrameModule>("MainFrame");
    	void* handle = mainFrame.GetParentWindow()->GetNativeWindow()->GetOSWindowHandle();//NativeWindow()가 실제 창 객체. GetOSWindowHandle()는 각 운영체제에 맞는 WindowHandle를 리턴해준다.//WindowHandle식별자는 dword x64면 가변형이다. 4byte로 처리가능하면 4byte, 불가능하면 8byte이다.
    
    	FString path;
    	FPaths::GetPath(path);
    
    	TArray<FString> fileNames;
    
    	IDesktopPlatform* platform = FDesktopPlatformModule::Get();
    	platform->OpenFileDialog(handle, "Open Mesh File", path, "", "Mesh Binary File(*.bin)|*.bin", EFileDialogFlags::None, fileNames);//title은 파일 이름, EFileDialogFlags는 공유속성(None으로 설정하였다)
    	if (fileNames.Num() < 1) return;
    
    	FBufferArchive buffer;
    	FFileHelper::LoadFileToArray(buffer, *fileNames[0]);//파일을 buffer에 읽어놓는다.
    
    	FMemoryReader reader = FMemoryReader(buffer, true);
    	reader.Seek(0);
    
    	//reader로 파일을 읽음
    	FStaticMesh_DetailData data;
    	reader << data;
    	reader.FlushCache();
    	reader.Close();
    
    	GLog->Logf(L"Vertex Count : %d", data.Positions.Num());
    	GLog->Logf(L"Triangle Count : %d", data.Indices.Num() / 3);
    	GLog->Logf(L"Extent : %s", *data.Extent.ToString());
    	GLog->Logf(L"Radius : %f", data.Radius);
    
    
    	FString text;
    	for (int32 i = 0; i < data.Positions.Num(); i++)
    	{
    		text.Append(data.Positions[i].ToString() + ", ");
    		text.Append(data.Normals[i].ToString() + ", ");
    		text.Append(data.Uvs[i].ToString() + ", ");
    		text.Append(data.Colors[i].ToString() + "\r\n");
    	}
    
    	FString textFileName = FPaths::GetBaseFilename(fileNames[0], false);
    	FString textSaveName = textFileName + "_Copied.csv";
    
    	FFileHelper::SaveStringToFile(text, *textSaveName);
    
    	//FLevelEditorViewportClient* client = dynamic_cast<FLevelEditorViewportClient*>(GEditor->GetActiveViewport()->GetClient()); //현재 활성화된 뷰포트
    	FLevelEditorViewportClient* client = (FLevelEditorViewportClient*)GEditor->GetActiveViewport()->GetClient(); //현재 활성화된 뷰포트
    	if (client == nullptr) return; //clinet가 없다면 리턴
    
    	FVector start = client->GetViewLocation();
    	FVector end = start + client->GetViewRotation().RotateVector(FVector(1000, 0, 0));
    
    	FHitResult hitResult;
    	UWorld* world = GEditor->GetEditorWorldContext().World();
    
    	world->LineTraceSingleByChannel(hitResult, start, end, ECollisionChannel::ECC_Visibility);//보이는것 다 수정.
    	if(hitResult.bBlockingHit == false)
    	{
    		FMessageDialog dialog;
    		dialog.Debugf(FText::FromString("Can't be placed in this location."));
    
    		return;
    	}
    
    	FTransform transform;
    	FVector direction = (hitResult.TraceEnd - hitResult.TraceStart);//방향 설정.
    	direction.Normalize();//방향 Normalize
    
    	FVector location = hitResult.TraceStart + direction * (hitResult.Distance - data.Radius);
    	transform.SetLocation(location);//location에 배치.
    
    	FRotator rotator = FRotator(0, direction.Rotation().Yaw, 0);//카메라 회전값
    	transform.SetRotation(FQuat(rotator));//회전값 적용하여 배치.
    
    	//지연시켜서 생성하도록 SpawnActorDeferred 사용.
    	ACStaticMesh_Copied* actor = world->SpawnActorDeferred<ACStaticMesh_Copied>
    	(
    		ACStaticMesh_Copied::StaticClass(),//ACStaticMesh_Copied안의 StaticClass()
    		transform,			//배치될 때 충돌 o,x인지 판별할 transform
    		nullptr,			//owner 없음
    		nullptr,			//Instigator 없음
    		ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn //조정해서 Spawn
    	);
    
    	actor->SetPositions(data.Positions);
    	actor->SetIndices(data.Indices);
    	actor->SetNormals(data.Normals);
    	actor->SetUvs(data.Uvs);
    	actor->SetColors(data.Colors);
    
    	actor->FinishSpawning(transform);//transform 위치에 배치하여 최종 Spawn 시켜준다.
    }

    OnClicked_LoadMesh() 추가

    • 매쉬 파일을 임포트 시 뷰포트 기준 충돌지점에 매쉬를 배치한다. 해당 과정을 수행하기 위해 코드를 추가하였다.
    • FTransfrom transform; 
      • FVection direction; FVector location;  FRotator rotator;를 구한 뒤 transform에 넣어준다.
      • transform을 활용하여 임포트될 매쉬의 배치 정보로 활용한다.

     


     

    Source

     


     

     

     

    U2212_05.Build.cs

     

    U2212_05.Build.cs

    더보기
    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");
            PrivateDependencyModuleNames.Add("ProceduralMeshComponent");
        }
    }

    추가

    • PrivateDependencyModuleNames.Add("ProceduralMeshComponent");

     

    CStaticMesh_Copied 생성

     

    CStaticMesh_Copied.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "CStaticMesh_Copied.generated.h"
    
    UCLASS()
    class U2212_05_API ACStaticMesh_Copied : public AActor
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(VisibleDefaultsOnly)
    		class UProceduralMeshComponent* Mesh;
    
    	UPROPERTY(VisibleDefaultsOnly)
    		class UMaterialInstanceConstant* Material;
    
    public:
    #if WITH_EDITOR
    	FORCEINLINE void SetPositions(TArray<FVector> InPositions) { Positions = InPositions; }
    	FORCEINLINE void SetIndices(TArray<int32> InIndices) { Indices = InIndices; }
    	FORCEINLINE void SetNormals(TArray<FVector> InNormals) { Normals = InNormals; }
    	FORCEINLINE void SetUvs(TArray<FVector2D> InUvs) { Uvs = InUvs; }
    	FORCEINLINE void SetColors(TArray<FColor> InColors) { Colors = InColors; }
    #endif
    
    public:
    	ACStaticMesh_Copied();
    
    	void OnConstruction(const FTransform& Transform) override; //OnConstruction 재정의
    
    protected:
    	virtual void BeginPlay() override;
    
    private:
    	TArray<FVector> Positions;
    	TArray<int32> Indices;
    	TArray<FVector> Normals;
    	TArray<FVector2D> Uvs;
    	TArray<FColor> Colors;
    };

     

     

     

    CStaticMesh_Copied.cpp

    더보기
    #include "CStaticMesh_Copied.h"
    #include "Global.h"
    #include "ProceduralMeshComponent.h"
    #include "Materials/MaterialInstanceConstant.h"
    
    ACStaticMesh_Copied::ACStaticMesh_Copied()
    {
    	bRunConstructionScriptOnDrag = false;//Drag 놓을 때만 호출될 수 있게 false로 설정한다.
    
    	CHelpers::CreateComponent(this, &Mesh, "Mesh");
    
    	CHelpers::GetAsset<UMaterialInstanceConstant>(&Material, "MaterialInstanceConstant'/Game/M_StaticMesh_Inst.M_StaticMesh_Inst'");
    	Mesh->SetMaterial(0, Material);
    }
    
    void ACStaticMesh_Copied::OnConstruction(const FTransform& Transform)
    {
    	Super::OnConstruction(Transform);
    
    	Mesh->CreateMeshSection(0, Positions, Indices, Normals, Uvs, Colors, TArray<FProcMeshTangent>(), true);
    }
    
    void ACStaticMesh_Copied::BeginPlay()
    {
    	Super::BeginPlay();
    }

     

     


     

     

    실행화면