레이어(Layer)
FbxLayer 클래스는 FBX SDK 레이어 메커니즘을 구현하는 기본 클래스입니다. FBX에서는 메쉬의 표면을 덮는 레이어라는 개념을 사용합니다. 만약 박스가 하나 있고, 이 박스를 포장지로 덮는다면 이 포장지는 FBX에서의 레이어같은 역할을 합니다.
레이어(FbxLayer)는 아래와 같은 많은 레이어 요소(FbxLayerElement)를 포함할 수 있습니다.
- Normals (FbxLayerElementNormal)
- Binormals (FbxLayerElementBinormal)
- Tangents (FbxLayerElementTangent)
- Uvs (FbxLayerElementUV)
- More...
레이어 요소(Layer Element)
예를 들어 메쉬의 노말 벡터는 FbxLayerElementNormal의 인스턴스로 정의됩니다.
FbxMesh::GetElementNormal() 멤버 함수로 접근 가능합니다.
// 정점 노말을 읽는 함수
vec3 ReadNormal(const FbxMesh* mesh, int controlPointIndex, int vertexCounter)
{
if (mesh->GetElementNormalCount() < 1) // 노말의 개수를 센다.
std::cout << "No normals!" << std::endl;
const FbxGeometryElementNormal* vertexNormal = mesh->GetElementNormal(0); // 노말 획득
vec3 result; // 노말 벡터를 저장할 벡터
// ...
}
/* 생략 */
vec3* positions = nullptr; // 정점 위치 리스트
ProcessControlPoints(mesh); // 제어점으로부터 위치 리스트를 채운다.
unsigned int triCount = mesh->GetPolygonCount(); // 메쉬의 삼각형 개수를 가져온다.
unsigned int vertexCount = 0; // 정점의 개수
for(unsigned int i = 0; i < triCount; ++i) // 삼각형의 개수
{
for(unsigned int j = 0; j < 3; ++j) // 삼각형은 세 개의 정점으로 구성
{
int controlPointIndex = mesh->GetPolygonVertex(i, j); // 제어점 인덱스를 가져온다.
vec3& position = positions[controlPointIndex]; // 현재 정점에 대한 위치
vec3 normal = ReadNormal(mesh, controlPointIndex, vertexCounter); // 노말 벡터
vertexCount++; // 정점의 개수++
}
}
노말과 같은 레이어 요소는 아래와 같은 다양한 방법으로 메쉬에 표면에 매핑 될 수 있습니다.
- 제어점(control point): eByControlPoint
- polygon vertex: eByPolygonVertex
- etc...
매핑 모드는 FbxLayerElement::GetMappingMode() 멤버 함수로 알 수 있습니다.
// 정점 노말을 읽는 함수
vec3 ReadNormal(const FbxMesh* mesh, int controlPointIndex, int vertexCounter)
{
if (mesh->GetElementNormalCount() < 1) // 노말의 개수를 센다.
std::cout << "No normals!" << std::endl;
const FbxGeometryElementNormal* vertexNormal = mesh->GetElementNormal(0); // 노말 획득
vec3 result; // 노말 벡터를 저장할 벡터
switch(vertexNormal->GetMappingMode) // 매핑 모드
{
case FbxGeometryElement::eByControlPoint:
// control point mapping
break;
case FbxGeometryElement::eByPolygonVertex:
// polygon vertex mapping
}
return result;
}
제어점(control point): eByControlPoint에 매핑된 경우
각 제어점(정점)마다 하나의 매핑 좌표가 있음울 의미합니다.
노말 벡터의 배열과 제어점의 배열이 주어지면 노말 벡터의 배열이 제어점의 배열로 참조되는 방법을 알 수 있습니다.
참조되는 방법은 GetReferenceMode() 멤버 함수로 알 수 있으며, 아래와 같은 참조 모드를 가지고 있습니다.
- FbxLayerElement::eDirect : 이것은 n 번째 요소에 대한 매핑 정보가 FbxLayerElementTemplate::mDirectArray서의 n번째 위치에서 발견되었음을 나타냅니다.
- FbxLayerElement::eIndexToDirect : 이것은 FbxLayerElementTemplate::mIndexArray의 각 요소에 FbxLayerElementTemplate::mDirectArray의 요소를 나타내는 인덱스가 있음을 나타냅니다.
- etc..
// 정점 노말을 읽는 함수
vec3 ReadNormal(const FbxMesh* mesh, int controlPointIndex, int vertexCounter)
{
if (mesh->GetElementNormalCount() < 1) // 노말의 개수를 센다.
std::cout << "No normals!" << std::endl;
const FbxGeometryElementNormal* vertexNormal = mesh->GetElementNormal(0); // 노말 획득
vec3 result; // 노말 벡터를 저장할 벡터
switch(vertexNormal->GetMappingMode) // 매핑 모드
{
case FbxGeometryElement::eByControlPoint:
// control point mapping
switch (vertexNormal->GetReferenceMode())
{
case FbxGeometryElement::eDirect:
{
result.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(controlPointIndex).mData[0]);
result.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(controlPointIndex).mData[1]);
result.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(controlPointIndex).mData[2]);
}
break;
case FbxGeometryElement::eIndexToDirect:
{
int index = vertexNormal->GetIndexArray().GetAt(controlPointIndex); // 인덱스를 얻어온다.
result.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[0]);
result.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[1]);
result.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[2]);
}
break;
break;
case FbxGeometryElement::eByPolygonVertex:
// polygon vertex mapping
}
return result;
}
polygon vertex: eByPolygonVertex에 매핑된 경우
각 꼭지점(정점)마다 하나의 매핑 좌표가 있음울 의미합니다.
switch(vertexNormal->GetMappingMode) // 매핑 모드
{
case FbxGeometryElement::eByControlPoint:
// control point mapping
switch (vertexNormal->GetReferenceMode())
{
/* 생략 */
break;
case FbxGeometryElement::eByPolygonVertex:
// polygon vertex mapping
switch (vertexNormal->GetReferenceMode())
{
case FbxGeometryElement::eDirect:
{
result.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(vertexCounter).mData[0]);
result.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(vertexCounter).mData[1]);
result.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(vertexCounter).mData[2]);
}
break;
case FbxGeometryElement::eIndexToDirect:
{
int index = vertexNormal->GetIndexArray().GetAt(vertexCounter); // 인덱스를 얻어온다.
result.x = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[0]);
result.y = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[1]);
result.z = static_cast<float>(vertexNormal->GetDirectArray().GetAt(index).mData[2]);
}
break;
break;
}