Parse ior and transmittance of material parameter.
Add .obj sticher example.
This commit is contained in:
82
examples/obj_sticher/obj_sticher.cc
Normal file
82
examples/obj_sticher/obj_sticher.cc
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
//
|
||||||
|
// Stiches multiple .obj files into one .obj.
|
||||||
|
//
|
||||||
|
#include "../../tiny_obj_loader.h"
|
||||||
|
#include "obj_writer.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
typedef std::vector<tinyobj::shape_t> Shape;
|
||||||
|
|
||||||
|
void
|
||||||
|
StichObjs(
|
||||||
|
std::vector<tinyobj::shape_t>& out,
|
||||||
|
const std::vector<Shape>& shapes)
|
||||||
|
{
|
||||||
|
int numShapes = 0;
|
||||||
|
for (size_t i = 0; i < shapes.size(); i++) {
|
||||||
|
numShapes += (int)shapes[i].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Total # of shapes = %d\n", numShapes);
|
||||||
|
|
||||||
|
size_t face_offset = 0;
|
||||||
|
for (size_t i = 0; i < shapes.size(); i++) {
|
||||||
|
for (size_t k = 0; k < shapes[i].size(); k++) {
|
||||||
|
|
||||||
|
std::string new_name = shapes[i][k].name;
|
||||||
|
// Add suffix
|
||||||
|
char buf[1024];
|
||||||
|
sprintf(buf, "_%04d", (int)i);
|
||||||
|
new_name += std::string(buf);
|
||||||
|
|
||||||
|
printf("shape[%ld][%ld].name = %s\n", i, k, shapes[i][k].name.c_str());
|
||||||
|
assert((shapes[i][k].mesh.indices.size() % 3) == 0);
|
||||||
|
assert((shapes[i][k].mesh.positions.size() % 3) == 0);
|
||||||
|
|
||||||
|
tinyobj::shape_t new_shape = shapes[i][k];
|
||||||
|
new_shape.name = new_name;
|
||||||
|
printf("shape[%ld][%ld].new_name = %s\n", i, k, new_shape.name.c_str());
|
||||||
|
|
||||||
|
out.push_back(new_shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(
|
||||||
|
int argc,
|
||||||
|
char **argv)
|
||||||
|
{
|
||||||
|
if (argc < 3) {
|
||||||
|
printf("Usage: obj_sticher input0.obj input1.obj ... output.obj\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_objfiles = argc - 2;
|
||||||
|
std::string out_filename = std::string(argv[argc-1]); // last element
|
||||||
|
|
||||||
|
std::vector<Shape> shapes;
|
||||||
|
shapes.resize(num_objfiles);
|
||||||
|
|
||||||
|
for (int i = 0; i < num_objfiles; i++) {
|
||||||
|
std::cout << "Loading " << argv[i+1] << " ... " << std::flush;
|
||||||
|
|
||||||
|
std::string err = tinyobj::LoadObj(shapes[i], argv[i+1]);
|
||||||
|
if (!err.empty()) {
|
||||||
|
std::cerr << err << std::endl;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "DONE." << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<tinyobj::shape_t> out;
|
||||||
|
StichObjs(out, shapes);
|
||||||
|
|
||||||
|
bool ret = WriteObj(out_filename, out);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
139
examples/obj_sticher/obj_writer.cc
Normal file
139
examples/obj_sticher/obj_writer.cc
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
//
|
||||||
|
// Simple wavefront .obj writer
|
||||||
|
//
|
||||||
|
#include "obj_writer.h"
|
||||||
|
|
||||||
|
static std::string GetFileBasename(const std::string& FileName)
|
||||||
|
{
|
||||||
|
if(FileName.find_last_of(".") != std::string::npos)
|
||||||
|
return FileName.substr(0, FileName.find_last_of("."));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteMat(const std::string& filename, std::vector<tinyobj::shape_t> shapes) {
|
||||||
|
FILE* fp = fopen(filename.c_str(), "w");
|
||||||
|
if (!fp) {
|
||||||
|
fprintf(stderr, "Failed to open file [ %s ] for write.\n", filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, tinyobj::material_t> mtl_table;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < shapes.size(); i++) {
|
||||||
|
mtl_table[shapes[i].material.name] = shapes[i].material;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::map<std::string, tinyobj::material_t>::iterator it = mtl_table.begin(); it != mtl_table.end(); it++) {
|
||||||
|
|
||||||
|
tinyobj::material_t mat = it->second;
|
||||||
|
|
||||||
|
fprintf(fp, "newmtl %s\n", mat.name.c_str());
|
||||||
|
fprintf(fp, "Ka %f %f %f\n", mat.ambient[0], mat.ambient[1], mat.ambient[2]);
|
||||||
|
fprintf(fp, "Kd %f %f %f\n", mat.diffuse[0], mat.diffuse[1], mat.diffuse[2]);
|
||||||
|
fprintf(fp, "Ks %f %f %f\n", mat.specular[0], mat.specular[1], mat.specular[2]);
|
||||||
|
fprintf(fp, "Kt %f %f %f\n", mat.transmittance[0], mat.specular[1], mat.specular[2]);
|
||||||
|
fprintf(fp, "Ke %f %f %f\n", mat.emission[0], mat.emission[1], mat.emission[2]);
|
||||||
|
fprintf(fp, "Ns %f\n", mat.shininess);
|
||||||
|
fprintf(fp, "Ni %f\n", mat.ior);
|
||||||
|
// @todo { texture }
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteObj(const std::string& filename, std::vector<tinyobj::shape_t> shapes) {
|
||||||
|
FILE* fp = fopen(filename.c_str(), "w");
|
||||||
|
if (!fp) {
|
||||||
|
fprintf(stderr, "Failed to open file [ %s ] for write.\n", filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string basename = GetFileBasename(filename);
|
||||||
|
std::string material_filename = basename + ".mtl";
|
||||||
|
|
||||||
|
int v_offset = 0;
|
||||||
|
int vn_offset = 0;
|
||||||
|
int vt_offset = 0;
|
||||||
|
|
||||||
|
fprintf(fp, "mtllib %s\n", material_filename.c_str());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < shapes.size(); i++) {
|
||||||
|
|
||||||
|
bool has_vn = false;
|
||||||
|
bool has_vt = false;
|
||||||
|
|
||||||
|
if (shapes[i].name.empty()) {
|
||||||
|
fprintf(fp, "g Unknown\n");
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "g %s\n", shapes[i].name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shapes[i].material.name.empty()) {
|
||||||
|
fprintf(fp, "usemtl %s\n", shapes[i].material.name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// vtx
|
||||||
|
for (size_t k = 0; k < shapes[i].mesh.positions.size() / 3; k++) {
|
||||||
|
fprintf(fp, "v %f %f %f\n",
|
||||||
|
shapes[i].mesh.positions[3*k+0],
|
||||||
|
shapes[i].mesh.positions[3*k+1],
|
||||||
|
shapes[i].mesh.positions[3*k+2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// normal
|
||||||
|
for (size_t k = 0; k < shapes[i].mesh.normals.size() / 3; k++) {
|
||||||
|
fprintf(fp, "vn %f %f %f\n",
|
||||||
|
shapes[i].mesh.normals[3*k+0],
|
||||||
|
shapes[i].mesh.normals[3*k+1],
|
||||||
|
shapes[i].mesh.normals[3*k+2]);
|
||||||
|
}
|
||||||
|
if (shapes[i].mesh.normals.size() > 0) has_vn = true;
|
||||||
|
|
||||||
|
// texcoord
|
||||||
|
for (size_t k = 0; k < shapes[i].mesh.texcoords.size() / 2; k++) {
|
||||||
|
fprintf(fp, "vt %f %f\n",
|
||||||
|
shapes[i].mesh.texcoords[2*k+0],
|
||||||
|
shapes[i].mesh.texcoords[2*k+1]);
|
||||||
|
}
|
||||||
|
if (shapes[i].mesh.texcoords.size() > 0) has_vt = true;
|
||||||
|
|
||||||
|
// face
|
||||||
|
for (size_t k = 0; k < shapes[i].mesh.indices.size() / 3; k++) {
|
||||||
|
|
||||||
|
// Face index is 1-base.
|
||||||
|
int v0 = shapes[i].mesh.indices[3*k+0] + 1 + v_offset;
|
||||||
|
int v1 = shapes[i].mesh.indices[3*k+1] + 1 + v_offset;
|
||||||
|
int v2 = shapes[i].mesh.indices[3*k+2] + 1 + v_offset;
|
||||||
|
|
||||||
|
if (has_vn && has_vt) {
|
||||||
|
fprintf(fp, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
|
||||||
|
v0, v0, v0, v1, v1, v1, v2, v2, v2);
|
||||||
|
} else if (has_vn && !has_vt) {
|
||||||
|
fprintf(fp, "f %d//%d %d//%d %d//%d\n", v0, v0, v1, v1, v2, v2);
|
||||||
|
} else if (!has_vn && has_vt) {
|
||||||
|
fprintf(fp, "f %d/%d %d/%d %d/%d\n", v0, v0, v1, v1, v2, v2);
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "f %d %d %d\n", v0, v1, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
v_offset += shapes[i].mesh.positions.size() / 3;
|
||||||
|
vn_offset += shapes[i].mesh.normals.size() / 3;
|
||||||
|
vt_offset += shapes[i].mesh.texcoords.size() / 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write material file
|
||||||
|
//
|
||||||
|
bool ret = WriteMat(material_filename, shapes);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
9
examples/obj_sticher/obj_writer.h
Normal file
9
examples/obj_sticher/obj_writer.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef __OBJ_WRITER_H__
|
||||||
|
#define __OBJ_WRITER_H__
|
||||||
|
|
||||||
|
#include "../../tiny_obj_loader.h"
|
||||||
|
|
||||||
|
extern bool WriteObj(const std::string& filename, std::vector<tinyobj::shape_t> shapes);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __OBJ_WRITER_H__
|
||||||
38
examples/obj_sticher/premake4.lua
Normal file
38
examples/obj_sticher/premake4.lua
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
lib_sources = {
|
||||||
|
"../../tiny_obj_loader.cc"
|
||||||
|
}
|
||||||
|
|
||||||
|
sources = {
|
||||||
|
"obj_sticher.cc",
|
||||||
|
"obj_writer.cc",
|
||||||
|
}
|
||||||
|
|
||||||
|
-- premake4.lua
|
||||||
|
solution "ObjStickerSolution"
|
||||||
|
configurations { "Release", "Debug" }
|
||||||
|
|
||||||
|
if (os.is("windows")) then
|
||||||
|
platforms { "x32", "x64" }
|
||||||
|
else
|
||||||
|
platforms { "native", "x32", "x64" }
|
||||||
|
end
|
||||||
|
|
||||||
|
includedirs {
|
||||||
|
"../../"
|
||||||
|
}
|
||||||
|
|
||||||
|
-- A project defines one build target
|
||||||
|
project "obj_sticher"
|
||||||
|
kind "ConsoleApp"
|
||||||
|
language "C++"
|
||||||
|
files { lib_sources, sources }
|
||||||
|
|
||||||
|
configuration "Debug"
|
||||||
|
defines { "DEBUG" } -- -DDEBUG
|
||||||
|
flags { "Symbols" }
|
||||||
|
targetname "obj_sticher_debug"
|
||||||
|
|
||||||
|
configuration "Release"
|
||||||
|
-- defines { "NDEBUG" } -- -NDEBUG
|
||||||
|
flags { "Symbols", "Optimize" }
|
||||||
|
targetname "obj_sticher"
|
||||||
1
test.cc
1
test.cc
@@ -46,6 +46,7 @@ TestLoadObj(
|
|||||||
printf(" material.Tr = (%f, %f ,%f)\n", shapes[i].material.transmittance[0], shapes[i].material.transmittance[1], shapes[i].material.transmittance[2]);
|
printf(" material.Tr = (%f, %f ,%f)\n", shapes[i].material.transmittance[0], shapes[i].material.transmittance[1], shapes[i].material.transmittance[2]);
|
||||||
printf(" material.Ke = (%f, %f ,%f)\n", shapes[i].material.emission[0], shapes[i].material.emission[1], shapes[i].material.emission[2]);
|
printf(" material.Ke = (%f, %f ,%f)\n", shapes[i].material.emission[0], shapes[i].material.emission[1], shapes[i].material.emission[2]);
|
||||||
printf(" material.Ns = %f\n", shapes[i].material.shininess);
|
printf(" material.Ns = %f\n", shapes[i].material.shininess);
|
||||||
|
printf(" material.Ni = %f\n", shapes[i].material.ior);
|
||||||
printf(" material.map_Ka = %s\n", shapes[i].material.ambient_texname.c_str());
|
printf(" material.map_Ka = %s\n", shapes[i].material.ambient_texname.c_str());
|
||||||
printf(" material.map_Kd = %s\n", shapes[i].material.diffuse_texname.c_str());
|
printf(" material.map_Kd = %s\n", shapes[i].material.diffuse_texname.c_str());
|
||||||
printf(" material.map_Ks = %s\n", shapes[i].material.specular_texname.c_str());
|
printf(" material.map_Ks = %s\n", shapes[i].material.specular_texname.c_str());
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
//
|
//
|
||||||
|
// version 0.9.6: Support Ni(index of refraction) mtl parameter.
|
||||||
|
// Parse transmittance material parameter correctly.
|
||||||
// version 0.9.5: Parse multiple group name.
|
// version 0.9.5: Parse multiple group name.
|
||||||
// Add support of specifying the base path to load material file.
|
// Add support of specifying the base path to load material file.
|
||||||
// version 0.9.4: Initial suupport of group tag(g)
|
// version 0.9.4: Initial suupport of group tag(g)
|
||||||
@@ -372,14 +374,21 @@ std::string LoadMtl (
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// specular
|
// transmittance
|
||||||
if (token[0] == 'K' && token[1] == 't' && isSpace((token[2]))) {
|
if (token[0] == 'K' && token[1] == 't' && isSpace((token[2]))) {
|
||||||
token += 2;
|
token += 2;
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
parseFloat3(r, g, b, token);
|
parseFloat3(r, g, b, token);
|
||||||
material.specular[0] = r;
|
material.transmittance[0] = r;
|
||||||
material.specular[1] = g;
|
material.transmittance[1] = g;
|
||||||
material.specular[2] = b;
|
material.transmittance[2] = b;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ior(index of refraction)
|
||||||
|
if (token[0] == 'N' && token[1] == 'i' && isSpace((token[2]))) {
|
||||||
|
token += 2;
|
||||||
|
material.ior = parseFloat(token);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ typedef struct
|
|||||||
float transmittance[3];
|
float transmittance[3];
|
||||||
float emission[3];
|
float emission[3];
|
||||||
float shininess;
|
float shininess;
|
||||||
|
float ior; // index of refraction
|
||||||
|
|
||||||
std::string ambient_texname;
|
std::string ambient_texname;
|
||||||
std::string diffuse_texname;
|
std::string diffuse_texname;
|
||||||
|
|||||||
Reference in New Issue
Block a user