학습 페이지
www.inflearn.com
1.Assimp
※이론
오늘은 Assimp를 통해 fbx 파일을 로드해보자 유니티나 언리얼에서 기존의 3D 모델을 사용하려고 한다면 하나의 모델이 굉장히 많은 animation, material Texture등으로 구성되어 있는 것을 볼 수 있다.
이때 Material은 shader에 넘겨주고싶은 인자 값을 모아서 관리하는 것이라고 보면 되고 shader는 gpu에 명령을 내리기 위한 기술서라고 보면 된다.
이 fbx 파일은 오브젝트에 mesh, material, Texture, light 등의 정보가 모두 적용된 완성된 오브젝트 파일이라고 보면 된다. 지금은 cube,Sphere과 같은 하나의 도형이라서 코드상에서 만들어줄 수 있지만 만약 하나의 캐릭터를 만들어주려고 한다면 굉장히 어려울 것이다. 이러한 부분을 해결하기 위해 fbx파일을 사용한다.
이 fbx 파일로 가져온 오브젝트는 트리구조를 따른다. 만약 이때 제일 하위의 물체의 transform 정보를 살펴보자면 제일 상위의 물체를 타고타고 해서 상대적인 transform으로 설정되어있다는 것을 알 수 있다.
이제 본격적으로 코드를 살펴보자면 일단 이미지파일처럼 불러온다음 분석하면 된다.
보통은 fbx파일을 불러온 다음 자신만의 포맷으로 변환하여 저장하는 식으로 사용한다.
※외부 라이브러리 가져오는 방법
보통 fbx같은 파일을 가져오려면 외부 라이브러리를 사용하게 되는데 이때 어떻게 가져오면 되는지 알아보자
지금은 fbx파일을 로드하기위해 Assimp를 사용하려고 하고있으니 Assimp를 가져오는 방법을 알아보자
일단 Assimp를 검색해보면 github가 나오는데 전체 코드를 다운받아주면 된다.
만약 받는 파일에 솔루션 파일에 있다면 바로 사용하면 된다. 없다면 Cmake를 통해 솔루션파일을 만들어주자 솔루션
파일이 만들어진다면 솔루션파일에 들어간 다음 실행시켜주면 우리가 원하는 코드가 만들어지게 된다. 필요한 코드파일
을 가져와서 저장해주면 된다.
이제 외부라이브러리 Assimp를 통해 fbx파일을 불러오기 위해 컴파일헤더에 라이브러리를 추가해주고 include문을 추가해주자
EnginePch.h
// Assimp
#include <Assimp/Importer.hpp>
#include <Assimp/scene.h>
#include <Assimp/postprocess.h>
#ifdef _DEBUG
#pragma comment(lib, "DirectXTex/DirectXTex_debug.lib")
#pragma comment(lib, "FX11/Effects11d.lib")
#pragma comment(lib, "Assimp/assimp-vc143-mtd.lib")
#else
#pragma comment(lib, "DirectXTex/DirectXTex.lib")
#pragma comment(lib, "FX11/Effects11.lib")
#pragma comment(lib, "Assimp/assimp-vc143-mtd.lib")
#endif
이렇게 하고 이제 코드를 작성해줘야 하는데 이 Assimp부분의 코드를 Engine에서 만들어줄 지 Client 부분에서 만들어줄
지 애매하며 이 부분의 코드가 둘의 징검다리 역활을 해주기 때문에 새롭게 Tool 프로젝트를 만들어서 관리해주도록 하자.
데스크톱 애플리케이션으로 새로운 프로젝트를 만든 후 이전 프로젝트와 동일하게 외부 라이브러리, 미리 컴파일된 헤더등을 설정해주고 Client 프로젝트에서 main 클래스와 CameraScript 클래스를 복사해서 가져와 주자
그리고 Assimp를 사용하는 코드를 Converter 클래스를 통해 만들어주자
지금은 상대 경로를 통해 파일을 가져오자
또한 std의 filesystem을 사용하여 파일 로드한 다음 importer를 통해 scene 객체에 할당해주자
Converter.h
#pragma once
class Converter
{
public:
Converter();
~Converter();
public:
void ReadAssetFile(wstring file);
private:
wstring _assetPath = L"../Resources/Assets/";
wstring _modelPath = L"../Resources/Models/";
wstring _texturePath = L"../Resources/Texture/";
private:
shared_ptr<Assimp::Importer> _importer;
const aiScene* _scene; //로드했을 때 제일 상위계층
};
Converter.cpp
#include "pch.h"
#include "Converter.h"
#include "filesystem"
#include "Utils.h"
Converter::Converter()
{
_importer = make_shared<Assimp::Importer>();
}
Converter::~Converter()
{
}
void Converter::ReadAssetFile(wstring file)
{
wstring fileStr = _assetPath + file;
//파일가져오기
auto p = std::filesystem::path(fileStr);
assert(std::filesystem::exists(p));
_scene = _importer->ReadFile(
Utils::ToString(fileStr),
aiProcess_ConvertToLeftHanded |
aiProcess_Triangulate | //삼각형 단위만 파싱
aiProcess_GenUVCoords | //uv좌표 생성
aiProcess_GenNormals | //노멀 매핑
aiProcess_CalcTangentSpace
);
assert(_scene != nullptr);
}
그리고 Resources 폴더에 원본파일을 저장할 Asset, 이 파일을 Assimp를 통해 convert된 결과를 저장할 Models 폴더를 생성해주자
밑의 그림을 보면 assimp가 어떻게 fbx를 로드해주는지 계층별로 나와있다. 구성된 계층구조대로 메모리에 전달해주어야한다.
우리가 사용할 fbx파일은 밑의 사이트에서 다운받아서 사용하도록하자.
무료 3D 모델 - Free3D.com
free3d.com
이제 converter클래스를 사용하여 fbx파일을 로드하고 사용하기 위해 AssimpTool이라는 클래스를 만들어주자.
AssimpTool.h
#pragma once
#include "IExecute.h"
class AssimpTool : public IExecute
{
public:
void Init() override;
void Update() override;
void Render() override;
};
AssimpTool.cpp
#include "pch.h"
#include "AssimpTool.h"
#include "Converter.h"
void AssimpTool::Init()
{
{
shared_ptr<Converter> converter = make_shared<Converter>();
// FBX -> Memory
converter->ReadAssetFile(L"House/House.fbx");
//Memory -> CustomData
//CustomData -> Memory
}
}
void AssimpTool::Update()
{
}
void AssimpTool::Render()
{
}
이렇게 해주면 이제 Fbx파일에서 Memory로 가져오는 것은 성공했다.
이제 Memory에서 우리가 정의해준 데이터로 바꿔줘야한다. 이를 위하여 계층 정보에 맞게 구조체를 만들어주자
VertexData.h
struct VertexTextureNormalTangentBlendData
{
Vec3 position = { 0, 0, 0 };
Vec2 uv = { 0, 0 };
Vec3 normal = { 0, 0, 0 };
Vec3 tangent = { 0, 0, 0 };
Vec4 blendIndicies = { 0,0,0,0 }; //애니메이션
Vec4 blendWeights = { 0,0,0,0 };
};
AsTypes.h
#pragma once
using VetexType = VertexTextureNormalTangentBlendData;
struct asBone
{
string name;
int32 index = -1;
int32 parent = -1;
Matrix transform;
};
struct asMesh
{
string name;
aiMesh* mesh;
vector<VetexType> vertices;
vector<uint32> indicies;
int32 boneIndex; //계층구조
string materialName;
};
struct asMaterial
{
string name;
Color ambient;
Color diffuse;
Color specular;
Color emissive;
string diffuseFile;
string specularFile;
string normalFile;
};
이제 만들어준 구조체대로 모델, 매쉬등을 가져오고 저장하는 함수를 만들어주자 오늘은 일단 Material만을 가져오고 우리만의 포맷으로 저장할 수 있는 기능만 구현해보자
'게임공부 > Directx11' 카테고리의 다른 글
[Directx11][C++][3D]9. Assimp(Bone & Model) (0) | 2024.09.14 |
---|---|
[Directx11][C++][3D]8. Assimp(Material) (0) | 2024.09.14 |
[Directx11][C++][3D]6. Normal Mapping (4) | 2024.09.07 |
[Directx11][C++][3D]5. 빛 통합,Material (0) | 2024.09.06 |
[Directx11][C++][3D]5. Light (0) | 2024.09.04 |