• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Paul C Skertich

Texture UVs on FBX mesh are foo bared

12 posts in this topic

I ventured into loading FBX Meshes do to the ability for morph targets, skeletal mesh animation and other neat stuff that we all love. However, tutorials on FBX SDK are hard to come by like finding the last milk in a apocolypic future store. I grabbed some samples from others and somehow miracably able to create a mesh. However, the UV's aren't right.

 

As sceen in the attachment.  I looked at it closely and it appears to me that the UV's are using something other than the UV's. The code i have is:

for (int j = 0; j < meshArray.Size(); j++) {

			vCount = meshArray[j]->GetControlPointsCount();

			m_vertices = new myVertex[vCount];
			Face face;
			 polygonCount = meshArray[j]->GetPolygonVertexCount() / 3;
			numIndices = meshArray[j]->GetPolygonVertexCount();

			FbxVector4 *vert = meshArray[j]->GetControlPoints();
			int arrayIndex = 0;


			//memcpy(vert, meshArray[j]->GetControlPoints(), sizeof(FbxVector4)* vCount);


			for (int i = 0; i < polygonCount; i++) {
				for (unsigned int k = 0; k < 3; k++) {
					int index = 0;
					FbxVector4 fbxNorm(0, 0, 0, 0);
					FbxVector2 fbxUV(0, 0);
					FbxVector4 Vers(0, 0, 0, 0);

					FbxStringList UVStringNames;
					meshArray[j]->GetUVSetNames(UVStringNames);

					bool texCoordFound = false;
					face.indices[k] = index = meshArray[j]->GetPolygonVertex(i, k);
					Vers = vert[index];
					m_vertices[index].position = XMFLOAT4(Vers.mData[0],Vers.mData[2],Vers.mData[1],0.0f);
					
					meshArray[j]->GetPolygonVertexNormal(i, k, fbxNorm);
					m_vertices[index].normal = XMFLOAT3(fbxNorm.mData[0], fbxNorm.mData[2], fbxNorm.mData[1]);

					FbxLayerElementUV* fbxLayerUV = meshArray[j]->GetLayer(0)->GetUVs();
					if (fbxLayerUV) {
						int fbxUVIndex = 0;
						
						switch (fbxLayerUV->GetMappingMode())
						{
						case FbxLayerElement::eByControlPoint :
							fbxUVIndex = face.indices[k];
							break;
						case FbxLayerElement::eByPolygonVertex :
							fbxUVIndex = meshArray[j]->GetTextureUVIndex(i, k, FbxLayerElement::eTextureDiffuse);
							break;
						}
						fbxUV = fbxLayerUV->GetDirectArray().GetAt(fbxUVIndex);
					}
					m_vertices[index].texture = XMFLOAT2(fbxUV.mData[0], fbxUV.mData[1]);
	
				}
				Faces.push_back(face);

			}

		}

		int indexCount = Faces.size() * 3;
		indices = new unsigned long[indexCount];
		int indicie = 0;
		for (unsigned int i = 0; i < Faces.size(); ++i) {
			indices[indicie++] = Faces[i].indices[2];
			indices[indicie++] = Faces[i].indices[1];
			indices[indicie++] = Faces[i].indices[0];
		}
		Faces.clear();

Perhaps the indices aren't really well. I believe I switched the order of how the indices are drawn for some reason but can't remember why because I moved on to MD5 mesh and MD5 animation loading. However, unhappy with loading MD5 and want to continue looking into how I can correct the FBX mesh's texture coordiants.

 

I'll also look at the viewScene sample that came with the SDK as well in the meantime.

0

Share this post


Link to post
Share on other sites

Also I provided some visual debugging for the UV Textures in the shader.  The incorrect one is the first one. The corrected UV are in my own model file format.

 

It appears to me I have the UV's reversed and the coloration in black is where the UV coords are messed up representing 0.0f perhaps?

0

Share this post


Link to post
Share on other sites

Since you have access to the texture coordinate CPU side, break into the code or print the uv values while the model is being loaded to verify that they are on par with your loader. I've seen cases with 3DS Max, where the sign of the texture coordinate is flip due to wrapping...

2

Share this post


Link to post
Share on other sites

Since you have access to the texture coordinate CPU side, break into the code or print the uv values while the model is being loaded to verify that they are on par with your loader. I've seen cases with 3DS Max, where the sign of the texture coordinate is flip due to wrapping...

 Alright, I'm tweaking the code now to see if I see anything different. If not then I'll output to file.

0

Share this post


Link to post
Share on other sites

Are you converting the uv origin? Your 3D package probably thinks the origin is the lower-left corner, whereas DX puts the origin at the upper-left corner:

for( auto& vertex : mesh.vertex_buffer )
{
     // other xforms...

     if( gSettings.FlipTexV )
     {
          vertex.texcoord.y = 1.0f - vertex.texcoord.y;
     }
}

And here's how I extract the uv from FBX:

                        //---------------------------------------------------------
			// uv
			//---------------------------------------------------------
			FbxVector2 uv;
			FbxGeometryElementUV* leUV = mpMesh->GetElementUV( 0 );
			if( leUV == nullptr )
			{
				ERRPRINT( "No UV layers in mesh. Aborting." );
				return false;
			}
			else
			{
				switch( leUV->GetMappingMode() )
				{
					case FbxGeometryElement::eByControlPoint:
					{
						switch( leUV->GetReferenceMode() )
						{
							case FbxGeometryElement::eDirect:
							uv = leUV->GetDirectArray().GetAt( cp_index );
							break;
							case FbxGeometryElement::eIndexToDirect:
							{
								int id = leUV->GetIndexArray().GetAt( cp_index );
								uv = leUV->GetDirectArray().GetAt( id );
							}
							break;
							default:
								break;
						}
					}
					break;

					case FbxGeometryElement::eByPolygonVertex:
					{
						int lTextureUVIndex = mpMesh->GetTextureUVIndex( i, j );
						switch( leUV->GetReferenceMode() )
						{
							case FbxGeometryElement::eDirect:
							case FbxGeometryElement::eIndexToDirect:
							{
								uv = leUV->GetDirectArray().GetAt( lTextureUVIndex );
							}
							break;
							default:
								break;
						}
					}
					default:
						break;
				}
				vertex.texcoord = Vec2FromFbx( &uv );
			}
1

Share this post


Link to post
Share on other sites

 

Are you converting the uv origin? Your 3D package probably thinks the origin is the lower-left corner, whereas DX puts the origin at the upper-left corner:

for( auto& vertex : mesh.vertex_buffer )
{
     // other xforms...

     if( gSettings.FlipTexV )
     {
          vertex.texcoord.y = 1.0f - vertex.texcoord.y;
     }
}

And here's how I extract the uv from FBX:

                        //---------------------------------------------------------
			// uv
			//---------------------------------------------------------
			FbxVector2 uv;
			FbxGeometryElementUV* leUV = mpMesh->GetElementUV( 0 );
			if( leUV == nullptr )
			{
				ERRPRINT( "No UV layers in mesh. Aborting." );
				return false;
			}
			else
			{
				switch( leUV->GetMappingMode() )
				{
					case FbxGeometryElement::eByControlPoint:
					{
						switch( leUV->GetReferenceMode() )
						{
							case FbxGeometryElement::eDirect:
							uv = leUV->GetDirectArray().GetAt( cp_index );
							break;
							case FbxGeometryElement::eIndexToDirect:
							{
								int id = leUV->GetIndexArray().GetAt( cp_index );
								uv = leUV->GetDirectArray().GetAt( id );
							}
							break;
							default:
								break;
						}
					}
					break;

					case FbxGeometryElement::eByPolygonVertex:
					{
						int lTextureUVIndex = mpMesh->GetTextureUVIndex( i, j );
						switch( leUV->GetReferenceMode() )
						{
							case FbxGeometryElement::eDirect:
							case FbxGeometryElement::eIndexToDirect:
							{
								uv = leUV->GetDirectArray().GetAt( lTextureUVIndex );
							}
							break;
							default:
								break;
						}
					}
					default:
						break;
				}
				vertex.texcoord = Vec2FromFbx( &uv );
			}

I'll give it a shot - as far as origion. I did flip the V to 1.0f - texcoord.mData[1]

 

I'll try out your code in a bit and I'll let you know what's up. Why are FBX so hard to work with or is the lack of tutorials?

0

Share this post


Link to post
Share on other sites

I have the Max 3DS SDK and I'm dying to know how to create export my own custom file format and put together what I desire. However, that's for another thread. I'll let you know what's going on and take more debug shots if needed, Scott.

0

Share this post


Link to post
Share on other sites

Interestingly enough, I am able to write out the uV and I checked them with copy of the FBX as FBX ASCII file. Here's the UV in a text document the program wrote out:

0.709074,0.551956
0.709074,0.551956
0.709074,1
1,0.551956
0.418147,0.551956
0.418147,0.551956
0.418147,1
0.709074,0.551956

And here's the section where the UVS are in the mesh file:

LayerElementUV: 0 {
			Version: 101
			Name: "UVChannel_1"
			MappingInformationType: "ByPolygonVertex"
			ReferenceInformationType: "IndexToDirect"
			UV: *48 {
				a: 0.418147087097168,0,0.418147087097168,0.448043644428253,0,0.448043644428253,0,0,0.418147087097168,0.896087288856506,0,0.896087288856506,0,0.448043644428253,0.418147087097168,0.448043644428253,0.999999940395355,0,0.999999940395355,0.418147087097168,0.709073543548584,0.418147087097168,0.709073543548584,0,0.709073543548584,0.448043644428253,0.709073543548584,0.896087288856506,0.418147087097168,0.896087288856506,0.418147087097168,0.448043644428253,0.999999940395355,0.448043644428253,0.999999940395355,0.866190731525421,0.709073543548584,0.866190731525421,0.709073543548584,0.448043644428253,0.709073543548584,0,0.709073543548584,0.448043644428253,0.418147087097168,0.448043644428253,0.418147087097168,0
			} 
			UVIndex: *36 {
				a: 3,0,2,0,1,2,6,7,4,6,4,5,10,11,8,10,8,9,14,15,12,14,12,13,18,19,16,18,16,17,22,23,20,22,20,21
			} 
		}

Yeah, I have the V flipped. Maybe it's a index things?

 

I did what Scott said and checked the code to this: I'm confused on the whole cp_index though does he mean index what I have in my previous code?

FbxGeometryElementUV *uv = meshArray[j]->GetElementUV(0);
					if (uv == nullptr){
						//no texture uv detected.
						MessageBox(0, L"No UVs.", L"", 0);
						return false;
					}
					else {
						switch (uv->GetMappingMode())
						{
						case FbxGeometryElement::eByControlPoint:
						{
							switch (uv->GetReferenceMode())
							{
							case FbxGeometryElement::eDirect:
								fbxUV = uv->GetDirectArray().GetAt(index);
								
								break;
							case FbxGeometryElement::eIndexToDirect:{
								int id = uv->GetIndexArray().GetAt(index);
								fbxUV = uv->GetDirectArray().GetAt(id);

							}
								break;

							default:
								break;
							}
						}
							break;

						case FbxGeometryElement::eByPolygonVertex:
						{
							int lTextureUVIndex = meshArray[j]->GetTextureUVIndex(i, k);
							switch (uv->GetReferenceMode())
							{
							case FbxGeometryElement::eDirect:
								break;
							case FbxGeometryElement::eIndexToDirect: {
								fbxUV = uv->GetDirectArray().GetAt(lTextureUVIndex);

							} break;

							}

						}
						default:
							break;
						}
					}
					m_vertices[index].texture = XMFLOAT2(fbxUV.mData[0], 1.0f - fbxUV.mData[1]);

				}
				Faces.push_back(face);

			}

		}

		int indexCount = Faces.size() * 3;
		indices = new unsigned long[indexCount];
		int indicie = 0;
		for (unsigned int i = 0; i < Faces.size(); ++i) {
			indices[indicie++] = Faces[i].indices[2];
			indices[indicie++] = Faces[i].indices[1];
			indices[indicie++] = Faces[i].indices[0];
		}
		Faces.clear();

It's a possible indexing issue, yes?

0

Share this post


Link to post
Share on other sites

Apologies; the cp_index is part of the overall loop of how I extract the data. I only posted the UV snippet above. Here's the whole thing for how I extract the vertex data and the subset of material properties I care about:

// This is where things start to get nasty...

bool Import_FBX::ExtractGeometry()
{
	// control points
	uint32 countCP = mpMesh->GetControlPointsCount();
	control_points.reserve( countCP );
	FbxVector4* ControlPoints = mpMesh->GetControlPoints();

	for( uint32 i = 0; i < countCP; i++ )
	{
		control_points.push_back( Vec3FromFbx( &ControlPoints[i] ) );
	}

	// polygons
	uint32 countPolys = mpMesh->GetPolygonCount();
	polygons.reserve( countPolys );

	int vertexID = 0;
	for( uint32 i = 0; i < countPolys; i++ )
	{
		xPolygon polygon;

		uint32 countPolyVerts = mpMesh->GetPolygonSize( i );
		if( countPolyVerts < 3 || countPolyVerts > 4 ) // only tris and quads for now
		{
			ERRPRINT("Found poly (index %d) with unsupported vertex count: %d", i, countPolyVerts);
			return false;
		}
		for( uint32 j = 0; j < countPolyVerts; j++ )
		{
			vertex_type vertex;

			//---------------------------------------------------------
			// position
			//---------------------------------------------------------
			int cp_index = mpMesh->GetPolygonVertex( i, j );
			FbxVector4 cp = ControlPoints[cp_index];
			vertex.position = Vec3FromFbx( &cp );


			//---------------------------------------------------------
			// normal
			//---------------------------------------------------------
			FbxVector4 fbxNormal;
			FbxGeometryElementNormal* leNormal = mpMesh->GetElementNormal( 0 );
			if( leNormal == nullptr )
			{
//				ERRPRINT("No normals in mesh");
			}
			else
			{
				FbxLayerElement::EMappingMode normals_MapMode = leNormal->GetMappingMode();
				if( normals_MapMode == FbxGeometryElement::eByPolygonVertex )
				{
					switch( leNormal->GetReferenceMode() )
					{
					case FbxGeometryElement::eDirect:
						fbxNormal = leNormal->GetDirectArray().GetAt( vertexID );
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leNormal->GetIndexArray().GetAt( vertexID );
						fbxNormal = leNormal->GetDirectArray().GetAt( id );
					}
						break;
					default:
						break;
					}
				}
				else if( normals_MapMode == FbxGeometryElement::eByControlPoint )
				{
					switch( leNormal->GetReferenceMode() )
					{
					case FbxGeometryElement::eDirect:
						fbxNormal = leNormal->GetDirectArray().GetAt( cp_index );
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leNormal->GetIndexArray().GetAt( cp_index );
						fbxNormal = leNormal->GetDirectArray().GetAt( id );
					}
						break;
					default:
						break;
					}
				}
				vertex.normal = Vec3FromFbx( &fbxNormal );
			}

			//---------------------------------------------------------
			// tangent
			//---------------------------------------------------------
			FbxVector4 fbxTangent;
			FbxGeometryElementTangent* leTangent = mpMesh->GetElementTangent( 0 );
			if( leTangent == nullptr )
			{
//				ERRPRINT("No tangents in mesh");
			}
			else
			{
				FbxLayerElement::EMappingMode tangent_MapMode = leTangent->GetMappingMode();
				if( tangent_MapMode == FbxGeometryElement::eByPolygonVertex )
				{
					switch( leTangent->GetReferenceMode() )
					{
					case FbxGeometryElement::eDirect:
						fbxTangent = leTangent->GetDirectArray().GetAt( vertexID );
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leTangent->GetIndexArray().GetAt( vertexID );
						fbxTangent = leTangent->GetDirectArray().GetAt( id );
					}
						break;
					default:
						break;
					}
				}
				else if( tangent_MapMode == FbxGeometryElement::eByControlPoint )
				{
					switch( leTangent->GetReferenceMode() )
					{
					case FbxGeometryElement::eDirect:
						fbxTangent = leTangent->GetDirectArray().GetAt( cp_index );
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leTangent->GetIndexArray().GetAt( cp_index );
						fbxTangent = leTangent->GetDirectArray().GetAt( id );
					}
						break;
					default:
						break;
					}
				}
				vertex.tangent = Vec3FromFbx( &fbxTangent );
			}



			//---------------------------------------------------------
			// binormal
			//---------------------------------------------------------
			FbxVector4 fbxBinormal;
			FbxGeometryElementBinormal* leBinormal = mpMesh->GetElementBinormal( 0 );
			if( leBinormal == nullptr )
			{
//				ERRPRINT( "No binormals in mesh" );
			}
			else
			{
				FbxLayerElement::EMappingMode binormal_MapMode = leTangent->GetMappingMode();
				if( binormal_MapMode == FbxGeometryElement::eByPolygonVertex )
				{
					switch( leBinormal->GetReferenceMode() )
					{
					case FbxGeometryElement::eDirect:
						fbxBinormal = leBinormal->GetDirectArray().GetAt( vertexID );
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leBinormal->GetIndexArray().GetAt( vertexID );
						fbxBinormal = leBinormal->GetDirectArray().GetAt( id );
					}
						break;
					default:
						break;
					}
				}
				else if( binormal_MapMode == FbxGeometryElement::eByControlPoint )
				{
					switch( leBinormal->GetReferenceMode() )
					{
					case FbxGeometryElement::eDirect:
						fbxBinormal = leBinormal->GetDirectArray().GetAt( cp_index );
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leBinormal->GetIndexArray().GetAt( cp_index );
						fbxBinormal = leBinormal->GetDirectArray().GetAt( id );
					}
						break;
					default:
						break;
					}
				}
				vertex.binormal = Vec3FromFbx( &fbxBinormal );
			}



			//---------------------------------------------------------
			// uv
			//---------------------------------------------------------
			FbxVector2 uv;
			FbxGeometryElementUV* leUV = mpMesh->GetElementUV( 0 );
			if( leUV == nullptr )
			{
				ERRPRINT( "No UV layers in mesh. Aborting." );
				return false;
			}
			else
			{
				switch( leUV->GetMappingMode() )
				{
					case FbxGeometryElement::eByControlPoint:
					{
						switch( leUV->GetReferenceMode() )
						{
							case FbxGeometryElement::eDirect:
							uv = leUV->GetDirectArray().GetAt( cp_index );
							break;
							case FbxGeometryElement::eIndexToDirect:
							{
								int id = leUV->GetIndexArray().GetAt( cp_index );
								uv = leUV->GetDirectArray().GetAt( id );
							}
							break;
							default:
								break;
						}
					}
					break;

					case FbxGeometryElement::eByPolygonVertex:
					{
						int lTextureUVIndex = mpMesh->GetTextureUVIndex( i, j );
						switch( leUV->GetReferenceMode() )
						{
							case FbxGeometryElement::eDirect:
							case FbxGeometryElement::eIndexToDirect:
							{
								uv = leUV->GetDirectArray().GetAt( lTextureUVIndex );
							}
							break;
							default:
								break; 
						}
					}
					default:
						break;
				}
				vertex.texcoord = Vec2FromFbx( &uv );
			}
			polygon.vertices.push_back( vertex );
			++vertexID;
		}

		polygon.vertex_count = polygon.vertices.size();
		polygons.push_back( polygon );
	}
	return true;
}

bool Import_FBX::ExtractMaterials()
{
	//------------------------------------------------------------
	// Initialize material list and get material index per polygon
	//------------------------------------------------------------
	int lMtrlCount = mpNode->GetMaterialCount();
	for( int i = 0; i < lMtrlCount; i++ )
	{
		SerializedMaterial m;
		m.id = i;
		materials.push_back( m );
	}
	for( int l = 0; l < mpMesh->GetElementMaterialCount(); l++ )
	{
		FbxGeometryElementMaterial* leMat = mpMesh->GetElementMaterial( l );
		if( leMat != nullptr )
		{
			if( leMat->GetReferenceMode() == FbxGeometryElement::eIndex || leMat->GetReferenceMode() == FbxGeometryElement::eIndexToDirect )
			{
				int lIndexArrayCount = leMat->GetIndexArray().GetCount();
				for( int i = 0; i < lIndexArrayCount; i++ )
				{
					polygons[i].material_id = leMat->GetIndexArray().GetAt( i );
				}
			}
		}
	}

	//----------------------------------------------------------------
	// From each material extract the diffuse texture and uv repeat
	// The rest of the maps and properties will be set in our own tool
	//----------------------------------------------------------------
	int lMaterialIndex;
    FbxProperty lProperty;
	int lNbMat = mpNode->GetSrcObjectCount<FbxSurfaceMaterial>();
	for( lMaterialIndex = 0; lMaterialIndex < lNbMat; lMaterialIndex++ )
	{
		FbxSurfaceMaterial *lMaterial = mpNode->GetSrcObject<FbxSurfaceMaterial>( lMaterialIndex );
		if( lMaterial != nullptr )
		{
			SerializedMaterial& material = materials[lMaterialIndex];
			strcpy( material.tex_0, "default.dds" );
			material.texture_flags |= tex_Diffuse;

			lProperty = lMaterial->FindProperty( FbxLayerElement::sTextureChannelNames[0] );
			cstring propertyName = lProperty.GetNameAsCStr();
			propertyName.makeLower();
			if( propertyName == "diffusecolor" )
			{
				FbxTexture* lTexture = lProperty.GetSrcObject<FbxTexture>( 0 );
				if( lTexture )
				{
					FbxFileTexture *lFileTexture = FbxCast<FbxFileTexture>( lTexture );
					if( lFileTexture != nullptr )
					{
						//TODO: Revisit when archives are reworked
						cstring texname1 = lFileTexture->GetRelativeFileName();
						cstring texname2 = lFileTexture->GetFileName();

						strcpy( material.tex_0, texname1.c_str() );
						material.map_scales.x = static_cast<float>( lFileTexture->GetScaleU() );
						material.map_scales.y = static_cast<float>( lFileTexture->GetScaleV() );
					}
				}
			}
		}
	}
}

xPolygon is just a simple struct that contains the vertex array for that poly and some helper functions for calculating tangents, centroid; stuff like that. Basically I extract the FBX into my own list of polys, do whatever processing I want on them, and then create the per-material submeshes I'll write out to the model format, from that list of polys.

Edited by Scott Bruno
1

Share this post


Link to post
Share on other sites

I'll have to check out your code. Of what I've understand is that you get the control points which are the vertices inside the mesh. You get the total, reserve a vector or some type of stl container then stuff the control points inside that container. When down to the nitty gritty of getting the polygon count size whether the mesh is quad or triangulated. The local variable index or cp_index which is where the index of the vertice's (control points) are...Responsible of getting the normals, bitangents, texture uv's. So, polygon is indices in FBX terms, right? so for instance myMesh->GetPolygonSize() would return the number of indices or would it be more myMesh->GetPolygonVertexCount() to receive indice count or the number of polygons inside the mesh?

 

I think control points and polygons are tripping me a bit because to me loading a simple box FBX mesh isn't like loading a OBJ file. I understand it's composed of vertices, normals, tangents, bitangents and uv maps as in every model format kind of similar does. Tangents and bitangents have to be calculated when loading OBJ files.

 

Anyways, I'm going to have a look at your code - my brain has to cool down from storing a lot new information.

0

Share this post


Link to post
Share on other sites

Of what I've understand is that you get the control points which are the vertices inside the mesh.

Yes. Control points = vertices.

So, polygon is indices in FBX terms, right?

No, they are faces (see below).

When down to the nitty gritty of getting the polygon count size whether the mesh is quad or triangulated.

Meshes are always stored as an array of faces and these faces are stored as triangle fans. These need to be triangulated, stored, and reduced (eliminate duplicates) manually.
For each face you have 1 triangle fan with any number of triangles in it. Converting a triangle fan into a triangle list is trivial.



GetPolygonCount() returns the number of faces.
Here is a sample from my book that shows how to loop over each face in the mesh and get the start and total of each.

We now have something to use with an std::map to sort faces and their vertices on a per-material basis. Next, inside of CMesh::LoadMesh(), we declare the map as a local and begin to go over the faces of the mesh. Each face represents a triangle fan, but if we kept them in this format we would have to issue one draw call for each face, with each draw call rendering only a few triangles. We want to pack as many triangles into each draw call as we can, so we convert each face into a triangle list so that many faces can be packed into a single vertex buffer and drawn at once. The Autodesk® FBX® SDK refers to faces as polygons (which is not uncommon) and each polygon/face has a starting index (into a pool of polygon/face indices stored by the mesh) and number of consecutive indices that belong to that polygon/face. The skeleton of our loop over the faces is added to the end of CMesh::LoadMesh().
Listing 15-17 FCMesh.cpp

    // #include <map> added to the header.
    std::map<FC_MATERIAL_KEY, FC_FACE_VERTEX_PAIR> mBuckets;
    std::vector<FC_FACE::FC_FACE_VERTEX> vVertexPool;
    u32 ui32FaceCount = m_pfmMesh->GetPolygonCount();	
    for ( u32 I = 0; I < ui32FaceCount; ++I ) {
        u32 ui32PolyTotal = m_pfmMesh->GetPolygonSize( I );
        u32 ui32PolyStart = m_pfmMesh->GetPolygonVertexIndex( I );
    }	



The only hard part is how you have to index into the pools of normals, UV’s, colors, etc., as there are 2 possible indices you can use (the index of the control point directly or the result of indexing the control point index into another array) and once you have that index you use it to either directly index into the pool or once again get an intermediate pool index.

In Scott Bruno’s code, the if checks (“normals_MapMode == FbxGeometryElement::eByPolygonVertex” and “normals_MapMode == FbxGeometryElement::eByControlPoint”) determine which index you are supposed to use (notice the use of vertexID in one case and cp_index in the other) and then the switch cases on leNormal->GetReferenceMode() determine how to use that index (directly into the pool or into a pool of indices and then into the pool).



These are basically the most confusing points in the FBX SDK, until you get to animation blend weights and indices and building a proper local matrix for all the meshes.
Point of advice: Don’t just export only the meshes but the whole hierarchy. This has nothing to do with the FBX® SDK, but any 3D file format you make period. It is the only way to ensure animations run both properly and efficiently. Ignore “unwanted” data such as group nodes at your own risk.


L. Spiro
2

Share this post


Link to post
Share on other sites

Thanks again everyone. I'll let everyone know how it goes.Meantime, I'll be looking up the samples inside the FBX SDK. I'll be interested in your book L. Spiro when will it be released or has it been released already?

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0