//-------------------------------------------------------------------------------------------------------------------------------------------
void transferNormals(FbxMesh* fbxMesh, Mesh* mesh){
    int numVertices = fbxMesh->GetControlPointsCount();
    FbxGeometryElementNormal* normals = fbxMesh->GetElementNormal(0);

    mesh->InitEmptyNormals(numVertices);
    for (int i = 0; i < numVertices; i++){
        FbxVector4 normal = normals->GetDirectArray().GetAt(i);
        mesh->Push_back(Mesh::MeshType::NORMAL, &Vector3s((double)normal[0], (double)normal[1], (double)normal[2]));
    }

    LOG_DEBUG << "Transfer normals successfully! ";
}
Beispiel #2
0
void Mesh::GetNormals(FbxMesh* pMesh, MeshInfo& pMeshInfo)
{
	FbxGeometryElementNormal* lNormalElement = pMesh->GetElementNormal();

	if (lNormalElement)
	{


		if (lNormalElement->GetReferenceMode() == FbxGeometryElement::eDirect)
		{
			for (int lVertexIndex = 0; lVertexIndex < pMesh->GetLayer(0)->GetNormals()->GetDirectArray().GetCount(); lVertexIndex++)
			{
				int lNormalIndex = 0;

				lNormalIndex = lVertexIndex;

				pMeshInfo.normals.push_back(lNormalElement->GetDirectArray().GetAt(lNormalIndex));
			}
		}

		if (lNormalElement->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
		{
			for (int lVertexIndex = 0; lVertexIndex < pMesh->GetLayer(0)->GetNormals()->GetIndexArray().GetCount(); lVertexIndex++)
			{
				int lNormalIndex = 0;

				lNormalIndex = lNormalElement->GetIndexArray().GetAt(lVertexIndex);

				pMeshInfo.normals.push_back(lNormalElement->GetDirectArray().GetAt(lNormalIndex));
			}
		}
	}
}
void		LoaderFbxMesh::parseVertexNormals(FbxMesh* mesh, int controlPointIndex, int vertexId)
{
	for(int i=0; i<mesh->GetElementNormalCount(); i++)
	{
		FbxVector4 fbxNormal(0, 0, 0, 0);
		FbxGeometryElementNormal* normalElement = mesh->GetElementNormal(i);
		switch(normalElement->GetMappingMode())
		{
		case FbxGeometryElement::eByControlPoint:
			fbxNormal = parseVertexNormalsByControlPoint(normalElement, controlPointIndex);
			break;
		case FbxGeometryElement::eByPolygonVertex:
			fbxNormal = parseVertexNormalsByPolygonVertex(normalElement, vertexId);
			break;
		default:
			break;
		}
		Float3 normal;
		normal.x = static_cast<float>(fbxNormal.mData[0]);
		normal.y = static_cast<float>(fbxNormal.mData[1]);
		normal.z = static_cast<float>(fbxNormal.mData[2]);
		vertexNormals_.push_back(normal);
	}
}
reVec3 reFBXAsset::getNormal(FbxMesh* fmesh, int vi)
{
	FbxVector4 normal;
	for(int l = 0; l < fmesh->GetElementNormalCount(); ++l)
	{
		FbxGeometryElementNormal* leNormal = fmesh->GetElementNormal(l);
		if(leNormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
		{
			switch (leNormal->GetReferenceMode())
			{
			case FbxGeometryElement::eDirect:
				normal = leNormal->GetDirectArray().GetAt(vi);
				return reVec3(normal[0], normal[1], normal[2]);
			case FbxGeometryElement::eIndexToDirect:
				int id = leNormal->GetIndexArray().GetAt(vi);
				normal = leNormal->GetDirectArray().GetAt(id);
				return reVec3(normal[0], normal[1], normal[2]);
			}
		}
	}
	return reVec3(0,0,0);
}
Beispiel #5
0
void FbxParser::ReadNormal(FbxMesh* pMesh, int ctrlPointIndex , int vertexCounter , GS::double3& normal)  
{  
    if(pMesh->GetElementNormalCount() < 1)  
    {  
        return;  
    }  

    FbxGeometryElementNormal* leNormal = pMesh->GetElementNormal( 0);
    switch(leNormal->GetMappingMode())  
    {  
    case FbxGeometryElement::eByControlPoint:  
        {  
            switch(leNormal->GetReferenceMode())  
            {  
            case  FbxGeometryElement::eDirect:  
                {  
                    normal.x = leNormal->GetDirectArray().GetAt(ctrlPointIndex)[0];  
                    normal.y = leNormal->GetDirectArray().GetAt(ctrlPointIndex)[1];  
                    normal.z = leNormal->GetDirectArray().GetAt(ctrlPointIndex)[2];  
                }  
                break;  
  
            case FbxGeometryElement::eIndexToDirect:  
                {  
                    int id = leNormal->GetIndexArray().GetAt(ctrlPointIndex);  
                    normal.x = leNormal->GetDirectArray().GetAt(id)[0];  
                    normal.y = leNormal->GetDirectArray().GetAt(id)[1];  
                    normal.z = leNormal->GetDirectArray().GetAt(id)[2];  
                }  
                break;  
  
            default:  
                break;  
            }  
        }  
        break;  
  
    case FbxGeometryElement::eByPolygonVertex:  
        {  
            switch(leNormal->GetReferenceMode())  
            {  
            case FbxGeometryElement::eDirect:   
                {  
                    normal.x = leNormal->GetDirectArray().GetAt(vertexCounter)[0];  
                    normal.y = leNormal->GetDirectArray().GetAt(vertexCounter)[1];  
                    normal.z = leNormal->GetDirectArray().GetAt(vertexCounter)[2];  
                }  
                break;  
  
            case FbxGeometryElement::eIndexToDirect:  
                {  
                    int id = leNormal->GetIndexArray().GetAt(vertexCounter);  
                    normal.x = leNormal->GetDirectArray().GetAt(id)[0];  
                    normal.y = leNormal->GetDirectArray().GetAt(id)[1];  
                    normal.z = leNormal->GetDirectArray().GetAt(id)[2];  
                }  
                break;  
  
            default:  
                break;  
            }  
        }  
        break;  
    }  
}  
Beispiel #6
0
void FBXImporter::ReadNormals(FBXMeshData* fbxMeshData, int contorlPointIndex, int normalIndex)
{
	FbxMesh* mesh = fbxMeshData->mMesh;
	vector<XMFLOAT3>& normals = fbxMeshData->mNormals;

	if (mesh->GetElementNormalCount() < 1)
	{
		return;
	}

	FbxGeometryElementNormal* normalElement = mesh->GetElementNormal(0);
	switch (normalElement->GetMappingMode())
	{
	case FbxGeometryElement::eByControlPoint:
		switch (normalElement->GetReferenceMode())
		{
		case FbxGeometryElement::eDirect:
		{
			FbxVector4 fbxNormal = normalElement->GetDirectArray().GetAt(contorlPointIndex);
			XMFLOAT3 normal;
			normal.x = static_cast<float>(fbxNormal[0]);
			normal.y = static_cast<float>(fbxNormal[1]);
			normal.z = static_cast<float>(fbxNormal[2]);
			normals.push_back(normal);
		}
			break;

		case FbxGeometryElement::eIndexToDirect:
		{
			int id = normalElement->GetIndexArray().GetAt(contorlPointIndex);
			FbxVector4 fbxNormal = normalElement->GetDirectArray().GetAt(id);
			XMFLOAT3 normal;
			normal.x = static_cast<float>(fbxNormal[0]);
			normal.y = static_cast<float>(fbxNormal[1]);
			normal.z = static_cast<float>(fbxNormal[2]);
			normals.push_back(normal);
		}
		default:
			break;
		}

		break;

	case FbxGeometryElement::eByPolygonVertex:
		switch (normalElement->GetReferenceMode())
		{
		case FbxGeometryElement::eDirect:
		{
			FbxVector4 fbxNormal = normalElement->GetDirectArray().GetAt(normalIndex);
			XMFLOAT3 normal;
			normal.x = static_cast<float>(fbxNormal[0]);
			normal.y = static_cast<float>(fbxNormal[1]);
			normal.z = static_cast<float>(fbxNormal[2]);
			normals.push_back(normal);
		}
			break;

		case FbxGeometryElement::eIndexToDirect:
		{
			int id = normalElement->GetIndexArray().GetAt(normalIndex);
			FbxVector4 fbxNormal = normalElement->GetDirectArray().GetAt(id);
			XMFLOAT3 normal;
			normal.x = static_cast<float>(fbxNormal[0]);
			normal.y = static_cast<float>(fbxNormal[1]);
			normal.z = static_cast<float>(fbxNormal[2]);
			normals.push_back(normal);
		}
		default:
			break;
		}
		break;

	default:
		break;
	}
}
Beispiel #7
0
//converts a FBX mesh to a CC mesh
static ccMesh* FromFbxMesh(FbxMesh* fbxMesh, bool alwaysDisplayLoadDialog/*=true*/, bool* coordinatesShiftEnabled/*=0*/, CCVector3d* coordinatesShift/*=0*/)
{
	if (!fbxMesh)
		return 0;

	int polyCount = fbxMesh->GetPolygonCount();
	//fbxMesh->GetLayer(
	unsigned triCount = 0;
	unsigned polyVertCount = 0; //different from vertCount (vertices can be counted multiple times here!)
	//as we can't load all polygons (yet ;) we already look if we can load any!
	{
		unsigned skipped = 0;
		for (int i=0; i<polyCount; ++i)
		{
			int pSize = fbxMesh->GetPolygonSize(i);

			if (pSize == 3)
			{
				++triCount;
				polyVertCount += 3;
			}
			else if (pSize == 4)
			{
				triCount += 2;
				polyVertCount += 4;
			}
			else
			{
				++skipped;
			}
		}

		if (triCount == 0)
		{
			ccLog::Warning(QString("[FBX] No triangle or quad found in mesh '%1'! (polygons with more than 4 vertices are not supported for the moment)").arg(fbxMesh->GetName()));
			return 0;
		}
		else if (skipped != 0)
		{
			ccLog::Warning(QString("[FBX] Some polygons in mesh '%1' were ignored (%2): polygons with more than 4 vertices are not supported for the moment)").arg(fbxMesh->GetName()).arg(skipped));
			return 0;
		}
	}

	int vertCount = fbxMesh->GetControlPointsCount();
	if (vertCount <= 0)
	{
		ccLog::Warning(QString("[FBX] Mesh '%1' has no vetex or no polygon?!").arg(fbxMesh->GetName()));
		return 0;
	}

	ccPointCloud* vertices = new ccPointCloud("vertices");
	ccMesh* mesh = new ccMesh(vertices);
	mesh->setName(fbxMesh->GetName());
	mesh->addChild(vertices);
	vertices->setEnabled(false);
	
	if (!mesh->reserve(static_cast<unsigned>(triCount)) || !vertices->reserve(vertCount))
	{
		ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1'!").arg(fbxMesh->GetName()));
		delete mesh;
		return 0;
	}

	//colors
	{
		for (int l=0; l<fbxMesh->GetElementVertexColorCount(); l++)
		{
			FbxGeometryElementVertexColor* vertColor = fbxMesh->GetElementVertexColor(l);
			//CC can only handle per-vertex colors
			if (vertColor->GetMappingMode() == FbxGeometryElement::eByControlPoint)
			{
				if (vertColor->GetReferenceMode() == FbxGeometryElement::eDirect
					|| vertColor->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
				{
					if (vertices->reserveTheRGBTable())
					{
						switch (vertColor->GetReferenceMode())
						{
						case FbxGeometryElement::eDirect:
							{
								for (int i=0; i<vertCount; ++i)
								{
									FbxColor c = vertColor->GetDirectArray().GetAt(i);
									vertices->addRGBColor(	static_cast<colorType>(c.mRed	* MAX_COLOR_COMP),
															static_cast<colorType>(c.mGreen	* MAX_COLOR_COMP),
															static_cast<colorType>(c.mBlue	* MAX_COLOR_COMP) );
								}
							}
							break;
						case FbxGeometryElement::eIndexToDirect:
							{
								for (int i=0; i<vertCount; ++i)
								{
									int id = vertColor->GetIndexArray().GetAt(i);
									FbxColor c = vertColor->GetDirectArray().GetAt(id);
									vertices->addRGBColor(	static_cast<colorType>(c.mRed	* MAX_COLOR_COMP),
															static_cast<colorType>(c.mGreen	* MAX_COLOR_COMP),
															static_cast<colorType>(c.mBlue	* MAX_COLOR_COMP) );
								}
							}
							break;
						default:
							assert(false);
							break;
						}

						vertices->showColors(true);
						mesh->showColors(true);
						break; //no need to look for other color fields (we won't be able to handle them!
					}
					else
					{
						ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' colors!").arg(fbxMesh->GetName()));
					}
				}
				else
				{
					ccLog::Warning(QString("[FBX] Color field #%i of mesh '%1' will be ignored (unhandled type)").arg(l).arg(fbxMesh->GetName()));
				}
			}
			else
			{
				ccLog::Warning(QString("[FBX] Color field #%i of mesh '%1' will be ignored (unhandled type)").arg(l).arg(fbxMesh->GetName()));
			}
		}
	}


	//normals can be per vertices or per-triangle
	int perPointNormals = -1;
	int perVertexNormals = -1;
	int perPolygonNormals = -1;
	{
        for (int j=0; j<fbxMesh->GetElementNormalCount(); j++)
        {
			FbxGeometryElementNormal* leNormals = fbxMesh->GetElementNormal(j);
			switch(leNormals->GetMappingMode())
			{
			case FbxGeometryElement::eByControlPoint:
				perPointNormals = j;
				break;
			case FbxGeometryElement::eByPolygonVertex:
				perVertexNormals = j;
				break;
			case FbxGeometryElement::eByPolygon:
				perPolygonNormals = j;
				break;
			default:
				//not handled
				break;
			}
		}
	}

	//per-point normals
	if (perPointNormals >= 0)
	{
		FbxGeometryElementNormal* leNormals = fbxMesh->GetElementNormal(perPointNormals);
		FbxLayerElement::EReferenceMode refMode = leNormals->GetReferenceMode();
		const FbxLayerElementArrayTemplate<FbxVector4>& normals = leNormals->GetDirectArray();
		assert(normals.GetCount() == vertCount);
		if (normals.GetCount() != vertCount)
		{
			ccLog::Warning(QString("[FBX] Wrong number of normals on mesh '%1'!").arg(fbxMesh->GetName()));
			perPointNormals = -1;
		}
		else if (!vertices->reserveTheNormsTable())
		{
			ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' normals!").arg(fbxMesh->GetName()));
			perPointNormals = -1;
		}
		else
		{
			//import normals
			for (int i=0; i<vertCount; ++i)
			{
				int id = refMode != FbxGeometryElement::eDirect ? leNormals->GetIndexArray().GetAt(i) : i;
				FbxVector4 N = normals.GetAt(id);
				//convert to CC-structure
				CCVector3 Npc(	static_cast<PointCoordinateType>(N.Buffer()[0]),
								static_cast<PointCoordinateType>(N.Buffer()[1]),
								static_cast<PointCoordinateType>(N.Buffer()[2]) );
				vertices->addNorm(Npc.u);
			}
			vertices->showNormals(true);
			mesh->showNormals(true);
			//no need to import the other normals (if any)
			perVertexNormals = -1;
			perPolygonNormals = -1;
		}
	}

	//per-triangle normals
	NormsIndexesTableType* normsTable = 0;
	if (perVertexNormals >= 0 || perPolygonNormals >= 0)
	{
		normsTable = new NormsIndexesTableType();
		if (!normsTable->reserve(polyVertCount) || !mesh->reservePerTriangleNormalIndexes())
		{
			ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' normals!").arg(fbxMesh->GetName()));
			normsTable->release();
			normsTable = 0;
		}
		else
		{
			mesh->setTriNormsTable(normsTable);
			mesh->addChild(normsTable);
			vertices->showNormals(true);
			mesh->showNormals(true);
		}
	}

	//import textures UV
	int perVertexUV = -1;
	bool hasTexUV = false;
	{
		for (int l=0; l<fbxMesh->GetElementUVCount(); ++l)
		{
			FbxGeometryElementUV* leUV = fbxMesh->GetElementUV(l);
			//per-point UV coordinates
			if (leUV->GetMappingMode() == FbxGeometryElement::eByControlPoint)
			{
				TextureCoordsContainer* vertTexUVTable = new TextureCoordsContainer();
				if (!vertTexUVTable->reserve(vertCount) || !mesh->reservePerTriangleTexCoordIndexes())
				{
					vertTexUVTable->release();
					ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' UV coordinates!").arg(fbxMesh->GetName()));
				}
				else
				{
					FbxLayerElement::EReferenceMode refMode = leUV->GetReferenceMode();
					for (int i=0; i<vertCount; ++i)
					{
						int id = refMode != FbxGeometryElement::eDirect ? leUV->GetIndexArray().GetAt(i) : i;
						FbxVector2 uv = leUV->GetDirectArray().GetAt(id);
						//convert to CC-structure
						float uvf[2] = {static_cast<float>(uv.Buffer()[0]),
										static_cast<float>(uv.Buffer()[1])};
						vertTexUVTable->addElement(uvf);
					}
					mesh->addChild(vertTexUVTable);
					hasTexUV = true;
				}
				perVertexUV = -1;
				break; //no need to look to the other UV fields (can't handle them!)
			}
			else if (leUV->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
			{
				//per-vertex UV coordinates
				perVertexUV = l;
			}
		}
	}

	//per-vertex UV coordinates
	TextureCoordsContainer* texUVTable = 0;
	if (perVertexUV >= 0)
	{
		texUVTable = new TextureCoordsContainer();
		if (!texUVTable->reserve(polyVertCount) || !mesh->reservePerTriangleTexCoordIndexes())
		{
			texUVTable->release();
			ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' UV coordinates!").arg(fbxMesh->GetName()));
		}
		else
		{
			mesh->addChild(texUVTable);
			hasTexUV = true;
		}
	}

	//import polygons
	{
		for (int i=0; i<polyCount; ++i)
		{
			int pSize = fbxMesh->GetPolygonSize(i);

			if (pSize > 4)
			{
				//not handled for the moment
				continue;
			}
			//we split quads into two triangles

			//vertex indices
			int i1 = fbxMesh->GetPolygonVertex(i, 0);
			int i2 = fbxMesh->GetPolygonVertex(i, 1);
			int i3 = fbxMesh->GetPolygonVertex(i, 2);
			mesh->addTriangle(i1,i2,i3);

			int i4 = -1;
			if (pSize == 4)
			{
				i4 = fbxMesh->GetPolygonVertex(i, 3);
				mesh->addTriangle(i1,i3,i4);
			}

			if (hasTexUV)
			{
				if (texUVTable)
				{
					assert(perVertexUV >= 0);

					int uvIndex = static_cast<int>(texUVTable->currentSize());
					for (int j=0; j<pSize; ++j)
					{
						int lTextureUVIndex = fbxMesh->GetTextureUVIndex(i, j);
						FbxGeometryElementUV* leUV = fbxMesh->GetElementUV(perVertexUV);
						FbxVector2 uv = leUV->GetDirectArray().GetAt(lTextureUVIndex);
						//convert to CC-structure
						float uvf[2] = {static_cast<float>(uv.Buffer()[0]),
										static_cast<float>(uv.Buffer()[1])};
						texUVTable->addElement(uvf);
					}
					mesh->addTriangleTexCoordIndexes(uvIndex,uvIndex+1,uvIndex+2);
					if (pSize == 4)
						mesh->addTriangleTexCoordIndexes(uvIndex,uvIndex+2,uvIndex+3);
				}
				else
				{
					mesh->addTriangleTexCoordIndexes(i1,i2,i3);
					if (pSize == 4)
						mesh->addTriangleTexCoordIndexes(i1,i3,i4);
				}
			}

			//per-triangle normals
			if (normsTable)
			{
				int nIndex = static_cast<int>(normsTable->currentSize());
				for (int j=0; j<pSize; ++j)
				{
					FbxVector4 N;
					fbxMesh->GetPolygonVertexNormal(i, j, N);
					CCVector3 Npc(	static_cast<PointCoordinateType>(N.Buffer()[0]),
									static_cast<PointCoordinateType>(N.Buffer()[1]),
									static_cast<PointCoordinateType>(N.Buffer()[2]) );
					normsTable->addElement(ccNormalVectors::GetNormIndex(Npc.u));
				}

				mesh->addTriangleNormalIndexes(nIndex,nIndex+1,nIndex+2);
				if (pSize == 4)
					mesh->addTriangleNormalIndexes(nIndex,nIndex+2,nIndex+3);
			}
		}
		
		if (mesh->size() == 0)
		{
			ccLog::Warning(QString("[FBX] No triangle found in mesh '%1'! (only triangles are supported for the moment)").arg(fbxMesh->GetName()));
			delete mesh;
			return 0;
		}
	}

	//import vertices
	{
		const FbxVector4* fbxVertices = fbxMesh->GetControlPoints();
		assert(vertices && fbxVertices);
		CCVector3d Pshift(0,0,0);
		for (int i=0; i<vertCount; ++i, ++fbxVertices)
		{
			const double* P = fbxVertices->Buffer();
			assert(P[3] == 0);

			//coordinate shift management
			if (i == 0)
			{
				bool shiftAlreadyEnabled = (coordinatesShiftEnabled && *coordinatesShiftEnabled && coordinatesShift);
				if (shiftAlreadyEnabled)
					Pshift = *coordinatesShift;
				bool applyAll = false;
				if (	sizeof(PointCoordinateType) < 8
					&&	ccCoordinatesShiftManager::Handle(P,0,alwaysDisplayLoadDialog,shiftAlreadyEnabled,Pshift,0,applyAll))
				{
					vertices->setGlobalShift(Pshift);
					ccLog::Warning("[FBX] Mesh has been recentered! Translation: (%.2f,%.2f,%.2f)",Pshift.x,Pshift.y,Pshift.z);

					//we save coordinates shift information
					if (applyAll && coordinatesShiftEnabled && coordinatesShift)
					{
						*coordinatesShiftEnabled = true;
						*coordinatesShift = Pshift;
					}
				}
			}

			CCVector3 PV(	static_cast<PointCoordinateType>(P[0] + Pshift.x),
							static_cast<PointCoordinateType>(P[1] + Pshift.y),
							static_cast<PointCoordinateType>(P[2] + Pshift.z) );

			vertices->addPoint(PV);
		}
	}

	//import textures
	{
		//TODO
	}

	return mesh;
}
Beispiel #8
0
// Converts a CC mesh to an FBX mesh
static FbxNode* ToFbxMesh(ccGenericMesh* mesh, FbxScene* pScene)
{
	if (!mesh)
		return 0;

    FbxMesh* lMesh = FbxMesh::Create(pScene, qPrintable(mesh->getName()));

	ccGenericPointCloud* cloud = mesh->getAssociatedCloud();
	if (!cloud)
		return 0;
	unsigned vertCount = cloud->size();
	unsigned faceCount = mesh->size();

    // Create control points.
	{
		lMesh->InitControlPoints(vertCount);
		FbxVector4* lControlPoints = lMesh->GetControlPoints();

		for (unsigned i=0; i<vertCount; ++i)
		{
			const CCVector3* P = cloud->getPoint(i);
			lControlPoints[i] = FbxVector4(P->x,P->y,P->z);
		}
	}

	ccMesh* asCCMesh = 0;
	if (mesh->isA(CC_MESH))
		asCCMesh = static_cast<ccMesh*>(mesh);

    // normals
	if (mesh->hasNormals())
	{
		FbxGeometryElementNormal* lGeometryElementNormal = lMesh->CreateElementNormal();
		if (mesh->hasTriNormals())
		{
			// We want to have one normal per vertex of each polygon,
			// so we set the mapping mode to eByPolygonVertex.
			lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
			lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
			lGeometryElementNormal->GetIndexArray().SetCount(faceCount*3);
			
			if (asCCMesh)
			{
				NormsIndexesTableType* triNorms = asCCMesh->getTriNormsTable();
				assert(triNorms);
				for (unsigned i=0; i<triNorms->currentSize(); ++i)
				{
					const PointCoordinateType* N = ccNormalVectors::GetNormal(triNorms->getValue(i));
					FbxVector4 Nfbx(N[0],N[1],N[2]);
					lGeometryElementNormal->GetDirectArray().Add(Nfbx);
				}
				for (unsigned j=0; j<faceCount; ++j)
				{
					int i1,i2,i3;
					asCCMesh->getTriangleNormalIndexes(j,i1,i2,i3);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, i1);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, i2);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, i3);
				}
			}
			else
			{
				for (unsigned j=0; j<faceCount; ++j)
				{
					//we can't use the 'NormsIndexesTable' so we save all the normals of all the vertices
					CCVector3 Na,Nb,Nc;
					lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Na.x,Na.y,Na.z));
					lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nb.x,Nb.y,Nb.z));
					lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nc.x,Nc.y,Nc.z));
					
					mesh->getTriangleNormals(j,Na,Nb,Nc);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, static_cast<int>(j)*3+0);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, static_cast<int>(j)*3+1);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, static_cast<int>(j)*3+2);
				}
			}
		}
		else
		{
			// We want to have one normal for each vertex (or control point),
			// so we set the mapping mode to eByControlPoint.
			lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
			// The first method is to set the actual normal value
			// for every control point.
			lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
			for (unsigned i=0; i<vertCount; ++i)
			{
				const PointCoordinateType* N = cloud->getPointNormal(i);
				FbxVector4 Nfbx(N[0],N[1],N[2]);
				lGeometryElementNormal->GetDirectArray().Add(Nfbx);
			}
		}
	}
	else
	{
		ccLog::Warning("[FBX] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")");
	}

    // colors
	if (cloud->hasColors())
	{
		FbxGeometryElementVertexColor* lGeometryElementVertexColor = lMesh->CreateElementVertexColor();
		lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint);
		lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect);
		for (unsigned i=0; i<vertCount; ++i)
		{
			const colorType* C = cloud->getPointColor(i);
			FbxColor col( FbxDouble3(	static_cast<double>(C[0])/MAX_COLOR_COMP,
										static_cast<double>(C[1])/MAX_COLOR_COMP,
										static_cast<double>(C[2])/MAX_COLOR_COMP ) );
			lGeometryElementVertexColor->GetDirectArray().Add(col);
		}
	}

	// Set material mapping.
    //FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial();
    //lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon);
    //lMaterialElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

    // Create polygons. Assign material indices.
	{
		for (unsigned j=0; j<faceCount; ++j)
		{
			const CCLib::TriangleSummitsIndexes* tsi = mesh->getTriangleIndexes(j);

			lMesh->BeginPolygon(static_cast<int>(j));
			lMesh->AddPolygon(tsi->i1);
			lMesh->AddPolygon(tsi->i2);
			lMesh->AddPolygon(tsi->i3);
			lMesh->EndPolygon();
		}
	}

    FbxNode* lNode = FbxNode::Create(pScene,qPrintable(mesh->getName()));

    lNode->SetNodeAttribute(lMesh);

    //CreateMaterials(pScene, lMesh);

    return lNode;
}
HRESULT CStaticMesh::Load_StaticMesh(const char* szFilePath,const char* szFileName, FbxManager* _pFBXManager, FbxIOSettings* _pIOsettings, FbxScene* _pFBXScene, FbxImporter* _pImporter)
{
	HRESULT hr = E_FAIL;

	vector<UINT> vecIndeces;

	string	strFullPath;

	strFullPath.clear();
	strFullPath = szFilePath;
	strFullPath += szFileName;//경로에 파일이름 추가

	if (!(_pImporter->Initialize(strFullPath.c_str(), -1, _pFBXManager->GetIOSettings())))
		FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Init Failed");
	if (!(_pImporter->Import(_pFBXScene)))
		FAILED_CHECK_MSG(E_FAIL, L"Static Mesh Import Failed");

	FbxGeometryConverter clsConverter(_pFBXManager);
	clsConverter.Triangulate(_pFBXScene, false);
	FbxNode* pRootNode = _pFBXScene->GetRootNode();

	if (!pRootNode)
		return E_FAIL;

	vector<VTXTEX> vecVTXTEX;

	for (int i = 0; i < pRootNode->GetChildCount(); ++i)
	{
		FbxNode* pChildNode = pRootNode->GetChild(i);

		if (pChildNode->GetNodeAttribute() == NULL)
			continue;

		FbxNodeAttribute::EType AttributeType = pChildNode->GetNodeAttribute()->GetAttributeType();

		if (AttributeType != FbxNodeAttribute::eMesh)
			continue;

		FbxMesh* pMesh = (FbxMesh*)pChildNode->GetNodeAttribute();  // 임폴트 하려는 메쉬의 데이터
		D3DXVECTOR3 vPos;
		D3DXVECTOR2 vOutUV;
		D3DXVECTOR3 vOutNormal;
		FbxVector4* mControlPoints = pMesh->GetControlPoints();
		int iVTXCounter = 0;



		for (int j = 0; j < pMesh->GetPolygonCount(); j++) // 폴리곤의 인덱스
		{
			int iNumVertices = pMesh->GetPolygonSize(j);
			assert(iNumVertices == 3);
			FbxGeometryElementUV* VtxUV = pMesh->GetElementUV(0);
			FbxGeometryElementNormal* VtxNormal = pMesh->GetElementNormal(0);



			for (int k = 0; k < iNumVertices; k++) // 폴리곤을 구성하는 버텍스의 인덱스
			{
				//정점 데이터 얻는곳
				int iControlPointIndex = pMesh->GetPolygonVertex(j, k); // 컨트롤 포인트 = 하나의 버텍스
				int iTextureUVIndex = pMesh->GetTextureUVIndex(j, k);  // Control = Vertex
				//int iNormalIndex = pMesh->GetPolygonVertexIndex(j, k);
				++iVTXCounter;

				vPos.x = (float)mControlPoints[iControlPointIndex].mData[0];
				vPos.y = -(float)mControlPoints[iControlPointIndex].mData[1];
				vPos.z = (float)mControlPoints[iControlPointIndex].mData[2];

				//uv 얻기
				switch (VtxUV->GetMappingMode()) // UV값 추출
				{
				case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때

					switch (VtxUV->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
					{
						vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[0]);
						vOutUV.y = static_cast<float>(VtxUV->GetDirectArray().GetAt(iControlPointIndex).mData[1]);
					}
					break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int index = VtxUV->GetIndexArray().GetAt(iControlPointIndex);
						vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[0]);
						vOutUV.y =  static_cast<float>(VtxUV->GetDirectArray().GetAt(index).mData[1]);
					}
					break;

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


					break;


				case FbxGeometryElement::eByPolygonVertex:  // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳
					switch (VtxUV->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
					{
						vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]);
						vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]);
					}
					case FbxGeometryElement::eIndexToDirect:
					{

						vOutUV.x = static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[0]);
						vOutUV.y = 1 - static_cast<float>(VtxUV->GetDirectArray().GetAt(iTextureUVIndex).mData[1]);
					}
					break;
					default:
						throw std::exception("invalid Reference");
					}
					break;
				default:
					throw std::exception("Invalid Reference");
					break;
				}

				//노멀얻기
				switch (VtxNormal->GetMappingMode()) // 노멀값 추출
				{
				case FbxGeometryElement::eByControlPoint: // 하나의 컨트롤 포인트가 하나의 노멀벡터를 가질때

					switch (VtxNormal->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
					{
						vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[0]);
						vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[1]);
						vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(iControlPointIndex).mData[2]);
					}
					break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int index = VtxNormal->GetIndexArray().GetAt(iControlPointIndex);
						vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]);
						vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]);
						vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]);
					}
					break;

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


					break;


				case FbxGeometryElement::eByPolygonVertex:  // Sharp Edge 포인트가 존재할때 고로 우리가 실질적으로 쓰는곳
					switch (VtxNormal->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
					{
						int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter);
						vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]);
						vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]);
						vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]);
					}
					case FbxGeometryElement::eIndexToDirect:
					{
						int index = VtxNormal->GetIndexArray().GetAt(iVTXCounter);
						vOutNormal.x = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[0]);
						vOutNormal.y = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[1]);
						vOutNormal.z = static_cast<float>(VtxNormal->GetDirectArray().GetAt(index).mData[2]);
					}
					break;
					default:
						throw std::exception("invalid Reference");
					}
					break;
				default:
					throw std::exception("Invalid Reference");
					break;
				}


				VTXTEX vtxtex;
				vtxtex.vPos = vPos;
				vtxtex.vNormal = vOutNormal;
				vtxtex.vTexUV = vOutUV;
				vecVTXTEX.push_back(vtxtex);


				//int index = VtxUV->GetIndexArray().GetAt(iTextureUVIndex);
				vecIndeces.push_back(VtxUV->GetIndexArray().GetAt(iTextureUVIndex));
			}
		}
	}

	unsigned int n = vecVTXTEX.size();
	VTXTEX* pVTXTex = new VTXTEX[n];
	for (unsigned int i = 0; i < vecVTXTEX.size(); ++i)
	{
		pVTXTex[i].vPos = vecVTXTEX[i].vPos;
		pVTXTex[i].vNormal = vecVTXTEX[i].vNormal;
		pVTXTex[i].vTexUV = vecVTXTEX[i].vTexUV;
	}

	m_iVertices = vecVTXTEX.size();
	m_iVertexStrides = sizeof(VTXTEX);
	m_iVertexOffsets = 0;

	MakeVertexNormal((BYTE*)pVTXTex, NULL);

	D3D11_BUFFER_DESC tBufferDesc;
	ZeroMemory(&tBufferDesc, sizeof(D3D11_BUFFER_DESC));
	tBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	tBufferDesc.ByteWidth = m_iVertexStrides * m_iVertices;
	tBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	tBufferDesc.CPUAccessFlags = 0;

	D3D11_SUBRESOURCE_DATA tData;
	ZeroMemory(&tData, sizeof(D3D11_SUBRESOURCE_DATA));
	tData.pSysMem = pVTXTex;
	hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&tBufferDesc, &tData, &m_VertexBuffer);


	::Safe_Delete(pVTXTex);
	if (FAILED(hr))
		return E_FAIL;


	D3D11_BUFFER_DESC cbd;
	cbd.Usage = D3D11_USAGE_DEFAULT;
	cbd.ByteWidth = sizeof(ConstantBuffer);
	cbd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	cbd.CPUAccessFlags = 0;
	cbd.MiscFlags = 0;
	cbd.StructureByteStride = 0;
	hr = CDevice::GetInstance()->m_pDevice->CreateBuffer(&cbd, NULL, &m_ConstantBuffer);

	if (FAILED(hr))
	{
		MessageBox(NULL, L"System Message", L"Constant Buffer Error", MB_OK);
		return hr;
	}


	return S_OK;
}
Beispiel #10
0
void ExportFbxMesh(const Value& obj)
{
	string name = obj["Name"].GetString();

	FbxNode* pNode = FbxNode::Create(pManager, name.c_str());
	FbxMesh* pMesh = FbxMesh::Create(pManager, name.c_str());
	pNode->AddNodeAttribute(pMesh);
	pScene->GetRootNode()->AddChild(pNode);

	int numVertex = obj["NumVertex"].GetInt();
	
	{
		pMesh->InitControlPoints(numVertex);
		FbxVector4* lControlPoints = pMesh->GetControlPoints();
		const Value& pos = obj["Position"];
		for (int i = 0; i < numVertex; i++)
		{
			double x = pos[i * 3 + 0].GetDouble();
			x = -x;
			double y = pos[i * 3 + 1].GetDouble();
			double z = pos[i * 3 + 2].GetDouble();
			lControlPoints[i] = FbxVector4(x, y, z);
		}
	}

	{
		FbxGeometryElementNormal* lGeometryElementNormal = pMesh->CreateElementNormal();
		lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
		lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
		FbxLayerElementArrayTemplate<FbxVector4>& array = lGeometryElementNormal->GetDirectArray();

		const Value& normal = obj["Normal"];
		for (int i = 0; i < numVertex; i++)
		{
			double x = normal[i * 3 + 0].GetDouble();
			x = -x;
			double y = normal[i * 3 + 1].GetDouble();
			double z = normal[i * 3 + 2].GetDouble();
			array.Add(FbxVector4(x, y, z));
		}
	}

	{
		FbxGeometryElementUV* lUVDiffuseElement = pMesh->CreateElementUV("DiffuseUV");
		FBX_ASSERT(lUVDiffuseElement != NULL);
		lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByControlPoint);
		lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eDirect);
		FbxLayerElementArrayTemplate<FbxVector2>& array = lUVDiffuseElement->GetDirectArray();

		const Value& v = obj["UV0"];
		for (int i = 0; i < numVertex; i++)
		{
			double x = v[i * 2 + 0].GetDouble();
			double y = v[i * 2 + 1].GetDouble();
			array.Add(FbxVector2(x, y));
		}
	}

	{
		const Value& color = obj["Color"];
		if (!color.IsNull())
		{
			FbxGeometryElementVertexColor* pColorElement = pMesh->CreateElementVertexColor();
			FBX_ASSERT(pColorElement != NULL);
			pColorElement->SetMappingMode(FbxGeometryElement::eByControlPoint);
			pColorElement->SetReferenceMode(FbxGeometryElement::eDirect);
			FbxLayerElementArrayTemplate<FbxColor>& array = pColorElement->GetDirectArray();

			for (int i = 0; i < numVertex; i++)
			{
				double r = color[i * 4 + 0].GetDouble();
				double g = color[i * 4 + 1].GetDouble();
				double b = color[i * 4 + 2].GetDouble();
				double a = color[i * 4 + 3].GetDouble();
				array.Add(FbxColor(r, g, b, a));
			}
		}
	}

	{
		const Value& Indeices = obj["Indeices"];

		for (uint32_t subMesh = 0; subMesh < Indeices.Size(); subMesh++)
		{
			const Value& index0 = Indeices[subMesh];
			int numIndex = index0.Size();
			printf("index %d\n", numIndex);
			for (int i = 0; i < numIndex / 3; i++)
			{
				pMesh->BeginPolygon(-1, -1, subMesh);
				int index[3] = {
					index0[i * 3 + 0].GetInt(),
					index0[i * 3 + 1].GetInt(),
					index0[i * 3 + 2].GetInt(),
				};

				pMesh->AddPolygon(index[0]);
				pMesh->AddPolygon(index[2]);
				pMesh->AddPolygon(index[1]);
				pMesh->EndPolygon();
			}
		}
	}

	//////////////////////////////////////////////////////////////////////////

	// export skin
	const Value& boneIndex = obj["BoneIndex"];

	if (!boneIndex.IsNull())
	{
		if (fbxBones.empty())
		{
			printf("no bones, can not export skin");
			return;
		}

		const Value& boneWeight = obj["BoneWeight"];
		vector<FbxCluster*> clusters(fbxBones.size(), NULL);
		for (uint32_t i = 0; i < fbxBones.size(); i++) {
			FbxCluster* pCluster = FbxCluster::Create(pScene, "");
			pCluster->SetLink(fbxBones[i]);
			pCluster->SetLinkMode(FbxCluster::eTotalOne);
			clusters[i] = pCluster;
		}

		for (int i = 0; i < numVertex; i++) {
			for (int j = 0; j < 4; j++) {
				int bone = boneIndex[i * 4 + j].GetInt();
				double weight = boneWeight[i * 4 + j].GetDouble();
				clusters[bone]->AddControlPointIndex(i, weight);
			}
		}

		FbxSkin* lSkin = FbxSkin::Create(pScene, "");

		FbxScene* p = pNode->GetScene();
		FbxAMatrix modelMatrix = pNode->EvaluateGlobalTransform();
		for (uint32_t i = 0; i < clusters.size(); i++) {
			clusters[i]->SetTransformMatrix(modelMatrix);
			FbxAMatrix boneMatrix = fbxBones[i]->EvaluateGlobalTransform();
			clusters[i]->SetTransformLinkMatrix(boneMatrix);
			lSkin->AddCluster(clusters[i]);
		}

		pMesh->AddDeformer(lSkin);
	}

}
Beispiel #11
0
void fbxLoader2::readNormal(FbxMesh* mesh, int controlPointIndex, D3DXVECTOR3* normal)
{
	if (mesh->GetElementNormalCount()<1)
	{
		return;
	}

	FbxGeometryElementNormal* normalEl = mesh->GetElementNormal(0);

	switch(normalEl->GetMappingMode())
	{
	case FbxGeometryElement::eDirect:
		{
			switch(normalEl->GetReferenceMode())
			{
			case FbxGeometryElement::eDirect:
				{
					normal->x = (float)normalEl->GetDirectArray().GetAt(controlPointIndex).mData[0];
					normal->y = (float)normalEl->GetDirectArray().GetAt(controlPointIndex).mData[1];
					normal->z = (float)normalEl->GetDirectArray().GetAt(controlPointIndex).mData[2];
				}
				break;

			case FbxGeometryElement::eIndexToDirect:
				{
					int id = normalEl->GetIndexArray().GetAt(controlPointIndex);
					normal->x = (float)normalEl->GetDirectArray().GetAt(id).mData[0];
					normal->y = (float)normalEl->GetDirectArray().GetAt(id).mData[1];
					normal->z = (float)normalEl->GetDirectArray().GetAt(id).mData[2];
				}
				break;
			}
		}
		break;

	case FbxGeometryElement::eByPolygonVertex:
		{
			switch(normalEl->GetReferenceMode())
			{
			case FbxGeometryElement::eDirect:
				{
					normal->x = (float)normalEl->GetDirectArray().GetAt(controlPointIndex).mData[0];
					normal->y = (float)normalEl->GetDirectArray().GetAt(controlPointIndex).mData[1];
					normal->z = (float)normalEl->GetDirectArray().GetAt(controlPointIndex).mData[2];
				}
				break;

			case FbxGeometryElement::eIndexToDirect:
				{
					int id = normalEl->GetIndexArray().GetAt(controlPointIndex);
					normal->x = (float)normalEl->GetDirectArray().GetAt(id).mData[0];
					normal->y = (float)normalEl->GetDirectArray().GetAt(id).mData[1];
					normal->z = (float)normalEl->GetDirectArray().GetAt(id).mData[2];
				}
				break;
			}
		}
		break;
	default:
		int id = normalEl->GetIndexArray().GetAt(controlPointIndex);
		normal->x = (float)normalEl->GetDirectArray().GetAt(id).mData[0];
		normal->y = (float)normalEl->GetDirectArray().GetAt(id).mData[1];
		normal->z = (float)normalEl->GetDirectArray().GetAt(id).mData[2];
	}
}
Beispiel #12
0
//converts a FBX mesh to a CC mesh
static ccMesh* FromFbxMesh(FbxMesh* fbxMesh, FileIOFilter::LoadParameters& parameters)
{
	if (!fbxMesh)
		return 0;

	int polyCount = fbxMesh->GetPolygonCount();
	//fbxMesh->GetLayer(
	unsigned triCount = 0;
	unsigned polyVertCount = 0; //different from vertCount (vertices can be counted multiple times here!)
	//as we can't load all polygons (yet ;) we already look if we can load any!
	{
		unsigned skipped = 0;
		for (int i=0; i<polyCount; ++i)
		{
			int pSize = fbxMesh->GetPolygonSize(i);

			if (pSize == 3)
			{
				++triCount;
				polyVertCount += 3;
			}
			else if (pSize == 4)
			{
				triCount += 2;
				polyVertCount += 4;
			}
			else
			{
				++skipped;
			}
		}

		if (triCount == 0)
		{
			ccLog::Warning(QString("[FBX] No triangle or quad found in mesh '%1'! (polygons with more than 4 vertices are not supported for the moment)").arg(fbxMesh->GetName()));
			return 0;
		}
		else if (skipped != 0)
		{
			ccLog::Warning(QString("[FBX] Some polygons in mesh '%1' were ignored (%2): polygons with more than 4 vertices are not supported for the moment)").arg(fbxMesh->GetName()).arg(skipped));
			return 0;
		}
	}

	int vertCount = fbxMesh->GetControlPointsCount();
	if (vertCount <= 0)
	{
		ccLog::Warning(QString("[FBX] Mesh '%1' has no vetex or no polygon?!").arg(fbxMesh->GetName()));
		return 0;
	}

	ccPointCloud* vertices = new ccPointCloud("vertices");
	ccMesh* mesh = new ccMesh(vertices);
	mesh->setName(fbxMesh->GetName());
	mesh->addChild(vertices);
	vertices->setEnabled(false);
	
	if (!mesh->reserve(static_cast<unsigned>(triCount)) || !vertices->reserve(vertCount))
	{
		ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1'!").arg(fbxMesh->GetName()));
		delete mesh;
		return 0;
	}

	//colors
	{
		for (int l=0; l<fbxMesh->GetElementVertexColorCount(); l++)
		{
			FbxGeometryElementVertexColor* vertColor = fbxMesh->GetElementVertexColor(l);
			//CC can only handle per-vertex colors
			if (vertColor->GetMappingMode() == FbxGeometryElement::eByControlPoint)
			{
				if (vertColor->GetReferenceMode() == FbxGeometryElement::eDirect
					|| vertColor->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
				{
					if (vertices->reserveTheRGBTable())
					{
						switch (vertColor->GetReferenceMode())
						{
						case FbxGeometryElement::eDirect:
							{
								for (int i=0; i<vertCount; ++i)
								{
									FbxColor c = vertColor->GetDirectArray().GetAt(i);
									vertices->addRGBColor(	static_cast<colorType>(c.mRed	* ccColor::MAX),
															static_cast<colorType>(c.mGreen	* ccColor::MAX),
															static_cast<colorType>(c.mBlue	* ccColor::MAX) );
								}
							}
							break;
						case FbxGeometryElement::eIndexToDirect:
							{
								for (int i=0; i<vertCount; ++i)
								{
									int id = vertColor->GetIndexArray().GetAt(i);
									FbxColor c = vertColor->GetDirectArray().GetAt(id);
									vertices->addRGBColor(	static_cast<colorType>(c.mRed	* ccColor::MAX),
															static_cast<colorType>(c.mGreen	* ccColor::MAX),
															static_cast<colorType>(c.mBlue	* ccColor::MAX) );
								}
							}
							break;
						default:
							assert(false);
							break;
						}

						vertices->showColors(true);
						mesh->showColors(true);
						break; //no need to look for other color fields (we won't be able to handle them!
					}
					else
					{
						ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' colors!").arg(fbxMesh->GetName()));
					}
				}
				else
				{
					ccLog::Warning(QString("[FBX] Color field #%i of mesh '%1' will be ignored (unhandled type)").arg(l).arg(fbxMesh->GetName()));
				}
			}
			else
			{
				ccLog::Warning(QString("[FBX] Color field #%i of mesh '%1' will be ignored (unhandled type)").arg(l).arg(fbxMesh->GetName()));
			}
		}
	}

	//normals can be per vertices or per-triangle
	int perPointNormals = -1;
	int perVertexNormals = -1;
	int perPolygonNormals = -1;
	{
		for (int j=0; j<fbxMesh->GetElementNormalCount(); j++)
		{
			FbxGeometryElementNormal* leNormals = fbxMesh->GetElementNormal(j);
			switch(leNormals->GetMappingMode())
			{
			case FbxGeometryElement::eByControlPoint:
				perPointNormals = j;
				break;
			case FbxGeometryElement::eByPolygonVertex:
				perVertexNormals = j;
				break;
			case FbxGeometryElement::eByPolygon:
				perPolygonNormals = j;
				break;
			default:
				//not handled
				break;
			}
		}
	}

	//per-point normals
	if (perPointNormals >= 0)
	{
		FbxGeometryElementNormal* leNormals = fbxMesh->GetElementNormal(perPointNormals);
		FbxLayerElement::EReferenceMode refMode = leNormals->GetReferenceMode();
		const FbxLayerElementArrayTemplate<FbxVector4>& normals = leNormals->GetDirectArray();
		assert(normals.GetCount() == vertCount);
		if (normals.GetCount() != vertCount)
		{
			ccLog::Warning(QString("[FBX] Wrong number of normals on mesh '%1'!").arg(fbxMesh->GetName()));
			perPointNormals = -1;
		}
		else if (!vertices->reserveTheNormsTable())
		{
			ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' normals!").arg(fbxMesh->GetName()));
			perPointNormals = -1;
		}
		else
		{
			//import normals
			for (int i=0; i<vertCount; ++i)
			{
				int id = refMode != FbxGeometryElement::eDirect ? leNormals->GetIndexArray().GetAt(i) : i;
				FbxVector4 N = normals.GetAt(id);
				//convert to CC-structure
				CCVector3 Npc(	static_cast<PointCoordinateType>(N.Buffer()[0]),
								static_cast<PointCoordinateType>(N.Buffer()[1]),
								static_cast<PointCoordinateType>(N.Buffer()[2]) );
				vertices->addNorm(Npc);
			}
			vertices->showNormals(true);
			mesh->showNormals(true);
			//no need to import the other normals (if any)
			perVertexNormals = -1;
			perPolygonNormals = -1;
		}
	}

	//per-triangle normals
	NormsIndexesTableType* normsTable = 0;
	if (perVertexNormals >= 0 || perPolygonNormals >= 0)
	{
		normsTable = new NormsIndexesTableType();
		if (!normsTable->reserve(polyVertCount) || !mesh->reservePerTriangleNormalIndexes())
		{
			ccLog::Warning(QString("[FBX] Not enough memory to load mesh '%1' normals!").arg(fbxMesh->GetName()));
			normsTable->release();
			normsTable = 0;
		}
		else
		{
			mesh->setTriNormsTable(normsTable);
			vertices->showNormals(true);
			mesh->showNormals(true);
		}
	}

	//materials
	ccMaterialSet* materials = 0;
	{
		FbxNode* lNode = fbxMesh->GetNode();
		int lMaterialCount = lNode ? lNode->GetMaterialCount() : 0;
		for (int i=0; i<lMaterialCount; i++)
		{
			FbxSurfaceMaterial *lBaseMaterial = lNode->GetMaterial(i);

			bool isLambert = lBaseMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId);
			bool isPhong = lBaseMaterial->GetClassId().Is(FbxSurfacePhong::ClassId);
			if (isLambert || isPhong)
			{
				ccMaterial::Shared mat(new ccMaterial(lBaseMaterial->GetName()));

				FbxSurfaceLambert* lLambertMat = static_cast<FbxSurfaceLambert*>(lBaseMaterial);
			
				float ambient[4];
				float diffuse[4];
				float emission[4];
				float specular[4];

				FbxSurfacePhong* lPhongMat = isPhong ? static_cast<FbxSurfacePhong*>(lBaseMaterial) : 0;

				for (int k=0; k<3; ++k)
				{
					ambient[k]  = static_cast<float>(lLambertMat->Ambient.Get()[k]);
					diffuse[k]  = static_cast<float>(lLambertMat->Diffuse.Get()[k]);
					emission[k] = static_cast<float>(lLambertMat->Emissive.Get()[k]);

					if (lPhongMat)
					{
						specular[k]		= static_cast<float>(lPhongMat->Specular.Get()[k]);
					}
				}

				mat->setAmbient(ambient);
				mat->setDiffuse(diffuse);
				mat->setEmission(emission);
				if (isPhong)
				{
					mat->setSpecular(specular);
					assert(lPhongMat);
					mat->setShininess(static_cast<float>(lPhongMat->Shininess));
				}

				//import associated texture (if any)
				{
					int lTextureIndex;
					FBXSDK_FOR_EACH_TEXTURE(lTextureIndex)
					{
						FbxProperty lProperty = lBaseMaterial->FindProperty(FbxLayerElement::sTextureChannelNames[lTextureIndex]);
						if( lProperty.IsValid() )
						{
							int lTextureCount = lProperty.GetSrcObjectCount<FbxTexture>();
							FbxTexture* texture = 0; //we can handle only one texture per material! We'll take the non layered one by default (if any)
							for (int j = 0; j < lTextureCount; ++j)
							{
								//Here we have to check if it's layeredtextures, or just textures:
								FbxLayeredTexture *lLayeredTexture = lProperty.GetSrcObject<FbxLayeredTexture>(j);
								if (lLayeredTexture)
								{
									//we don't handle layered textures!
									/*int lNbTextures = lLayeredTexture->GetSrcObjectCount<FbxTexture>();
									for (int k=0; k<lNbTextures; ++k)
									{
										FbxTexture* lTexture = lLayeredTexture->GetSrcObject<FbxTexture>(k);
										if(lTexture)
										{
										}
									}
									//*/
								}
								else
								{
									//non-layered texture
									FbxTexture* lTexture = lProperty.GetSrcObject<FbxTexture>(j);
									if(lTexture)
									{
										//we take the first non layered texture by default
										texture = lTexture;
										break;
									}
								}
							}

							if (texture)
							{
								FbxFileTexture *lFileTexture = FbxCast<FbxFileTexture>(texture);
								if (lFileTexture)
								{
									const char* texAbsoluteFilename = lFileTexture->GetFileName();
									ccLog::PrintDebug(QString("[FBX] Texture absolue filename: %1").arg(texAbsoluteFilename));
									if (texAbsoluteFilename != 0 && texAbsoluteFilename[0] != 0)
									{
										if (!mat->loadAndSetTexture(texAbsoluteFilename))
										{
											ccLog::Warning(QString("[FBX] Failed to load texture file: %1").arg(texAbsoluteFilename));
										}
									}
								}
							}
						}
					}
				}

				if (!materials)
				{
					materials = new ccMaterialSet("materials");
					mesh->addChild(materials);
				}
				materials->addMaterial(mat);
			}
			else
			{
				ccLog::Warning(QString("[FBX] Material '%1' has an unhandled type").arg(lBaseMaterial->GetName()));
			}
		}
Beispiel #13
0
// Converts a CC mesh to an FBX mesh
static FbxNode* ToFbxMesh(ccGenericMesh* mesh, FbxScene* pScene, QString filename, size_t meshIndex)
{
	if (!mesh)
		return 0;

	FbxNode* lNode = FbxNode::Create(pScene,qPrintable(mesh->getName()));
	FbxMesh* lMesh = FbxMesh::Create(pScene, qPrintable(mesh->getName()));
	lNode->SetNodeAttribute(lMesh);


	ccGenericPointCloud* cloud = mesh->getAssociatedCloud();
	if (!cloud)
		return 0;
	unsigned vertCount = cloud->size();
	unsigned faceCount = mesh->size();

	// Create control points.
	{
		lMesh->InitControlPoints(vertCount);
		FbxVector4* lControlPoints = lMesh->GetControlPoints();

		for (unsigned i=0; i<vertCount; ++i)
		{
			const CCVector3* P = cloud->getPoint(i);
			lControlPoints[i] = FbxVector4(P->x,P->y,P->z);
			//lControlPoints[i] = FbxVector4(P->x,P->z,-P->y); //DGM: see loadFile (Y and Z are inverted)
		}
	}

	ccMesh* asCCMesh = 0;
	if (mesh->isA(CC_TYPES::MESH))
		asCCMesh = static_cast<ccMesh*>(mesh);

	// normals
	if (mesh->hasNormals())
	{
		FbxGeometryElementNormal* lGeometryElementNormal = lMesh->CreateElementNormal();
		if (mesh->hasTriNormals())
		{
			// We want to have one normal per vertex of each polygon,
			// so we set the mapping mode to eByPolygonVertex.
			lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
			lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
			lGeometryElementNormal->GetIndexArray().SetCount(faceCount*3);
			
			if (asCCMesh)
			{
				NormsIndexesTableType* triNorms = asCCMesh->getTriNormsTable();
				assert(triNorms);
				for (unsigned i=0; i<triNorms->currentSize(); ++i)
				{
					const CCVector3& N = ccNormalVectors::GetNormal(triNorms->getValue(i));
					FbxVector4 Nfbx(N.x,N.y,N.z);
					lGeometryElementNormal->GetDirectArray().Add(Nfbx);
				}
				for (unsigned j=0; j<faceCount; ++j)
				{
					int i1,i2,i3;
					asCCMesh->getTriangleNormalIndexes(j,i1,i2,i3);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, i1);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, i2);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, i3);
				}
			}
			else
			{
				for (unsigned j=0; j<faceCount; ++j)
				{
					//we can't use the 'NormsIndexesTable' so we save all the normals of all the vertices
					CCVector3 Na,Nb,Nc;
					lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Na.x,Na.y,Na.z));
					lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nb.x,Nb.y,Nb.z));
					lGeometryElementNormal->GetDirectArray().Add(FbxVector4(Nc.x,Nc.y,Nc.z));
					
					mesh->getTriangleNormals(j,Na,Nb,Nc);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+0, static_cast<int>(j)*3+0);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+1, static_cast<int>(j)*3+1);
					lGeometryElementNormal->GetIndexArray().SetAt(static_cast<int>(j)*3+2, static_cast<int>(j)*3+2);
				}
			}
		}
		else
		{
			// We want to have one normal for each vertex (or control point),
			// so we set the mapping mode to eByControlPoint.
			lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
			// The first method is to set the actual normal value
			// for every control point.
			lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
			for (unsigned i=0; i<vertCount; ++i)
			{
				const CCVector3& N = cloud->getPointNormal(i);
				FbxVector4 Nfbx(N.x,N.y,N.z);
				lGeometryElementNormal->GetDirectArray().Add(Nfbx);
			}
		}
	}
	else
	{
		ccLog::Warning("[FBX] Mesh has no normal! You can manually compute them (select it then call \"Edit > Normals > Compute\")");
	}

	// Set material mapping.
	bool hasMaterial = false;
	if (asCCMesh && asCCMesh->hasMaterials())
	{
		const ccMaterialSet* matSet = asCCMesh->getMaterialSet();
		size_t matCount = matSet->size();

		//check if we have textures
		bool hasTextures = asCCMesh->hasTextures();
		if (hasTextures)
		{
			//check that we actually have materials with textures as well!
			hasTextures = false;
			for (size_t i=0; i<matCount; ++i)
			{
				ccMaterial::CShared mat = matSet->at(i);
				if (mat->hasTexture())
				{
					hasTextures = true;
					break;
				}
			}
		}

		static const char gDiffuseElementName[] = "DiffuseUV";

		// Create UV for Diffuse channel
		if (hasTextures)
		{
			FbxGeometryElementUV* lUVDiffuseElement = lMesh->CreateElementUV(gDiffuseElementName);
			assert(lUVDiffuseElement != 0);
			lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByPolygonVertex);
			lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);

			//fill Direct Array
			const TextureCoordsContainer* texCoords = asCCMesh->getTexCoordinatesTable();
			assert(texCoords);
			if (texCoords)
			{
				unsigned count = texCoords->currentSize();
				lUVDiffuseElement->GetDirectArray().SetCount(static_cast<int>(count));
				for (unsigned i=0; i<count; ++i)
				{
					const float* uv = texCoords->getValue(i);
					lUVDiffuseElement->GetDirectArray().SetAt(i,FbxVector2(uv[0],uv[1]));
				}
			}

			//fill Indexes Array
			assert(asCCMesh->hasPerTriangleTexCoordIndexes());
			if (asCCMesh->hasPerTriangleTexCoordIndexes())
			{
				unsigned triCount = asCCMesh->size();
				lUVDiffuseElement->GetIndexArray().SetCount(static_cast<int>(3*triCount));
				for (unsigned j=0; j<triCount; ++j)
				{
					int t1=0, t2=0, t3=0;
					asCCMesh->getTriangleTexCoordinatesIndexes(j, t1, t2, t3);

					lUVDiffuseElement->GetIndexArray().SetAt(j*3+0,t1);
					lUVDiffuseElement->GetIndexArray().SetAt(j*3+1,t2);
					lUVDiffuseElement->GetIndexArray().SetAt(j*3+2,t3);
				}
			}
		}

		//Textures used in this file
		QMap<QString,QString> texFilenames;
		//directory to save textures (if any)
		QFileInfo info(filename);
		QString textDirName = info.baseName() + QString(".fbm");
		QDir baseDir = info.absoluteDir();
		QDir texDir = QDir(baseDir.absolutePath() + QString("/") + textDirName);

		for (size_t i=0; i<matCount; ++i)
		{
			ccMaterial::CShared mat = matSet->at(i);
			FbxSurfacePhong *lMaterial = FbxSurfacePhong::Create(pScene, qPrintable(mat->getName()));

			const ccColor::Rgbaf& emission = mat->getEmission();
			const ccColor::Rgbaf& ambient = mat->getAmbient();
			const ccColor::Rgbaf& diffuse = mat->getDiffuseFront();
			const ccColor::Rgbaf& specular = mat->getDiffuseFront();
			lMaterial->Emissive.Set(FbxDouble3(emission.r,emission.g,emission.b));
			lMaterial->Ambient .Set(FbxDouble3( ambient.r, ambient.g, ambient.b));
			lMaterial->Diffuse .Set(FbxDouble3( diffuse.r, diffuse.g, diffuse.b));
			lMaterial->Specular.Set(FbxDouble3(specular.r,specular.g,specular.b));
			lMaterial->Shininess = mat->getShininessFront();
			lMaterial->ShadingModel.Set("Phong");

			if (hasTextures && mat->hasTexture())
			{
				QString texFilename = mat->getTextureFilename();
				
				//texture has not already been processed
				if (!texFilenames.contains(texFilename))
				{
					//if necessary, we (try to) create a subfolder to store textures
					if (!texDir.exists())
					{
						texDir = baseDir;
						if (texDir.mkdir(textDirName))
						{
							texDir.cd(textDirName);
						}
						else
						{
							textDirName = QString();
							ccLog::Warning("[FBX] Failed to create subfolder '%1' to store texture files (files will be stored next to the .fbx file)");
						}
					}

					QFileInfo fileInfo(texFilename);
					QString baseTexName = fileInfo.fileName();
					//add extension
					QString extension = QFileInfo(texFilename).suffix();
					if (fileInfo.suffix().isEmpty())
						baseTexName += QString(".png");

					QString absoluteFilename = texDir.absolutePath() + QString("/") + baseTexName;
					ccLog::PrintDebug(QString("[FBX] Material '%1' texture: %2").arg(mat->getName()).arg(absoluteFilename));

					texFilenames[texFilename] = absoluteFilename;
				}
				//mat.texture.save(absoluteFilename);

				// Set texture properties.
				FbxFileTexture* lTexture = FbxFileTexture::Create(pScene,"DiffuseTexture");
				assert(!texFilenames[texFilename].isEmpty());
				lTexture->SetFileName(qPrintable(texFilenames[texFilename]));
				lTexture->SetTextureUse(FbxTexture::eStandard);
				lTexture->SetMappingType(FbxTexture::eUV);
				lTexture->SetMaterialUse(FbxFileTexture::eModelMaterial);
				lTexture->SetSwapUV(false);
				lTexture->SetTranslation(0.0, 0.0);
				lTexture->SetScale(1.0, 1.0);
				lTexture->SetRotation(0.0, 0.0);
				lTexture->UVSet.Set(FbxString(gDiffuseElementName)); // Connect texture to the proper UV

				// don't forget to connect the texture to the corresponding property of the material
				lMaterial->Diffuse.ConnectSrcObject(lTexture);
			}

			int matIndex = lNode->AddMaterial(lMaterial);
			assert(matIndex  == static_cast<int>(i));
		}

		//don't forget to save the texture files
		{
			for (QMap<QString,QString>::ConstIterator it = texFilenames.begin(); it != texFilenames.end(); ++it)
			{
				const QImage image = ccMaterial::GetTexture(it.key());
				image.mirrored().save(it.value());
			}
			
			texFilenames.clear(); //don't need this anymore!
		}

		// Create 'triangle to material index' mapping
		{
			FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial();
			lMaterialElement->SetMappingMode(FbxGeometryElement::eByPolygon);
			lMaterialElement->SetReferenceMode(FbxGeometryElement::eIndexToDirect);
		}

		hasMaterial = true;
	}

	// colors
	if (cloud->hasColors())
	{
		FbxGeometryElementVertexColor* lGeometryElementVertexColor = lMesh->CreateElementVertexColor();
		lGeometryElementVertexColor->SetMappingMode(FbxGeometryElement::eByControlPoint);
		lGeometryElementVertexColor->SetReferenceMode(FbxGeometryElement::eDirect);
		lGeometryElementVertexColor->GetDirectArray().SetCount(vertCount);
		for (unsigned i=0; i<vertCount; ++i)
		{
			const colorType* C = cloud->getPointColor(i);
			FbxColor col(	static_cast<double>(C[0])/ccColor::MAX,
							static_cast<double>(C[1])/ccColor::MAX,
							static_cast<double>(C[2])/ccColor::MAX );
			lGeometryElementVertexColor->GetDirectArray().SetAt(i,col);
		}

		if (!hasMaterial)
		{
			//it seems that we have to create a fake material in order for the colors to be displayed (in Unity and FBX Review at least)!
			FbxSurfacePhong *lMaterial = FbxSurfacePhong::Create(pScene, "ColorMaterial");

			lMaterial->Emissive.Set(FbxDouble3(0,0,0));
			lMaterial->Ambient.Set(FbxDouble3(0,0,0));
			lMaterial->Diffuse.Set(FbxDouble3(1,1,1));
			lMaterial->Specular.Set(FbxDouble3(0,0,0));
			lMaterial->Shininess = 0;
			lMaterial->ShadingModel.Set("Phong");

			FbxGeometryElementMaterial* lMaterialElement = lMesh->CreateElementMaterial();
			lMaterialElement->SetMappingMode(FbxGeometryElement::eAllSame);
			lMaterialElement->SetReferenceMode(FbxGeometryElement::eDirect);
			lNode->AddMaterial(lMaterial);
		}
	}

	// Create polygons
	{
		for (unsigned j=0; j<faceCount; ++j)
		{
			const CCLib::TriangleSummitsIndexes* tsi = mesh->getTriangleIndexes(j);

			int matIndex = hasMaterial ? asCCMesh->getTriangleMtlIndex(j) : -1;
			lMesh->BeginPolygon(matIndex);
			lMesh->AddPolygon(tsi->i1);
			lMesh->AddPolygon(tsi->i2);
			lMesh->AddPolygon(tsi->i3);
			lMesh->EndPolygon();
		}
	}

	return lNode;
}
Beispiel #14
0
//===============================================================================================================================
bool FBXLoader::LoadVertexNormal(FbxMesh* mesh, int inCtrlPointIndex, int inVertexCounter, int normalElement, XMFLOAT3& outNormal)
{
	if (mesh->GetElementNormalCount() < 1)
	{
		throw std::exception("Invalid Normal Number");
	}
	
	int directIndex = -1;
	
	FbxGeometryElementNormal* vertexNormal = mesh->GetElementNormal(normalElement);
	
	switch (vertexNormal->GetMappingMode())
	{
		case FbxGeometryElement::eByControlPoint:
		{
			switch (vertexNormal->GetReferenceMode())
			{
				case FbxGeometryElement::eDirect:
				{
					directIndex = inCtrlPointIndex;
					//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:
				{
					directIndex = vertexNormal->GetIndexArray().GetAt(inCtrlPointIndex);
					//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;
		}
		break;
		case FbxGeometryElement::eByPolygonVertex:
		{
			switch (vertexNormal->GetReferenceMode())
			{
				case FbxGeometryElement::eDirect:
				{
					directIndex = inVertexCounter;
					//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:
				{
					directIndex = vertexNormal->GetIndexArray().GetAt(inVertexCounter);
					//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;
	}
	
	if (directIndex != -1)
	{
		FbxVector4 norm = vertexNormal->GetDirectArray().GetAt(directIndex);
		
		outNormal = XMFLOAT3((float)norm.mData[0], (float)norm.mData[1], (float)norm.mData[2]);
		
		return true;
	}
	
	return false;
}
Beispiel #15
0
	std::shared_ptr<Mesh> FbxUtil::CreateMesh(FbxMesh *fbxMesh)
	{
		Mesh::Ptr mesh = Mesh::Create(fbxMesh->GetName());

		// read physical data.

		int polygonCount = fbxMesh->GetPolygonCount();
		int indicesCount = polygonCount * 3;

		mesh->Positions.Data.reserve(indicesCount * 3);
		mesh->Indices.Data.reserve(indicesCount);

		if ((m_Options & Options::UV) && fbxMesh->GetElementUVCount() > 0)
			mesh->UVs.Data.reserve(indicesCount * 2);

		if ((m_Options & Options::NORMAL) && fbxMesh->GetElementNormalCount() > 0)
			mesh->Normals.Data.reserve(indicesCount * 3);

		if ((m_Options & Options::TANGENT) && fbxMesh->GetElementTangent() > 0)
			mesh->Tangents.Data.reserve(indicesCount * 3);

		int normalCounter = 0, uvCounter = 0, tangentCounter = 0;

		for (int i = 0; i < polygonCount; i++)
		{
			for (int j = 0; j < 3; j++)
			{
				int ctrPtrIndex = fbxMesh->GetPolygonVertex(i, j);

				auto position = fbxMesh->GetControlPointAt(ctrPtrIndex);
				mesh->Positions.Data.push_back((float)position.mData[0]);
				mesh->Positions.Data.push_back((float)position.mData[1]);
				mesh->Positions.Data.push_back((float)position.mData[2]);

				// uv
				if ((m_Options & Options::UV) && fbxMesh->GetElementUVCount() > 0)
				{
					int uvIndex = 0;
					FbxGeometryElementUV* vertexUV = fbxMesh->GetElementUV();

					if (vertexUV->GetMappingMode() == FbxGeometryElement::eByControlPoint)
					{
						if (vertexUV->GetReferenceMode() == FbxGeometryElement::eDirect)
							uvIndex = ctrPtrIndex;
						else if (vertexUV->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							uvIndex = vertexUV->GetIndexArray().GetAt(ctrPtrIndex);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");
					}
					else if (vertexUV->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
					{
						if (vertexUV->GetReferenceMode() == FbxGeometryElement::eDirect)
							uvIndex = uvCounter;
						else if (vertexUV->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							uvIndex = vertexUV->GetIndexArray().GetAt(uvCounter);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");

						uvCounter++;
					}

					auto uv = vertexUV->GetDirectArray().GetAt(uvIndex);
					mesh->UVs.Data.push_back((float)uv.mData[0]);
					mesh->UVs.Data.push_back(1.0f - (float)uv.mData[1]);
				}

				// normal
				if ((m_Options & Options::NORMAL) && fbxMesh->GetElementNormalCount() > 0)
				{
					int normalIndex = 0;
					FbxGeometryElementNormal* vertexNormal = fbxMesh->GetElementNormal();

					if (vertexNormal->GetMappingMode() == FbxGeometryElement::eByControlPoint)
					{
						if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eDirect)
							normalIndex = ctrPtrIndex;
						else if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							normalIndex = vertexNormal->GetIndexArray().GetAt(ctrPtrIndex);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");
					}
					else if (vertexNormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
					{
						if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eDirect)
							normalIndex = normalCounter;
						else if (vertexNormal->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							normalIndex = vertexNormal->GetIndexArray().GetAt(normalCounter);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");

						normalCounter++;
					}

					auto normal = vertexNormal->GetDirectArray().GetAt(normalIndex);
					mesh->Normals.Data.push_back((float)normal.mData[0]);
					mesh->Normals.Data.push_back((float)normal.mData[1]);
					mesh->Normals.Data.push_back((float)normal.mData[2]);
				}

				// tangent
				if ((m_Options & Options::TANGENT) && fbxMesh->GetElementNormalCount() > 0)
				{
					int tangentIndex = 0;
					FbxGeometryElementTangent* vertexTangent = fbxMesh->GetElementTangent();

					if (vertexTangent->GetMappingMode() == FbxGeometryElement::eByControlPoint)
					{
						if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eDirect)
							tangentIndex = ctrPtrIndex;
						else if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							tangentIndex = vertexTangent->GetIndexArray().GetAt(ctrPtrIndex);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");
					}
					else if (vertexTangent->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
					{
						if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eDirect)
							tangentIndex = tangentCounter;
						else if (vertexTangent->GetReferenceMode() == FbxGeometryElement::eIndexToDirect)
							tangentIndex = vertexTangent->GetIndexArray().GetAt(tangentCounter);
						else
							ASSERT_MSG(false, "Error: Invalid Reference Mode!");

						tangentCounter++;
					}

					auto tangent = vertexTangent->GetDirectArray().GetAt(tangentIndex);
					mesh->Tangents.Data.push_back((float)tangent.mData[0]);
					mesh->Tangents.Data.push_back((float)tangent.mData[1]);
					mesh->Tangents.Data.push_back((float)tangent.mData[2]);
				}

				mesh->Indices.Data.push_back(i * 3 + j);
			}
		}

		LOGD << mesh->GetName() << " [vtx: " << mesh->Positions.Data.size() / 3 << " tris: " << mesh->Indices.Data.size() / 3 << "]";

		if(m_Options & Options::OPTIMIZE_MESH)
			MeshUtil::Instance()->OptimizeMesh(mesh);

		mesh->CalculateAABB();

		return mesh;
	}
Beispiel #16
0
void loadNormal(FbxMesh* fbxMesh, int vertexIndex, int controlPointIndex, Vertex* vertex)
{
    if (fbxMesh->GetElementNormalCount() > 0)
    {
        // Get only the first
        FbxGeometryElementNormal* normal = fbxMesh->GetElementNormal(0);
        FbxGeometryElement::EMappingMode mappingMode = normal->GetMappingMode();
        if (mappingMode == FbxGeometryElement::eByControlPoint)
        {
            switch (normal->GetReferenceMode())
            {
            case FbxGeometryElement::eDirect:
                {
                    FbxVector4 vec4 = normal->GetDirectArray().GetAt(controlPointIndex);
                    vertex->hasNormal = true;
                    vertex->normal.x = (float)vec4[0];
                    vertex->normal.y = (float)vec4[1];
                    vertex->normal.z = (float)vec4[2];
                }
                break;
            case FbxGeometryElement::eIndexToDirect:
                {
                    int id = normal->GetIndexArray().GetAt(controlPointIndex);
                    FbxVector4 vec4 = normal->GetDirectArray().GetAt(id);
                    vertex->hasNormal = true;
                    vertex->normal.x = (float)vec4[0];
                    vertex->normal.y = (float)vec4[1];
                    vertex->normal.z = (float)vec4[2];
                }
                break;
            default:
                break;
            }
        }
        else if (mappingMode == FbxGeometryElement::eByPolygonVertex)
        {
            switch (normal->GetReferenceMode())
            {
            case FbxGeometryElement::eDirect:
                {
                    FbxVector4 vec4 = normal->GetDirectArray().GetAt(vertexIndex);
                    vertex->hasNormal = true;
                    vertex->normal.x = (float)vec4[0];
                    vertex->normal.y = (float)vec4[1];
                    vertex->normal.z = (float)vec4[2];
                }
                break;
            case FbxGeometryElement::eIndexToDirect:
                {
                    int id = normal->GetIndexArray().GetAt(vertexIndex);
                    FbxVector4 vec4 = normal->GetDirectArray().GetAt(id);
                    vertex->hasNormal = true;
                    vertex->normal.x = (float)vec4[0];
                    vertex->normal.y = (float)vec4[1];
                    vertex->normal.z = (float)vec4[2];
                }
                break;
            default:
                break;
            }
        }
    }
}
Beispiel #17
0
void FBXSceneImporter::read_mesh(FbxNode *pNode, FbxMesh* pMesh)
{
	std::vector<Mesh::Vertex> vertices;
	std::vector<int> indices;
	
	//pMesh->GenerateTangentsDataForAllUVSets();

	Mesh *new_mesh = new Mesh();
	
	new_mesh->set_name(pNode->GetName());

	int polygonCount = pMesh->GetPolygonCount();
	FbxVector4* controlPoints = pMesh->GetControlPoints();
	int controlPointCount = pMesh->GetControlPointsCount();

	int vertexID = 0;

	for (int polygon = polygonCount - 1; polygon > -1; polygon--)
	{
		int polyVertCount = pMesh->GetPolygonSize(polygon);
		assert(polyVertCount == 3);

		for (int polyVert = 0; polyVert < polyVertCount; polyVert++)
		{
			Mesh::Vertex vertex;

			int cpIndex = pMesh->GetPolygonVertex(polygon, polyVert);

			// Grab our CP index as well our position information
			//uniqueVert.m_nControlPointIndex = cpIndex;
			vertex.position[0] = controlPoints[cpIndex].mData[0];
			vertex.position[1] = controlPoints[cpIndex].mData[1];
			vertex.position[2] = controlPoints[cpIndex].mData[2];
			vertex.position[3] = 1;

			// Grab UVs
			int uvElementCount = pMesh->GetElementUVCount();
			int ctrlPointIndex = pMesh->GetPolygonVertex(polygon, polyVert);

			for (int uvElement = 0; uvElement < uvElementCount; uvElement++)
			{
				FbxGeometryElementUV* geomElementUV = pMesh->GetElementUV(uvElement);

				FbxLayerElement::EMappingMode mapMode = geomElementUV->GetMappingMode();
				FbxLayerElement::EReferenceMode refMode = geomElementUV->GetReferenceMode();

				if (FbxGeometryElement::eByControlPoint == mapMode)
				{
					switch (geomElementUV->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
					{
						vertex.texture_coord.x = static_cast<float>(geomElementUV->GetDirectArray().GetAt(ctrlPointIndex).mData[0]);
						vertex.texture_coord.y = static_cast<float>(geomElementUV->GetDirectArray().GetAt(ctrlPointIndex).mData[1]);
					}
					break;

					case FbxGeometryElement::eIndexToDirect:
					{
						int index = geomElementUV->GetIndexArray().GetAt(ctrlPointIndex);
						vertex.texture_coord.x = static_cast<float>(geomElementUV->GetDirectArray().GetAt(index).mData[0]);
						vertex.texture_coord.y = static_cast<float>(geomElementUV->GetDirectArray().GetAt(index).mData[1]);
					}
					break;

					default:
						throw std::exception("Invalid Reference");
					}
				}
				if (FbxGeometryElement::eByPolygonVertex == mapMode)
				{
					int directIndex = -1;
					if (FbxGeometryElement::eDirect == refMode)
					{
						directIndex = vertexID;
					}
					else if (FbxGeometryElement::eIndexToDirect == refMode)
					{
						directIndex = geomElementUV->GetIndexArray().GetAt(vertexID);
					}

					// If we got an index
					if (directIndex != -1)
					{
						FbxVector4 texture_coord = geomElementUV->GetDirectArray().GetAt(directIndex);

						vertex.texture_coord = D3DXVECTOR4((float)texture_coord.mData[0], (float)texture_coord.mData[1], 0, 0);
					}
				}
			}

			// Grab normals
			int normElementCount = pMesh->GetElementNormalCount();

			for (int normalElement = 0; normalElement < normElementCount; normalElement++)
			{
				FbxGeometryElementNormal* geomElementNormal = pMesh->GetElementNormal(normalElement);

				FbxLayerElement::EMappingMode mapMode = geomElementNormal->GetMappingMode();
				FbxLayerElement::EReferenceMode refMode = geomElementNormal->GetReferenceMode();

				FbxVector4 fbxNormal;
				pMesh->GetPolygonVertexNormal(polygon, polyVert, fbxNormal);
				fbxNormal.Normalize();

				vertex.normal = D3DXVECTOR4(fbxNormal.mData[0], fbxNormal.mData[1], fbxNormal.mData[2], 0);

				//if (FbxGeometryElement::eByControlPoint == mapMode)
				//{ 
				//	switch (geomElementNormal->GetReferenceMode())
				//	{
				//	case FbxGeometryElement::eDirect:
				//	{
				//		vertex.normal.x = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(ctrlPointIndex).mData[0]);
				//		vertex.normal.y = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(ctrlPointIndex).mData[1]);
				//		vertex.normal.z = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(ctrlPointIndex).mData[2]);
				//		D3DXVec4Normalize(&vertex.normal, &vertex.normal);
				//	}
				//	break;
				//
				//	case FbxGeometryElement::eIndexToDirect:
				//	{
				//		int index = geomElementNormal->GetIndexArray().GetAt(ctrlPointIndex);
				//		vertex.normal.x = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(index).mData[0]);
				//		vertex.normal.y = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(index).mData[1]);
				//		vertex.normal.z = static_cast<float>(geomElementNormal->GetDirectArray().GetAt(index).mData[2]);
				//		D3DXVec4Normalize(&vertex.normal, &vertex.normal);
				//	}
				//	break;
				//
				//	default:
				//		throw std::exception("Invalid Reference");
				//	}
				//}
				//if (FbxGeometryElement::eByPolygonVertex == mapMode)
				//{
				//	int directIndex = -1;
				//	if (FbxGeometryElement::eDirect == refMode)
				//	{
				//		directIndex = vertexID;
				//	}
				//	else if (FbxGeometryElement::eIndexToDirect == refMode)
				//	{
				//		directIndex = geomElementNormal->GetIndexArray().GetAt(vertexID);
				//	}
				//
				//	// If we got an index
				//	if (directIndex != -1)
				//	{
				//		FbxVector4 norm = geomElementNormal->GetDirectArray().GetAt(directIndex);
				//
				//		D3DXVECTOR4 normal_final((float)norm.mData[0], (float)norm.mData[1], (float)norm.mData[2], 0);
				//		D3DXVec4Normalize(&vertex.normal, &normal_final);
				//	}
				//}


			}

			// grab tangents
			int tangentElementCount = pMesh->GetElementTangentCount();

			for (int normalElement = 0; normalElement < tangentElementCount; normalElement++)
			{
				FbxGeometryElementTangent* geomElementTangent = pMesh->GetElementTangent(normalElement);

				FbxLayerElement::EMappingMode mapMode = geomElementTangent->GetMappingMode();
				FbxLayerElement::EReferenceMode refMode = geomElementTangent->GetReferenceMode();

				int directIndex = -1;

				if (FbxGeometryElement::eByPolygonVertex == mapMode)
				{
					if (FbxGeometryElement::eDirect == refMode)
					{
						directIndex = vertexID;
					}
					else if (FbxGeometryElement::eIndexToDirect == refMode)
					{
						directIndex = geomElementTangent->GetIndexArray().GetAt(vertexID);
					}
				}

				// If we got an index
				if (directIndex != 1)
				{
					FbxVector4 tangent = geomElementTangent->GetDirectArray().GetAt(directIndex);

					vertex.tangent = D3DXVECTOR4((float)tangent.mData[0], (float)tangent.mData[1], (float)tangent.mData[2], 0);
				}

			}

			size_t size = vertices.size();
			size_t i = size;

			//for (i = 0; i < size; i++)
			//{
			//	if (vertex == vertices[i])
			//	{
			//		break;
			//	}
			//}
			//
			if (i == size)
			{
				vertices.push_back(vertex);
			}

			indices.push_back(i);
			++vertexID;
		}

		//int cur_size = indices.size();
		//int temp = indices[cur_size - 3];
		//indices[cur_size - 3] = indices[cur_size - 1];
		//indices[cur_size - 1] = temp;
	}

	int materialCount = pNode->GetSrcObjectCount<FbxSurfaceMaterial>();

	new_mesh->create_from_buffers(vertices, indices);
	scene_to_fill->add_mesh(new_mesh);

	if (materialCount > 0)
	{
		FbxSurfaceMaterial* material = (FbxSurfaceMaterial*)pNode->GetSrcObject<FbxSurfaceMaterial>(0);
		new_mesh->set_material(read_material(pNode, material));
	}

	get_transformation_matrix(pNode, new_mesh);
	cout << "Read mesh : " << new_mesh->get_name() << "\n";

}
Beispiel #18
0
//--------------------------------------------------------------------------
void SaveMesh(FbxNode* pNode, const VeDirectoryPtr& spDest) noexcept
{
	Mesh kMesh;
	FbxMesh* pMesh = (FbxMesh*)pNode->GetNodeAttribute();
	
	kMesh.m_kName = pNode->GetName();
	kMesh.m_stFaces = pMesh->GetPolygonCount();
	kMesh.m_stVerts = kMesh.m_stFaces * 3;

	kMesh.m_kIndices.resize(kMesh.m_stVerts);
	kMesh.m_kPosition.resize(kMesh.m_stVerts);

	kMesh.m_kNormals.resize(pMesh->GetElementNormalCount());
	for (auto& v : kMesh.m_kNormals)
	{
		v.resize(kMesh.m_stVerts);
	}
	kMesh.m_kTexcoords.resize(pMesh->GetElementUVCount());
	for (auto& v : kMesh.m_kTexcoords)
	{
		v.resize(kMesh.m_stVerts);
	}
	kMesh.m_kColors.resize(pMesh->GetElementVertexColorCount());
	for (auto& v : kMesh.m_kColors)
	{
		v.resize(kMesh.m_stVerts);
	}	

	int element_mat = -1;
	for (int i(0); i < pMesh->GetElementMaterialCount(); ++i)
	{
		FbxGeometryElementMaterial* lMaterialElement = pMesh->GetElementMaterial(i);
		if (lMaterialElement->GetMappingMode() == FbxGeometryElement::eByPolygon)
		{
			element_mat = i;
			break;
		}
	}
	if (element_mat >= 0)
	{
		kMesh.m_kAttributes.resize(kMesh.m_stFaces);
	}

	FbxVector4* lControlPoints = pMesh->GetControlPoints();
	for (int i(0); i < (int)(kMesh.m_stFaces); ++i)
	{
		int lPolygonSize = pMesh->GetPolygonSize(i);
		VE_ASSERT_ALWAYS(lPolygonSize == 3);
		for (int j(0); j < lPolygonSize; ++j)
		{
			uint32_t u32Index = i * 3 + j;
			kMesh.m_kIndices[u32Index] = u32Index;
			int lControlPointIndex = pMesh->GetPolygonVertex(i, j);
			auto& pos = kMesh.m_kPosition[u32Index];
			pos.x = (float)lControlPoints[lControlPointIndex][0];
			pos.y = (float)lControlPoints[lControlPointIndex][1];
			pos.z = (float)lControlPoints[lControlPointIndex][2];
			
			for (int k(0); k < (int)(kMesh.m_kColors.size()); ++k)
			{
				FbxColor c;
				FbxGeometryElementVertexColor* leVtxc = pMesh->GetElementVertexColor(k);
				switch (leVtxc->GetMappingMode())
				{
				default:
					break;
				case FbxGeometryElement::eByControlPoint:
					switch (leVtxc->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
						c = leVtxc->GetDirectArray().GetAt(lControlPointIndex);
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leVtxc->GetIndexArray().GetAt(lControlPointIndex);
						c = leVtxc->GetDirectArray().GetAt(id);
					}
					break;
					default:
						break; // other reference modes not shown here!
					}
					break;

				case FbxGeometryElement::eByPolygonVertex:
				{
					switch (leVtxc->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
						c = leVtxc->GetDirectArray().GetAt(u32Index);
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leVtxc->GetIndexArray().GetAt(u32Index);
						c = leVtxc->GetDirectArray().GetAt(id);
					}
					break;
					default:
						break; // other reference modes not shown here!
					}
				}
				break;
				case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs
				case FbxGeometryElement::eAllSame:   // doesn't make much sense for UVs
				case FbxGeometryElement::eNone:       // doesn't make much sense for UVs
					break;
				}
				auto& color = kMesh.m_kColors[k][u32Index];
				color.x = (float)c[0];
				color.y = (float)c[1];
				color.z = (float)c[2];
				color.w = (float)c[3];
			}

			for (int k(0); k < (int)(kMesh.m_kTexcoords.size()); ++k)
			{
				FbxVector2 uv;
				FbxGeometryElementUV* leUV = pMesh->GetElementUV(k);
				switch (leUV->GetMappingMode())
				{
				default:
					break;
				case FbxGeometryElement::eByControlPoint:
					switch (leUV->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
						uv = leUV->GetDirectArray().GetAt(lControlPointIndex);
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leUV->GetIndexArray().GetAt(lControlPointIndex);
						uv = leUV->GetDirectArray().GetAt(id);
					}
					break;
					default:
						break; // other reference modes not shown here!
					}
					break;

				case FbxGeometryElement::eByPolygonVertex:
				{
					int lTextureUVIndex = pMesh->GetTextureUVIndex(i, j);
					switch (leUV->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
					case FbxGeometryElement::eIndexToDirect:
					{
						uv = leUV->GetDirectArray().GetAt(lTextureUVIndex);
					}
					break;
					default:
						break; // other reference modes not shown here!
					}
				}
				break;

				case FbxGeometryElement::eByPolygon: // doesn't make much sense for UVs
				case FbxGeometryElement::eAllSame:   // doesn't make much sense for UVs
				case FbxGeometryElement::eNone:       // doesn't make much sense for UVs
					break;
				}

				auto& texcoord = kMesh.m_kTexcoords[k][u32Index];
				texcoord.x = (float)uv[0];
				texcoord.y = (float)uv[1];
			}
			
			for (int k(0); k < (int)(kMesh.m_kNormals.size()); ++k)
			{
				FbxVector4 n;
				FbxGeometryElementNormal* leNormal = pMesh->GetElementNormal(k);
				if (leNormal->GetMappingMode() == FbxGeometryElement::eByPolygonVertex)
				{
					switch (leNormal->GetReferenceMode())
					{
					case FbxGeometryElement::eDirect:
						n = leNormal->GetDirectArray().GetAt(u32Index);
						break;
					case FbxGeometryElement::eIndexToDirect:
					{
						int id = leNormal->GetIndexArray().GetAt(u32Index);
						n = leNormal->GetDirectArray().GetAt(id);
					}
					break;
					default:
						break; // other reference modes not shown here!
					}
				}

				auto& normal = kMesh.m_kNormals[k][u32Index];
				normal.x = (float)n[0];
				normal.y = (float)n[1];
				normal.z = (float)n[2];
			}

			if (element_mat >= 0)
			{
				FbxGeometryElementMaterial* lMaterialElement = pMesh->GetElementMaterial(element_mat);
				FbxSurfaceMaterial* lMaterial = NULL;
				int lMatId = -1;
				lMaterial = pMesh->GetNode()->GetMaterial(lMaterialElement->GetIndexArray().GetAt(i));
				lMatId = lMaterialElement->GetIndexArray().GetAt(i);
				kMesh.m_kAttributes[i] = lMatId;
			}
		}
	}
	kMesh.Process();
	kMesh.Save(spDest);
}