I tried to build what you described. I couldn't do it. I need help!
Loading FBX with Directx 11
@galop1n I managed to write std::map code. But my std::map code doesn't work.
it doesn't generate duplicate vertices. For example, when I load Plane.fbx, it gives me the vertex array of
-5 -5 0
5 -5 0
-5 5 0
5 5 0
0 0 0
0 0 0
the index array is simply, 0, 1, 2, 3, 4, 5 not 0, 1, 2, 2, 1, 3
Can you help me?
bool operator < ( const FBXVTX &lValue, const FBXVTX &rValue)
{
if (lValue.Position.x != rValue.Position.x) return(lValue.Position.x < rValue.Position.x);
if (lValue.Position.y != rValue.Position.y) return(lValue.Position.y < rValue.Position.y);
if (lValue.Position.z != rValue.Position.z) return(lValue.Position.z < rValue.Position.z);
if (lValue.TextureCoord.x != rValue.TextureCoord.x) return(lValue.TextureCoord.x < rValue.TextureCoord.x);
if (lValue.TextureCoord.y != rValue.TextureCoord.y) return(lValue.TextureCoord.y < rValue.TextureCoord.y);
if (lValue.Normal.x != rValue.Normal.x) return(lValue.Normal.x < rValue.Normal.x);
if (lValue.Normal.y != rValue.Normal.y) return(lValue.Normal.y < rValue.Normal.y);
return(lValue.Normal.z < rValue.Normal.z);
}
struct FBXVTX
{
XMFLOAT3 Position;
XMFLOAT2 TextureCoord;
XMFLOAT3 Normal;
};
std::map< FBXVTX, int > myVertsMap;
std::vector<FBXVTX> myVerts;
std::vector<int> myInds;
HRESULT FBXLoader::Open(HWND hWnd, char* Filename, bool UsePositionOnly)
{
HRESULT hr = S_OK;
if (FBXM)
{
FBXIOS = FbxIOSettings::Create(FBXM, IOSROOT);
FBXM->SetIOSettings(FBXIOS);
FBXI = FbxImporter::Create(FBXM, "");
if (!(FBXI->Initialize(Filename, -1, FBXIOS)))
{
hr = E_FAIL;
MessageBox(hWnd, (wchar_t*)FBXI->GetStatus().GetErrorString(), TEXT("ALM"), MB_OK);
}
FBXS = FbxScene::Create(FBXM, "REALMS");
if (!FBXS)
{
hr = E_FAIL;
MessageBox(hWnd, TEXT("Failed to create the scene"), TEXT("ALM"), MB_OK);
}
if (!(FBXI->Import(FBXS)))
{
hr = E_FAIL;
MessageBox(hWnd, TEXT("Failed to import fbx file content into the scene"), TEXT("ALM"), MB_OK);
}
FbxAxisSystem OurAxisSystem = FbxAxisSystem::DirectX;
FbxAxisSystem SceneAxisSystem = FBXS->GetGlobalSettings().GetAxisSystem();
if(SceneAxisSystem != OurAxisSystem)
{
FbxAxisSystem::DirectX.ConvertScene(FBXS);
}
FbxSystemUnit SceneSystemUnit = FBXS->GetGlobalSettings().GetSystemUnit();
if( SceneSystemUnit.GetScaleFactor() != 1.0 )
{
FbxSystemUnit::cm.ConvertScene( FBXS );
}
if (FBXI)
FBXI->Destroy();
FbxNode* MainNode = FBXS->GetRootNode();
int NumKids = MainNode->GetChildCount();
FbxNode* ChildNode = NULL;
for (int i=0; i<NumKids; i++)
{
ChildNode = MainNode->GetChild(i);
FbxNodeAttribute* NodeAttribute = ChildNode->GetNodeAttribute();
if (NodeAttribute->GetAttributeType() == FbxNodeAttribute::eMesh)
{
FbxMesh* Mesh = ChildNode->GetMesh();
if (UsePositionOnly)
{
NumVertices = Mesh->GetControlPointsCount();//number of vertices
MyV = new XMFLOAT3[NumVertices];
for (DWORD j = 0; j < NumVertices; j++)
{
FbxVector4 Vertex = Mesh->GetControlPointAt(j);//Gets the control point at the specified index.
MyV[j] = XMFLOAT3((float)Vertex.mData[0], (float)Vertex.mData[1], (float)Vertex.mData[2]);
}
NumIndices = Mesh->GetPolygonVertexCount();//number of indices
MyI = (DWORD*)Mesh->GetPolygonVertices();//index array
}
else
{
FbxLayerElementArrayTemplate<FbxVector2>* uvVertices = NULL;
Mesh->GetTextureUV(&uvVertices);
int idx = 0;
for (int i = 0; i < Mesh->GetPolygonCount(); i++)//polygon(=mostly triangle) count
{
for (int j = 0; j < Mesh->GetPolygonSize(i); j++)//retrieves number of vertices in a polygon
{
FBXVTX myVert;
int p_index = 3*i+j;
int t_index = Mesh->GetTextureUVIndex(i, j);
FbxVector4 Vertex = Mesh->GetControlPointAt(p_index);//Gets the control point at the specified index.
myVert.Position = XMFLOAT3((float)Vertex.mData[0], (float)Vertex.mData[1], (float)Vertex.mData[2]);
FbxVector4 Normal;
Mesh->GetPolygonVertexNormal(i, j, Normal);
myVert.Normal = XMFLOAT3((float)Normal.mData[0], (float)Normal.mData[1], (float)Normal.mData[2]);
FbxVector2 uv = uvVertices->GetAt(t_index);
myVert.TextureCoord = XMFLOAT2((float)uv.mData[0], (float)uv.mData[1]);
if ( myVertsMap.find( myVert ) != myVertsMap.end() )
myInds.push_back( myVertsMap[ myVert ]);
else
{
myVertsMap.insert( std::pair<FBXVTX, int> (myVert, idx ) );
myVerts.push_back(myVert);
myInds.push_back(idx);
idx++;
}
}
}
}
}
}
}
else
{
hr = E_FAIL;
MessageBox(hWnd, TEXT("Failed to create the FBX Manager"), TEXT("ALM"), MB_OK);
}
return hr;
}
@isu diss I think you should work a little bit on your manners here in the forum ;-)
Anyways, when the UV is stored per index you have to resolve this list first and duplicate the vertices if more than one index is using the same vertex. You need a list of homogenous pairs of vertex and texture coordinate.
x y z u v, x y z u v, ....
So everytime you are "reusing" a vertex in the indices you have to copy it and also modify the index in the list to the new copied one.
When you just want to load the model and don't do this for educational purposes, may have a look at Assimp. This library is doing all the hard stuff of nearly all 3D-formats for you and gives you a simpler data structure which can be just easily.
@AuskennfuchsThanks for your advice on manners. @galop1nThanks for your big help. I finally managed to do it. std::map code works like a charm. All I did is change p_index to its correct index, the value, returned by Mesh->GetPolygonVertex(i, j) and then magic happned. Anyone who wishes to make a fbx loader, can use my code. It works!!! Thanks everybody for support. Case closed.