Add io_trimesh/import_fbx.h and sample file
This commit is contained in:
parent
5eb5363d01
commit
161c2c04f9
|
@ -0,0 +1,60 @@
|
||||||
|
/****************************************************************************
|
||||||
|
* VCGLib o o *
|
||||||
|
* Visual and Computer Graphics Library o o *
|
||||||
|
* _ O _ *
|
||||||
|
* Copyright(C) 2004-2016 \/)\/ *
|
||||||
|
* Visual Computing Lab /\/| *
|
||||||
|
* ISTI - Italian National Research Council | *
|
||||||
|
* \ *
|
||||||
|
* All rights reserved. *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||||
|
* for more details. *
|
||||||
|
* *
|
||||||
|
****************************************************************************/
|
||||||
|
/*! \file trimesh_create.cpp
|
||||||
|
\ingroup code_sample
|
||||||
|
|
||||||
|
\brief A very simple example that open a fbx file and save it as an obj.
|
||||||
|
Just as an example of what you should add to your project to compile it:
|
||||||
|
../../../wrap/openfbx/src/ofbx.cpp
|
||||||
|
../../../wrap/openfbx/src/miniz.c
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include <vcg/complex/complex.h>
|
||||||
|
#include <wrap/io_trimesh/import_fbx.h>
|
||||||
|
#include <wrap/io_trimesh/export_obj.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
using namespace vcg;
|
||||||
|
|
||||||
|
class MyFace;
|
||||||
|
class MyEdge;
|
||||||
|
class MyVertex;
|
||||||
|
|
||||||
|
struct MyUsedTypes : public UsedTypes<Use<MyVertex>::AsVertexType, Use<MyFace>::AsFaceType>{};
|
||||||
|
|
||||||
|
class MyVertex : public Vertex< MyUsedTypes, vertex::Coord3f, vertex::Normal3f, vertex::Qualityf, vertex::Color4b,vertex::BitFlags >{};
|
||||||
|
class MyFace : public Face < MyUsedTypes, face::VertexRef, face::Normal3f, face::Qualityf, face::WedgeTexCoord2f, face::Color4b, face::BitFlags > {};
|
||||||
|
class MyMesh : public tri::TriMesh< std::vector<MyVertex>, std::vector<MyFace> >{};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
MyMesh openMesh;
|
||||||
|
|
||||||
|
// tri::io::ImporterFBX<MyMesh>::Open(openMesh,"Arabic_Censer/Arabic_Censer.FBX");
|
||||||
|
// tri::io::ImporterFBX<MyMesh>::Open(openMesh,"elephant/ELEPHANT_M.fbx");
|
||||||
|
tri::io::ImporterFBX<MyMesh>::Open(openMesh,"liontemple/sketchfabTemp.obj.fbx");
|
||||||
|
|
||||||
|
tri::io::ExporterOBJ<MyMesh>::Save(openMesh,"sphere.obj",tri::io::Mask::IOM_WEDGTEXCOORD);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
include(../common.pri)
|
||||||
|
TARGET = trimesh_import_fbx
|
||||||
|
SOURCES += trimesh_import_fbx.cpp \
|
||||||
|
../../../wrap/openfbx/src/ofbx.cpp \
|
||||||
|
../../../wrap/openfbx/src/miniz.c
|
||||||
|
|
||||||
|
CONFIG += c++14
|
||||||
|
|
|
@ -1,62 +1,59 @@
|
||||||
#ifndef IMPORT_FBX
|
/****************************************************************************
|
||||||
#define IMPORT_FBX
|
* VCGLib o o *
|
||||||
|
* Visual and Computer Graphics Library o o *
|
||||||
|
* _ O _ *
|
||||||
|
* Copyright(C) 2004-2018 \/)\/ *
|
||||||
|
* Visual Computing Lab /\/| *
|
||||||
|
* ISTI - Italian National Research Council | *
|
||||||
|
* \ *
|
||||||
|
* All rights reserved. *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
|
||||||
|
* for more details. *
|
||||||
|
* *
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
#include<vcg/complex/allocate.h>
|
/**
|
||||||
#include <wrap/callback.h>
|
@name Open FBX format
|
||||||
#include <wrap/io_trimesh/io_mask.h>
|
|
||||||
#include <wrap/io_trimesh/io_material.h>
|
|
||||||
#include <vcg/space/color4.h>
|
|
||||||
#include <fbxsdk.h>
|
|
||||||
#include <vcg/complex/algorithms/update/bounding.h>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <cmath>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
/******************************
|
|
||||||
ImporterFBX is the class devoted to import the info contained in a FBX file inside a mesh defined following the vcg standards.
|
|
||||||
In order to compile the following class you need to:
|
|
||||||
- download the VCGlib from our SVN server and put the code in ../../vcglib
|
|
||||||
- download from Autodesk website the FBXSDK-2012.1 and put the lib and include folders in ../fbx-2012.1
|
|
||||||
*/
|
*/
|
||||||
|
//@{
|
||||||
|
|
||||||
|
#ifndef VCGLIB_IMPORT_FBX
|
||||||
|
#define VCGLIB_IMPORT_FBX
|
||||||
|
#include <wrap/openfbx/src/ofbx.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <vcg/complex/complex.h>
|
||||||
|
#include <vcg/complex/algorithms/clean.h>
|
||||||
|
#include <wrap/io_trimesh/io_mask.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief ImporterFBX is the class devoted to import the info contained in a FBX file inside a mesh defined following the vcg standards.
|
||||||
|
|
||||||
|
To use it you need to add the following two files to your project:
|
||||||
|
|
||||||
|
wrap/openfbx/src/ofbx.cpp
|
||||||
|
wrap/openfbx/src/miniz.c
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
namespace vcg {
|
||||||
|
namespace tri {
|
||||||
|
namespace io {
|
||||||
|
|
||||||
template <class OpenMeshType>
|
template <class OpenMeshType>
|
||||||
class ImporterFBX
|
class ImporterFBX
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
class Info
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
Info()
|
|
||||||
{
|
|
||||||
mask = 0;
|
|
||||||
cb = 0;
|
|
||||||
numVertices = 0;
|
|
||||||
numFaces = 0;
|
|
||||||
numMeshPatches = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// It returns a bit mask describing the field preesnt in the ply file
|
|
||||||
int mask;
|
|
||||||
|
|
||||||
/// a Simple callback that can be used for long obj parsing.
|
|
||||||
// it returns the current position, and formats a string with a description of what th efunction is doing (loading vertexes, faces...)
|
|
||||||
vcg::CallBackPos *cb;
|
|
||||||
|
|
||||||
/// number of vertices
|
|
||||||
int numVertices;
|
|
||||||
/// number of faces (the number of triangles could be
|
|
||||||
/// larger in presence of polygonal faces
|
|
||||||
int numFaces;
|
|
||||||
/// number meshes inside the fbx file
|
|
||||||
int numMeshPatches;
|
|
||||||
|
|
||||||
}; // end class
|
|
||||||
|
|
||||||
typedef typename OpenMeshType::VertexPointer VertexPointer;
|
typedef typename OpenMeshType::VertexPointer VertexPointer;
|
||||||
typedef typename OpenMeshType::ScalarType ScalarType;
|
typedef typename OpenMeshType::ScalarType ScalarType;
|
||||||
typedef typename OpenMeshType::VertexType VertexType;
|
typedef typename OpenMeshType::VertexType VertexType;
|
||||||
|
@ -66,467 +63,7 @@ public:
|
||||||
typedef typename OpenMeshType::CoordType CoordType;
|
typedef typename OpenMeshType::CoordType CoordType;
|
||||||
typedef typename OpenMeshType::VertexType::ColorType ColorType;
|
typedef typename OpenMeshType::VertexType::ColorType ColorType;
|
||||||
typedef typename OpenMeshType::VertexType::ColorType::ScalarType CSType;
|
typedef typename OpenMeshType::VertexType::ColorType::ScalarType CSType;
|
||||||
private:
|
typedef typename vcg::Matrix44<ScalarType> Matrix44Type;
|
||||||
class VCGMaterialBridge
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
//colorAttributeName is something like: diffuse color,ambient color etc.
|
|
||||||
void insertMaterialInfoAndTextureName(KFbxSurfaceMaterial& mat,const char* colorAttributeName,OpenMeshType& m)
|
|
||||||
{
|
|
||||||
MaterialInfo matinfo;
|
|
||||||
matinfo.setSurfaceMaterial(&mat);
|
|
||||||
//bool hastextcoords = (vcg::tri::HasPerWedgeTexCoord(m) || vcg::tri::HasPerVertexTexCoord(m));
|
|
||||||
//bool hascolors = (vcg::tri::HasPerWedgeColor(m) || vcg::tri::HasPerVertexColor(m) || vcg::tri::HasPerFaceColor(m));
|
|
||||||
KFbxFileTexture* tex = matinfo.getTextureFileObject(colorAttributeName);
|
|
||||||
if(tex)
|
|
||||||
{
|
|
||||||
const char* texfile = tex->GetFileName();
|
|
||||||
std::vector<std::string>::iterator it = std::find(m.textures.begin(),m.textures.end(),texfile);
|
|
||||||
if (it == m.textures.end())
|
|
||||||
{
|
|
||||||
m.textures.push_back(texfile);
|
|
||||||
matinfo.setTextureIndex(m.textures.size() - 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int dist = int(std::distance(m.textures.begin(),it));
|
|
||||||
matinfo.setTextureIndex(dist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (mat.GetClassId().Is(KFbxSurfaceLambert::ClassId))
|
|
||||||
{
|
|
||||||
KFbxPropertyDouble3 diffProp = ((KFbxSurfaceLambert* ) (&mat))->Diffuse;
|
|
||||||
fbxDouble3 diffCol = diffProp.Get();
|
|
||||||
vcg::Color4b tmpc = vcg::Color4b(diffCol[0] * 255,diffCol[1] * 255,diffCol[2] * 255,255);
|
|
||||||
matinfo.setColor(tmpc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material[colorAttributeName] = matinfo;
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
//given a texture or color attribute return
|
|
||||||
|
|
||||||
VCGMaterialBridge(OpenMeshType& m,KFbxSurfaceMaterial& mat)
|
|
||||||
:material()
|
|
||||||
{
|
|
||||||
insertMaterialInfoAndTextureName(mat,KFbxSurfaceMaterial::sDiffuse,m);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MaterialInfo
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int textindex;
|
|
||||||
ColorType color;
|
|
||||||
bool hascolor;
|
|
||||||
KFbxSurfaceMaterial* surfMat;
|
|
||||||
public:
|
|
||||||
MaterialInfo():hascolor(false),textindex(-1),surfMat(NULL){}
|
|
||||||
void setColor(const ColorType& col) {color = col;hascolor= true;}
|
|
||||||
void setTextureIndex(const int i) {textindex = i;}
|
|
||||||
bool hasColor() const {return hascolor;}
|
|
||||||
bool hasTexture() const {return (textindex != -1);}
|
|
||||||
int getTextureIndex() const {return textindex;}
|
|
||||||
KFbxSurfaceMaterial* getSurfaceMaterial() const {return surfMat;}
|
|
||||||
void setSurfaceMaterial(KFbxSurfaceMaterial* mat) {surfMat = mat;}
|
|
||||||
KFbxFileTexture* getTextureFileObject (const char* attributeName)
|
|
||||||
{
|
|
||||||
if (surfMat)
|
|
||||||
{
|
|
||||||
KFbxProperty prop = surfMat->FindProperty(attributeName);
|
|
||||||
if(prop.IsValid())
|
|
||||||
{
|
|
||||||
int texnum = prop.GetSrcObjectCount(KFbxTexture::ClassId);
|
|
||||||
//the texnum value should be or 0 or 1 (i.e. for a diffuse texture i should have at most one texture file) but in order to avoid extremely strange file...
|
|
||||||
if (texnum > 0)
|
|
||||||
return KFbxCast <KFbxFileTexture> (prop.GetSrcObject(KFbxTexture::ClassId,0));
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorType getColor() const {return color;}
|
|
||||||
};
|
|
||||||
|
|
||||||
MaterialInfo* getMaterial(const char* attr)
|
|
||||||
{
|
|
||||||
typename std::map<const char*,MaterialInfo>::iterator it = material.find(attr);
|
|
||||||
if (it != material.end())
|
|
||||||
return &(it->second);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::map<const char*,MaterialInfo> material;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int ImportNode(OpenMeshType& m,KFbxNode* node,KFbxPose* pose,KFbxXMatrix* globPosMat,Info &oi)
|
|
||||||
{
|
|
||||||
int result = E_NOERROR;
|
|
||||||
if (node)
|
|
||||||
{
|
|
||||||
KFbxXMatrix mat = getGlobalMatrix(node, KTime(), pose, globPosMat);
|
|
||||||
|
|
||||||
|
|
||||||
KFbxNodeAttribute* attr = node->GetNodeAttribute();
|
|
||||||
if (attr != NULL)
|
|
||||||
{
|
|
||||||
KFbxNodeAttribute::EAttributeType att = attr->GetAttributeType();
|
|
||||||
if (attr->GetAttributeType() == KFbxNodeAttribute::eMESH)
|
|
||||||
{
|
|
||||||
KFbxXMatrix geoOff = GetGeometry(node);
|
|
||||||
KFbxXMatrix final = mat * geoOff;
|
|
||||||
|
|
||||||
result = ImportMesh(m,node,final,oi);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
for(int ii = 0;ii < node->GetChildCount();++ii)
|
|
||||||
ImportNode(m,node->GetChild(ii),pose,&mat,oi);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ImportScene(OpenMeshType& m,KFbxScene* scene,Info &oi)
|
|
||||||
{
|
|
||||||
scene->ConnectTextures();
|
|
||||||
KFbxPose* pose = NULL;
|
|
||||||
int ii = scene->GetPoseCount();
|
|
||||||
if (ii > 0)
|
|
||||||
pose = scene->GetPose(ii-1);
|
|
||||||
//KFbxAnimEvaluator* eval = scene->GetEvaluator();
|
|
||||||
KFbxNode* node = scene->GetRootNode();
|
|
||||||
int result = E_NOERROR;
|
|
||||||
KFbxXMatrix globPosMat;
|
|
||||||
for (int ii = 0; ii < scene->GetRootNode()->GetChildCount(); ++ii)
|
|
||||||
result = ImportNode(m,scene->GetRootNode()->GetChild(ii),pose,&globPosMat,oi);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ImportMesh(OpenMeshType& m,KFbxNode* node,const KFbxXMatrix& mat,Info& oi)
|
|
||||||
{
|
|
||||||
KFbxMesh* newMesh = node->GetMesh();
|
|
||||||
if (!newMesh->IsTriangleMesh())
|
|
||||||
{
|
|
||||||
KFbxGeometryConverter* conv = new KFbxGeometryConverter(newMesh->GetFbxSdkManager());
|
|
||||||
newMesh = conv->TriangulateMesh(newMesh);
|
|
||||||
}
|
|
||||||
//KFbxMatrix mat2(mat);
|
|
||||||
vcg::Matrix44<ScalarType> mat2;
|
|
||||||
for(int ll = 0;ll < 4;++ll)
|
|
||||||
for(int vv = 0;vv < 4;++vv)
|
|
||||||
mat2[ll][vv] = mat[vv][ll];
|
|
||||||
|
|
||||||
|
|
||||||
vcg::Matrix33<ScalarType> matnorm;
|
|
||||||
for(int ll = 0;ll < 3;++ll)
|
|
||||||
for(int vv = 0;vv < 3;++vv)
|
|
||||||
matnorm[ll][vv] = mat[vv][ll];
|
|
||||||
|
|
||||||
int matnum = node->GetSrcObjectCount(KFbxSurfaceMaterial::ClassId);
|
|
||||||
KFbxLayerElementArrayTemplate< int >* matarr = NULL;
|
|
||||||
bool found = newMesh->GetMaterialIndices(&matarr);
|
|
||||||
//displacement of material inside m.textures and number of textures inside the material
|
|
||||||
std::vector<VCGMaterialBridge> matAtlas;
|
|
||||||
for (int matind = 0; matind < matnum; ++matind)
|
|
||||||
{
|
|
||||||
KFbxSurfaceMaterial *mater = KFbxCast <KFbxSurfaceMaterial>(node->GetSrcObject(KFbxSurfaceMaterial::ClassId, matind));
|
|
||||||
matAtlas.push_back(VCGMaterialBridge(m,*mater));
|
|
||||||
}
|
|
||||||
size_t vertDispl = m.vert.size();
|
|
||||||
int currmeshvert = newMesh->GetControlPointsCount();
|
|
||||||
vcg::tri::Allocator<OpenMeshType>::AddVertices(m,currmeshvert);
|
|
||||||
int currmeshface = newMesh->GetPolygonCount();
|
|
||||||
size_t faceDispl = m.face.size();
|
|
||||||
vcg::tri::Allocator<OpenMeshType>::AddFaces(m,currmeshface);
|
|
||||||
KFbxVector4* posVert = newMesh->GetControlPoints();
|
|
||||||
KFbxLayerElementArrayTemplate<KFbxVector2>* UVArr = NULL;
|
|
||||||
int uvparcount = newMesh->GetElementUVCount();
|
|
||||||
|
|
||||||
KFbxLayer* lnorm = newMesh->GetLayer(0,KFbxLayerElement::eNORMAL);
|
|
||||||
KFbxLayerElementNormal* normalLayer = NULL;
|
|
||||||
if (lnorm)
|
|
||||||
normalLayer = lnorm->GetNormals();
|
|
||||||
KFbxLayerElement::EMappingMode normalMapMode = KFbxLayerElement::eNONE;
|
|
||||||
if (normalLayer)
|
|
||||||
normalMapMode = normalLayer->GetMappingMode();
|
|
||||||
KFbxLayer* lcol = newMesh->GetLayer(0,KFbxLayerElement::eVERTEX_COLOR);
|
|
||||||
KFbxLayerElementVertexColor* colorLayer = NULL;
|
|
||||||
if (lcol)
|
|
||||||
colorLayer = lcol->GetVertexColors();
|
|
||||||
KFbxLayerElement::EMappingMode colorMapMode = KFbxLayerElement::eNONE;
|
|
||||||
if (colorLayer)
|
|
||||||
colorMapMode = colorLayer->GetMappingMode();
|
|
||||||
|
|
||||||
newMesh->GetTextureUV(&UVArr, KFbxLayerElement::eDIFFUSE_TEXTURES);
|
|
||||||
|
|
||||||
int numFacPlusVert = oi.numFaces + oi.numVertices;
|
|
||||||
float det = mat2.Determinant();
|
|
||||||
bool invert = (det< 0.0);
|
|
||||||
for(int ii = 0;ii < currmeshvert;++ii)
|
|
||||||
{
|
|
||||||
|
|
||||||
ScalarType a = ScalarType(posVert[ii][0]);
|
|
||||||
ScalarType b = ScalarType(posVert[ii][1]);
|
|
||||||
ScalarType c = ScalarType(posVert[ii][2]);
|
|
||||||
vcg::Point4<ScalarType> fbxpos(a,b,c,ScalarType(1.0));
|
|
||||||
fbxpos = mat2 * fbxpos;
|
|
||||||
CoordType t(fbxpos[0],fbxpos[1],fbxpos[2]);
|
|
||||||
m.vert[ii + vertDispl].P() = t;
|
|
||||||
/*if (vcg::tri::HasPerVertexColor(m) && )*/
|
|
||||||
if (vcg::tri::HasPerVertexNormal(m) && (normalLayer) && (normalMapMode == KFbxLayerElement::eBY_CONTROL_POINT))
|
|
||||||
{
|
|
||||||
KFbxVector4 n;
|
|
||||||
int normInd = -1;
|
|
||||||
switch(normalLayer->GetReferenceMode())
|
|
||||||
{
|
|
||||||
case (KFbxLayerElement::eDIRECT):
|
|
||||||
{
|
|
||||||
normInd = ii;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case (KFbxLayerElement::eINDEX_TO_DIRECT):
|
|
||||||
{
|
|
||||||
normInd = normalLayer->GetIndexArray()[ii];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n = normalLayer->GetDirectArray()[normInd];
|
|
||||||
CoordType nn(n[0],n[1],n[2]);
|
|
||||||
nn = (matnorm * nn);
|
|
||||||
|
|
||||||
nn.Normalize();
|
|
||||||
//if (invert)
|
|
||||||
// nn = -nn;
|
|
||||||
m.vert[ii + vertDispl].N() = nn;
|
|
||||||
}
|
|
||||||
if (vcg::tri::HasPerVertexColor(m) && (colorLayer) && (colorMapMode == KFbxLayerElement::eBY_CONTROL_POINT))
|
|
||||||
{
|
|
||||||
KFbxColor c;
|
|
||||||
int colorInd = -1;
|
|
||||||
switch(colorLayer->GetReferenceMode())
|
|
||||||
{
|
|
||||||
case (KFbxLayerElement::eDIRECT):
|
|
||||||
{
|
|
||||||
colorInd = ii;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case (KFbxLayerElement::eINDEX_TO_DIRECT):
|
|
||||||
{
|
|
||||||
colorInd = colorLayer->GetIndexArray()[ii];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c = colorLayer->GetDirectArray()[colorInd];
|
|
||||||
vcg::Color4b vcgcol(c[0] * 255,c[1] * 255,c[2] * 255,c[3] * 255);
|
|
||||||
m.vert[ii + vertDispl].C() = vcgcol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int* index = newMesh->GetPolygonVertices();
|
|
||||||
bool allsame = false;
|
|
||||||
int matarrsize = -1;
|
|
||||||
if (matarr)
|
|
||||||
matarrsize = matarr->GetCount();
|
|
||||||
if (matarrsize == 1)
|
|
||||||
allsame = true;
|
|
||||||
|
|
||||||
for(int ii = 0;ii < currmeshface;++ii)
|
|
||||||
{
|
|
||||||
int diffusematind = -1;
|
|
||||||
int matptr = -1;
|
|
||||||
typename VCGMaterialBridge::MaterialInfo* mymat = NULL;
|
|
||||||
if (matAtlas.size() > 0)
|
|
||||||
{
|
|
||||||
if ((!allsame) && (matarrsize == currmeshface))
|
|
||||||
matptr = (*matarr)[ii];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (allsame)
|
|
||||||
{
|
|
||||||
matptr = (*matarr)[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((matptr >= 0) && (matptr < matAtlas.size()))
|
|
||||||
{
|
|
||||||
mymat = matAtlas[matptr].getMaterial(KFbxSurfaceMaterial::sDiffuse);
|
|
||||||
if (mymat && mymat->hasTexture())
|
|
||||||
diffusematind = mymat->getTextureIndex();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if (matptr == node->GetMaterialCount())
|
|
||||||
{
|
|
||||||
mymat = matAtlas[matptr-1].getMaterial(KFbxSurfaceMaterial::sDiffuse);
|
|
||||||
if (mymat && mymat->hasTexture())
|
|
||||||
diffusematind = mymat->getTextureIndex();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int jj = 0;jj < 3;++jj)
|
|
||||||
{
|
|
||||||
VertexIterator mov = m.vert.begin();
|
|
||||||
std::advance(mov,index[ii * 3 + jj] + vertDispl);
|
|
||||||
int invind = (3 - jj) % 3;
|
|
||||||
if (!invert)
|
|
||||||
m.face[ii + faceDispl].V(jj) = &(*mov);
|
|
||||||
else
|
|
||||||
m.face[ii + faceDispl].V(invind) = &(*mov);
|
|
||||||
if (vcg::tri::HasPerWedgeTexCoord(m) && (uvparcount > 0) && mymat && mymat->hasTexture())
|
|
||||||
{
|
|
||||||
int texind = -1;
|
|
||||||
KFbxLayerElement::EReferenceMode mapmode = newMesh->GetElementUV(0)->GetReferenceMode();
|
|
||||||
if (mapmode == KFbxLayerElement::eINDEX_TO_DIRECT)
|
|
||||||
texind = newMesh->GetTextureUVIndex(ii,jj);
|
|
||||||
else
|
|
||||||
if (mapmode == KFbxLayerElement::eDIRECT)
|
|
||||||
texind = ii * 3 + jj;
|
|
||||||
if (UVArr)
|
|
||||||
{
|
|
||||||
|
|
||||||
KFbxVector2 texcoord = UVArr->GetAt(texind);
|
|
||||||
if (!invert)
|
|
||||||
{
|
|
||||||
m.face[ii + faceDispl].WT(jj).U() = ScalarType(texcoord[0]);
|
|
||||||
m.face[ii + faceDispl].WT(jj).V() = ScalarType(texcoord[1]);
|
|
||||||
m.face[ii + faceDispl].WT(jj).N() = diffusematind;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m.face[ii + faceDispl].WT(invind).U() = ScalarType(texcoord[0]);
|
|
||||||
m.face[ii + faceDispl].WT(invind).V() = ScalarType(texcoord[1]);
|
|
||||||
m.face[ii + faceDispl].WT(invind).N() = diffusematind;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else
|
|
||||||
if (vcg::tri::HasPerVertexColor(m) && mymat && mymat->hasColor())
|
|
||||||
{
|
|
||||||
if (!invert)
|
|
||||||
m.face[ii + faceDispl].V(jj)->C() = mymat->getColor();
|
|
||||||
else
|
|
||||||
m.face[ii + faceDispl].V(invind)->C() = mymat->getColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (oi.cb)
|
|
||||||
{
|
|
||||||
char numstr[33];
|
|
||||||
sprintf(numstr,"%d",oi.numMeshPatches);
|
|
||||||
std::string st("Loading Vertices and Faces from ");
|
|
||||||
st = st + numstr + " submeshes";
|
|
||||||
oi.cb( (100*(m.vert.size() +m.face.size()))/ numFacPlusVert, st.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//std::string tx = m.textures[firstTexInd];
|
|
||||||
return E_NOERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void LoadMaskNode(KFbxNode* node, Info &oi)
|
|
||||||
{
|
|
||||||
if (node)
|
|
||||||
{
|
|
||||||
KFbxNodeAttribute* attr = node->GetNodeAttribute();
|
|
||||||
if (attr != NULL)
|
|
||||||
{
|
|
||||||
KFbxNodeAttribute::EAttributeType att = attr->GetAttributeType();
|
|
||||||
if (attr->GetAttributeType() == KFbxNodeAttribute::eMESH)
|
|
||||||
{
|
|
||||||
int matnum = node->GetSrcObjectCount(KFbxSurfaceMaterial::ClassId);
|
|
||||||
KFbxMesh* newMesh = node->GetMesh();
|
|
||||||
int uvparcount = newMesh->GetElementUVCount();
|
|
||||||
if (uvparcount > 0)
|
|
||||||
oi.mask |= vcg::tri::io::Mask::IOM_WEDGTEXCOORD;
|
|
||||||
|
|
||||||
KFbxLayer* lcolo = newMesh->GetLayer(0,KFbxLayerElement::eVERTEX_COLOR);
|
|
||||||
if (matnum || lcolo)
|
|
||||||
oi.mask |= vcg::tri::io::Mask::IOM_VERTCOLOR;
|
|
||||||
KFbxLayer* lnorm = newMesh->GetLayer(0,KFbxLayerElement::eNORMAL);
|
|
||||||
KFbxLayerElementNormal* nnom = lnorm->GetNormals();
|
|
||||||
if (lnorm)
|
|
||||||
oi.mask |= vcg::tri::io::Mask::IOM_VERTNORMAL;
|
|
||||||
oi.numVertices = oi.numVertices + newMesh->GetControlPointsCount();
|
|
||||||
if (!newMesh->IsTriangleMesh())
|
|
||||||
{
|
|
||||||
KFbxGeometryConverter* conv = new KFbxGeometryConverter(newMesh->GetFbxSdkManager());
|
|
||||||
newMesh = conv->TriangulateMesh(newMesh);
|
|
||||||
}
|
|
||||||
oi.numFaces = oi.numFaces + newMesh->GetPolygonCount();
|
|
||||||
oi.numMeshPatches += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(int ii = 0;ii < node->GetChildCount();++ii)
|
|
||||||
LoadMaskNode(node->GetChild(ii),oi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static KFbxXMatrix getGlobalMatrix(KFbxNode* pNode, const KTime& pTime, KFbxPose* pPose, KFbxXMatrix* pParentGlobalPosition = NULL)
|
|
||||||
{
|
|
||||||
KFbxXMatrix lGlobalPosition;
|
|
||||||
bool lPositionFound = false;
|
|
||||||
|
|
||||||
if (pPose)
|
|
||||||
{
|
|
||||||
int lNodeIndex = pPose->Find(pNode);
|
|
||||||
|
|
||||||
if (lNodeIndex > -1)
|
|
||||||
{
|
|
||||||
if (pPose->IsBindPose() || !pPose->IsLocalMatrix(lNodeIndex))
|
|
||||||
{
|
|
||||||
lGlobalPosition = GetPoseMatrix(pPose, lNodeIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
KFbxXMatrix lParentGlobalPosition;
|
|
||||||
|
|
||||||
if (pParentGlobalPosition)
|
|
||||||
{
|
|
||||||
lParentGlobalPosition = *pParentGlobalPosition;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pNode->GetParent())
|
|
||||||
{
|
|
||||||
lParentGlobalPosition = getGlobalMatrix(pNode->GetParent(), pTime, pPose);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
KFbxXMatrix lLocalPosition = GetPoseMatrix(pPose, lNodeIndex);
|
|
||||||
lGlobalPosition = lParentGlobalPosition * lLocalPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
lPositionFound = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lPositionFound)
|
|
||||||
{
|
|
||||||
lGlobalPosition = pNode->EvaluateGlobalTransform(pTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lGlobalPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
static KFbxXMatrix GetPoseMatrix(KFbxPose* pPose, int pNodeIndex)
|
|
||||||
{
|
|
||||||
KFbxXMatrix lPoseMatrix;
|
|
||||||
KFbxMatrix lMatrix = pPose->GetMatrix(pNodeIndex);
|
|
||||||
|
|
||||||
memcpy((double*)lPoseMatrix, (double*)lMatrix, sizeof(lMatrix.mData));
|
|
||||||
|
|
||||||
return lPoseMatrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
static KFbxXMatrix GetGeometry(KFbxNode* pNode)
|
|
||||||
{
|
|
||||||
const KFbxVector4 lT = pNode->GetGeometricTranslation(KFbxNode::eSOURCE_SET);
|
|
||||||
const KFbxVector4 lR = pNode->GetGeometricRotation(KFbxNode::eSOURCE_SET);
|
|
||||||
const KFbxVector4 lS = pNode->GetGeometricScaling(KFbxNode::eSOURCE_SET);
|
|
||||||
|
|
||||||
return KFbxXMatrix(lT, lR, lS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*****
|
/*****
|
||||||
|
@ -538,12 +75,6 @@ public:
|
||||||
E_NOERROR = 0,
|
E_NOERROR = 0,
|
||||||
|
|
||||||
// Critical Opening Errors (only even numbers)
|
// Critical Opening Errors (only even numbers)
|
||||||
E_CANTCREATEFBXMANAGER = 1,
|
|
||||||
E_CANTCREATEFBXSCENE = 2,
|
|
||||||
E_CANTCREATEFBXIMPORTER = 3,
|
|
||||||
E_CANTFINDFILE = 4,
|
|
||||||
E_CANTFINDFBXFILE = 5,
|
|
||||||
E_CANTIMPORTFBXFILE = 6
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/****
|
/****
|
||||||
|
@ -564,19 +95,13 @@ public:
|
||||||
static const char* fbx_error_msg[] =
|
static const char* fbx_error_msg[] =
|
||||||
{
|
{
|
||||||
"No errors",
|
"No errors",
|
||||||
|
|
||||||
"Failed to create a KFbxSdkManager",
|
|
||||||
"Failed to create a KFbxScene",
|
|
||||||
"Failed to create a KFbxImporter",
|
|
||||||
"Failed to locate requested file",
|
|
||||||
"Failed to import requested file",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if(error>6 || error<0)
|
if(error>1 || error<0)
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
else
|
else
|
||||||
return fbx_error_msg[error];
|
return fbx_error_msg[error];
|
||||||
};
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
The open function import info contained in a FBX file into a mesh defined using the VCG standards.
|
The open function import info contained in a FBX file into a mesh defined using the VCG standards.
|
||||||
|
@ -599,41 +124,103 @@ public:
|
||||||
Please note that if the file is composed by a set of meshes we compact all these meshes in a single one.
|
Please note that if the file is composed by a set of meshes we compact all these meshes in a single one.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int Open( OpenMeshType &m, const char * filename, Info &oi)
|
static int Open( OpenMeshType &m, const char * filename, CallBackPos *cb = nullptr)
|
||||||
{
|
{
|
||||||
int result = E_NOERROR;
|
|
||||||
|
FILE* fp = fopen(filename, "rb");
|
||||||
|
if (!fp) return false;
|
||||||
|
|
||||||
|
fseek(fp, 0, SEEK_END);
|
||||||
|
long file_size = ftell(fp);
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
ofbx::u8* content = new ofbx::u8[file_size];
|
||||||
|
fread(content, 1, size_t(file_size), fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
ofbx::IScene* scene =ofbx::load(content, int(file_size));
|
||||||
|
|
||||||
m.Clear();
|
m.Clear();
|
||||||
vcg::CallBackPos *cb = oi.cb;
|
int mesh_count = scene->getMeshCount();
|
||||||
|
printf("mesh count %i\n",mesh_count);
|
||||||
|
int totVert=0;
|
||||||
|
for (int i = 0; i < mesh_count; ++i)
|
||||||
|
totVert += scene->getMesh(i)->getGeometry()->getVertexCount();
|
||||||
|
|
||||||
KFbxSdkManager* FBXmanager = KFbxSdkManager::Create();
|
int baseVertexCount;
|
||||||
if (FBXmanager==NULL)
|
printf("Scene has %i meshes\n",mesh_count);
|
||||||
return E_CANTCREATEFBXMANAGER;
|
for (int i = 0; i < mesh_count; ++i)
|
||||||
KFbxScene* FBXscene = KFbxScene::Create(FBXmanager,"");
|
|
||||||
if (FBXscene==NULL)
|
|
||||||
return E_CANTCREATEFBXSCENE;
|
|
||||||
KFbxImporter* importer = KFbxImporter::Create(FBXmanager,"");
|
|
||||||
if (importer==NULL)
|
|
||||||
return E_CANTCREATEFBXIMPORTER;
|
|
||||||
|
|
||||||
bool initfile = importer->Initialize(filename);
|
|
||||||
if (!initfile)
|
|
||||||
{
|
{
|
||||||
printf("Fbx error: %s",importer->GetLastErrorString());
|
baseVertexCount=m.vert.size();
|
||||||
return E_CANTFINDFBXFILE;
|
const ofbx::Mesh& mesh = *scene->getMesh(i);
|
||||||
|
const ofbx::Geometry& geom = *mesh.getGeometry();
|
||||||
|
int materialId = *geom.getMaterials();
|
||||||
|
const ofbx::Material *mat = mesh.getMaterial(materialId);
|
||||||
|
assert(mat);
|
||||||
|
const ofbx::Texture *tex = mat->getTexture(ofbx::Texture::DIFFUSE);
|
||||||
|
char buf[128];
|
||||||
|
int curTexId = m.textures.size();
|
||||||
|
if(tex){
|
||||||
|
tex->getRelativeFileName().toString(buf);
|
||||||
|
printf("Texture %s ",buf);
|
||||||
|
m.textures.push_back(buf);
|
||||||
}
|
}
|
||||||
bool importfile = importer->Import(FBXscene);
|
else printf ("mesh %i has no texture\n",i);
|
||||||
if (!importfile)
|
|
||||||
|
Matrix44d globTransfd(mesh.getGlobalTransform().m);
|
||||||
|
Matrix44f globTransf;
|
||||||
|
globTransf.SetIdentity();
|
||||||
|
globTransf.Import(globTransfd);
|
||||||
|
Transpose(globTransf);
|
||||||
|
int vertex_count = geom.getVertexCount();
|
||||||
|
const ofbx::Vec3* vertices = geom.getVertices();
|
||||||
|
const ofbx::Vec2* texcoords = geom.getUVs();
|
||||||
|
printf(" Mesh %i has %i vertices\n",i,vertex_count);
|
||||||
|
|
||||||
|
for (int j = 0; j < vertex_count; ++j)
|
||||||
{
|
{
|
||||||
printf("Fbx error: %s",importer->GetLastErrorString());
|
ofbx::Vec3 vt = vertices[j];
|
||||||
return E_CANTIMPORTFBXFILE;
|
CoordType v = globTransf*CoordType(vt.x, vt.y, vt.z);
|
||||||
|
tri::Allocator<OpenMeshType>::AddVertex(m,v);
|
||||||
|
if(cb && (m.vert.size()%1000) == 0 ) cb(m.vert.size() * 100 / totVert, "Vertex Loading");
|
||||||
}
|
}
|
||||||
result = ImportScene(m,FBXscene,oi);
|
|
||||||
|
|
||||||
// if LoadMask has not been called yet, we call it here
|
// bool has_normals = geom.getNormals() != nullptr;
|
||||||
|
bool has_uvs = texcoords != nullptr;
|
||||||
|
|
||||||
|
const ofbx::Skin* skin = geom.getSkin();
|
||||||
|
if(!skin)
|
||||||
|
{
|
||||||
|
printf("Geom has no skin\n");
|
||||||
|
for (int j = 0; j < vertex_count/3; ++j)
|
||||||
|
{int curTriBase = baseVertexCount + j*3;
|
||||||
|
tri::Allocator<OpenMeshType>::AddFace(m,curTriBase,curTriBase+1,curTriBase+2);
|
||||||
|
if(has_uvs)
|
||||||
|
{
|
||||||
|
for(int k=0;k<3;++k)
|
||||||
|
{
|
||||||
|
m.face.back().WT(k).u() = texcoords[j*3+k].x;
|
||||||
|
m.face.back().WT(k).v() = texcoords[j*3+k].y;
|
||||||
|
m.face.back().WT(k).n() = curTexId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int cluster_count = skin->getClusterCount();
|
||||||
|
|
||||||
|
printf("Mesh %i has %i clusters\n",i,cluster_count);
|
||||||
|
for (int k = 0; k < cluster_count; ++k)
|
||||||
|
{
|
||||||
|
// const ofbx::Cluster *cluster=skin->getCluster(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tri::Clean<OpenMeshType>::RemoveDuplicateVertex(m);
|
||||||
|
tri::Allocator<OpenMeshType>::CompactEveryVector(m);
|
||||||
|
return E_NOERROR;
|
||||||
|
|
||||||
if (FBXmanager)
|
|
||||||
FBXmanager->Destroy();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****
|
/****
|
||||||
|
@ -647,40 +234,15 @@ public:
|
||||||
( for example if I want to check if the file contains the vertex normal layer I have to call the LoadMask function and after check if (oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL) is true).
|
( for example if I want to check if the file contains the vertex normal layer I have to call the LoadMask function and after check if (oi.mask & vcg::tri::io::Mask::IOM_VERTNORMAL) is true).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int LoadMask(const char * filename, Info &oi)
|
static int LoadMask(const char * /*filename*/)
|
||||||
{
|
{
|
||||||
KFbxSdkManager* FBXmanager = KFbxSdkManager::Create();
|
return tri::io::Mask::IOM_WEDGTEXCOORD;
|
||||||
if (FBXmanager==NULL)
|
|
||||||
return E_CANTCREATEFBXMANAGER;
|
|
||||||
KFbxScene* FBXscene = KFbxScene::Create(FBXmanager,"");
|
|
||||||
if (FBXscene==NULL)
|
|
||||||
return E_CANTCREATEFBXSCENE;
|
|
||||||
KFbxImporter* importer = KFbxImporter::Create(FBXmanager,"");
|
|
||||||
if (importer==NULL)
|
|
||||||
return E_CANTCREATEFBXIMPORTER;
|
|
||||||
|
|
||||||
bool initfile = importer->Initialize(filename);
|
|
||||||
if (!initfile)
|
|
||||||
{
|
|
||||||
printf("Fbx error: %s",importer->GetLastErrorString());
|
|
||||||
return E_CANTFINDFBXFILE;
|
|
||||||
}
|
|
||||||
bool importfile = importer->Import(FBXscene);
|
|
||||||
if (!importfile)
|
|
||||||
{
|
|
||||||
printf("Fbx error: %s",importer->GetLastErrorString());
|
|
||||||
return E_CANTIMPORTFBXFILE;
|
|
||||||
}
|
|
||||||
LoadMaskNode(FBXscene->GetRootNode(),oi);
|
|
||||||
|
|
||||||
// if LoadMask has not been called yet, we call it here
|
|
||||||
|
|
||||||
if (FBXmanager)
|
|
||||||
FBXmanager->Destroy();
|
|
||||||
return E_NOERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // end class
|
}; // end class
|
||||||
|
} // end namespace tri
|
||||||
|
} // end namespace io
|
||||||
|
} // end namespace vcg
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue