diff options
author | Syoyo Fujita <syoyo@lighttransport.com> | 2020-08-09 21:22:52 +0900 |
---|---|---|
committer | Syoyo Fujita <syoyo@lighttransport.com> | 2020-08-09 21:22:52 +0900 |
commit | ca47da4ae450f3477b52a46f00d0c23efe134cf6 (patch) | |
tree | 1e33d5192166b993a790f4bc47ff6eaac536957a | |
parent | 53f17f2fc84913995b938a101fdb95882b465f38 (diff) | |
parent | c7268cabea6fa649490d6b4cb91a20add51b08b4 (diff) | |
download | tinyobjloader-ca47da4ae450f3477b52a46f00d0c23efe134cf6.tar.gz |
Merge branch 'vertex_weight'
-rw-r--r-- | examples/skin_weight/Makefile | 2 | ||||
-rw-r--r-- | examples/skin_weight/README.md | 7 | ||||
-rw-r--r-- | examples/skin_weight/main.cc | 103 | ||||
-rw-r--r-- | models/skin-weight.obj | 43 | ||||
-rw-r--r-- | tiny_obj_loader.h | 86 |
5 files changed, 233 insertions, 8 deletions
diff --git a/examples/skin_weight/Makefile b/examples/skin_weight/Makefile new file mode 100644 index 0000000..59e4e3c --- /dev/null +++ b/examples/skin_weight/Makefile @@ -0,0 +1,2 @@ +all: + clang++ -std=c++11 -o skin_weight -I../../ -g main.cc diff --git a/examples/skin_weight/README.md b/examples/skin_weight/README.md new file mode 100644 index 0000000..800d847 --- /dev/null +++ b/examples/skin_weight/README.md @@ -0,0 +1,7 @@ +This example printf skin weight of vertex(`vw`). TinyObjLoader extension. + +## Run example + +``` +$ ./skin_weight ../../models/skin-weight.obj +``` diff --git a/examples/skin_weight/main.cc b/examples/skin_weight/main.cc new file mode 100644 index 0000000..a3770af --- /dev/null +++ b/examples/skin_weight/main.cc @@ -0,0 +1,103 @@ +// +// g++ -g -std=c++11 main.cc +// +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" + +#include <cassert> +#include <cstdio> +#include <cstdlib> +#include <fstream> +#include <iostream> +#include <sstream> + +#include <unordered_map> // C++11 + +#ifdef __clang__ +#pragma clang diagnostic push +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#endif + +static void ConstructVertexWeight( + const std::vector<tinyobj::real_t> &vertices, + const std::vector<tinyobj::skin_weight_t> &skin_weights, + std::vector<tinyobj::skin_weight_t> *vertex_skin_weights) +{ + size_t num_vertices = vertices.size() / 3; + + vertex_skin_weights->resize(num_vertices); + + for (size_t i = 0; i < skin_weights.size(); i++) { + const tinyobj::skin_weight_t &skin = skin_weights[i]; + + assert(skin.vertex_id >= 0); + assert(skin.vertex_id < num_vertices); + + (*vertex_skin_weights)[skin.vertex_id] = skin; + } + + // now you can lookup i'th vertex skin weight by `vertex_skin_weights[i]` + + +} + +static bool TestLoadObj(const char* filename, const char* basepath = nullptr, + bool triangulate = true) { + std::cout << "Loading " << filename << std::endl; + + tinyobj::attrib_t attrib; + std::vector<tinyobj::shape_t> shapes; + std::vector<tinyobj::material_t> materials; + + std::string warn; + std::string err; + bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename, + basepath, triangulate); + if (!warn.empty()) { + std::cout << "WARN: " << warn << std::endl; + } + + if (!err.empty()) { + std::cerr << "ERR: " << err << std::endl; + } + + if (!ret) { + printf("Failed to load/parse .obj.\n"); + return false; + } + + std::vector<tinyobj::skin_weight_t> vertex_skin_weights; + + ConstructVertexWeight( + attrib.vertices, + attrib.skin_weights, + &vertex_skin_weights); + + for (size_t v = 0; v < vertex_skin_weights.size(); v++) { + std::cout << "vertex[" << v << "] num_weights = " << vertex_skin_weights[v].weightValues.size() << "\n"; + for (size_t w = 0; w < vertex_skin_weights[v].weightValues.size(); w++) { + std::cout << " w[" << w << "] joint = " << vertex_skin_weights[v].weightValues[w].joint_id + << ", weight = " << vertex_skin_weights[v].weightValues[w].weight << "\n"; + } + } + + return true; +} + + +int main(int argc, char** argv) { + if (argc < 2) { + std::cerr << "Need input.obj\n"; + return EXIT_FAILURE; + } + + const char* basepath = nullptr; + if (argc > 2) { + basepath = argv[2]; + } + assert(true == TestLoadObj(argv[1], basepath)); + + return 0; +} diff --git a/models/skin-weight.obj b/models/skin-weight.obj new file mode 100644 index 0000000..41f182f --- /dev/null +++ b/models/skin-weight.obj @@ -0,0 +1,43 @@ +mtllib cube.mtl + +v 0.000000 2.000000 2.000000 +v 0.000000 0.000000 2.000000 +v 2.000000 0.000000 2.000000 +v 2.000000 2.000000 2.000000 +v 0.000000 2.000000 0.000000 +v 0.000000 0.000000 0.000000 +v 2.000000 0.000000 0.000000 +v 2.000000 2.000000 0.000000 +# 8 vertices + +vw 0 0 1.0 +vw 1 0 0.5 1 0.5 +vw 2 1 1.0 +vw 3 2 1.0 +vw 4 3 1.0 +vw 5 0 0.25 1 0.25 2 0.25 3 0.25 +# No weight for 6th vertex +# vw 6 0 1.0 +vw 7 0 1.0 +# max 4 joints + +g front cube +usemtl white +f 1 2 3 4 +# two white spaces between 'back' and 'cube' +g back cube +# expects white material +f 8 7 6 5 +g right cube +usemtl red +f 4 3 7 8 +g top cube +usemtl white +f 5 1 4 8 +g left cube +usemtl green +f 5 6 2 1 +g bottom cube +usemtl white +f 2 6 7 3 +# 6 elements diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 7fa95c9..edd18f5 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -27,6 +27,7 @@ THE SOFTWARE. // * Support line primitive. // * Support points primitive. // * Support multiple search path for .mtl(v1 API). +// * Support vertex weight `vw`(as an tinyobj extension) // version 1.4.0 : Modifed ParseTextureNameAndOption API // version 1.3.1 : Make ParseTextureNameAndOption API public // version 1.3.0 : Separate warning and error message(breaking API of LoadObj) @@ -162,8 +163,9 @@ struct texture_option_t { real_t origin_offset[3]; // -o u [v [w]] (default 0 0 0) real_t scale[3]; // -s u [v [w]] (default 1 1 1) real_t turbulence[3]; // -t u [v [w]] (default 0 0 0) - int texture_resolution; // -texres resolution (No default value in the spec. We'll use -1) - bool clamp; // -clamp (default false) + int texture_resolution; // -texres resolution (No default value in the spec. + // We'll use -1) + bool clamp; // -clamp (default false) char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm') bool blendu; // -blendu (default on) bool blendv; // -blendv (default on) @@ -316,7 +318,6 @@ struct material_t { } #endif - }; struct tag_t { @@ -327,6 +328,18 @@ struct tag_t { std::vector<std::string> stringValues; }; +struct joint_and_weight_t { + int joint_id; + real_t weight; +}; + +struct skin_weight_t { + int vertex_id; // Corresponding vertex index in `attrib_t::vertices`. + // Compared to `index_t`, this index must be positive and + // start with 0(does not allow relative indexing) + std::vector<joint_and_weight_t> weightValues; +}; + // Index struct to support different indices for vtx/normal/texcoord. // -1 means not used. struct index_t { @@ -383,6 +396,16 @@ struct attrib_t { std::vector<real_t> texcoord_ws; // 'vt'(w) std::vector<real_t> colors; // extension: vertex colors + // + // TinyObj extension. + // + + // NOTE(syoyo): array index is based on the appearance order. + // To get a corresponding skin weight for a specific vertex id `vid`, + // Need to reconstruct a look up table: `skin_weight_t::vertex_id` == `vid` + // (e.g. using std::map, std::unordered_map) + std::vector<skin_weight_t> skin_weights; + attrib_t() {} // @@ -625,11 +648,10 @@ bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt, #include <cstddef> #include <cstdlib> #include <cstring> -#include <limits> -#include <utility> - #include <fstream> +#include <limits> #include <sstream> +#include <utility> namespace tinyobj { @@ -1917,8 +1939,7 @@ void LoadMtl(std::map<std::string, int> *material_map, // Set a decent diffuse default value if a diffuse texture is specified // without a matching Kd value. - if (!has_kd) - { + if (!has_kd) { material.diffuse[0] = static_cast<real_t>(0.6); material.diffuse[1] = static_cast<real_t>(0.6); material.diffuse[2] = static_cast<real_t>(0.6); @@ -2181,6 +2202,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes, std::vector<real_t> vn; std::vector<real_t> vt; std::vector<real_t> vc; + std::vector<skin_weight_t> vw; std::vector<tag_t> tags; PrimGroup prim_group; std::string name; @@ -2274,6 +2296,53 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes, continue; } + // skin weight. tinyobj extension + if (token[0] == 'v' && token[1] == 'w' && IS_SPACE((token[2]))) { + token += 3; + + // vw <vid> <joint_0> <weight_0> <joint_1> <weight_1> ... + // example: + // vw 0 0 0.25 1 0.25 2 0.5 + + // TODO(syoyo): Add syntax check + int vid = 0; + vid = parseInt(&token); + + skin_weight_t sw; + + sw.vertex_id = vid; + + while (!IS_NEW_LINE(token[0])) { + real_t j, w; + // joint_id should not be negative, weight may be negative + // TODO(syoyo): # of elements check + parseReal2(&j, &w, &token, -1.0); + + if (j < 0.0) { + if (err) { + std::stringstream ss; + ss << "Failed parse `vw' line. joint_id is negative. " + "line " + << line_num << ".)\n"; + (*err) += ss.str(); + } + return false; + } + + joint_and_weight_t jw; + + jw.joint_id = int(j); + jw.weight = w; + + sw.weightValues.push_back(jw); + + size_t n = strspn(token, " \t\r"); + token += n; + } + + vw.push_back(sw); + } + // line if (token[0] == 'l' && IS_SPACE((token[1]))) { token += 2; @@ -2676,6 +2745,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes, attrib->texcoords.swap(vt); attrib->texcoord_ws.swap(vt); attrib->colors.swap(vc); + attrib->skin_weights.swap(vw); return true; } |