aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSyoyo Fujita <syoyo@lighttransport.com>2020-08-09 21:22:52 +0900
committerSyoyo Fujita <syoyo@lighttransport.com>2020-08-09 21:22:52 +0900
commitca47da4ae450f3477b52a46f00d0c23efe134cf6 (patch)
tree1e33d5192166b993a790f4bc47ff6eaac536957a
parent53f17f2fc84913995b938a101fdb95882b465f38 (diff)
parentc7268cabea6fa649490d6b4cb91a20add51b08b4 (diff)
downloadtinyobjloader-ca47da4ae450f3477b52a46f00d0c23efe134cf6.tar.gz
Merge branch 'vertex_weight'
-rw-r--r--examples/skin_weight/Makefile2
-rw-r--r--examples/skin_weight/README.md7
-rw-r--r--examples/skin_weight/main.cc103
-rw-r--r--models/skin-weight.obj43
-rw-r--r--tiny_obj_loader.h86
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;
}