Example #1
0
FbxNode *WccToFbxExporter::createSphere(FbxScene *pScene, const char *pName, float size)
{
    FbxNurbs* lNurbs = FbxNurbs::Create(pScene,pName);
    // Set nurbs properties.
    lNurbs->SetOrder(4, 4);
    lNurbs->SetStep(2, 2);
    lNurbs->InitControlPoints(8, FbxNurbs::ePeriodic, 7, FbxNurbs::eOpen);
    double lUKnotVector[] = { -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0 };
    memcpy(lNurbs->GetUKnotVector(), lUKnotVector, lNurbs->GetUKnotCount()*sizeof(double));
    double lVKnotVector[] = { 0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 4.0, 4.0, 4.0 };
    memcpy(lNurbs->GetVKnotVector(), lVKnotVector, lNurbs->GetVKnotCount()*sizeof(double));
    FbxVector4* lVector4 = lNurbs->GetControlPoints();
    int i, j;
    double lPi = 3.14159;
    double lYAngle[] = { 90.0, 90.0, 52.0, 0.0, -52.0, -90.0, -90.0 };
    double lRadius[] = { 0.0, 0.283, 0.872, 1.226, 0.872, 0.283, 0.0};
    for (i = 0; i < 7; i++)
    {
        for (j = 0; j < 8; j++)
        {
            double lX = size * lRadius[i] * cos(lPi/4*j);
            double lY = size * sin(2*lPi/360*lYAngle[i]);
            double lZ = size * lRadius[i] * sin(lPi/4*j);
            double lWeight = 1.0;
            lVector4[8*i + j].Set(lX, lY, lZ, lWeight);
        }
    }
    FbxNode* lNode = FbxNode::Create(pScene,pName);
    lNode->SetNodeAttribute(lNurbs);
    lNode->LclTranslation.Set(FbxVector4(0.0, 0.0, 0.0));
    lNode->LclRotation.Set(FbxVector4(0.0, 0.0, 0.0));
    lNode->LclScaling.Set(FbxVector4(1.0, 1.0, 1.0));
    return lNode;
}
Example #2
0
FbxNode* ILDLMesh::CreateMesh( FbxScene* pScene, const char* pName )
{
    int nVerts  = (int)m_vertex_list.size();

    FbxMesh* lMesh = FbxMesh::Create(pScene,pName);
    lMesh->InitControlPoints( nVerts );
    FbxVector4* lControlPoints = lMesh->GetControlPoints();
    FbxGeometryElementNormal* lGeometryElementNormal= lMesh->CreateElementNormal();
    lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
    lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);


    int vi = 0, glidx = 0;
    for( ILDLVertexIter i = m_vertex_list.begin();
        i !=  m_vertex_list.end(); ++i, vi++ )
    {
        ILDLVertexPtr vp = (*i);
        vp->m_glIdx = glidx;
        vec3 coords = vp->getCoords();
        lControlPoints[vi] = FbxVector4( coords[0], coords[1], coords[2] );
        vec3 normal = vp->getNormal();
        lGeometryElementNormal->GetDirectArray().Add( FbxVector4( normal[0], normal[1], normal[2] ) );
        glidx++;
    }

    for( ILDLFaceIter i = m_face_list.begin();
        i != m_face_list.end(); ++i )
    {
        ILDLFacePtr fp = *i;
        ILDLFaceVertexPtr fvp = fp->front();

        lMesh->BeginPolygon(-1, -1, -1, false);
        lMesh->AddPolygon( fvp->getVertexPtr()->m_glIdx );
        fvp = fvp->next();
        lMesh->AddPolygon( fvp->getVertexPtr()->m_glIdx );
        fvp = fvp->next();
        lMesh->AddPolygon( fvp->getVertexPtr()->m_glIdx );
        lMesh->EndPolygon ();
    }


    FbxNode* lNode = FbxNode::Create(pScene,pName);
    lNode->SetNodeAttribute(lMesh);

    return lNode;
}
Example #3
0
int main(int argc, char** argv) {
	if (argc < 2) {
		printf("Usage: emdfbx model.emd skeleton.esk output.fbx\n       Can include multiple emd and esk files into one fbx.");
		getchar();
		return 1;
	}

	LibXenoverse::initializeDebuggingLog();

	vector<string> model_filenames;
	vector<string> skeleton_filenames;
	vector<string> animation_filenames;
	string export_filename = "";

	for (int i = 1; i < argc; i++)  {
		string parameter = ToString(argv[i]);

		string extension = LibXenoverse::extensionFromFilename(parameter);

		if (extension == "emd") {
			model_filenames.push_back(parameter);
		}

		if (extension == "esk") {
			skeleton_filenames.push_back(parameter);
		}

		if (extension == "ean") {
			animation_filenames.push_back(parameter);
		}

		if (extension == "fbx") {
			export_filename = parameter;
		}
	}

	if (!export_filename.size()) {
		if (model_filenames.size()) {
			export_filename = model_filenames[0] + ".fbx";
		}
		else if (skeleton_filenames.size()) {
			export_filename = skeleton_filenames[0] + ".fbx";
		}
		else {
			export_filename = "Out.fbx";
		}
	}

	// Create FBX Manager
	FbxManager *sdk_manager = FbxManager::Create();
	FbxIOSettings *ios = FbxIOSettings::Create(sdk_manager, IOSROOT);
	ios->SetBoolProp(EXP_FBX_EMBEDDED, true);
	sdk_manager->SetIOSettings(ios);

	// Create Scene
	vector<FbxNode *> global_fbx_bones;
	global_fbx_bones.reserve(300);
	vector<size_t> global_fbx_bones_index;													//TODO find a better way to link skeleton and animations
	global_fbx_bones_index.reserve(300);

	vector<FbxAnimCurveNode *> global_fbx_animation;
	global_fbx_animation.reserve(300);

	FbxScene *scene = FbxScene::Create(sdk_manager, "EMDFBXScene");


	// Load Shaders and convert it to fx file (will be use by fbx).
	vector<string> shader_names;
	shader_names.push_back("adam_shader/shader_age_vs.emb");								//must specified vs folloxed by ps shaders
	shader_names.push_back("adam_shader/shader_age_ps.emb");
	shader_names.push_back("adam_shader/shader_default_vs.emb");
	shader_names.push_back("adam_shader/shader_default_ps.emb");
	

	bool needs_install_shaders = false;
	for (size_t i = 0; i < shader_names.size(); i++) {
		if (!LibXenoverse::fileCheck(shader_names[i])) {
			needs_install_shaders = true;
			break;
		}
	}

	if (needs_install_shaders) {
		printf("Shaders not found. Please use Xenoviewer to prepare shaders in bin folder.");
		return -1;
	}

	for (size_t i = 0; i+1 < shader_names.size(); i+=2) {
		
		LibXenoverse::EMB *shader_pack_vs = new LibXenoverse::EMB();
		LibXenoverse::EMB *shader_pack_ps = new LibXenoverse::EMB();

		if (!shader_pack_vs->load(shader_names[i])) {
			delete shader_pack_vs;
			printf("Couldn't load Shader Pack %s. File is either missing, open by another application, or corrupt.", shader_names[i].c_str());
			continue;
		}
		if (!shader_pack_ps->load(shader_names[i+1])) {
			delete shader_pack_vs;
			delete shader_pack_ps;
			printf("Couldn't load Shader Pack %s. File is either missing, open by another application, or corrupt.", shader_names[i].c_str());
			continue;
		}

		shader_pack_vs->exportShadersToFx(shader_pack_vs, shader_pack_ps);					//convert all shaders in fx file with defaults program parameters (like Ogre's version).
	}



	//build FBX skeleton
	for (size_t i = 0; i < skeleton_filenames.size(); i++) {
		LibXenoverse::ESK *esk_skeleton = new LibXenoverse::ESK();
		esk_skeleton->load(skeleton_filenames[i]);
		vector<FbxNode *> fbx_bones = esk_skeleton->createFBXSkeleton(scene);

		for (size_t j = 0; j < fbx_bones.size(); j++) {
			global_fbx_bones.push_back(fbx_bones[j]);
			global_fbx_bones_index.push_back(j);											//kepp index of bone to link with animations.
		}
	}



	//build FBX animations
	for (size_t i = 0; i < animation_filenames.size(); i++) {
		
		string filename = animation_filenames.at(i);
		string ean_name = LibXenoverse::nameFromFilenameNoExtension(filename, true);

		//vector<FbxAnimCurveNode *> global_fbx_animation;

		LibXenoverse::EAN *animation = new LibXenoverse::EAN();
		if (animation->load(filename)) {

			std::vector<FbxAnimStack *> list_AnimStack;
			size_t nbAnims = animation->getAnimations().size();
			for (size_t j = 0; j < nbAnims; j++) {													//we create only one stack and one layer by animation. each will animate all bones of all skeleton.

				LibXenoverse::EANAnimation *anim_tmp = &(animation->getAnimations().at(j));

				FbxAnimStack* lAnimStack = FbxAnimStack::Create(scene, anim_tmp->getName().c_str());
				FbxAnimLayer* lAnimLayer = FbxAnimLayer::Create(scene, (anim_tmp->getName() + "_Layer0").c_str());
				lAnimStack->AddMember(lAnimLayer);

				list_AnimStack.push_back(lAnimStack);
			}

			size_t k = 0;
			for (vector<FbxNode *>::iterator it = global_fbx_bones.begin(); it != global_fbx_bones.end(); it++) {

				vector<FbxAnimCurveNode *> fbx_anim = animation->exportFBXAnimations(scene, list_AnimStack, *it, global_fbx_bones_index.at(k));

				for (size_t j = 0; j < fbx_anim.size(); j++) {
					global_fbx_animation.push_back(fbx_anim[j]);
				}
				k++;
			}
		}
		else {
			delete animation;
			animation = NULL;
		}
	}




	for (size_t i = 0; i < model_filenames.size(); i++) {
		string node_name = LibXenoverse::nameFromFilenameNoExtension(model_filenames[i]);
		string path = model_filenames[i].substr(0, model_filenames[i].size() - LibXenoverse::nameFromFilename(model_filenames[i]).size());

		LibXenoverse::EMD *emd_model = new LibXenoverse::EMD();
		emd_model->load(model_filenames[i]);

		// Fill Scene
		FbxNode *lMeshNode = NULL;

		// Create Node
		lMeshNode = FbxNode::Create(scene, node_name.c_str());
		lMeshNode->LclTranslation.Set(FbxVector4(0, 0, 0));
		lMeshNode->LclScaling.Set(FbxVector4(1, 1, 1));
		lMeshNode->LclRotation.Set(FbxVector4(0, 0, 0));

		// Create and attach Mesh
		FbxMesh *lMesh = emd_model->exportFBX(scene, lMeshNode, path);
		lMeshNode->SetNodeAttribute(lMesh);

		if (global_fbx_bones.size()) {
			emd_model->exportFBXSkin(scene, lMesh, global_fbx_bones, lMeshNode->EvaluateGlobalTransform());
		}

		// Add node to scene
		FbxNode *lRootNode = scene->GetRootNode();
		lRootNode->AddChild(lMeshNode);

	}

	// Export FBX
	int lFileFormat = sdk_manager->GetIOPluginRegistry()->GetNativeWriterFormat();
	FbxExporter* lExporter = FbxExporter::Create(sdk_manager, "");
	bool lExportStatus = lExporter->Initialize(export_filename.c_str(), lFileFormat, sdk_manager->GetIOSettings());

	if (!lExportStatus) {
		printf("Call to FbxExporter::Initialize() failed.\n");
		printf("Error returned: %s\n\n", lExporter->GetStatus().GetErrorString());
		return 1;
	}

	scene->GetGlobalSettings().SetAxisSystem(FbxAxisSystem::eMax);
	scene->GetGlobalSettings().SetSystemUnit(FbxSystemUnit::m);
	

	// Export scene
	lExporter->Export(scene);
	lExporter->Destroy();
	return 0;
}
/**
 * Adds an Fbx Mesh to the FBX scene based on the data in the given FStaticLODModel
 */
FbxNode* FFbxExporter::CreateMesh(const USkeletalMesh* SkelMesh, const TCHAR* MeshName)
{
	const FSkeletalMeshResource* SkelMeshResource = SkelMesh->GetImportedResource();
	const FStaticLODModel& SourceModel = SkelMeshResource->LODModels[0];
	const int32 VertexCount = SourceModel.NumVertices;

	// Verify the integrity of the mesh.
	if (VertexCount == 0) return NULL;

	// Copy all the vertex data from the various chunks to a single buffer.
	// Makes the rest of the code in this function cleaner and easier to maintain.  
	TArray<FSoftSkinVertex> Vertices;
	SourceModel.GetVertices(Vertices);
	if (Vertices.Num() != VertexCount) return NULL;

	FbxMesh* Mesh = FbxMesh::Create(Scene, TCHAR_TO_UTF8(MeshName));

	// Create and fill in the vertex position data source.
	Mesh->InitControlPoints(VertexCount);
	FbxVector4* ControlPoints = Mesh->GetControlPoints();
	for (int32 VertIndex = 0; VertIndex < VertexCount; ++VertIndex)
	{
		FVector Position			= Vertices[VertIndex].Position;
		ControlPoints[VertIndex]	= Converter.ConvertToFbxPos(Position);
	}

	// Create Layer 0 to hold the normals
	FbxLayer* LayerZero = Mesh->GetLayer(0);
	if (LayerZero == NULL)
	{
		Mesh->CreateLayer();
		LayerZero = Mesh->GetLayer(0);
	}

	// Create and fill in the per-face-vertex normal data source.
	// We extract the Z-tangent and drop the X/Y-tangents which are also stored in the render mesh.
	FbxLayerElementNormal* LayerElementNormal= FbxLayerElementNormal::Create(Mesh, "");

	LayerElementNormal->SetMappingMode(FbxLayerElement::eByControlPoint);
	// Set the normal values for every control point.
	LayerElementNormal->SetReferenceMode(FbxLayerElement::eDirect);

	for (int32 VertIndex = 0; VertIndex < VertexCount; ++VertIndex)
	{
		FVector Normal			= Vertices[VertIndex].TangentZ;
		FbxVector4 FbxNormal	= Converter.ConvertToFbxPos(Normal);

		LayerElementNormal->GetDirectArray().Add(FbxNormal);
	}

	LayerZero->SetNormals(LayerElementNormal);


	// Create and fill in the per-face-vertex texture coordinate data source(s).
	// Create UV for Diffuse channel.
	const int32 TexCoordSourceCount = SourceModel.NumTexCoords;
	TCHAR UVChannelName[32];
	for (int32 TexCoordSourceIndex = 0; TexCoordSourceIndex < TexCoordSourceCount; ++TexCoordSourceIndex)
	{
		FbxLayer* Layer = Mesh->GetLayer(TexCoordSourceIndex);
		if (Layer == NULL)
		{
			Mesh->CreateLayer();
			Layer = Mesh->GetLayer(TexCoordSourceIndex);
		}

		if (TexCoordSourceIndex == 1)
		{
			FCString::Sprintf(UVChannelName, TEXT("LightMapUV"));
		}
		else
		{
			FCString::Sprintf(UVChannelName, TEXT("DiffuseUV"));
		}

		FbxLayerElementUV* UVDiffuseLayer = FbxLayerElementUV::Create(Mesh, TCHAR_TO_UTF8(UVChannelName));
		UVDiffuseLayer->SetMappingMode(FbxLayerElement::eByControlPoint);
		UVDiffuseLayer->SetReferenceMode(FbxLayerElement::eDirect);

		// Create the texture coordinate data source.
		for (int32 TexCoordIndex = 0; TexCoordIndex < VertexCount; ++TexCoordIndex)
		{
			const FVector2D& TexCoord = Vertices[TexCoordIndex].UVs[TexCoordSourceIndex];
			UVDiffuseLayer->GetDirectArray().Add(FbxVector2(TexCoord.X, -TexCoord.Y + 1.0));
		}

		Layer->SetUVs(UVDiffuseLayer, FbxLayerElement::eTextureDiffuse);
	}

	FbxLayerElementMaterial* MatLayer = FbxLayerElementMaterial::Create(Mesh, "");
	MatLayer->SetMappingMode(FbxLayerElement::eByPolygon);
	MatLayer->SetReferenceMode(FbxLayerElement::eIndexToDirect);
	LayerZero->SetMaterials(MatLayer);


	// Create the per-material polygons sets.
	TArray<uint32> Indices;
	SourceModel.MultiSizeIndexContainer.GetIndexBuffer(Indices);

	int32 SectionCount = SourceModel.Sections.Num();
	for (int32 SectionIndex = 0; SectionIndex < SectionCount; ++SectionIndex)
	{
		const FSkelMeshSection& Section = SourceModel.Sections[SectionIndex];

		int32 MatIndex = Section.MaterialIndex;

		// Static meshes contain one triangle list per element.
		int32 TriangleCount = Section.NumTriangles;

		// Copy over the index buffer into the FBX polygons set.
		for (int32 TriangleIndex = 0; TriangleIndex < TriangleCount; ++TriangleIndex)
		{
			Mesh->BeginPolygon(MatIndex);
			for (int32 PointIndex = 0; PointIndex < 3; PointIndex++)
			{
				Mesh->AddPolygon(Indices[Section.BaseIndex + ((TriangleIndex * 3) + PointIndex)]);
			}
			Mesh->EndPolygon();
		}
	}

	// Create and fill in the vertex color data source.
	FbxLayerElementVertexColor* VertexColor = FbxLayerElementVertexColor::Create(Mesh, "");
	VertexColor->SetMappingMode(FbxLayerElement::eByControlPoint);
	VertexColor->SetReferenceMode(FbxLayerElement::eDirect);
	FbxLayerElementArrayTemplate<FbxColor>& VertexColorArray = VertexColor->GetDirectArray();
	LayerZero->SetVertexColors(VertexColor);

	for (int32 VertIndex = 0; VertIndex < VertexCount; ++VertIndex)
	{
		FLinearColor VertColor = Vertices[VertIndex].Color.ReinterpretAsLinear();
		VertexColorArray.Add( FbxColor(VertColor.R, VertColor.G, VertColor.B, VertColor.A ));
	}

	FbxNode* MeshNode = FbxNode::Create(Scene, TCHAR_TO_UTF8(MeshName));
	MeshNode->SetNodeAttribute(Mesh);



	// Add the materials for the mesh
	int32 MaterialCount = SkelMesh->Materials.Num();

	for(int32 MaterialIndex = 0; MaterialIndex < MaterialCount; ++MaterialIndex)
	{
		UMaterialInterface* MatInterface = SkelMesh->Materials[MaterialIndex].MaterialInterface;

		FbxSurfaceMaterial* FbxMaterial = NULL;
		if(MatInterface && !FbxMaterials.Find(MatInterface))
		{
			FbxMaterial = ExportMaterial(MatInterface);
		}
		else
		{
			// Note: The vertex data relies on there being a set number of Materials.  
			// If you try to add the same material again it will not be added, so create a 
			// default material with a unique name to ensure the proper number of materials

			TCHAR NewMaterialName[MAX_SPRINTF]=TEXT("");
			FCString::Sprintf( NewMaterialName, TEXT("Fbx Default Material %i"), MaterialIndex );

			FbxMaterial = FbxSurfaceLambert::Create(Scene, TCHAR_TO_UTF8(NewMaterialName));
			((FbxSurfaceLambert*)FbxMaterial)->Diffuse.Set(FbxDouble3(0.72, 0.72, 0.72));
		}

		MeshNode->AddMaterial(FbxMaterial);
	}

	int32 SavedMaterialCount = MeshNode->GetMaterialCount();
	check(SavedMaterialCount == MaterialCount);

	return MeshNode;
}
/**
 * Adds FBX skeleton nodes to the FbxScene based on the skeleton in the given USkeletalMesh, and fills
 * the given array with the nodes created
 */
FbxNode* FFbxExporter::CreateSkeleton(const USkeletalMesh* SkelMesh, TArray<FbxNode*>& BoneNodes)
{
	const FReferenceSkeleton& RefSkeleton= SkelMesh->RefSkeleton;

	if(RefSkeleton.GetNum() == 0)
	{
		return NULL;
	}

	// Create a list of the nodes we create for each bone, so that children can 
	// later look up their parent
	BoneNodes.Reserve(RefSkeleton.GetNum());

	for(int32 BoneIndex = 0; BoneIndex < RefSkeleton.GetNum(); ++BoneIndex)
	{
		const FMeshBoneInfo& CurrentBone = RefSkeleton.GetRefBoneInfo()[BoneIndex];
		const FTransform& BoneTransform = RefSkeleton.GetRefBonePose()[BoneIndex];

		FbxString BoneName = Converter.ConvertToFbxString(CurrentBone.ExportName);


		// Create the node's attributes
		FbxSkeleton* SkeletonAttribute = FbxSkeleton::Create(Scene, BoneName.Buffer());
		if(BoneIndex)
		{
			SkeletonAttribute->SetSkeletonType(FbxSkeleton::eLimbNode);
			//SkeletonAttribute->Size.Set(1.0);
		}
		else
		{
			SkeletonAttribute->SetSkeletonType(FbxSkeleton::eRoot);
			//SkeletonAttribute->Size.Set(1.0);
		}
		

		// Create the node
		FbxNode* BoneNode = FbxNode::Create(Scene, BoneName.Buffer());
		BoneNode->SetNodeAttribute(SkeletonAttribute);

		// Set the bone node's local orientation
		FVector UnrealRotation = BoneTransform.GetRotation().Euler();
		FbxVector4 LocalPos = Converter.ConvertToFbxPos(BoneTransform.GetTranslation());
		FbxVector4 LocalRot = Converter.ConvertToFbxRot(UnrealRotation);

		BoneNode->LclTranslation.Set(LocalPos);
		BoneNode->LclRotation.Set(LocalRot);


		// If this is not the root bone, attach it to its parent
		if(BoneIndex)
		{
			BoneNodes[CurrentBone.ParentIndex]->AddChild(BoneNode);
		}


		// Add the node to the list of nodes, in bone order
		BoneNodes.Push(BoneNode);
	}

	return BoneNodes[0];
}
Example #6
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;
}
Example #7
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;
}
Example #8
0
void ExportBones(const Value& obj)
{
	const Value& boneName = obj["BoneName"];
	if (boneName.IsNull())
	{
		return;
	}

	//string name = obj["Name"].GetString();

	const Value& parentIndex = obj["ParentIndex"];
	const Value& boneTransform = obj["BoneTransform"];

	fbxBones.resize(boneName.Size());
	for (uint32_t i = 0; i < fbxBones.size(); i++)
	{
		FbxNode* boneNode = FbxNode::Create(pScene, boneName[i].GetString());
		fbxBones[i] = boneNode;
		double x, y, z, w;
		x = boneTransform[i * 7 + 0].GetDouble();
		x = -x;
		y = boneTransform[i * 7 + 1].GetDouble();
		z = boneTransform[i * 7 + 2].GetDouble();
		boneNode->LclTranslation.Set(FbxDouble3(x, y, z));

		x = boneTransform[i * 7 + 3].GetDouble();
		y = boneTransform[i * 7 + 4].GetDouble();
		z = boneTransform[i * 7 + 5].GetDouble();
		w = boneTransform[i * 7 + 6].GetDouble();

		FbxSkeleton* pSkeleton = FbxSkeleton::Create(pScene, boneName[i].GetString());
		int parent = parentIndex[i].GetInt();
		if (parent == -1) {
			pSkeleton->SetSkeletonType(FbxSkeleton::eRoot);
		}
		else {
			pSkeleton->SetSkeletonType(FbxSkeleton::eLimbNode);
			pSkeleton->Size.Set(0.1);
		}

		boneNode->SetNodeAttribute(pSkeleton);
	}

	for (uint32_t i = 0; i < fbxBones.size(); i++) {
		int parent = parentIndex[i].GetInt();
		if (parent == -1) {
			pScene->GetRootNode()->AddChild(fbxBones[i]);
		}
		else {
			fbxBones[parent]->AddChild(fbxBones[i]);
		}
	}

	FbxPose* lPose = FbxPose::Create(pScene, boneName[0].GetString());
	// default pose type is rest pose, so we need to set the type as bind pose
	lPose->SetIsBindPose(true);

	for (uint32_t i = 0; i < fbxBones.size(); i++) {
		FbxNode*  lKFbxNode = fbxBones[i];
		FbxMatrix lBindMatrix = lKFbxNode->EvaluateGlobalTransform();
		lPose->Add(lKFbxNode, lBindMatrix);
	}

	pScene->AddPose(lPose);

}