diff --git a/examples/mesh-modify/Makefile b/examples/mesh-conv/Makefile similarity index 80% rename from examples/mesh-modify/Makefile rename to examples/mesh-conv/Makefile index be92d7f..e430fb9 100644 --- a/examples/mesh-modify/Makefile +++ b/examples/mesh-conv/Makefile @@ -2,4 +2,4 @@ EXTRA_CXXFLAGS := all: - clang++ -std=c++11 -g -O1 -I../../ -I../common $(EXTRA_CXXFLAGS) -o mesh-modify mesh-modify.cc mesh-util.cc tinygltf_impl.cc + clang++ -std=c++11 -g -O1 -I../../ -I../common $(EXTRA_CXXFLAGS) -o mesh-conv mesh-conv.cc mesh-util.cc tinygltf_impl.cc diff --git a/examples/mesh-conv/Makefile.meson b/examples/mesh-conv/Makefile.meson new file mode 100644 index 0000000..748dfdc --- /dev/null +++ b/examples/mesh-conv/Makefile.meson @@ -0,0 +1,5 @@ +all: + ninja + +clean: + ninja -t clean diff --git a/examples/mesh-conv/README.md b/examples/mesh-conv/README.md new file mode 100644 index 0000000..b545803 --- /dev/null +++ b/examples/mesh-conv/README.md @@ -0,0 +1,43 @@ +# Mesh modify experiment + +Sometimes we want to tweak mesh attributes(e.g. vertex position, uv coord, etc). +glTF itself does not allow ASCII representation of such data. + +This example show how to + +- Export mesh data from .bin to .obj +- Import mesh data to .bin(update corresponding buffer data) from .obj + +## Usage + +### Wavefront .obj to glTF + +``` +$ mesh-modify obj2gltf input.obj +``` + +All shapes in .obj are concatenated and create single glTF mesh. +(tinyobjloader's skin weight extension `vw` supported) + +#### Limitation + +Buffer is stored as external file(`.bin`) + +### glTF to Wavefront .obj + +``` +$ mesh-modify gltf2obj input.gltf +``` + +.obj will be created for each glTF Mesh. +(Skin weight data is exported to .obj using tinyobjloader's skin weight extension `vw`) + +#### Limitation + +Buffer is stored as external file(`.bin`) + +## TODO + +* [ ] obj2gltf: Assign glTF material from .mtl +* [ ] modify/patch mesh geometry in glTF + * By using JSON Patch or JSON Merge feature diff --git a/examples/mesh-conv/bootstrap-meson.sh b/examples/mesh-conv/bootstrap-meson.sh new file mode 100755 index 0000000..978b8d0 --- /dev/null +++ b/examples/mesh-conv/bootstrap-meson.sh @@ -0,0 +1,3 @@ +rm -rf build +CXX=clang++ CC=clang meson build -Db_sanitize=address -Db_lundef=false --buildtype=debug +cp Makefile.meson build/Makefile diff --git a/examples/mesh-modify/mesh-modify.cc b/examples/mesh-conv/mesh-conv.cc similarity index 85% rename from examples/mesh-modify/mesh-modify.cc rename to examples/mesh-conv/mesh-conv.cc index a8f6bf9..2dd56b3 100644 --- a/examples/mesh-modify/mesh-modify.cc +++ b/examples/mesh-conv/mesh-conv.cc @@ -148,13 +148,11 @@ struct MeshPrim { }; #endif -#if 0 static std::string GetFilePathExtension(const std::string &FileName) { if (FileName.find_last_of(".") != std::string::npos) return FileName.substr(FileName.find_last_of(".") + 1); return ""; } -#endif static size_t ComponentTypeByteSize(int type) { switch (type) { @@ -296,13 +294,11 @@ static std::string FindFile(const std::vector &paths, return std::string(); } -#if 0 static std::string GetBaseDir(const std::string &filepath) { if (filepath.find_last_of("/\\") != std::string::npos) return filepath.substr(0, filepath.find_last_of("/\\")); return ""; } -#endif static int GetSlotId(const std::string &name) { if (name.rfind("TEXCOORD_", 0) == 0) { @@ -575,7 +571,6 @@ static bool DumpMesh(const tinygltf::Model &model, const tinygltf::Mesh &mesh, return true; } -#if 0 static bool ExtractMesh(const std::string &asset_path, tinygltf::Model &model, std::vector *outs) { // Get .bin data @@ -623,117 +618,127 @@ static bool ExtractMesh(const std::string &asset_path, tinygltf::Model &model, return true; } -#endif } // namespace int main(int argc, char **argv) { - if (argc < 2) { - std::cout << "mesh-dump input.gltf" << std::endl; + if (argc < 3) { + std::cout << "mesh-modify " << std::endl; + std::cout << " op\n\n"; + std::cout << " gltf2obj input.gltf \n"; + std::cout << " obj2gltf input.obj \n"; + + return EXIT_FAILURE; } -#if 0 + std::string op = argv[1]; - tinygltf::Model model; - tinygltf::TinyGLTF loader; - std::string err; - std::string warn; + if (op == "gltf2obj") { -#ifdef _WIN32 - std::string input_filename(argv[1] ? argv[1] - : "../../../models/Cube/Cube.gltf"); -#else - std::string input_filename(argv[1] ? argv[1] : "../../models/Cube/Cube.gltf"); -#endif - - std::string ext = GetFilePathExtension(input_filename); - - { - bool ret = false; - if (ext.compare("glb") == 0) { - // assume binary glTF. - ret = loader.LoadBinaryFromFile(&model, &err, &warn, - input_filename.c_str()); - } else { - // assume ascii glTF. - ret = - loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str()); + bool flip_texcoord_y = true; + if (argc > 3) { + flip_texcoord_y = (std::atoi(argv[3]) > 0) ? true : false; } - if (!warn.empty()) { - printf("Warn: %s\n", warn.c_str()); + tinygltf::Model model; + tinygltf::TinyGLTF loader; + std::string err; + std::string warn; + + std::string input_filename(argv[2]); + + std::string ext = GetFilePathExtension(input_filename); + + { + bool ret = false; + if (ext.compare("glb") == 0) { + // assume binary glTF. + ret = loader.LoadBinaryFromFile(&model, &err, &warn, + input_filename.c_str()); + } else { + // assume ascii glTF. + ret = + loader.LoadASCIIFromFile(&model, &err, &warn, input_filename.c_str()); + } + + if (!warn.empty()) { + printf("Warn: %s\n", warn.c_str()); + } + + if (!err.empty()) { + printf("ERR: %s\n", err.c_str()); + } + if (!ret) { + printf("Failed to load .glTF : %s\n", argv[1]); + exit(-1); + } } - if (!err.empty()) { - printf("ERR: %s\n", err.c_str()); + json j; + { + std::ifstream i(input_filename); + i >> j; } - if (!ret) { - printf("Failed to load .glTF : %s\n", argv[1]); - exit(-1); - } - } + std::cout << "j = " << j << "\n"; - json j; - { - std::ifstream i(input_filename); - i >> j; - } - std::cout << "j = " << j << "\n"; + json j_patch = R"([ + { "op": "add", "path": "/buffers/-", "value": { + "name": "plane/data", + "byteLength": 480, + "uri": "plane1.bin" + } } + ])"_json; - json j_patch = R"([ - { "op": "add", "path": "/buffers/-", "value": { - "name": "plane/data", - "byteLength": 480, - "uri": "plane1.bin" - } } - ])"_json; + // a JSON value + json j_original = R"({ + "baz": ["one", "two", "three"], + "foo": "bar" + })"_json; - // a JSON value - json j_original = R"({ - "baz": ["one", "two", "three"], - "foo": "bar" - })"_json; + //json j_patch = R"([ + // { "op": "remove", "path": "/buffers" } + //])"_json; - //json j_patch = R"([ - // { "op": "remove", "path": "/buffers" } - //])"_json; + std::cout << "patch = " << j_patch.dump(2) << "\n"; - std::cout << "patch = " << j_patch.dump(2) << "\n"; + json j_ret = j.patch(j_patch); + std::cout << "patched = " << j_ret.dump(2) << "\n"; - json j_ret = j.patch(j_patch); - std::cout << "patched = " << j_ret.dump(2) << "\n"; + std::string basedir = GetBaseDir(input_filename); + std::vector meshes; + bool ret = ExtractMesh(basedir, model, &meshes); - std::string basedir = GetBaseDir(input_filename); - std::vector meshes; - bool ret = ExtractMesh(basedir, model, &meshes); + size_t n = 0; + for (const auto &mesh : meshes) { + // Assume no duplicated name in .glTF data + std::string filename; + if (mesh.name.empty()) { + filename = "untitled-" + std::to_string(n) + ".obj"; + } else { + filename = mesh.name + ".obj"; + } - size_t n = 0; - for (const auto &mesh : meshes) { - // Assume no duplicated name in .glTF data - std::string filename; - if (mesh.name.empty()) { - filename = "untitled-" + std::to_string(n) + ".obj"; - } else { - filename = mesh.name + ".obj"; + bool ok = example::SaveAsObjMesh(filename, mesh, flip_texcoord_y); + if (!ok) { + return EXIT_FAILURE; + } + n++; } - bool flip_y = true; // flip texcoord Y? - bool ok = example::SaveAsObjMesh(filename, mesh,); - if (!ok) { - return EXIT_FAILURE; + return ret ? EXIT_SUCCESS : EXIT_FAILURE; + } else if (op == "obj2gltf") { + std::string input_filename(argv[2]); + + bool verbose = false; + if (argc > 3) { + verbose = (std::atoi(argv[3]) > 0) ? true : false; } - n++; - } - - return ret ? EXIT_SUCCESS : EXIT_FAILURE; -#else - - { - std::string input_filename(argv[1]); // Require facevarying layout? - // false = try to keep GL-like mesh data as much as possible. - // true = reorder vertex data and re-assign vertex indices. + // facevarying representation is required if a vertex can have multiple normal/uv value. + // drawback of facevarying is mesh data increases. + // false = try to keep shared vertex representation as much as possible. + // true = reorder vertex data and re-assign vertex indices for facevarying data layout. bool facevarying = false; example::MeshPrim mesh; @@ -742,7 +747,9 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } - PrintMeshPrim(mesh); + if (verbose) { + PrintMeshPrim(mesh); + } std::string output_filename("output.gltf"); @@ -752,9 +759,11 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } std::cout << "Write glTF: " << output_filename << "\n"; + return EXIT_SUCCESS; + } else { + + std::cerr << "Unknown operation: " << op << "\n"; + return EXIT_FAILURE; } - return EXIT_SUCCESS; -#endif - } diff --git a/examples/mesh-modify/mesh-util.cc b/examples/mesh-conv/mesh-util.cc similarity index 100% rename from examples/mesh-modify/mesh-util.cc rename to examples/mesh-conv/mesh-util.cc diff --git a/examples/mesh-modify/mesh-util.hh b/examples/mesh-conv/mesh-util.hh similarity index 98% rename from examples/mesh-modify/mesh-util.hh rename to examples/mesh-conv/mesh-util.hh index ac00d48..a87a36e 100644 --- a/examples/mesh-modify/mesh-util.hh +++ b/examples/mesh-conv/mesh-util.hh @@ -54,7 +54,7 @@ struct MeshPrim { /// /// Save MeshPrim as wavefront .obj /// -bool SaveAsObjMesh(const std::string &filename, const MeshPrim &mesh); +bool SaveAsObjMesh(const std::string &filename, const MeshPrim &mesh, bool flip_texcoord_y = true); /// /// Save MeshPrim as glTF mesh diff --git a/examples/mesh-conv/meson.build b/examples/mesh-conv/meson.build new file mode 100644 index 0000000..02cc3fa --- /dev/null +++ b/examples/mesh-conv/meson.build @@ -0,0 +1,7 @@ +project('mesh-conv', 'cpp', default_options : ['cpp_std=c++11']) + +thread_dep = dependency('threads') + +incdir = include_directories(['../../', '../common']) + +executable('mesh-conv', ['mesh-conv.cc', 'mesh-util.cc', 'tinygltf_impl.cc'], include_directories : incdir, dependencies : thread_dep) diff --git a/examples/mesh-conv/tinygltf_impl.cc b/examples/mesh-conv/tinygltf_impl.cc new file mode 100644 index 0000000..03c779a --- /dev/null +++ b/examples/mesh-conv/tinygltf_impl.cc @@ -0,0 +1,9 @@ +#define TINYGLTF_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION + +#ifdef _WIN32 +#include "../../tiny_gltf.h" +#else +#include "tiny_gltf.h" +#endif diff --git a/examples/mesh-modify/README.md b/examples/mesh-modify/README.md deleted file mode 100644 index c57955f..0000000 --- a/examples/mesh-modify/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Mesh modify experiment - -Sometimes we want to tweak mesh attributes(e.g. vertex position, uv coord, etc). -glTF itself does not allow ASCII representation of such data. - -This example show how to - -- Export mesh data from .bin to .obj -- Import mesh data to .bin(update corresponding buffer data) from .obj - -## Requirement - -Assume Buffer is stored as external file(`.bin`) diff --git a/examples/mesh-modify/meson.build b/examples/mesh-modify/meson.build deleted file mode 100644 index 92e669c..0000000 --- a/examples/mesh-modify/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -project('mesh-modify', 'cpp', default_options : ['cpp_std=c++11']) - -thread_dep = dependency('threads') - -incdir = include_directories(['../../', '../common']) - -executable('mesh-modify', ['mesh-modify.cc', 'mesh-util.cc', 'tinygltf_impl.cc'], include_directories : incdir, dependencies : thread_dep)