diff --git a/examples/alembic_to_gltf/Makefile b/examples/alembic_to_gltf/Makefile index 99f2d83..e7321b2 100644 --- a/examples/alembic_to_gltf/Makefile +++ b/examples/alembic_to_gltf/Makefile @@ -7,7 +7,7 @@ ILMBASE_INC := -I/usr/local/include/OpenEXR EXTRA_CXXFLAGS := -Wno-deprecated-register -Weverything all: - clang++ -std=c++11 -g -o abc2gltf $(ABC_INC) $(ILMBASE_INC) $(EXTRA_CXXFLAGS) main.cc $(ABC_LDFLAGS) + clang++ -std=c++11 -g -o abc2gltf $(ABC_INC) $(ILMBASE_INC) $(EXTRA_CXXFLAGS) abc2gltf.cc $(ABC_LDFLAGS) run: ./abc2gltf suzanne.abc suzanne.gltf diff --git a/examples/alembic_to_gltf/README.md b/examples/alembic_to_gltf/README.md new file mode 100644 index 0000000..3909e09 --- /dev/null +++ b/examples/alembic_to_gltf/README.md @@ -0,0 +1,31 @@ +# Simple Alembic to glTF converter example + +## Features + +* Polygon mesh. + +## Limitations + +* Alembic data with Ogawa backend only +* Simple poly mesh only +* Static mesh only(Use first time sample. no animation) + +## Compile + +OpenEXR(ilmbase), and Alembic 1.6 or later are equired to compile the converter. + +Edit include and lib paths for Alembic OpenEXR(ilmbase) in `Makefile`, then simply: + + $ make + +## Alembic data + +I am testing with Alembic data using Blender's Alembic exporter(feature available from Blender 2.78) + +## TODO + +* [ ] Support normals and texcoords +* [ ] Support mutiple meshes +* [ ] Support animation(time samples) +* [ ] Support scene graph(node hierarchy) +* [ ] Support Point, Curve and SubD? diff --git a/examples/alembic_to_gltf/main.cc b/examples/alembic_to_gltf/abc2gltf.cc similarity index 75% rename from examples/alembic_to_gltf/main.cc rename to examples/alembic_to_gltf/abc2gltf.cc index fae638b..d198b8c 100644 --- a/examples/alembic_to_gltf/main.cc +++ b/examples/alembic_to_gltf/abc2gltf.cc @@ -31,12 +31,15 @@ #include #include +#define PICOJSON_USE_INT64 #include "../../picojson.h" #ifdef __clang__ #pragma clang diagnostic pop #endif +#include "../../tiny_gltf_loader.h" // To import some TINYGLTF_*** macros. + // @todo { texcoords, normals } typedef struct { @@ -337,8 +340,8 @@ static bool SaveGLTF(const std::string& output_filename, root["assets"] = picojson::value(asset); } - picojson::object buffers; { + picojson::object buffers; { std::string vertices_b64data = base64_encode(reinterpret_cast(mesh.vertices.data()), mesh.vertices.size() * sizeof(float)); picojson::object buf; @@ -359,12 +362,122 @@ static bool SaveGLTF(const std::string& output_filename, buf["uri"] = picojson::value( std::string("data:application/octet-stream;base64,") + faces_b64data); buf["byteLength"] = - picojson::value(static_cast(mesh.vertices.size() * sizeof(unsigned int))); + picojson::value(static_cast(mesh.faces.size() * sizeof(unsigned int))); buffers["indices"] = picojson::value(buf); } + root["buffers"] = picojson::value(buffers); } - root["buffers"] = picojson::value(buffers); + + { + picojson::object buffer_views; + { + picojson::object buffer_view_vertices; + buffer_view_vertices["buffer"] = picojson::value(std::string("vertices")); + buffer_view_vertices["byteLength"] = picojson::value(static_cast(mesh.vertices.size() * sizeof(float))); + buffer_view_vertices["byteOffset"] = picojson::value(static_cast(0)); + buffer_view_vertices["target"] = picojson::value(static_cast(TINYGLTF_TARGET_ARRAY_BUFFER)); + + buffer_views["bufferView_vertices"] = picojson::value(buffer_view_vertices); + } + + { + picojson::object buffer_view_indices; + buffer_view_indices["buffer"] = picojson::value(std::string("indices")); + buffer_view_indices["byteLength"] = picojson::value(static_cast(mesh.faces.size() * sizeof(unsigned int))); + buffer_view_indices["byteOffset"] = picojson::value(static_cast(0)); + buffer_view_indices["target"] = picojson::value(static_cast(TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)); + + buffer_views["bufferView_indices"] = picojson::value(buffer_view_indices); + } + + root["bufferViews"] = picojson::value(buffer_views); + } + + { + picojson::object attributes; + + attributes["POSITION"] = picojson::value(std::string("accessor_vertices")); + + picojson::object primitive; + primitive["attributes"] = picojson::value(attributes); + primitive["indices"] = picojson::value("accessor_indices"); + primitive["material"] = picojson::value("material_1"); + primitive["mode"] = picojson::value(static_cast(TINYGLTF_MODE_TRIANGLES)); + + picojson::array primitive_array; + primitive_array.push_back(picojson::value(primitive)); + + picojson::object m; + m["primitives"] = picojson::value(primitive_array); + + picojson::object meshes; + meshes["mesh_1"] = picojson::value(m); + + + root["meshes"] = picojson::value(meshes); + } + + { + picojson::object accessors; + picojson::object accessor_vertices; + picojson::object accessor_indices; + + accessor_vertices["bufferView"] = picojson::value(std::string("bufferView_vertices")); + accessor_vertices["byteOffset"] = picojson::value(static_cast(0)); + accessor_vertices["byteStride"] = picojson::value(static_cast(3 * sizeof(float))); + accessor_vertices["componentType"] = picojson::value(static_cast(TINYGLTF_COMPONENT_TYPE_FLOAT)); + accessor_vertices["count"] = picojson::value(static_cast(mesh.vertices.size())); + accessor_vertices["type"] = picojson::value(std::string("VEC3")); + accessors["accessor_vertices"] = picojson::value(accessor_vertices); + + accessor_indices["bufferView"] = picojson::value(std::string("bufferView_indices")); + accessor_indices["byteOffset"] = picojson::value(static_cast(0)); + accessor_indices["componentType"] = picojson::value(static_cast(TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)); + accessor_indices["count"] = picojson::value(static_cast(mesh.faces.size())); + accessor_indices["type"] = picojson::value(std::string("SCALAR")); + accessors["accessor_indices"] = picojson::value(accessor_indices); + root["accessors"] = picojson::value(accessors); + } + + { + // Use Default Material(Do not supply `material.technique`) + picojson::object default_material; + picojson::object materials; + + materials["material_1"] = picojson::value(default_material); + + root["materials"] = picojson::value(materials); + + } + + { + picojson::object nodes; + picojson::object node; + picojson::array meshes; + + meshes.push_back(picojson::value(std::string("mesh_1"))); + + node["meshes"] = picojson::value(meshes); + + nodes["node_1"] = picojson::value(node); + root["nodes"] = picojson::value(nodes); + } + + { + picojson::object defaultScene; + picojson::array nodes; + + nodes.push_back(picojson::value(std::string("node_1"))); + + defaultScene["nodes"] = picojson::value(nodes); + + root["scene"] = picojson::value("defaultScene"); + picojson::object scenes; + scenes["defaultScene"] = picojson::value(defaultScene); + root["scenes"] = picojson::value(scenes); + } + // @todo {} picojson::object shaders; @@ -422,7 +535,11 @@ int main(int argc, char** argv) { if (foundMesh) { bool ret = SaveGLTF(gltf_filename, mesh); - return ret ? EXIT_SUCCESS : EXIT_FAILURE; + if (ret) { + std::cout << "Wrote " << gltf_filename << std::endl; + } else { + return EXIT_FAILURE; + } } else { std::cout << "No polygon mesh found in Alembic file" << std::endl; } diff --git a/examples/alembic_to_gltf/suzanne.abc b/examples/alembic_to_gltf/suzanne.abc new file mode 100644 index 0000000..1825f76 Binary files /dev/null and b/examples/alembic_to_gltf/suzanne.abc differ