00001 #ifndef EXPORT_FBX
00002 #define EXPORT_FBX
00003
00004 #include <fbxsdk.h>
00005
00006
00007
00008
00009
00010
00011
00012
00013 template <class SaveMeshType>
00014 class ExporterFBX
00015 {
00016 public:
00017 typedef typename SaveMeshType::VertexPointer VertexPointer;
00018 typedef typename SaveMeshType::ScalarType ScalarType;
00019 typedef typename SaveMeshType::VertexType VertexType;
00020 typedef typename SaveMeshType::FaceType FaceType;
00021 typedef typename SaveMeshType::FacePointer FacePointer;
00022 typedef typename SaveMeshType::VertexIterator VertexIterator;
00023 typedef typename SaveMeshType::FaceIterator FaceIterator;
00024 typedef typename SaveMeshType::CoordType CoordType;
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 static int Save(SaveMeshType &m, const char * filename,const bool binary,const bool embed,const int mask)
00040 {
00041 KFbxSdkManager* sdkman = KFbxSdkManager::Create();
00042
00043 KFbxIOSettings * ios = KFbxIOSettings::Create(sdkman, IOSROOT );
00044 ios->SetBoolProp(EXP_FBX_MATERIAL,true);
00045 ios->SetBoolProp(EXP_FBX_TEXTURE,true);
00046 ios->SetBoolProp(EXP_FBX_EMBEDDED,embed);
00047 ios->SetBoolProp(EXP_FBX_SHAPE,true);
00048 ios->SetBoolProp(EXP_FBX_ANIMATION,false);
00049 ios->SetBoolProp(EXP_FBX_GLOBAL_SETTINGS, true);
00050 sdkman->SetIOSettings(ios);
00051
00052 if(sdkman == NULL)
00053 return -1;
00054
00055 KFbxExporter* lExporter = KFbxExporter::Create(sdkman,"VCGFbxFileExporter");
00056 int asciiexportind = -1;
00057
00058 if ((!binary) && (!embed))
00059 {
00060 int formatnum = sdkman->GetIOPluginRegistry()->GetWriterFormatCount();
00061 bool asciifound = false;
00062 int ii = 0;
00063 while ((!asciifound) && (ii<formatnum))
00064 {
00065 if (sdkman->GetIOPluginRegistry()->WriterIsFBX(ii))
00066 {
00067 KString plugdesc =sdkman->GetIOPluginRegistry()->GetWriterFormatDescription(ii);
00068 if (plugdesc.Find("ascii")>=0)
00069 {
00070 asciiexportind = ii;
00071 asciifound = true;
00072 }
00073 }
00074 ++ii;
00075 }
00076 }
00077
00078
00079 if(!lExporter->Initialize(filename, asciiexportind,ios))
00080 return false;
00081
00082 KFbxScene* scene = KFbxScene::Create(sdkman,"VCGScene");
00083 bool result = fillScene(m,*scene,mask);
00084 if (!result)
00085 return -1;
00086 result = lExporter->Export(scene);
00087 lExporter->Destroy();
00088 if (!result)
00089 return -1;
00090 return 0;
00091 }
00092
00093
00094
00095
00096
00097
00098
00099 static int GetExportMaskCapability()
00100 {
00101 int capability = 0;
00102 capability |= vcg::tri::io::Mask::IOM_VERTCOORD;
00103 capability |= vcg::tri::io::Mask::IOM_VERTCOLOR;
00104 capability |= vcg::tri::io::Mask::IOM_VERTNORMAL;
00105 capability |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD;
00106 return capability;
00107 }
00108
00109 private:
00110
00111 static KFbxFileTexture* newTexture(KFbxScene& scene,const char* name,const KFbxVector2& trans = KFbxVector2(0.0,0.0),const KFbxVector2& rot = KFbxVector2(0.0,0.0),const KFbxVector2& scal = KFbxVector2(1.0,1.0))
00112 {
00113 static int conttext = 0;
00114 std::string label = createName("texture_",conttext);
00115 KFbxFileTexture* text = KFbxFileTexture::Create(&scene,label.c_str());
00116 text->SetFileName(name);
00117 text->SetTextureUse(KFbxTexture::eSTANDARD);
00118 text->SetMappingType(KFbxTexture::eUV);
00119 text->SetMaterialUse(KFbxFileTexture::eMODEL_MATERIAL);
00120 text->SetSwapUV(false);
00121 text->SetTranslation(trans[0],trans[1]);
00122 text->SetScale(scal[0],scal[1]);
00123 text->SetRotation(rot[0],rot[1]);
00124 ++conttext;
00125 return text;
00126 }
00127
00128 static KFbxSurfacePhong* newPhongMaterial(KFbxScene& scene,const char* name,KFbxFileTexture* text = NULL,const fbxDouble3& dif = fbxDouble3(1.0,1.0,1.0))
00129 {
00130 KFbxSurfacePhong* mat = KFbxSurfacePhong::Create(&scene, name);
00131 mat->Diffuse.Set(dif);
00132
00133
00134
00135
00136
00137 if (text)
00138 mat->Diffuse.ConnectSrcObject(text);
00139 return mat;
00140 }
00141
00142 static void insertMaterialElementLayer(KFbxMesh* vcgmesh)
00143 {
00144 KFbxGeometryElementMaterial* lMaterialElement = vcgmesh->CreateElementMaterial();
00145 lMaterialElement->SetMappingMode(KFbxGeometryElement::eBY_POLYGON);
00146 lMaterialElement->SetReferenceMode(KFbxGeometryElement::eINDEX_TO_DIRECT);
00147 }
00148
00149 static std::string createName(const char* base,const int ind)
00150 {
00151 char buffer[33];
00152 sprintf(buffer,"%d",ind);
00153 std::string res = std::string(base) + std::string(buffer);
00154 return res;
00155 }
00156
00157 static bool fillScene(SaveMeshType& m,KFbxScene& scene,const int mask)
00158 {
00159 bool wedgetexcoord = (vcg::tri::HasPerWedgeTexCoord(m) && (mask | vcg::tri::io::Mask::IOM_WEDGTEXCOORD));
00160 bool vertnorm = (vcg::tri::HasPerVertexNormal(m) && (mask | vcg::tri::io::Mask::IOM_VERTNORMAL));
00161 bool facecolasmaterial = false;
00162 int fn = int(m.face.size());
00163 std::set<vcg::Color4b> matset;
00164
00165
00166
00167 if (wedgetexcoord)
00168 {
00169 for(int ii = 0;ii < fn;++ii)
00170 {
00171 if (!m.face[ii].IsD())
00172 {
00173 int ind = m.face[ii].WT(0).N();
00174 if ((ind == -1) && vcg::tri::HasPerVertexColor(m))
00175 {
00176 for(int hh = 0;hh < 3;++hh)
00177 matset.insert(m.face[ii].V(hh)->C());
00178 facecolasmaterial = true;
00179 }
00180 }
00181 }
00182 }
00183
00184 bool vertcol = (vcg::tri::HasPerVertexColor(m) && (mask | vcg::tri::io::Mask::IOM_VERTCOLOR)) && !facecolasmaterial;
00185
00186
00187 KFbxMesh* vcgmesh = KFbxMesh::Create(&scene,"VCGMeshAttribute");
00188 KFbxNode* meshnode = KFbxNode::Create(&scene,"VCGMeshNode");
00189 meshnode->SetNodeAttribute(vcgmesh);
00190 if (m.textures.size() > 0)
00191 meshnode->SetShadingMode(KFbxNode::eTEXTURE_SHADING);
00192 else
00193 meshnode->SetShadingMode(KFbxNode::eHARD_SHADING);
00194
00195 KFbxGeometryElementVertexColor* vcolorlay = NULL;
00196 if (vertcol)
00197 {
00198 vcolorlay = vcgmesh->CreateElementVertexColor();
00199 vcolorlay->SetMappingMode(KFbxGeometryElement::eBY_CONTROL_POINT);
00200 vcolorlay->SetReferenceMode(KFbxGeometryElement::eDIRECT);
00201 }
00202
00203 KFbxGeometryElementNormal* vnormlay = NULL;
00204 if (vertnorm)
00205 {
00206 vnormlay = vcgmesh->CreateElementNormal();
00207 vnormlay->SetMappingMode(KFbxGeometryElement::eBY_CONTROL_POINT);
00208 vnormlay->SetReferenceMode(KFbxGeometryElement::eDIRECT);
00209 }
00210 int zz;
00211 for(zz = 0;zz < m.textures.size();++zz)
00212 {
00213 KFbxFileTexture* tex = newTexture(scene,m.textures[zz].c_str());
00214 KFbxSurfacePhong* phong = newPhongMaterial(scene,createName("mat_",zz).c_str(),tex);
00215 KFbxNode* meshnode = vcgmesh->GetNode();
00216 if(meshnode == NULL)
00217 return false;
00218 meshnode->AddMaterial(phong);
00219 }
00220
00221 for(std::set<vcg::Color4b>::iterator it = matset.begin();it != matset.end();++it)
00222 {
00223 vcg::Color4b vcgcol = *it;
00224 fbxDouble3 fbxcol(vcgcol[0] / 255.0f,vcgcol[1]/ 255.0f,vcgcol[2]/ 255.0f);
00225 KFbxSurfacePhong* phong = newPhongMaterial(scene,createName("mat_",zz).c_str(),NULL,fbxcol);
00226 KFbxNode* meshnode = vcgmesh->GetNode();
00227 if(meshnode == NULL)
00228 return false;
00229 meshnode->AddMaterial(phong);
00230 ++zz;
00231 }
00232 if (m.textures.size() > 0)
00233 insertMaterialElementLayer(vcgmesh);
00234
00235 int vn = int(m.vert.size());
00236 int notdeletedvert = m.vn;
00237 int deletedvert = int(vn - notdeletedvert);
00238 vcgmesh->InitControlPoints(notdeletedvert);
00239 std::vector<int> deletedBeforeValid(vn);
00240 KFbxVector4* controlp = vcgmesh->GetControlPoints();
00241 int validvert = 0;
00242 int invalidvert = 0;
00243 for(int ii = 0;ii < vn;++ii)
00244 {
00245 if (!m.vert[ii].IsD())
00246 {
00247 deletedBeforeValid[ii] = invalidvert;
00248 vcg::Point3<ScalarType> p = m.vert[ii].P();
00249
00250 controlp[validvert] = KFbxVector4(p.X(),p.Y(),p.Z());
00251 if (vertcol)
00252 {
00253
00254 vcg::Color4b vcgcol = m.vert[ii].C();
00255 KFbxColor fbxcol(vcgcol[0] / 255.0f,vcgcol[1] / 255.0f,vcgcol[2] / 255.0f,vcgcol[3] / 255.0f);
00256 if (vcolorlay)
00257 {
00258 KFbxLayerElementArrayTemplate<KFbxColor>& carr = vcolorlay->GetDirectArray();
00259 carr.Add(fbxcol);
00260 }
00261 }
00262
00263 if(vertnorm)
00264 {
00265 CoordType vcgnorm = m.vert[ii].N();
00266 KFbxVector4 fbxnorm(vcgnorm[0],vcgnorm[1],vcgnorm[2]);
00267 if (vnormlay)
00268 {
00269 KFbxLayerElementArrayTemplate<KFbxVector4>& narr = vnormlay->GetDirectArray();
00270 narr.Add(fbxnorm);
00271 }
00272 }
00273 ++validvert;
00274 }
00275 else
00276 ++invalidvert;
00277 }
00278
00279 KFbxGeometryElementUV* uvel = NULL;
00280
00281
00282 if (wedgetexcoord)
00283 {
00284 uvel = vcgmesh->CreateElementUV("UV");
00285 uvel->SetMappingMode(KFbxGeometryElement::eBY_POLYGON_VERTEX);
00286 uvel->SetReferenceMode(KFbxGeometryElement::eINDEX_TO_DIRECT);
00287 }
00288
00289 int validface = 0;
00290 for(int ii = 0;ii < fn;++ii)
00291 {
00292 if (!m.face[ii].IsD())
00293 {
00294 if (wedgetexcoord)
00295 {
00296 vcg::Color4b facecol;
00297 int textind = m.face[ii].WT(0).N();
00298 int matind = textind;
00299 if ((textind == -1) && vcg::tri::HasPerVertexColor(m))
00300 {
00301 std::set<vcg::Color4b>::iterator it = matset.find(m.face[ii].V(0)->C());
00302 matind = int(std::distance(matset.begin(),it) + m.textures.size());
00303 }
00304 vcgmesh->BeginPolygon(matind,textind);
00305 }
00306 else
00307 vcgmesh->BeginPolygon();
00308 int validvertex = 0;
00309 for (int jj = 0;jj < 3;++jj)
00310 {
00311
00312 if (!m.face[ii].V(jj)->IsD())
00313 {
00314 int vi_with_invalid = int(m.face[ii].V(jj) - &(*m.vert.begin()));
00315 int vi = vi_with_invalid - deletedBeforeValid[vi_with_invalid];
00316 vcgmesh->AddPolygon(vi);
00317 if (wedgetexcoord)
00318 {
00319 ScalarType u = m.face[ii].WT(jj).U();
00320 ScalarType v = m.face[ii].WT(jj).V();
00321
00322 uvel->GetDirectArray().Add(KFbxVector2(u,v));
00323 uvel->GetIndexArray().Add(validface * 3 + validvertex);
00324 ++validvertex;
00325 }
00326 }
00327 }
00328 vcgmesh->EndPolygon();
00329 ++validface;
00330 }
00331 }
00332
00333
00334
00335 KFbxNode* root = scene.GetRootNode();
00336 root->AddChild(meshnode);
00337
00338 return true;
00339 }
00340 };
00341 #endif