• Advertisement
Sign in to follow this  

Fbx , UV and Normal per control point

This topic is 3034 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello. FIrst of all I'm going to post the code for extracting vertices for creating a vertex and index buffer in XNA/Direct 3D

KFbxMatrix
Importer::GetNodeTransform(fbxsdk_20102::KFbxNode *pNode)
{
	KFbxVector4 t = pNode->GetGeometricTranslation(KFbxNode::eSOURCE_SET);
	KFbxVector4 s = pNode->GetGeometricScaling(KFbxNode::eSOURCE_SET);
	KFbxVector4 r = pNode->GetGeometricRotation(KFbxNode::eSOURCE_SET);
	KFbxMatrix offset (t,r,s);
	KFbxMatrix world = pNode->GetGlobalFromDefaultTake();
	KFbxMatrix transform = world * offset;

	return transform;
}
void
Importer::TriangulateNode( fbxsdk_20102::KFbxNode* pNode )
{
	KFbxMesh* pMesh = (KFbxMesh*) pNode->GetNodeAttribute();
	if( pMesh->IsTriangleMesh())
		return;

	KFbxGeometryConverter lConverter(m_pSdkManager);
	bool status = lConverter.TriangulateInPlace( pNode);

	if( !status)
		PrintError("TriangulateNode() - failed to triangulate!");


}

KFbxMatrix
Importer::GetNodeTransform(fbxsdk_20102::KFbxNode *pNode)
{
	KFbxVector4 t = pNode->GetGeometricTranslation(KFbxNode::eSOURCE_SET);
	KFbxVector4 s = pNode->GetGeometricScaling(KFbxNode::eSOURCE_SET);
	KFbxVector4 r = pNode->GetGeometricRotation(KFbxNode::eSOURCE_SET);
	KFbxMatrix offset (t,r,s);
	KFbxMatrix world = pNode->GetGlobalFromDefaultTake();
	KFbxMatrix transform = world * offset;

	return transform;
}

Importer::DoMesh( fbxsdk_20102::KFbxNode* pNode )
{
	if( pNode->GetNodeAttribute()->GetAttributeType() != KFbxNodeAttribute::eMESH)
		return;
	//Very important, we don't wan't to deal with quads or such, nice pointy triangles please
	
	TriangulateNode(pNode);
	KFbxMesh* pMesh = (KFbxMesh*) pNode->GetNodeAttribute();
	


	Mesh myMesh;
	myMesh.name = pNode->GetName();

	myMesh.transform = GetNodeTransform( pNode );

	int controlPointsCount = pMesh->GetControlPointsCount();
	KFbxVector4* pControlPoints = pMesh->GetControlPoints();
	
	for( int i =0; i<controlPointsCount; i++)
	{
		Vertex v;
		v.pos.x =pControlPoints.GetAt(0);
		v.pos.y =pControlPoints.GetAt(1);
		v.pos.z =pControlPoints.GetAt(2);
		myMesh.vertices.push_back(v);
	}
	int triangleCount = pMesh->GetPolygonCount();	
	
	
	for( int i = 0; i< triangleCount; i++)
	{
		int TriSize = pMesh->GetPolygonSize(i);//Should be 3

		for( int j =0; j<TriSize; j++)
		{			
			int index = pMesh->GetPolygonVertex(i,j);
			myMesh.indices.push_back(index);

		}
	}
//justa a struct Model that has a std vector with Meshes
m_model.meshes.push_back(myMesh);
for( int i = 0; i< pNode->GetChildCount(); i++)
	DoMesh(pNode->GetChild(i));




This is enough to render a model in wire frame. I tested it on tank.fbx(from XNA sample), humonoid.fbx from the FBX sdk and some random dragon that I found on the webb. all models work. now to the point. I would of course like to use normals and uv coords, shader effects won't be as fun with out them.. tank.fbx is my test model since I know that it's a game friendly model made for XNA. My problem is that when I get the normal/uv count from the mesh it's not one normal/uv per control point, its many more. the mapping mode is not eBY_CONTROL_POINT. There is a function: intRemapIndexTo (KFbxLayerElement::EMappingMode pNewMapping) so I tried :
pLayer->GetNormals()->RemapIndexTo( KFbxLayerElement::eBY_CONTROL_POINT);


but the function return -1 : In case the function cannot remap to the desired mode because of incompatible modes or unsupported modes, returns -1. I know that it's posible to get the uv's and normals per unique vertex some how. XNA must do it some how, I supose they use the FBX sdk? I also checked the custom model import sample from xna that import the tank as a .obj. The vertex count is exactly the same as I get. So any sugestions are deeply appreciated. //HermanssoN

Share this post


Link to post
Share on other sites
Advertisement
If it's any help here is the mesh data I get when parsing a mesh:



//this is data from mesh[0] in tank.fbx, named tank_geo

meshData.controlIndices; // 3558 int's

meshData.controlPoints; // 609 kfbxVector4's

meshData.normalIndices; // empty normals are not indexed

meshData.normals; // 3558 kfbxVector4's

meshData.uvCoords; // 1099 kfbxVector2's

meshData.uvIndices; // 3558 int's




The normal approach when using models in games, in this case, would be to have 609 unique vertices that each that has a pos,uv and normal and draw those using the one index buffer for the control points.
When I asked at the fbx forum at autodesk they sugested using several mesh buffers, but that sounds like something that maybe would work for a modelviever rather than a game, right ??

Share this post


Link to post
Share on other sites
Don't worry too much about the numbers. FBX maps vertices differently than you're likely used to. Consider a cube, which has 8 vertices. If you want hard-edged on the cube, you duplicate each vertex 3 times and give it a different normal. FBX stores the 8 positions (control points) in one buffer, and then stores the 24 normals in another buffer. So a "vertex" is nothing more than a bunch of indexes into the various buffers.

Of course, it depends on the different mapping modes, but you should get the idea. So what you want to do is take each one of these "index vertices" and build your own by referencing the proper information. For position and normal, they actually have functions in the KFbxMesh class which will give it to you, but if you also want to grab tangents and binormals, you'll need to grab the layer and figure out all the mapping modes.

I can look up the functions for you if you can't find them. I'd also recommend referencing the ContentExporter sample in the March and August DirectX SDK.

Share this post


Link to post
Share on other sites
cool, I had no idea that there was such a sample in the Direct X SDK.
I'm sure that this will heöp me alot, thanks!

Share this post


Link to post
Share on other sites
Well, I've checked out the direct x sdk sample. I't seems to use alot of direct X mesh stuff that I'm not faimiar with. How ever the goal of my litle project is to extract the model info and save its to file as a human readable format.

What I got from the sample was that they actualy created every triangle and once they got all triangles, performed optimizations.

with this in mind i collected my data like this:


struct FBXVertex
{
int index; //index to the control point array
Vec3 position;
Vec2 uv;
Vec3 normal;
};
struct FBXPolygon
{
int index; //index to the mesh polygon array
std::vector<FBXVertex>vertices;

};
struct FBXMesh
{
std::string materialRef;//just a string with a material surface name
std::vector<Vec3>controlPoints;
std::vector<FBXPolygon>polygons;


};




I fill this up and now need a nifty way to optimize the trinagles into vertex and index arrays.

I just examined a xna sample for XNA where they import the tank as a .obj file. One thing I noticed was that they used the built in feture MeshBuilder. I have no idea what that does internaly but I guess it does some optmixations like in the Direct X C++ samples.

Are there any generic algorithms for creating a vertex and index buffer from a list of triangles?
Another thing I noticed when reading abouh a collada importer was that if the render system was Direct 3D all UVs should be flipped.
Do I need to flip the uv's in the fbx file, is there some flag??

[Edited by - HermanssoN on November 2, 2009 6:28:56 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement