본문 바로가기
Unreal

[Unreal] Parts System

by 카피마스터 2023. 2. 10.

설정된 파츠를 조합하여 Skeletal Mesh를 만들고

캐릭터의 Skeletal Mesh Component에 설정

 

필요 헤더

#include "SkeletalMeshMerge.h"

 

파츠 타입

UENUM(BlueprintType)
enum class EPartsType : uint8
{
    None		= 0,

    Head		= 1,	// 머리
    Torso		= 2,	// 몸통
    ArmT		= 3,	// 팔 상단
    ArmB		= 4,	// 팔 하단
    Hand		= 5,	// 손
    Waist		= 6,	// 허리
    LegT		= 7,	// 다리 상단
    LegB		= 8,	// 다리 하단
    Foot		= 9,	// 발
};

 

클래스 구조

UCLASS()
class RTSTEST_API APRPartsTestCharacter : public ACharacter
{
    GENERATED_BODY()
    ...
    
    // 여기서 설정된 파츠를 조합하여 스켈레탈 메쉬를 생성
    virtual void BeginPlay() override;
    
    // 메쉬 병합 로직
    void MergeMeshs();
    
    ...
    // 조합할 파츠맵
    TMap<EPartsType, TSoftObjectPtr<class USkeletalMesh>> PartsMap;
}

 

사용할 Parts 설정

void APRPartsTestCharacter::BeginPlay()
{
    ...
    // 기본 파츠 정보 설정
    // tableRow는 기본 파츠가 설정된 테이블
    {
        PartsMap.Add(EPartsType::Head, tableRow->HeadBaseParts);
        PartsMap.Add(EPartsType::Torso, tableRow->TorsoBaseParts);
        PartsMap.Add(EPartsType::ArmT, tableRow->ArmTBaseParts);
        PartsMap.Add(EPartsType::ArmB, tableRow->ArmBBaseParts);
        PartsMap.Add(EPartsType::Hand, tableRow->HandBaseParts);
        PartsMap.Add(EPartsType::Waist, tableRow->WaistBaseParts);
        PartsMap.Add(EPartsType::LegT, tableRow->LegTBaseParts);
        PartsMap.Add(EPartsType::LegB, tableRow->LegBBaseParts);
        PartsMap.Add(EPartsType::Foot, tableRow->FootBaseParts);
    }
    
    // 방어구가 설정되었다면 해당 방어구의 파츠를 맵에 덮어 씌운다
    // armorTableRow::PartsMap은 해당 방어구를 장착했을 때 적용할 파츠 정보
    ...
    for (auto& partsPair : armorTableRow->PartsMap)
    {
        EPartsType partsType = partsPair.Key;
        PartsMap[partsType] = partsPair.Value;
    }
    
    // 메쉬 병합
    MergeMeshs();
}

 

Merge 로직

void APRPartsTestCharacter::MergeMeshs()
{
    // 맵에 설정된 파츠 정보 루프
    TArray<USkeletalMesh*> mergeList;
    for (auto& pair : PartsMap)
    {
        // 파츠 인스턴스를 생성하여 리스트에 등록
        USkeletalMesh* partsMesh = pair.Value.LoadSynchronous();
        check(partsMesh);
        mergeList.Add(partsMesh);
    }
	
    // 파라미터
    TArray<FSkelMeshMergeSectionMapping> SectionMappings;
    TArray<FSkelMeshMergeUVTransforms> UvTransforms;

    // 새로운 스켈레탈 메쉬를 생성
    USkeletalMesh* baseMesh = NewObject<USkeletalMesh>();
    // 병합 처리
    FSkeletalMeshMerge Merger(baseMesh, mergeList, SectionMappings, 0, EMeshBufferAccess::Default, UvTransforms.GetData());
    if (false == Merger.DoMerge())
        return;

    // 본 설정
    baseMesh->Skeleton = mergeList[0]->Skeleton;
    
    // 새로운 스켈레탈 메쉬를 컴포넌트에 설정
    GetMesh()->SetSkeletalMesh(baseMesh);
}