FBX SDK 이용 방법 #2 (How to Work with FBX SDK 번역) Game develop

이전글 <- 클릭



자 이제 너님은 나님에게 "UV랑 노말이랑 탄젠트랑 바이노말은 어케 얻어옴?" 하고 물어볼거임. ㅇㅇ 그럼 잠시 메시에 대해 생각해보기로 하셈. 너님은 메시의 형태에 대해 정보를 얻었음. 하지만 이건(역자주:컨트롤포인트를 의미함) 메시의 지오메트리 정보일 뿐임. 표면에 대한 정보는 암것두 없음. 즉, 모양만 있는거지 어케 표현되는 표면인지는 모른다는거임.


FBX는 메시를 덮는 Layer라는 개념을 사용하고있음. 상자인 메시가 있다고 치면 Layer는 이 상자를 포장하는 포장지 같은거로 생각하면 될거임. 이 Layer에서 UV, 노말, 탄젠트, 바이노말을 추출 할 수 있음.


암튼간에, 어케 layer정보를 control point와 연결할 수 있을까 궁금할거임. 이게 좀 거지같은데 이에 관해서 코드를 보여주면서 설명을 좀 하게뜸.  


함수를 보기 전에 파라미터에 대해 설명을 먼저 좀 하겠음.

FbxMesh* inMesh : 우리가 익스포트하려는 바로 그 메시

int inCtrlPointIndex : Control point의 인덱스. 레이어 정보와 버텍스(Control Point)를 연결해주기 위해 필요함

int inVertexCounter : 현재 처리하고 있는 버텍스의 인텍스

XMFLOAT3& outNormal : 아웃풋. 함수 안에서 수정해서 아웃풋으로 사용하기 위해 콜바이 레퍼런스로 넘겨줌.  


파라미터들을 보면 의아한게 좀 있을거임. Control Point랑 버텍스는 같은거 아님? 왜 inCtrlPointIndex랑 inVertexCounter가 따로 존재하는거임? 두개가 같은거 아님?


즐. 두 개 같은거 아님. 앞서 설명했듯이, Control Point는 메시 지오메트리의 물리적인 버텍스임. 사각형으로 예를 들어보겠음. 사각형(두 개의 삼각형)에서는 Control Point가 몇개겠음? 정답은 4개임.


하지만 삼각형 기반의 게임 엔진에서는 버텍스가 몇개가 필요함. 바로 6개임. 삼각형 당 3개의 버텍스가 필요하고 2개의 삼각형이니 2*3=6


이게 FBXSDK의 Control Point와 우리가 생각하는 버텍스의 주요 차이점임. 즉, 버텍스는 삼각형 단위의 개념이지만 FBXSDK의 Control Point는 그렇지 않다는 것임. (역자주: 우리가 쓰던대로 버텍버퍼정보 인덱스버퍼 정보 깔끔하게 나뉘어져 있으면 좋으련만 또 그렇지도 않아서 열라 거지같음)

이제 코드 설명으로 돌아가겠음. 그러니 FBXSDK의 Control Point와 버텍스에 대한 이해가 깨랑까랑해도 일단 걱정마셈.


한가지 명심해야할 점은 이 함수 밖에서 루프를 돌면서 메시의 삼각형들의 모든 버텍스를 순회한다는 것이다. “루프를 돌면서 메시의 삼각형들의 모든 버텍스를 순회한다”는 의미가 헤깔린다면 꺼져가 아니라 위의 Mesh Data(position, UV, normal, tangent, binormal)섹션을 다시 보셈. 암튼 그래서 inCtrlPointIndex와 inVertexCounter가 그래서 필요한거임.


void FBXExporter::ReadNormal(FbxMesh* inMesh, int inCtrlPointIndex, int inVertexCounter, XMFLOAT3& outNormal)
{
if(inMesh->GetElementNormalCount() < 1)
{
throw std::exception("Invalid Normal Number");
}

FbxGeometryElementNormal* vertexNormal = inMesh->GetElementNormal(0);
switch(vertexNormal->GetMappingMode())
{
case FbxGeometryElement::eByControlPoint:
switch(vertexNormal->GetReferenceMode())
{
case FbxGeometryElement::eDirect:
{
outNormal.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inCtrlPointIndex).mData[0]);
outNormal.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inCtrlPointIndex).mData[1]);
outNormal.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inCtrlPointIndex).mData[2]);
}
break;

case FbxGeometryElement::eIndexToDirect:
{
int index = vertexNormal->GetIndexArray().GetAt(inCtrlPointIndex);
outNormal.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[0]);
outNormal.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[1]);
outNormal.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[2]);
}
break;

default:
throw std::exception("Invalid Reference");
}
break;

case FbxGeometryElement::eByPolygonVertex:
switch(vertexNormal->GetReferenceMode())
{
case FbxGeometryElement::eDirect:
{
outNormal.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inVertexCounter).mData[0]);
outNormal.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inVertexCounter).mData[1]);
outNormal.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(inVertexCounter).mData[2]);
}
break;

case FbxGeometryElement::eIndexToDirect:
{
int index = vertexNormal->GetIndexArray().GetAt(inVertexCounter);
outNormal.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[0]);
outNormal.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[1]);
outNormal.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[2]);
}
break;

default:
throw std::exception("Invalid Reference");
}
break;
}
}


뭐 코드가 좀 길긴한데 쫄지마셈. 사실 존내 간단한거임.


요건 layer의 노말 정보를 얻는거임


FbxGeometryElementNormal* vertexNormal = inMesh->GetElementNormal(0);


첫 스위치문은 MappinhMode()에 관한 것임. 게임 엔진의 경우라면 FbxGeometryElement::eByControlPoint랑 FbxGeometryElement::eByPolygonVertex 이 두 가지 경우만 고려하면 될 거임. 이 두 모드에 대해 설명하자면, 앞서 언급했다시피 Control Point는 기본적으로 버텍스임. 암튼 요게 문제임.


큐브는 8개의 Control Point를 가지지만, 큐브가 정상적으로 보이려면 노말이 8개보다 많이 필요함. Sharp EDGE를 표현하려면 두개 이상의 노말을 동일한 Control Point에 적용해야함. 그래야 면이 각진걸로 보임. (역자주:이해가 안간다면 이 이미지를 보셈)


이 컨셉을 게임 엔진에 가져온다치면, 위치는 같지만 다른 노말을 가지는 버텍스 세 개를 큐브의 모서리에 위치시켜야함.


암튼 결론적으로, sharp edge를 표현할 필요가 없이 각 control point마다 하나의 노말만 가지고 있는 상황이면 FbxGeometryElement::ebycontrolpoint임. FbxGeometryElement::eByPolygonVertex는 sharp edge를 나타내야하고 각각의 면 마다 각각의 다른 노말을 가지는 버텍스를 다루는 경우임. 같은 control point라도  각각의 면은 서로 다른 노말을가지는거임. 그래서, FbxGeometryElement::eByControlPoint는 control point의 노말을 control point의 인덱스로 접근할 수 있음을 뜻함. 하지만,  FbxGeometryElement::eByPolygonVertex는 면에 있는 버텍스의 노말을 버텍스의 인덱스로 접근해야 함을 뜻함.


이건 FBXSDK의 버텍스와 control point의 차이에 대한 좀 더 구체적인 예시임. 또한, 이 힘수에 대한 파라미터를 설명할 때 inCtrlPointIndex와 inVertexCounter를 나눈 이유이기도 함. 왜냐면 우리는 어느게 필요한 정보러 쓰일 지 모기때문에 일단 둘 다 넘겨준거임.


이제 그 안에 있는 다른 switch 문을 보셈. ReferenceMode()에 의한 분기가 있을거임. 이는 FBX의 최적화 방안같은거임. 우리가 컴퓨터 그래픽에서 알고있는 index buffer 같은거임. 너님은 동일한 vector3를 매번 생성하기 싫으면 대신 인덱스로 접근해서 참조하면 됨.


FbxGeometryElement::eDirect는 페이스 버텍스의 인덱스나 control point의 인덱스를 직접 접근해서 노말을 뽑을 수 있다는 의미임 FbxGeometryElement::eIndexToDirect는 control point의 인덱스나 vertex의 인덱스 사용이 오로지 우리가 원하는 노말의 인덱스만을 가리킨다는 의미임.(역자주:말이 좀 거지같은데 암튼 걍 한단계 더 거쳐서 접근해야한다는 의미임)


이 코드가 우리가 필요한 인덱스를 뽑아줌 ㅇㅇ


int index = vertexNormal->GetIndexArray().GetAt(inVertexCounter);


이게 위치를 넘겨주고 메시의 layer 정보를 넘겨주는 중요 단계임


자 고롬 이제 에니메이션으로 넘어가셈. 이게 FBX  데이터 추출에서 골빠개지는 단계임 ㅇㅇ


(역자주 : 한번에 다 번역할라니 빡심 에니메이션 부분은 다음에 하겠음 오늘은 일단 여기까지 ㅋㅋ)

공유하기 버튼

 

FBX SDK 이용 방법 #1 (How to Work with FBX SDK 번역) Game develop

유니티 에셋 스토어에는 쓸만한 모델 데이터들이 어마어마합니다. 이러한 리소솓들이 십중팔구는 FBX 포맷을 사용합니다. 즉 유니티 에셋 스토어의 리소스를 자체엔진에서 사용하기 위해서는 FBX 파싱을 해야한 다는 것이죠. 때문에 요즘 FBX 파일을 파싱하기 위해서 FBX SDK를 살펴보고 있는데 좋은 글을 하나 발견하게 되었습니다. FBX SDK를 살펴볼 분이 얼마나 계실지는 모르겠지만 번역좀 해서 올리고자 합니다... 만 귀찮아서 반만 번역하고 음셈체로 썼네요 ㅋㅋ 반말이나 음셈체에 반감 있으신분들은 그냥 원문만 보세요 ㅋ 어짜피 볼 사람도 얼마 안계실테니 다듬고 자시고 하긴 귀챠나여 걍 봐여 ㅋㅋ 번역 오역 의역 악(?)역 쩌니 역시 원문을 추천드림 ㅋㅋ

원문 :


나님은 FBX 파일을 자체포맷으로 변환하는 익스포터를 만들고 싶음. 아놔 FBX 공식 문서가 거지같아서 작업하기 빡셌음. 게다가, FBX 포맷이 게임 엔진만을 위한게 아니라 범용적인 기술을 다루고 있어서 샘플 코드도 게임 개발에 딱 맞지가 않았음. (역자주: 아 개공감 ㅠ)

아 그래서 존나 구글링 했는데 FBX파일을 자체 포맷으로 변환하는 내용에 대해서 쩔게 정리해 놓은 글이 없글래 나님이 정리해놓음. 님들 잘 거져드셈 우걱우걱


이 튜토리얼은 게임 엔진에 특화되어있음. 기본적으로는 게임 엔진에 필요한 데이터를 얻는 방법에 대해 다룰거임. FBX SDK를 초기화하는 방법같은거는 샘플 코드 보면서 알아서 하셈 ㅇㅇ ImportScene 샘플이 딱임

혹시 너님이 관절 에니메이션에 대해 잘 모르면 Buckeye의 글 “Skinned Mesh Animation Using Matrics”를 읽어보셈. 존나 좋음 ㅇㅇ


Mesh Data(position, UV, normal, tangent, binormal)

너님이 맨 처음 해야할 일은 mesh데이터를 얻어오는 것임. 정적 메시를 너님의 엔진에 임포트할 수 있다면 존나 좋을거임.

일단 이 섹션에 대해 명확히 하자면, 나님은 우선 FBX 파일을 순회하는 법에 대해 보여줄거임. 이는 메시 데이터를 얻기 위한 행위를 순차적으로 이해시켜줄거임. 각각의 함수가 정확히 뭥미인지 이해 못하더라도, 각 삼각형 당 3개의 정점을 순회하는 것에 대한 해답을 얻을 수 있을거임. 각각의 함수에 대해서는 차후 설명하겠음


에니메이션을 위한 블렌딩 정보와 연관 된 코드 일부가 요기잉네. 일단 자세한건 알비백 ㅇㅇ


void FBXExporter::ProcessMesh(FbxNode* inNode)
{
FbxMesh* currMesh = inNode->GetMesh();

mTriangleCount = currMesh->GetPolygonCount();
int vertexCounter = 0;
mTriangles.reserve(mTriangleCount);

for (unsigned int i = 0; i < mTriangleCount; ++i)
{
XMFLOAT3 normal[3];
XMFLOAT3 tangent[3];
XMFLOAT3 binormal[3];
XMFLOAT2 UV[3][2];
Triangle currTriangle;
mTriangles.push_back(currTriangle);

for (unsigned int j = 0; j < 3; ++j)
{
int ctrlPointIndex = currMesh->GetPolygonVertex(i, j);
CtrlPoint* currCtrlPoint = mControlPoints[ctrlPointIndex];


ReadNormal(currMesh, ctrlPointIndex, vertexCounter, normal[j]);
// We only have diffuse texture
for (int k = 0; k < 1; ++k)
{
ReadUV(currMesh, ctrlPointIndex, currMesh->GetTextureUVIndex(i, j), k, UV[j][k]);
}


PNTIWVertex temp;
temp.mPosition = currCtrlPoint->mPosition;
temp.mNormal = normal[j];
temp.mUV = UV[j][0];
// Copy the blending info from each control point
for(unsigned int i = 0; i < currCtrlPoint->mBlendingInfo.size(); ++i)
{
VertexBlendingInfo currBlendingInfo;
currBlendingInfo.mBlendingIndex = currCtrlPoint->mBlendingInfo[i].mBlendingIndex;
currBlendingInfo.mBlendingWeight = currCtrlPoint->mBlendingInfo[i].mBlendingWeight;
temp.mVertexBlendingInfos.push_back(currBlendingInfo);
}
// Sort the blending info so that later we can remove
// duplicated vertices
temp.SortBlendingInfoByWeight();

mVertices.push_back(temp);
mTriangles.back().mIndices.push_back(vertexCounter);
++vertexCounter;
}
}

// Now mControlPoints has served its purpose
// We can free its memory
for(auto itr = mControlPoints.begin(); itr != mControlPoints.end(); ++itr)
{
delete itr->second;
}
mControlPoints.clear();
}


FBX가 메쉬의 모든 정보를 어케 가지고 있는지를 설명하게뜸. FBX에는 컨트롤 포인트란게 있음. 요 컨트롤 포인트는 기본적으로 물리적인 버텍스임. 예를 들자면,큐브가 있다고 치셈. 큐브는 버텍스가 8개임. 이 8개의 버텍스는 8개의 컨트롤 포인트임. 결론적으로, 버텍스와 컨트롤포인트는 일맥상통한다고 보면 됨. 위치 정보가 이 컨트롤 포인트에 있음.


아래 코드가 메시의 모든 버텍스의 위치를 얻어오는 코드임


// inNode is the Node in this FBX Scene that contains the mesh
// this is why I can use inNode->GetMesh() on it to get the mesh
void FBXExporter::ProcessControlPoints(FbxNode* inNode)
{
FbxMesh* currMesh = inNode->GetMesh();
unsigned int ctrlPointCount = currMesh->GetControlPointsCount();
for(unsigned int i = 0; i < ctrlPointCount; ++i)
{
CtrlPoint* currCtrlPoint = new CtrlPoint();
XMFLOAT3 currPosition;
currPosition.x = static_cast<float>(currMesh->GetControlPointAt(i).mData[0]);
currPosition.y = static_cast<float>(currMesh->GetControlPointAt(i).mData[1]);
currPosition.z = static_cast<float>(currMesh->GetControlPointAt(i).mData[2]);
currCtrlPoint->mPosition = currPosition;
mControlPoints[i] = currCtrlPoint;
}
}



이어지는글. <- 클릭(아 이글루스 개병신. 글 길게 쓰는게 막혀있어서 두 개로 나눔)

아 폰트랑 글자 크기는 왜 이따구로 나오는거지 망할 이글루 망해라 망해라 거지같은 이글루스

공유하기 버튼

 

[KGC13] 쿠킹스타 제작 사례로 보는 cocos2d-x 소개 녹색깡통로봇


KGC13에서 발표했던 자료 올립니다. 이놈의 망할 이글루 iframe이 안먹으니 링크 들어가셔서 보세요 :)



공유하기 버튼

 

나의 슬럼프 극복기 영상 잡담

저희 회사는 연말마다 Ignite 행사를 합니다.(http://maietdev.tistory.com/6558) 자유주제로 발표를 하는 것인데요, 슬라이드 장당 15초로 총 20장이라는 제약이 있는 형식입니다.
뒷북이지만 2011년 사내 Ignite에서 슬럼프 극복기에 대한 주제로 발표를 했었던 영상을 올립니다. 당시에는 쪽팔려서 사내 블로그에는 올리지 않았었는데 오늘 디스크 정리하다 발견하고 올립니다. 이제는 웃을 수 있어요 ㅋ 근데 사실 내용은 예전에 올렸던 글이랑 정확히 일치합니다. (http://ozlael.egloos.com/3892839) 이 발표 스크립트를 그대로 글로 옮긴거였거든요 ㅎ
 
유투브 주소 : http://youtu.be/h_tBUTtG9HQ


공유하기 버튼

 

KGC2012 Deferred rendering case study 세션 영상 Deferred Rendering

심하게 뒷북이네요 ㅎ 디스크 정리하다가 발견해서 올립니다 ㅎ

KGC 2012에서 발표했던 디퍼드 렌더링 케이스 스터디 세션을 녹화했던 영상을 올립니다.
그냥 개인적으로 녹화한거라 음성 녹음 상태가 좋지는 않네요.양해 부탁드립니다. 

슬라이드 자료는 예전에 올렸었던거 참고하시면 됩니다. 이글루스가 slideshare가 삽입이 안되어 링크로 대신합니다. 

유투브 주소 : http://youtu.be/0LKqr5FXIE4

공유하기 버튼

 

1 2 3 4 5 6 7 8 9 10 다음


smallBanner

longBanner

rightSmallBanner

mobile

트위터큰거