Wavefront OBJ: export mesh color as well.

This commit is contained in:
EvilSpirit 2016-07-04 12:02:30 +06:00 committed by whitequark
parent aa958504af
commit f4e85127d6
4 changed files with 59 additions and 24 deletions

View File

@ -7,6 +7,8 @@ Changelog
New export/import features: New export/import features:
* Three.js: allow configuring projection for exported model, and initially * Three.js: allow configuring projection for exported model, and initially
use the current viewport projection. use the current viewport projection.
* Wavefront OBJ: a material file is exported alongside the model, containing
mesh color information.
New rendering features: New rendering features:
* The "Show/hide hidden lines" button is now a tri-state button that allows * The "Show/hide hidden lines" button is now a tri-state button that allows

View File

@ -532,7 +532,12 @@ public:
(int)((bgra) & 0xff), (int)((bgra) & 0xff),
(int)(255 - ((bgra >> 24) & 0xff))); (int)(255 - ((bgra >> 24) & 0xff)));
} }
};
struct RgbaColorCompare {
bool operator()(RgbaColor a, RgbaColor b) const {
return a.ToARGB32() < b.ToARGB32();
}
}; };
class BBox { class BBox {

View File

@ -816,7 +816,18 @@ void SolveSpaceUI::ExportMeshTo(const std::string &filename) {
if(FilenameHasExtension(filename, ".stl")) { if(FilenameHasExtension(filename, ".stl")) {
ExportMeshAsStlTo(f, m); ExportMeshAsStlTo(f, m);
} else if(FilenameHasExtension(filename, ".obj")) { } else if(FilenameHasExtension(filename, ".obj")) {
ExportMeshAsObjTo(f, m); std::string mtlFilename = filename.substr(0, filename.length() - 4) + ".mtl";
FILE *fMtl = ssfopen(mtlFilename, "wb");
if(!fMtl) {
Error("Couldn't write to '%s'", filename.c_str());
return;
}
std::string mtlBasename = mtlFilename.substr(mtlFilename.rfind(PATH_SEP) + 1);
fprintf(f, "mtllib %s\n", mtlBasename.c_str());
ExportMeshAsObjTo(f, fMtl, m);
fclose(fMtl);
} else if(FilenameHasExtension(filename, ".js") || } else if(FilenameHasExtension(filename, ".js") ||
FilenameHasExtension(filename, ".html")) { FilenameHasExtension(filename, ".html")) {
SOutlineList *e = &(SK.GetGroup(SS.GW.activeGroup)->displayOutlines); SOutlineList *e = &(SK.GetGroup(SS.GW.activeGroup)->displayOutlines);
@ -872,34 +883,51 @@ void SolveSpaceUI::ExportMeshAsStlTo(FILE *f, SMesh *sm) {
// Export the mesh as Wavefront OBJ format. This requires us to reduce all the // Export the mesh as Wavefront OBJ format. This requires us to reduce all the
// identical vertices to the same identifier, so do that first. // identical vertices to the same identifier, so do that first.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void SolveSpaceUI::ExportMeshAsObjTo(FILE *f, SMesh *sm) { void SolveSpaceUI::ExportMeshAsObjTo(FILE *fObj, FILE *fMtl, SMesh *sm) {
SPointList spl = {}; std::map<RgbaColor, std::string, RgbaColorCompare> colors;
STriangle *tr; for(const STriangle &t : sm->l) {
for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) { RgbaColor color = t.meta.color;
spl.IncrementTagFor(tr->a); if(colors.find(color) == colors.end()) {
spl.IncrementTagFor(tr->b); std::string id = ssprintf("h%02x%02x%02x",
spl.IncrementTagFor(tr->c); color.red,
color.green,
color.blue);
colors.emplace(color, id);
}
for(int i = 0; i < 3; i++) {
fprintf(fObj, "v %.10f %.10f %.10f\n",
CO(t.vertices[i].ScaledBy(1 / SS.exportScale)));
}
} }
// Output all the vertices. for(auto &it : colors) {
SPoint *sp; fprintf(fMtl, "newmtl %s\n",
for(sp = spl.l.First(); sp; sp = spl.l.NextAfter(sp)) { it.second.c_str());
fprintf(f, "v %.10f %.10f %.10f\r\n", fprintf(fMtl, "Kd %.3f %.3f %.3f\n",
sp->p.x / SS.exportScale, it.first.redF(), it.first.greenF(), it.first.blueF());
sp->p.y / SS.exportScale,
sp->p.z / SS.exportScale);
} }
// And now all the triangular faces, in terms of those vertices. The for(const STriangle &t : sm->l) {
// file format counts from 1, not 0. for(int i = 0; i < 3; i++) {
for(tr = sm->l.First(); tr; tr = sm->l.NextAfter(tr)) { Vector n = t.normals[i].WithMagnitude(1.0);
fprintf(f, "f %d %d %d\r\n", fprintf(fObj, "vn %.10f %.10f %.10f\n",
spl.IndexForPoint(tr->a) + 1, CO(n));
spl.IndexForPoint(tr->b) + 1, }
spl.IndexForPoint(tr->c) + 1);
} }
spl.Clear(); RgbaColor currentColor = {};
for(int i = 0; i < sm->l.n; i++) {
const STriangle &t = sm->l.elem[i];
if(!currentColor.Equals(t.meta.color)) {
currentColor = t.meta.color;
fprintf(fObj, "usemtl %s\n", colors[currentColor].c_str());
}
fprintf(fObj, "f %d//%d %d//%d %d//%d\n",
i * 3 + 1, i * 3 + 1,
i * 3 + 2, i * 3 + 2,
i * 3 + 3, i * 3 + 3);
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -815,7 +815,7 @@ public:
void ExportAsPngTo(const std::string &filename); void ExportAsPngTo(const std::string &filename);
void ExportMeshTo(const std::string &filename); void ExportMeshTo(const std::string &filename);
void ExportMeshAsStlTo(FILE *f, SMesh *sm); void ExportMeshAsStlTo(FILE *f, SMesh *sm);
void ExportMeshAsObjTo(FILE *f, SMesh *sm); void ExportMeshAsObjTo(FILE *fObj, FILE *fMtl, SMesh *sm);
void ExportMeshAsThreeJsTo(FILE *f, const std::string &filename, void ExportMeshAsThreeJsTo(FILE *f, const std::string &filename,
SMesh *sm, SOutlineList *sol); SMesh *sm, SOutlineList *sol);
void ExportViewOrWireframeTo(const std::string &filename, bool exportWireframe); void ExportViewOrWireframeTo(const std::string &filename, bool exportWireframe);