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;
}
Beispiel #2
0
		void GameEngine::FbxLoader::FbxLoader::ProcessAnimCurveR(FbxAnimCurve* curve[3], AnimTransformCurve& animCurve, FbxAMatrix & preRotation)
		{
			if(!curve) return;

			auto& curve3 = animCurve.rotation;

			int xKeys = curve[0]->KeyGetCount();
			int yKeys = curve[1]->KeyGetCount();
			int zKeys = curve[2]->KeyGetCount();

			// check key sync
			if(xKeys != yKeys || xKeys != zKeys)
				return;

			int nKeys = xKeys;

			curve3.curves[0].keyframes.resize(nKeys);
			curve3.curves[1].keyframes.resize(nKeys);
			curve3.curves[2].keyframes.resize(nKeys);

			animCurve.end = (float)curve[0]->KeyGetTime(nKeys - 1).GetSecondDouble();

			for(int ki = 0; ki < nKeys; ++ki) {
				auto& xkey = curve3.curves[0].keyframes[ki];
				auto& ykey = curve3.curves[1].keyframes[ki];
				auto& zkey = curve3.curves[2].keyframes[ki];

				curve[0]->KeySetTangentMode(ki, FbxAnimCurveDef::eTangentAuto);
				curve[1]->KeySetTangentMode(ki, FbxAnimCurveDef::eTangentAuto);
				curve[2]->KeySetTangentMode(ki, FbxAnimCurveDef::eTangentAuto);
				auto xvalue = curve[0]->KeyGetValue(ki);
				auto yvalue = curve[1]->KeyGetValue(ki);
				auto zvalue = curve[2]->KeyGetValue(ki);

				auto xlt = curve[0]->KeyGetLeftAuto(ki);
				auto xrt = curve[0]->KeyGetRightAuto(ki);
				auto ylt = curve[1]->KeyGetLeftAuto(ki);
				auto yrt = curve[1]->KeyGetRightAuto(ki);
				auto zlt = curve[2]->KeyGetLeftAuto(ki);
				auto zrt = curve[2]->KeyGetRightAuto(ki);

				FbxAMatrix temp;
				temp.SetR(FbxVector4(xvalue, yvalue, zvalue));
				auto R = (preRotation* temp).GetR();
				xvalue = (float)R[0]; yvalue = (float)R[1]; zvalue = (float)R[2];

				float t = (float)curve[0]->KeyGetTime(ki).GetSecondDouble();

				if(axismode == eLeftHanded) {
					yvalue *= -1; ylt *= -1; yrt *= -1;
					zvalue *= -1; zlt *= -1; zrt *= -1;
				}

				xkey.time = t; ykey.time = t; zkey.time = t;
				xkey.value = xvalue; ykey.value = yvalue; zkey.value = zvalue;
				xkey.leftTangent = xlt; xkey.rightTangent = xrt;
				ykey.leftTangent = ylt; ykey.rightTangent = yrt;
				zkey.leftTangent = zlt; zkey.rightTangent = zrt;
			}
		}
Beispiel #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;
}
Beispiel #4
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;
}
Beispiel #5
0
    bool Submesh::load(FbxNode* pNode, FbxMesh* pMesh, const std::vector<face>& faces, const std::vector<vertexInfo>& vertInfo, const std::vector<FbxVector4>& points, 
        const std::vector<FbxVector4>& normals, const std::vector<int>& texcoordsets, ParamList& params, const FbxAMatrix& bindPose, bool opposite )
    {
        //save the mesh from which this submesh will be created
        m_pNode = pNode;

        size_t i,j,k;
        FxOgreFBXLog( "Loading submesh associated to material: %s ...\n", m_pMaterial->name().c_str());
        
        //save uvsets info
        for (i=m_uvsets.size(); i<texcoordsets.size(); i++)
        {
            uvset uv;
            uv.size = 2;
            m_uvsets.push_back(uv);
        }
        //iterate over faces array, to retrieve vertices info
        for (i=0; i<faces.size(); i++)
        {
            face newFace;
            // if we are using shared geometry, indexes refer to the vertex buffer of the whole mesh
            if (params.useSharedGeom)
            {
                if(opposite)
                {	// reverse order of face vertices for correct culling
                    newFace.v[0] = faces[i].v[2];
                    newFace.v[1] = faces[i].v[1];
                    newFace.v[2] = faces[i].v[0];
                }
                else
                {
                    newFace.v[0] = faces[i].v[0];
                    newFace.v[1] = faces[i].v[1];
                    newFace.v[2] = faces[i].v[2];
                }
            }
            // otherwise we create a vertex buffer for this submesh
            else
            {	// faces are triangles, so retrieve index of the three vertices
                for (j=0; j<3; j++)
                {
                    vertex v;
                    vertexInfo vInfo = vertInfo[faces[i].v[j]];
                    // save vertex coordinates (rescale to desired length unit)
                    assert(vInfo.pointIdx >= 0 && vInfo.pointIdx < static_cast<int>(points.size()));
                    FbxVector4 point = points[vInfo.pointIdx] * params.lum;
                    if (fabs(point[0]) < PRECISION)
                        point[0] = 0;
                    if (fabs(point[1]) < PRECISION)
                        point[1] = 0;
                    if (fabs(point[2]) < PRECISION)
                        point[2] = 0;
                    v.x = point[0];
                    v.y = point[1];
                    v.z = point[2];
                    // save vertex normal
                    assert(vInfo.normalIdx >= 0 && vInfo.normalIdx < static_cast<int>(normals.size()));
                    FbxVector4 normal = normals[vInfo.normalIdx];
                    if (fabs(normal[0]) < PRECISION)
                        normal[0] = 0;
                    if (fabs(normal[1]) < PRECISION)
                        normal[1] = 0;
                    if (fabs(normal[2]) < PRECISION)
                        normal[2] = 0;
                    v.n.x = normal[0];
                    v.n.y = normal[1];
                    v.n.z = normal[2];
                    if (opposite)
                    {
                        // Reversing the winding order appears to be sufficent.
                        v.n.x = -normal[0];
                        v.n.y = -normal[1];
                        v.n.z = -normal[2];
                    }
                    v.n.Normalize();

                    // save vertex color
                    v.r = vInfo.r;
                    v.g = vInfo.g;
                    v.b = vInfo.b;
                    v.a = vInfo.a;
                    // save vertex bone assignements
                    for (k=0; k<vInfo.vba.size(); k++)
                    {
                        vba newVba;
                        newVba.jointIdx = vInfo.jointIds[k];
                        newVba.weight = vInfo.vba[k];
                        v.vbas.push_back(newVba);
                    }
                    // save texture coordinates
                    for (k=0; k<vInfo.u.size(); k++)
                    {
                        texcoord newTexCoords;
                        newTexCoords.u = vInfo.u[k];
                        newTexCoords.v = vInfo.v[k];
                        newTexCoords.w = 0;
                        v.texcoords.push_back(newTexCoords);
                    }
                    // save vertex index in mesh, to retrieve future positions of the same vertex
                    v.index = vInfo.pointIdx;
                    // add newly created vertex to vertex list
                    m_vertices.push_back(v);
                    if (opposite)	// reverse order of face vertices to get correct culling
                        newFace.v[2-j] = static_cast<int>(m_vertices.size()) - 1;
                    else
                        newFace.v[j] = static_cast<int>(m_vertices.size()) - 1;
                }
            }
            m_faces.push_back(newFace);
        }
        // set use32bitIndexes flag
        if (params.useSharedGeom || (m_vertices.size() > 65535) || (m_faces.size() > 65535))
            m_use32bitIndexes = true;
        else
            m_use32bitIndexes = false;

        pMesh->ComputeBBox();
        FbxDouble3 minDouble = pMesh->BBoxMin.Get();
        FbxDouble3 maxDouble = pMesh->BBoxMax.Get();

        FbxVector4 min = bindPose.MultT( FbxVector4(minDouble[0],minDouble[1],minDouble[2],0));
        FbxVector4 max = bindPose.MultT( FbxVector4(maxDouble[0],maxDouble[1],maxDouble[2],0));

        m_bbox.merge(Point3(max[0], max[1], max[2]));
        m_bbox.merge(Point3(min[0], min[1], min[2]));
        

        // add submesh pointer to m_params list
        params.loadedSubmeshes.push_back(this);

        FxOgreFBXLog( "DONE\n");
        
        return true;
    }
Beispiel #6
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 #7
0
bool SceneConverter::convert()
{
    //
    // Construt the scene
    //
    FbxNode *node = m_scene->GetRootNode();
    std::list<FbxNode *> nodes;
    std::map<FbxNode *, SceneNode *> fbxNode2SceneNodes;
    Scene scene;

    nodes.push_back(node);
    SceneNode *sceneNode = makeSceneNode(node);
    scene.addNode(sceneNode);
    fbxNode2SceneNodes.insert(std::make_pair(node, sceneNode));

    while (!nodes.empty())
    {
        FbxNode *ret = nodes.front();
        nodes.pop_front();

        for (int i = 0; i < ret->GetChildCount(); i++)
        {
            FbxNode *child = ret->GetChild(i);
            
            // Only output visible nodes.
            if (child->GetVisibility() && child->Show.Get())
            {
                SceneNode *sceneNode = makeSceneNode(child);
                if (sceneNode != NULL)
                {
                    if (sceneNode->type == "camera")
                    {
                        // The first camera will be the main camera of the scene
                        scene.setCamera(sceneNode);
                    }
                    scene.addNode(sceneNode, fbxNode2SceneNodes[ret]);
                    fbxNode2SceneNodes.insert(std::make_pair(child, sceneNode));
                }
            
                nodes.push_back(child);
            }
        }
    }

    // Create a camera if it is not included in FBX. The camera is evaluated
    // using the bounding box of all visible nodes.
    if (m_numCameras == 0)
    {
        FbxVector4 rootBboxMin;
        FbxVector4 rootBboxMax;
        FbxVector4 rootBboxCenter;

        rootBboxMin = FbxVector4(FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX);
        rootBboxMax = FbxVector4(-FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX);
    
        FbxNode *node = m_scene->GetRootNode();

        nodes.push_back(node);

        while (!nodes.empty())
        {
            FbxNode *ret = nodes.front();
            nodes.pop_front();

            for (int i = 0; i < ret->GetChildCount(); i++)
            {
                FbxNode *child = ret->GetChild(i);
                
                nodes.push_back(child);
            }
                
            if (ret->GetChildCount() == 0 &&
                ret->GetVisibility() && 
                ret->Show.Get() &&
                ret->GetMesh() != NULL)
            {
                FbxVector4 bboxMin;
                FbxVector4 bboxMax;
                FbxVector4 bboxCenter;

                ret->EvaluateGlobalBoundingBoxMinMaxCenter(bboxMin, bboxMax, bboxCenter);

                rootBboxMin[0] = std::min(rootBboxMin[0], bboxMin[0]);
                rootBboxMin[1] = std::min(rootBboxMin[1], bboxMin[1]);
                rootBboxMin[2] = std::min(rootBboxMin[2], bboxMin[2]);
                
                rootBboxMax[0] = std::max(rootBboxMax[0], bboxMax[0]);
                rootBboxMax[1] = std::max(rootBboxMax[1], bboxMax[1]);
                rootBboxMax[2] = std::max(rootBboxMax[2], bboxMax[2]);
            }
        }

        rootBboxCenter = (rootBboxMin + rootBboxMax) / 2;
        FbxVector4 rootBboxSize = rootBboxMax - rootBboxMin;
            
        SceneNode *sceneNode = new SceneNode();

        sceneNode->type = FbxString("camera");
        sceneNode->attributes.push_back(std::make_pair(FbxString("name"), FbxString("camera")));
        sceneNode->attributes.push_back(std::make_pair(FbxString("fixed"), FbxString("true")));

        double diag = sqrt(rootBboxSize[0] * rootBboxSize[0] + 
                           rootBboxSize[1] * rootBboxSize[1] + 
                           rootBboxSize[2] * rootBboxSize[2]) * 0.5;
            
        double eye = diag / tan(15.0 * FBXSDK_PI_DIV_180);

        double position[3];
        double up[3];
        double znear;
        double zfar;
            
        znear = eye - diag - 1.0f;
        zfar  = eye + diag + 1.0f;

        if (rootBboxSize[0] <= rootBboxSize[1] && rootBboxSize[0] <= rootBboxSize[2])
        {
            position[0] = eye + rootBboxCenter[0]; 
            position[1] = rootBboxCenter[1];
            position[2] = rootBboxCenter[2];

            up[0] = 0;
            up[1] = 1;
            up[2] = 0;
        }
        else if (rootBboxSize[1] <= rootBboxSize[0] && rootBboxSize[1] <= rootBboxSize[2])
        {
            position[0] = rootBboxCenter[0]; 
            position[1] = eye + rootBboxCenter[1];
            position[2] = rootBboxCenter[2];

            up[0] = 0;
            up[1] = 0;
            up[2] = 1;
        }
        else
        {
            position[0] = rootBboxCenter[0]; 
            position[1] = rootBboxCenter[1];
            position[2] = eye + rootBboxCenter[2];

            up[0] = 0;
            up[1] = 1;
            up[2] = 0;
        }

        char lookat[1024];
        char perspective[1024];
            
        FBXSDK_sprintf(lookat, 1024, "eye:%8.5f,%8.5f,%8.5f,center:%8.5f,%8.5f,%8.5f,up:%8.5f,%8.5f,%8.5f",
                    (float)position[0], (float)position[1], (float)position[2],
                    (float)rootBboxCenter[0], (float)rootBboxCenter[1], (float)rootBboxCenter[2],
                    (float)up[0], (float)up[1], (float)up[2]);
        sceneNode->attributes.push_back(std::make_pair(FbxString("lookat"), FbxString(lookat)));
            
        FBXSDK_sprintf(perspective, 1024, "perspective,fov:%8.5f,aspect:-1,znear:%8.5f,zfar:%8.5f",
                    30.0f, (float)znear, (float)zfar);
        sceneNode->attributes.push_back(std::make_pair(FbxString("projection"), FbxString(perspective)));
                    
        scene.setCamera(sceneNode);
        scene.addNode(sceneNode, scene.root());
    }

    //
    // Output the file.
    //
    //FbxString outputFilename = FbxPathUtils::GetFileName(m_arguments->FBXFileName.Buffer()).Lower();
    //outputFilename.FindAndReplace(".fbx", ".psc");
    FbxString outputFilename("scene.psc");
    FbxString path = FbxPathUtils::Bind(m_arguments->outputFolder, outputFilename.Buffer());
    bool ret = scene.output(path.Buffer());

    if (!ret)
    {
        FBXSDK_printf("Exporting failed!\n\n");
    }

    return ret;
}
void CameraZoom(FbxScene* pScene, int pZoomDepth, int pZoomMode)
{
    FbxCamera* lCamera = GetCurrentCamera(pScene);
    if( lCamera == NULL)
        return;
    if( pZoomMode == SceneContext::ZOOM_FOCAL_LENGTH)
    {
        if (lCamera->ProjectionType.Get() == FbxCamera::ePerspective)
        {
            double lTransform = 0 - pZoomDepth / 100.0;

            double lApertureW = lCamera->GetApertureWidth();
            lApertureW = TransformAperture( lApertureW, lTransform);

            double lApertureH = lCamera->GetApertureHeight();
            lApertureH = TransformAperture( lApertureH, lTransform);

            UpdatePerspCameraAttributes( lCamera, lApertureW, lApertureH);


        }
        else
        {
            if( pZoomDepth > 0)
                gsOrthoCameraScale *= 0.8;
            else
                gsOrthoCameraScale *= 1.25;
        }
    }
    else
    {
        FbxNode*   lCameraNode = lCamera ? lCamera->GetNode() : NULL;

        // Compute the camera position and direction.
        FbxVector4 lEye(0,0,1);
        FbxVector4 lCenter(0,0,0);
        FbxVector4 lForward(0,0,0);

        if (lCamera)
        {
            lEye = lCamera->Position.Get();
        }

        if (lCameraNode && lCameraNode->GetTarget())
        {
            lCenter = lCameraNode->GetTarget()->LclTranslation.Get();
            lForward = lCenter - lEye;
        }
        else
        {
            if (!lCameraNode || IsProducerCamera(pScene, lCamera))
            {
                if (lCamera)
                {
                    lCenter = lCamera->InterestPosition.Get();
                    lForward = lCenter - lEye;
                }
            }
            else
            {
                // Get the direction
                FbxAMatrix lGlobalRotation;
                FbxVector4 lRotationVector( lCameraNode->LclRotation.Get());
                lGlobalRotation.SetR(lRotationVector);

                // Set the center.
                // A camera with rotation = {0,0,0} points to the X direction. So create a
                // vector in the X direction, rotate that vector by the global rotation amount
                // and then position the center by scaling and translating the resulting vector
                lRotationVector = FbxVector4(1.0,0,0);
                lForward = lGlobalRotation.MultT(lRotationVector);
            }
        }
        lForward.Normalize();
        lEye += lForward * pZoomDepth;
        FbxDouble3 lPosition(lEye[0], lEye[1], lEye[2]);
        lCamera->Position.Set(lPosition);
        
    }
}
// Set the view to the current camera settings.
void SetCamera(FbxScene* pScene, 
               FbxTime& pTime, 
               FbxAnimLayer* pAnimLayer,
               const FbxArray<FbxNode*>& pCameraArray,
               int pWindowWidth, int pWindowHeight)
{
    // Find the current camera at the given time.
    FbxCamera* lCamera = GetCurrentCamera(pScene, pTime, pAnimLayer, pCameraArray);
    if( lCamera == NULL)
        return;
    FbxNode*   lCameraNode = lCamera ? lCamera->GetNode() : NULL;

    // Compute the camera position and direction.
    FbxVector4 lEye(0,0,1);
    FbxVector4 lCenter(0,0,0);
    FbxVector4 lUp(0,1,0);
    FbxVector4 lForward, lRight;

    if (lCamera)
    {
        lEye = lCamera->Position.Get();
        lUp = lCamera->UpVector.Get();
    }

    if (lCameraNode && lCameraNode->GetTarget())
    {
        lCenter = GetGlobalPosition(lCameraNode->GetTarget(), pTime).GetT();
    }
    else
    {
        if (!lCameraNode || IsProducerCamera(pScene, lCamera))
        {
            if (lCamera)
                lCenter = lCamera->InterestPosition.Get();
        }
        else
        {
            // Get the direction
            FbxAMatrix lGlobalRotation;
            FbxVector4 lRotationVector(GetGlobalPosition(lCameraNode, pTime).GetR());
            lGlobalRotation.SetR(lRotationVector);

            // Get the length
            FbxVector4 lInterestPosition(lCamera->InterestPosition.Get());
            FbxVector4 lCameraGlobalPosition(GetGlobalPosition(lCameraNode, pTime).GetT());
            double      lLength = (FbxVector4(lInterestPosition - lCameraGlobalPosition).Length());

            // Set the center.
            // A camera with rotation = {0,0,0} points to the X direction. So create a
            // vector in the X direction, rotate that vector by the global rotation amount
            // and then position the center by scaling and translating the resulting vector
            lRotationVector = FbxVector4(1.0,0,0);
            lCenter = lGlobalRotation.MultT(lRotationVector);
            lCenter *= lLength;
            lCenter += lEye;

            // Update the default up vector with the camera rotation.
            lRotationVector = FbxVector4(0,1.0,0);
            lUp = lGlobalRotation.MultT(lRotationVector);
        }
    }

    // Align the up vector.
    lForward = lCenter - lEye;
    lForward.Normalize();
    lRight = lForward.CrossProduct(lUp);
    lRight.Normalize();
    lUp = lRight.CrossProduct(lForward);
    lUp.Normalize();

    // Rotate the up vector with the roll value.
    double lRadians = 0;

    if (lCamera)
        lRadians = lCamera->Roll.Get() * FBXSDK_PI_DIV_180;
    lUp = lUp * cos( lRadians) + lRight * sin(lRadians);

    
    double lNearPlane = 0.01;
    if (lCamera)
        lNearPlane = lCamera->GetNearPlane();    
    double lFarPlane = 4000.0;
    if (lCamera)
        lFarPlane = lCamera->GetFarPlane();

    //Get global scaling.
    FbxVector4 lCameraScaling = GetGlobalPosition(lCameraNode, pTime).GetS();
    static const int  FORWARD_SCALE = 2;
    
    //scaling near plane and far plane
    lNearPlane *= lCameraScaling[ FORWARD_SCALE];
    lFarPlane *= lCameraScaling[ FORWARD_SCALE];






    // Get the relevant camera settings for a perspective view.
    if (lCamera && lCamera->ProjectionType.Get() == FbxCamera::ePerspective)
    {
        //get the aspect ratio
        FbxCamera::EAspectRatioMode lCamAspectRatioMode = lCamera->GetAspectRatioMode();
        double lAspectX = lCamera->AspectWidth.Get(); //ºñÀ²
        double lAspectY = lCamera->AspectHeight.Get();
        double lAspectRatio = 1.333333;
        switch( lCamAspectRatioMode)
        {
        case FbxCamera::eWindowSize:
            lAspectRatio = lAspectX / lAspectY;
            break;
        case FbxCamera::eFixedRatio:
            lAspectRatio = lAspectX;

            break;
        case FbxCamera::eFixedResolution:
            lAspectRatio = lAspectX / lAspectY * lCamera->GetPixelRatio();
            break;
        case FbxCamera::eFixedWidth:
            lAspectRatio = lCamera->GetPixelRatio() / lAspectY;
            break;
        case FbxCamera::eFixedHeight:
            lAspectRatio = lCamera->GetPixelRatio() * lAspectX;
            break;
        default:
            break;

        }

        //get the aperture ratio
        double lFilmHeight = lCamera->GetApertureHeight();
        double lFilmWidth = lCamera->GetApertureWidth() * lCamera->GetSqueezeRatio();
        //here we use Height : Width
        double lApertureRatio = lFilmHeight / lFilmWidth;


        //change the aspect ratio to Height : Width
        lAspectRatio = 1 / lAspectRatio;
        //revise the aspect ratio and aperture ratio
        FbxCamera::EGateFit lCameraGateFit = lCamera->GateFit.Get();
        switch( lCameraGateFit )
        {

        case FbxCamera::eFitFill:
            if( lApertureRatio > lAspectRatio)  // the same as eHORIZONTAL_FIT
            {
                lFilmHeight = lFilmWidth * lAspectRatio;
                lCamera->SetApertureHeight( lFilmHeight);
                lApertureRatio = lFilmHeight / lFilmWidth;
            }
            else if( lApertureRatio < lAspectRatio) //the same as eVERTICAL_FIT
            {
                lFilmWidth = lFilmHeight / lAspectRatio;
                lCamera->SetApertureWidth( lFilmWidth);
                lApertureRatio = lFilmHeight / lFilmWidth;
            }
            break;
        case FbxCamera::eFitVertical:
            lFilmWidth = lFilmHeight / lAspectRatio;
            lCamera->SetApertureWidth( lFilmWidth);
            lApertureRatio = lFilmHeight / lFilmWidth;
            break;
        case FbxCamera::eFitHorizontal:
            lFilmHeight = lFilmWidth * lAspectRatio;
            lCamera->SetApertureHeight( lFilmHeight);
            lApertureRatio = lFilmHeight / lFilmWidth;
            break;
        case FbxCamera::eFitStretch:
            lAspectRatio = lApertureRatio;
            break;
        case FbxCamera::eFitOverscan:
            if( lFilmWidth > lFilmHeight)
            {
                lFilmHeight = lFilmWidth * lAspectRatio;
            }
            else
            {
                lFilmWidth = lFilmHeight / lAspectRatio;
            }
            lApertureRatio = lFilmHeight / lFilmWidth;
            break;
        case FbxCamera::eFitNone:
        default:
            break;
        }
        //change the aspect ratio to Width : Height
        lAspectRatio = 1 / lAspectRatio;

        double lFieldOfViewX = 0.0;
        double lFieldOfViewY = 0.0;
        if ( lCamera->GetApertureMode() == FbxCamera::eVertical)
        {
                lFieldOfViewY = lCamera->FieldOfView.Get();
                lFieldOfViewX = VFOV2HFOV( lFieldOfViewY, 1 / lApertureRatio);
        }
        else if (lCamera->GetApertureMode() == FbxCamera::eHorizontal)
        {
            lFieldOfViewX = lCamera->FieldOfView.Get(); //get HFOV
            lFieldOfViewY = HFOV2VFOV( lFieldOfViewX, lApertureRatio);
        }
        else if (lCamera->GetApertureMode() == FbxCamera::eFocalLength)
        {
            lFieldOfViewX = lCamera->ComputeFieldOfView(lCamera->FocalLength.Get());    //get HFOV
            lFieldOfViewY = HFOV2VFOV( lFieldOfViewX, lApertureRatio);
        }
        else if (lCamera->GetApertureMode() == FbxCamera::eHorizAndVert) {
            lFieldOfViewX = lCamera->FieldOfViewX.Get();
            lFieldOfViewY = lCamera->FieldOfViewY.Get();
        }



        double lRealScreenRatio = (double)pWindowWidth / (double)pWindowHeight;
        int  lViewPortPosX = 0, 
            lViewPortPosY = 0, 
            lViewPortSizeX = pWindowWidth, 
            lViewPortSizeY = pWindowHeight;
        //compute the view port
        if( lRealScreenRatio > lAspectRatio)
        {
            lViewPortSizeY = pWindowHeight;
            lViewPortSizeX = (int)( lViewPortSizeY * lAspectRatio);
            lViewPortPosY = 0;
            lViewPortPosX = (int)((pWindowWidth - lViewPortSizeX) * 0.5);
        }
        else
        {
            lViewPortSizeX = pWindowWidth;
            lViewPortSizeY = (int)(lViewPortSizeX / lAspectRatio);
            lViewPortPosX = 0;
            lViewPortPosY = (int)((pWindowHeight - lViewPortSizeY) * 0.5);
        }

        //revise the Perspective since we have film offset
        double lFilmOffsetX = lCamera->FilmOffsetX.Get();
        double lFilmOffsetY = lCamera->FilmOffsetY.Get();
        lFilmOffsetX = 0 - lFilmOffsetX / lFilmWidth * 2.0;
        lFilmOffsetY = 0 - lFilmOffsetY / lFilmHeight * 2.0;

        GlSetCameraPerspective( lFieldOfViewY, lAspectRatio, lNearPlane, lFarPlane, lEye, lCenter, lUp, lFilmOffsetX, lFilmOffsetY);



    //glMatrixMode(GL_PROJECTION);
    //double lTestPerpMatrix[ 16];
    //glGetDoublev( GL_PROJECTION_MATRIX, lTestPerpMatrix);

    //lTestPerpMatrix[ 8] -= lFilmOffsetX;
    //lTestPerpMatrix[ 9] -= lFilmOffsetY;
    //
    //glLoadMatrixd( lTestPerpMatrix);
    //glMatrixMode(GL_MODELVIEW);
        

        glViewport( lViewPortPosX, lViewPortPosY, lViewPortSizeX, lViewPortSizeY);
        

    }
    // Get the relevant camera settings for an orthogonal view.
    else
    {
        double lPixelRatio = 1.0;
        if (lCamera)
            lPixelRatio = lCamera->GetPixelRatio();  

        double lLeftPlane, lRightPlane, lBottomPlane, lTopPlane;

        if(pWindowWidth < pWindowHeight) 
        {   
            lLeftPlane   = -gsOrthoCameraScale * lPixelRatio;
            lRightPlane  =  gsOrthoCameraScale * lPixelRatio;
            lBottomPlane = -gsOrthoCameraScale * pWindowHeight / pWindowWidth;
            lTopPlane    =  gsOrthoCameraScale * pWindowHeight / pWindowWidth;
        } 
        else 
        {
            pWindowWidth *= (int) lPixelRatio;
            lLeftPlane   = -gsOrthoCameraScale * pWindowWidth / pWindowHeight;
            lRightPlane  =  gsOrthoCameraScale * pWindowWidth / pWindowHeight;
            lBottomPlane = -gsOrthoCameraScale;
            lTopPlane    =  gsOrthoCameraScale;
        }

        GlSetCameraOrthogonal(lLeftPlane,
            lRightPlane,
            lBottomPlane,
            lTopPlane,
            lNearPlane,
            lFarPlane,
            lEye,
            lCenter,
            lUp);
    }
}
Beispiel #10
0
/**
 * メッシュ情報を読み込む
 *
 * @param mesh メッシュ情報
 */
void FbxFileLoader::load_mesh( FbxMesh* mesh )
{
	if ( ! mesh )
	{
		return;
	}

	if ( ! get_model()->get_mesh() )
	{
		get_model()->set_mesh( create_mesh() );
	}

	VertexIndexMap vertex_index_map;
	VertexList vertex_list;

	Mesh::PositionList position_list;
	Mesh::VertexWeightList vertex_weight_list;

	// load_mesh_vertex()
	for ( int n = 0; n < mesh->GetControlPointsCount(); n++ )
	{
		FbxVector4 v = mesh->GetControlPointAt( n );

		position_list.push_back(
			Mesh::Position(
				static_cast< float >( v[ 0 ] ),
				static_cast< float >( v[ 1 ] ),
				static_cast< float >( v[ 2 ] ) ) );
	}

	// load_mesh_vertex_weight()
	{
		int skin_count = mesh->GetDeformerCount( FbxDeformer::eSkin );

		if ( skin_count > 0 )
		{
			assert( skin_count == 1 );

			vertex_weight_list.resize( position_list.size() );

			FbxSkin* skin = FbxCast< FbxSkin >( mesh->GetDeformer( 0, FbxDeformer::eSkin ) );

			load_mesh_vertex_weight( skin, vertex_weight_list );
		}
	}

	FbxLayerElementSmoothing* smoothing = 0;

	// load_mesh_smoothing_info()
	{
		FbxLayer* layer = mesh->GetLayer( 0 );
		smoothing = layer->GetSmoothing();
	}

	if ( ! smoothing )
	{
		COMMON_THROW_EXCEPTION_MESSAGE( "this FBX format is not supported. ( no smoothing info )" );
	}

	// load_mesh_plygon()
	FbxLayerElementArrayTemplate< int >* material_indices;
	mesh->GetMaterialIndices( & material_indices );

	for ( int n = 0; n < mesh->GetPolygonCount(); n++ )
	{
		Mesh::VertexGroup* vertex_group = get_model()->get_mesh()->get_vertex_group_at( material_indices->GetAt( n ) );

		bool is_smooth = smoothing->GetDirectArray().GetAt( n ) != 0;
		FbxVector4 polygon_normal( 0.f, 0.f, 0.f );

		if ( ! is_smooth )
		{
			// ポリゴンの法線を計算する
			Mesh::Position p1( position_list.at( mesh->GetPolygonVertex( n, 0 ) ) );
			Mesh::Position p2( position_list.at( mesh->GetPolygonVertex( n, 1 ) ) );
			Mesh::Position p3( position_list.at( mesh->GetPolygonVertex( n, 2 ) ) );

			FbxVector4 a = FbxVector4( p1.x(), p1.y(), p1.z() );
			FbxVector4 b = FbxVector4( p2.x(), p2.y(), p2.z() );
			FbxVector4 c = FbxVector4( p3.x(), p3.y(), p3.z() );

			FbxVector4 ab( b - a );
			FbxVector4 bc( c - b );

			polygon_normal = ab.CrossProduct( bc );
			polygon_normal.Normalize();
		}

		for ( int m = 0; m < mesh->GetPolygonSize( n ); m++ )
		{
			int position_index = mesh->GetPolygonVertex( n, m );

			Mesh::Vertex v;
			v.Position = Mesh::Position( position_list.at( position_index ) );

			FbxVector2 uv_vector;
			bool unmapped;
			
			if ( mesh->GetPolygonVertexUV( n, m, "UVMap", uv_vector, unmapped) )
			{
				v.TexCoord = Mesh::TexCoord(
					static_cast< float >( uv_vector[ 0 ] ),
					1.f - static_cast< float >( uv_vector[ 1 ] ) );
			}

			if ( is_smooth )
			{
				FbxVector4 normal_vector;

				// 頂点の法線
				if ( mesh->GetPolygonVertexNormal( n, m, normal_vector ) )
				{
					v.Normal = Mesh::Normal(
						static_cast< float >( normal_vector[ 0 ] ),
						static_cast< float >( normal_vector[ 1 ] ),
						static_cast< float >( normal_vector[ 2 ] ) );
				}
			}
			else
			{
				// ポリゴンの法線
				v.Normal = Mesh::Normal(
					static_cast< float >( polygon_normal[ 0 ] ),
					static_cast< float >( polygon_normal[ 1 ] ),
					static_cast< float >( polygon_normal[ 2 ] ) );
			}
			
			// 頂点の一覧に追加
			{
				VertexIndexMap::iterator i = vertex_index_map.find( v );

				if ( i != vertex_index_map.end() )
				{
					vertex_group->add_index( i->second );
				}
				else
				{
					Mesh::Index vertex_index = static_cast< Mesh::Index >( get_model()->get_mesh()->get_vertex_count() );

					get_model()->get_mesh()->add_vertex( v );

					if ( ! vertex_weight_list.empty() )
					{
						get_model()->get_mesh()->add_vertex_weight( vertex_weight_list.at( position_index ) );
					}

					vertex_group->add_index( vertex_index );

					vertex_index_map[ v ] = vertex_index;
				}
			}
		}
	}
}
	void FBXConverter::CalcTangentSpace(const Vertex& v1, const Vertex& v2, const Vertex& v3, FbxVector4& binormal, FbxVector4& tangent)
	{
		binormal = FbxVector4();
		tangent = FbxVector4();

		FbxVector4 cp0[3];
		cp0[0] = FbxVector4(v1.Position[0], v1.UV[0], v1.UV[1]);
		cp0[1] = FbxVector4(v1.Position[1], v1.UV[0], v1.UV[1]);
		cp0[2] = FbxVector4(v1.Position[2], v1.UV[0], v1.UV[1]);

		FbxVector4 cp1[3];
		cp1[0] = FbxVector4(v2.Position[0], v2.UV[0], v2.UV[1]);
		cp1[1] = FbxVector4(v2.Position[1], v2.UV[0], v2.UV[1]);
		cp1[2] = FbxVector4(v2.Position[2], v2.UV[0], v2.UV[1]);

		FbxVector4 cp2[3];
		cp2[0] = FbxVector4(v3.Position[0], v3.UV[0], v3.UV[1]);
		cp2[1] = FbxVector4(v3.Position[1], v3.UV[0], v3.UV[1]);
		cp2[2] = FbxVector4(v3.Position[2], v3.UV[0], v3.UV[1]);

		double u[3];
		double v[3];
		
		for (int32_t i = 0; i < 3; i++)
		{
			auto v1 = cp1[i] - cp0[i];
			auto v2 = cp2[i] - cp1[i];
			auto abc = v1.CrossProduct(v2);

			if (abc[0] == 0.0f)
			{
				return;
			}
			else
			{
				u[i] = -abc[1] / abc[0];
				v[i] = -abc[2] / abc[0];
			}
		}

		tangent = FbxVector4(u[0], u[1], u[2]);
		tangent.Normalize();

		binormal = FbxVector4(v[0], v[1], v[2]);
		binormal.Normalize();
	}
	std::shared_ptr<Mesh> FBXConverter::LoadMesh(FbxMesh* fbxMesh)
	{
		assert(fbxMesh->GetLayerCount() > 0);

		auto node = fbxMesh->GetNode();
		auto layer = fbxMesh->GetLayer(0);

		if (layer->GetNormals() == nullptr)
		{
			fbxMesh->GenerateNormals(true);
		}

		auto uvs = layer->GetUVs();
		auto vcolors = layer->GetVertexColors();
		auto normals = layer->GetNormals();
		auto binormals = layer->GetBinormals();
		auto materials = layer->GetMaterials();

		auto controlPoints = fbxMesh->GetControlPoints();
		auto controlPointsCount = fbxMesh->GetControlPointsCount();

		auto polygonCount = fbxMesh->GetPolygonCount();

		std::vector<FbxFace> faces;

		// Load weights
		std::vector<BoneConnector> bcs_temp;
		std::vector<Vertex> vs_temp;
		LoadSkin(fbxMesh, bcs_temp, vs_temp);

		// generate face vertex
		int32_t vertexID = 0;
		for (int32_t polygonIndex = 0; polygonIndex < polygonCount; polygonIndex++)
		{
			int polygonPointCount = fbxMesh->GetPolygonSize(polygonIndex);

			FbxFace face;

			for (int32_t polygonPointIndex = 0; polygonPointIndex < polygonPointCount; polygonPointIndex++)
			{
				auto ctrlPointIndex = fbxMesh->GetPolygonVertex(polygonIndex, polygonPointIndex);

				Vertex v;

				v.Position = LoadPosition(fbxMesh, ctrlPointIndex);
				
				v.Weights = vs_temp[ctrlPointIndex].Weights;

				if (normals != nullptr)
				{
					v.Normal = LoadNormal(normals, vertexID, ctrlPointIndex);
				}
		
				if (uvs != nullptr)
				{
					v.UV = LoadUV(fbxMesh, uvs, vertexID, ctrlPointIndex, polygonIndex, polygonPointIndex);
				}
				else
				{
					// Auto generated
					v.UV[0] = v.Position[0] + v.Position[2];
					v.UV[1] = v.Position[1];
				}

				if (vcolors != nullptr)
				{
					v.VertexColor = LoadVertexColor(fbxMesh, vcolors, vertexID, ctrlPointIndex, polygonIndex, polygonPointIndex);
				}

				face.Vertecies.push_back(v);
				vertexID++;
			}

			faces.push_back(face);
		}



		// 面の表裏入れ替え
		for (auto& face : faces)
		{
			std::reverse(face.Vertecies.begin(), face.Vertecies.end());
		}

		// メッシュで使用可能な形式に変換
	
		// 頂点変換テーブル作成
		int32_t vInd = 0;
		std::map<Vertex, int32_t> v2ind;
		std::map<int32_t, Vertex> ind2v;

		for (auto& face : faces)
		{
			for (int32_t vi = 0; vi < (int32_t)face.Vertecies.size(); vi++)
			{
				auto vertex = face.Vertecies[vi];

				auto it = v2ind.find(vertex);
				if (it == v2ind.end())
				{
					v2ind[vertex] = vInd;
					ind2v[vInd] = vertex;
					vInd++;
				}
			}
		}

		// 設定
		auto mesh = std::make_shared<Mesh>();
		mesh->Name = node->GetName();
		mesh->BoneConnectors = bcs_temp;

		mesh->Vertexes.resize(vInd);
		for (auto& iv : ind2v)
		{
			mesh->Vertexes[iv.first] = iv.second;
		}

		for (auto& face : faces)
		{
			if (face.Vertecies.size() < 3) continue;

			if (face.Vertecies.size() == 3)
			{
				Face f;
				f.Index[0] = v2ind[face.Vertecies[0]];
				f.Index[1] = v2ind[face.Vertecies[1]];
				f.Index[2] = v2ind[face.Vertecies[2]];
				mesh->Faces.push_back(f);
			}
			
			if (face.Vertecies.size() == 4)
			{
				Face f0;
				f0.Index[0] = v2ind[face.Vertecies[0]];
				f0.Index[1] = v2ind[face.Vertecies[1]];
				f0.Index[2] = v2ind[face.Vertecies[2]];
				mesh->Faces.push_back(f0);

				Face f1;
				f1.Index[0] = v2ind[face.Vertecies[0]];
				f1.Index[1] = v2ind[face.Vertecies[2]];
				f1.Index[2] = v2ind[face.Vertecies[3]];
				mesh->Faces.push_back(f1);
			}
		}

		// Binormal,Tangent計算
		std::map<int32_t, VertexNormals> vInd2Normals;

		for (const auto& face : mesh->Faces)
		{
			FbxVector4 binormal, tangent;
			CalcTangentSpace(
				mesh->Vertexes[face.Index[0]],
				mesh->Vertexes[face.Index[1]],
				mesh->Vertexes[face.Index[2]],
				binormal,
				tangent);

			for (auto i = 0; i < 3; i++)
			{
				vInd2Normals[face.Index[i]].Binormal += binormal;
				vInd2Normals[face.Index[i]].Tangent += tangent;
				vInd2Normals[face.Index[i]].Count += 1;
			}
		}

		for (auto& vn : vInd2Normals)
		{
			vn.second.Binormal /= vn.second.Count;
			vn.second.Tangent /= vn.second.Count;
		}

		for (auto& vn : vInd2Normals)
		{
			mesh->Vertexes[vn.first].Binormal = vn.second.Binormal;
			mesh->Vertexes[vn.first].Tangent = vn.second.Tangent;

			// 適当な値を代入する
			if (mesh->Vertexes[vn.first].Binormal.Length() == 0.0f)
			{
				if (mesh->Vertexes[vn.first].Normal != FbxVector4(1, 0, 0))
				{
					mesh->Vertexes[vn.first].Binormal = FbxVector4(1, 0, 0);
					mesh->Vertexes[vn.first].Tangent = FbxVector4(0, 1, 0);
				}
				else
				{
					mesh->Vertexes[vn.first].Binormal = FbxVector4(0, 1, 0);
					mesh->Vertexes[vn.first].Tangent = FbxVector4(1, 0, 0);
				}
			}
		}

		return mesh;
	}