📄 vrml2mesh.cpp
字号:
#include "stdafx.h"
struct vertex {
int pos, tc, normal, colour;
bool operator<(const vertex &v) const {
if (pos < v.pos) return true;
if (pos > v.pos) return false;
if (normal < v.normal) return true;
if (normal > v.normal) return false;
if (tc < v.tc) return true;
if (tc > v.tc) return false;
return colour < v.colour;
}
};
// VRML face
struct face {
std::vector<int> indices;
};
// OGRE face
struct triangle {
int vertices[3];
};
typedef std::vector<Vector3> Vec3Vec;
typedef std::vector<vertex> VertVec;
typedef std::vector<face> FaceVec;
typedef std::vector<triangle> TriVec;
typedef std::vector<int> IntVec;
typedef std::map<vertex, int> VertMap;
// traverse the scene graph looking for Shapes
void parseFile(Mesh *, const vrmllib::file &);
void parseNode(Mesh *, const vrmllib::node *, Matrix4 = Matrix4::IDENTITY);
// generate a SubMesh from a Shape
void parseShape(Mesh *, const Shape *, Matrix4);
// helpers:
Ogre::Material *parseMaterial(const Appearance *, const String &name);
void parseFaces(FaceVec &, const IndexedFaceSet *);
void triangulateAndExpand(TriVec &, VertVec &, const FaceVec &, const Shape *);
void copyToSubMesh(SubMesh *, const TriVec &, const VertVec &, const Shape *, const Matrix4 &);
// get the array index for a VRML vertex property
int getIndex(const IntVec &coordIndex, const IntVec &, bool perVertex, int facenr, int vertnr);
// used by findName*
typedef std::map<const vrmllib::node *, String> NameMap;
NameMap gNameMap;
// find name of DEFined node
const String *findName(const vrmllib::node *n);
const String *findNameRecursive(const vrmllib::node *n);
String gBaseName; // base name of the input file (no path or extension)
// conversion functions:
inline Vector3 vec(const vrmllib::vec3 &v) { return Vector3(v.x, v.y, v.z); }
inline ColourValue col(const vrmllib::col3 &c) { return ColourValue(c.r, c.g, c.b); }
inline void copyVec(Real *d, const Vector3 &s) { d[0] = s.x; d[1] = s.y; d[2] = s.z; }
inline void copyVec(Real *d, const vec2 &s) { d[0] = s.x; d[1] = s.y; }
Matrix4 transMat(vrmllib::vec3, bool inverse = false);
Matrix4 scaleMat(vrmllib::vec3, bool inverse = false);
Matrix4 rotMat(vrmllib::rot, bool inverse = false);
int main(int argc, char **argv)
{
try
{
String inname, outname, path;
if (argc != 2 && argc != 3)
throw
"Wrong number of arguments.\n"
" Usage: VRML2mesh <input vrml file> [output mesh file]";
inname = argv[1];
// get base name
gBaseName = inname;
size_t p = gBaseName.find_last_of("/\\");
if (p != gBaseName.npos) {
path.assign(gBaseName, 0, p+1);
gBaseName.erase(0, p+1);
}
p = gBaseName.rfind('.');
if (p != gBaseName.npos)
gBaseName.erase(p);
if (argc == 3)
outname = argv[2];
else
outname = path + gBaseName + ".mesh";
LogManager log;
log.createLog(path + "VRML2mesh.log");
Math math;
MaterialManager materialMgr;
MeshSerializer meshSer;
Mesh mesh("conversionTarget");
try {
log.logMessage("Reading " + inname);
// read VRML file
std::ifstream infile(inname.c_str());
if (!infile.is_open())
throw "failed to open input file";
vrmllib::file vfile(infile);
log.logMessage("Finished parsing VRML file");
// populate name map
for (vrmllib::file::defs_t::iterator i=vfile.defs.begin(), e=vfile.defs.end(); i!=e; ++i)
gNameMap[i->second] = i->first;
// search from SubMeshes
parseFile(&mesh, vfile);
if (mesh.getNumSubMeshes() == 0)
throw "No SubMeshes were generated, aborting.";
log.logMessage("Exporting Mesh");
meshSer.exportMesh(&mesh, outname, true);
log.logMessage("Done.");
}
catch (const char *e) {
log.logMessage(LML_NORMAL, "Error: %s", e);
return 1;
}
catch (std::exception &e) {
log.logMessage(LML_NORMAL, "Exception: %s", e.what());
return 1;
}
catch (Exception &e) {
log.logMessage("Exception: " + e.getFullDescription());
return 1;
}
}
catch (Exception &e) {
std::cerr << "Exception: " << e.getFullDescription() << std::endl;
return 1;
}
catch (const char *e) {
std::cerr << e << std::endl;
return 1;
}
}
void parseFile(Mesh *mesh, const vrmllib::file &file)
{
for (vrmllib::file::roots_t::const_iterator i=file.roots.begin(), e=file.roots.end(); i!=e; ++i)
parseNode(mesh, *i);
}
void parseNode(Mesh *mesh, const vrmllib::node *n, Matrix4 m)
{
if (const Transform *tr = dynamic_cast<const Transform *>(n)) {
// TODO: handle center, scaleOrientation
Matrix4 trans;
trans.makeTrans(vec(tr->translation));
Matrix4 scale = Matrix4::IDENTITY;
scale[0][0] = tr->scale.x;
scale[1][1] = tr->scale.y;
scale[2][2] = tr->scale.z;
Matrix3 rot3;
rot3.FromAxisAngle(vec(tr->rotation.vector), tr->rotation.radians);
Matrix4 rot = Matrix4::IDENTITY;
rot = rot3;
m = m * transMat(tr->translation) * transMat(tr->center)
* rotMat(tr->rotation) * rotMat(tr->scaleOrientation) * scaleMat(tr->scale)
* rotMat(tr->scaleOrientation, true) * transMat(tr->center, true);
}
if (const grouping_node *gn = dynamic_cast<const grouping_node *>(n)) {
for (std::vector<vrmllib::node *>::const_iterator
i=gn->children.begin(), e=gn->children.end(); i!=e; ++i)
parseNode(mesh, *i, m);
} else if (const Shape *sh = dynamic_cast<const Shape *>(n))
parseShape(mesh, sh, m);
}
void parseShape(Mesh *mesh, const Shape *sh, Matrix4 mat)
{
try
{
LogManager &log = LogManager::getSingleton();
log.logMessage("Found a Shape...");
IndexedFaceSet *ifs = dynamic_cast<IndexedFaceSet *>(sh->geometry);
if (!ifs)
throw "Geometry was not an IndexedFaceSet, keep looking";
Coordinate *coord = dynamic_cast<Coordinate *>(ifs->coord);
if (!coord)
throw "Invalid Coordinate node";
if (coord->point.empty())
throw "No coordinates found, ignoring this Shape";
SubMesh *sub;
if (const String *name = findNameRecursive(sh)) {
log.logMessage("Creating SubMesh: " + *name);
sub = mesh->createSubMesh(*name);
} else {
log.logMessage("Creating unnamed SubMesh");
sub = mesh->createSubMesh();
}
Appearance *app = dynamic_cast<Appearance *>(sh->appearance);
TextureCoordinate *tcs = dynamic_cast<TextureCoordinate *>(ifs->texCoord);
Normal *norm = dynamic_cast<Normal *>(ifs->normal);
Color *color = dynamic_cast<Color *>(ifs->color);
String message = "Found: geometry";
if (tcs)
message += ", texcoords";
if (norm)
message += ", normals";
if (color)
message += ", colours";
log.logMessage(message);
if (!tcs && !norm && !color)
log.logMessage("Warning: OGRE will refuse to render SubMeshes that have neither\n"
"\ttexture coordinates, normals or vertex colours.");
if (!norm) {
log.logMessage("Warning: No normals found.\n"
"\tVRML dictates that normals should be generated, but this program\n"
"\tdoes not do so. If you want the resulting mesh to contain normals,\n"
"\tmake sure they are exported.");
}
// process material
static std::map<Appearance *, Ogre::Material *> matMap;
Ogre::Material *&material = matMap[app];
if (material && app) {
log.logMessage("Using material " + material->getName());
sub->setMaterialName(material->getName());
} else {
String matName;
const String *mn;
if (mn = findName(app))
matName = *mn;
else if (app && (mn = findName(app->material))) {
static std::map<String, int> postfix;
std::stringstream ss;
int &num = postfix[*mn];
ss << *mn << '/' << num++;
matName = ss.str();
} else {
static int matNum;
std::stringstream ss;
ss << gBaseName << '/' << matNum++;
matName = ss.str();
log.logMessage("No material name found, using " + matName);
}
log.logMessage("Reading material " + matName);
material = parseMaterial(app, matName);
sub->setMaterialName(matName);
}
FaceVec faces;
parseFaces(faces, ifs);
VertVec vertices;
TriVec triangles;
log.logMessage("Processing geometry...");
triangulateAndExpand(triangles, vertices, faces, sh);
copyToSubMesh(sub, triangles, vertices, sh, mat);
log.logMessage("Done with this SubMesh.");
}
catch (const char *e) {
LogManager::getSingleton().logMessage(e);
}
}
void copyToSubMesh(SubMesh *sub, const TriVec &triangles, const VertVec &vertices,
const Shape *sh, const Matrix4 &mat)
{
IndexedFaceSet *ifs = dynamic_cast<IndexedFaceSet *>(sh->geometry);
Coordinate *coord = dynamic_cast<Coordinate *>(ifs->coord);
TextureCoordinate *tcs = dynamic_cast<TextureCoordinate *>(ifs->texCoord);
Normal *norm = dynamic_cast<Normal *>(ifs->normal);
Color *color = dynamic_cast<Color *>(ifs->color);
int nvertices = vertices.size();
int nfaces = triangles.size();
GeometryData &geom = sub->geometry;
sub->useSharedVertices = false;
sub->numFaces = nfaces;
sub->faceVertexIndices = new unsigned short[nfaces*3];
geom.hasColours = color;
geom.hasNormals = norm;
geom.numTexCoords = tcs ? 1 : 0;
geom.numTexCoordDimensions[0] = 2;
geom.numVertices = nvertices;
geom.pVertices = new Real[nvertices*3];
if (tcs)
geom.pTexCoords[0] = new Real[nvertices*2];
if (norm)
geom.pNormals = new Real[nvertices*3];
if (color)
geom.pColours = new unsigned long[nvertices];
Matrix3 normMat;
mat.extract3x3Matrix(normMat);
normMat = normMat.Inverse().Transpose();
// populate face list
for (int i=0; i!=nfaces; ++i) {
unsigned short *f = sub->faceVertexIndices + i*3;
f[0] = triangles[i].vertices[0];
f[1] = triangles[i].vertices[1];
f[2] = triangles[i].vertices[2];
}
// populate vertex arrays
for (int i=0; i!=nvertices; ++i) {
const vertex &v = vertices[i];
Real *pos = geom.pVertices + i*3;
Real *tc = geom.pTexCoords[0] + i*2;
Real *n = geom.pNormals + i*3;
unsigned long *col = geom.pColours + i;
copyVec(pos, mat * vec(coord->point[v.pos]));
if (norm) {
Vector3 t = normMat * vec(norm->vector[v.normal]);
t.normalise();
copyVec(n, t);
}
if (tcs)
copyVec(tc, tcs->point[v.tc]);
if (color) {
col3 c = color->color[v.colour];
ColourValue cv(c.r, c.g, c.b);
*col = cv.getAsLongRGBA();
}
}
}
void triangulateAndExpand(TriVec &triangles, VertVec &vertices, const FaceVec &faces, const Shape *sh)
{
IndexedFaceSet *ifs = dynamic_cast<IndexedFaceSet *>(sh->geometry);
Coordinate *coord = dynamic_cast<Coordinate *>(ifs->coord);
TextureCoordinate *tcs = dynamic_cast<TextureCoordinate *>(ifs->texCoord);
Normal *norm = dynamic_cast<Normal *>(ifs->normal);
Color *color = dynamic_cast<Color *>(ifs->color);
VertMap vertexMap;
// triangulate and expand vertices
for (FaceVec::const_iterator f=faces.begin(), e=faces.end(); f!=e; ++f) {
int faceNr = f - faces.begin();
int triVertNr = 0;
int triVerts[2] = { -1, -1 };
for (IntVec::const_iterator i = f->indices.begin(), e=f->indices.end(); i!=e; ++i, ++triVertNr) {
int triVertNr = i - f->indices.begin();
int index = *i;
vertex vert;
// get full indices for vertex data
vert.pos = ifs->coordIndex[index];
vert.normal = norm ? getIndex(ifs->coordIndex, ifs->normalIndex,
ifs->normalPerVertex, faceNr, index) : 0;
vert.colour = color ? getIndex(ifs->coordIndex, ifs->colorIndex,
ifs->colorPerVertex, faceNr, index) : 0;
vert.tc = tcs ? getIndex(ifs->coordIndex, ifs->texCoordIndex,
true, faceNr, index) : 0;
// avoid duplication
int nvert = vertexMap.size();
int &vpos = vertexMap[vert];
if (nvert != vertexMap.size()) {
vpos = vertices.size();
vertices.push_back(vert);
}
// emit triangle (maybe)
if (triVertNr == 0)
triVerts[0] = vpos;
else if (triVertNr == 1)
triVerts[1] = vpos;
else {
triangle t;
t.vertices[0] = triVerts[0];
t.vertices[1] = triVerts[1];
t.vertices[2] = vpos;
if (!ifs->ccw)
std::swap(t.vertices[1], t.vertices[2]);
triangles.push_back(t);
triVerts[1] = vpos;
}
}
}
}
int getIndex(const IntVec &coordIndex, const IntVec &vec, bool perVertex, int facenr, int index)
{
if (!perVertex) {
if (!vec.empty())
return vec[facenr];
else
return facenr;
} else {
if (!vec.empty())
return vec[index];
else
return coordIndex[index];
}
}
const String *findName(const vrmllib::node *n)
{
NameMap::const_iterator i = gNameMap.find(n);
if (i == gNameMap.end())
return 0;
else
return &i->second;
}
const String *findNameRecursive(const vrmllib::node *n)
{
if (const String *name = findName(n))
return name;
else if (n->parent)
return findNameRecursive(n->parent);
else
return 0;
}
void parseFaces(FaceVec &faces, const IndexedFaceSet *ifs)
{
face f;
for (IntVec::const_iterator i=ifs->coordIndex.begin(), e=ifs->coordIndex.end(); i!=e; ++i) {
if (*i == -1) {
faces.resize(faces.size()+1);
faces.back().indices.swap(f.indices);
} else
f.indices.push_back(i - ifs->coordIndex.begin());
}
if (!f.indices.empty()) {
faces.resize(faces.size()+1);
faces.back().indices.swap(f.indices);
}
}
Ogre::Material *parseMaterial(const Appearance *app, const String &name)
{
vrmllib::Material *vm = app ? dynamic_cast<vrmllib::Material *>(app->material) : 0;
vrmllib::ImageTexture *texture = app ? dynamic_cast<vrmllib::ImageTexture *>(app->texture) : 0;
Ogre::Material *m = MaterialManager::getSingleton().createDeferred(name);
ColourValue diffuse = texture ? ColourValue::White : col(vm->diffuseColor);
// diffuse colour is unused by VRML when a texture is avaliable,
// set to white to give the same effect in OGRE
ColourValue a = diffuse;
a.r *= vm->ambientIntensity;
a.g *= vm->ambientIntensity;
a.b *= vm->ambientIntensity;
m->setAmbient(a);
m->setDiffuse(diffuse);
m->setSelfIllumination(col(vm->emissiveColor));
m->setShininess(vm->shininess);
m->setSpecular(col(vm->specularColor));
m->setLightingEnabled(app);
if (texture && !texture->url.empty()) {
String texName = texture->url.front();
size_t p = texName.find_last_of("/\\");
if (p != texName.npos) {
LogManager::getSingleton().logMessage("Stripping path from texture " + texName);
texName.erase(0, p+1);
}
LogManager::getSingleton().logMessage("Adding texture layer for " + texName);
Ogre::TextureUnitState *l = m->addTextureLayer(texName);
l->setTextureAddressingMode(texture->repeatS ?
Ogre::TextureUnitState::TAM_WRAP : Ogre::TextureUnitState::TAM_CLAMP);
}
return m;
}
Matrix4 transMat(vrmllib::vec3 v, bool inverse)
{
if (inverse)
return Matrix4::getTrans(-v.x, -v.y, -v.z);
else
return Matrix4::getTrans(v.x, v.y, v.z);
}
Matrix4 scaleMat(vrmllib::vec3 v, bool inverse)
{
if (inverse)
return Matrix4::getScale(1/v.x, 1/v.y, 1/v.z);
else
return Matrix4::getScale(v.x, v.y, v.z);
}
Matrix4 rotMat(vrmllib::rot r, bool inverse)
{
Matrix3 rot3;
rot3.FromAxisAngle(vec(r.vector), inverse ? -r.radians : r.radians);
Matrix4 rot = Matrix4::IDENTITY;
rot = rot3;
return rot;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -