2021년 1월 2일 토요일

FBX SDK - 기본적 사용

0. 배경

Assimp 를 쓰니까 Animation Export 가 안된다.

그래서 다른 방법이 없을까 하다가 이거 쓰기로 했다.

https://www.autodesk.com/developer-network/platform-technologies/fbx-sdk-2019-0

위에서 SDK 를 다운받자.


기본 경로가 "C:\Program Files\Autodesk\FBX\FBX SDK\2019.0" 일텐데 여기서 Lib, Include 경로를 프로젝트에 추가하자.

그리고 Lib 안에 dll 파일이 있으므로 실행경로에 "C:\Program Files\Autodesk\FBX\FBX SDK\2019.0\lib\vs2015\x64\release" 를 추가하는 것도 잊지 말자.

1
2
3
#include <fbxsdk.h>
 
#pragma comment(lib, "libfbxsdk.lib")
cs

그리고 Preprocess Definition 에 FBXSDK_SHARED 를 추가하자. 이건 libfbxsdk.lib 을 쓰면서 dynamic memory 를 사용할 때 필요하다고 하는데 안하면 Unresolved Definition 에러가 뜰 가능성이 있다. 이것처럼 말이다.

그리고 라이브러리를 넣어주고 헤더도 추가하면 준비 끝.


대강의 이해는 아래에 잘 정리되어 있었음.

https://boycoding.tistory.com/129



개념


ControlPoint, Polygon

ControlPoint 가 Vertex 의 개념이고

Polygon 이 Face 또는 Index 의 개념임.


Polygon 의 경우 조금 복잡한데, BeginPolygon 함수의 인자로 FaceNumber 를 전달하게 됨.

그 상태에서 AddPolygon 을 하면 지금부터 넣는 Index 는 하나의 변을 구성함.

그리고 EndPolygon 을 호출하면 하나의 면이 끝남. 


Layer

Normal, Uv 같은 정보는 mesh 에 Layer 를 넣으면서 만듦.


EMappingMode

왜 ControlPoint 에 몰빵하지 않냐면, 정육면체같은 각이 진 사각형을 표현하기 위해선

하나의 정점에 어러개의 normal 이 필요하기 때문임.

물론 연결된 각 지점의 평균을 내서 normal 을 사용하는게 간단하긴 한데, FbxSDK 는 게임목적만이 아니기 때문에 그렇게 할 수가 없었음.


EReferenceMode

Layer 의 정보를 얻기위해서 최적화하는 방법.

eDirect 를 사용하면 ControlPoint 의 index 나 Polygon 에서 꺼내올 수 있는 index 로 바로 꺼낸다는 말임.

eIndexToDirect 는 바로 위에서 말한 index 와 layer 의 값 사이를 이어주는 index 를 추가로 만들어서 연결한다는 말임. 메모리 절약에선 좋은데 복잡해보임. 


1
2
3
4
5
6
7
8
int n_layer = mesh->CreateLayer();
FbxLayerElementNormal* normal = FbxLayerElementNormal::Create(mesh, "Normal");
normal->SetMappingMode(FbxLayerElement::EMappingMode::eByControlPoint);
normal->SetReferenceMode(FbxLayerElement::EReferenceMode::eDirect);  

//Add Nomral  

mesh->GetLayer(0)->SetNormals(normal);
cs


Skinning - Cluster

skinning 을 하기 위해선 Cluster 개념이 들어감.

vertex 마다 bone 과 weight 의 정보를 갖는게 아님.

mesh 정보를 담은 node 에 Cluster 를 넣어서 각 Cluster 마다 bone 과 vertex_id, weight 를 가지고 있음. Assimp 랑 같음.

 

Animation

FbxAnimStack 을 만들고 그 안에 FbxAnimLayer 를 여러개 넣는 구조.

FbxAnimLayer 안에 FbxAnimCurve 를 넣는데 이때 각 node 의 LclTranslation, LclRotation, LclScale 에서 만듦. 

이때 넣는 값은 기존 Node 의 local Transform 의 값을 덮어 씌우는 방식이므로 부모 자식 Node 간의 offset 역시 포함된 값이어야함. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FbxAnimStack* lAnimStack = FbxAnimStack::Create(pScene, "MMD Animation");
FbxAnimLayer* lAnimLayer = FbxAnimLayer::Create(pScene, "Base Layer");
lAnimStack->AddMember(lAnimLayer);
 
lCurve = bone_node->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); 
lCurve->KeyModifyBegin();
                    
for (const auto& frame : channel_data._posKeys)
{
    lTime.SetSecondDouble(frame.first / Anim_Tick);
    lKeyIndex = lCurve->KeyAdd(lTime);
    lCurve->KeySetValue(lKeyIndex, frame.second.mData[channel_index]);
    lCurve->KeySetInterpolation(lKeyIndex, FbxAnimCurveDef::eInterpolationCubic);
}
 
lCurve->KeyModifyEnd();
cs


FbxVertexCacheDeformer 

FbxDeformer 는 위에서 말한 Skinning 과 지금 말할 VertexCacheDeformer 를 가짐.

VertexCacheDeformer 는 Vertex Animation 을 위한 것으로 Bone 이 아니라 Vertex 각각에 대해서 움직임을 할 수 있도록 하는 것임.

이때 이 데이터는 fbx 파일 내에 있지 않고 별도의 외부 파일에 저장이 됨.

사용되는 형식은 Maya 에서 사용하는 mcx 형식의 파일과, Unity 에서 플러그인 추가해서 쓰는 pc2 형식, UE4 에서 유일하게 지원하는 abc(Alembic) 형식이 있음.

FBXSDK 는 읽기는 모두 지원하나 쓰기는 앞에 두개만 지원함. 


기타

이름 고유성이 없음. 

대신 Create 할 때 부모 자식간의 관계나, 오브젝트에 메소드를 이용한 설정으로 처리함.

즉 객체 리스트에서 원하는걸 찾는걸 구현하는건 알아서 하란 소리.



List