subd support: n-sided polygons & pixar crease tags

+ optional parameter to triangulate polygons to maintain compatibility
+ added create tag test & example subd crease tag file from OpenSubD source code
This commit is contained in:
dboogert
2016-01-28 18:34:08 +00:00
parent b96ee06bb6
commit 2fcdd32bc3
4 changed files with 309 additions and 56 deletions

101
catmark_torus_creases0.obj Normal file
View File

@@ -0,0 +1,101 @@
#
# Copyright 2013 Pixar
#
# Licensed under the Apache License, Version 2.0 (the "Apache License")
# with the following modification; you may not use this file except in
# compliance with the Apache License and the following modification to it:
# Section 6. Trademarks. is deleted and replaced with:
#
# 6. Trademarks. This License does not grant permission to use the trade
# names, trademarks, service marks, or product names of the Licensor
# and its affiliates, except as required to comply with Section 4(c) of
# the License and to reproduce the content of the NOTICE file.
#
# You may obtain a copy of the Apache License at
#
# http:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the Apache License with the above modification is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the Apache License for the specific
# language governing permissions and limitations under the Apache License.
#
# This file uses centimeters as units for non-parametric coordinates.
v 1.25052 0.517982 0.353553
v 0.597239 0.247384 0.353553
v 0.597239 0.247384 -0.353553
v 1.25052 0.517982 -0.353553
v 0.517982 1.25052 0.353553
v 0.247384 0.597239 0.353553
v 0.247384 0.597239 -0.353553
v 0.517982 1.25052 -0.353553
v -0.517982 1.25052 0.353553
v -0.247384 0.597239 0.353553
v -0.247384 0.597239 -0.353553
v -0.517982 1.25052 -0.353553
v -1.25052 0.517982 0.353553
v -0.597239 0.247384 0.353553
v -0.597239 0.247384 -0.353553
v -1.25052 0.517982 -0.353553
v -1.25052 -0.517982 0.353553
v -0.597239 -0.247384 0.353553
v -0.597239 -0.247384 -0.353553
v -1.25052 -0.517982 -0.353553
v -0.517982 -1.25052 0.353553
v -0.247384 -0.597239 0.353553
v -0.247384 -0.597239 -0.353553
v -0.517982 -1.25052 -0.353553
v 0.517982 -1.25052 0.353553
v 0.247384 -0.597239 0.353553
v 0.247384 -0.597239 -0.353553
v 0.517982 -1.25052 -0.353553
v 1.25052 -0.517982 0.353553
v 0.597239 -0.247384 0.353553
v 0.597239 -0.247384 -0.353553
v 1.25052 -0.517982 -0.353553
vt 0 0
vt 1 0
vt 1 1
vt 0 1
f 5/1/1 6/2/2 2/3/3 1/4/4
f 6/1/5 7/2/6 3/3/7 2/4/8
f 7/1/9 8/2/10 4/3/11 3/4/12
f 8/1/13 5/2/14 1/3/15 4/4/16
f 9/1/17 10/2/18 6/3/19 5/4/20
f 10/1/21 11/2/22 7/3/23 6/4/24
f 11/1/25 12/2/26 8/3/27 7/4/28
f 12/1/29 9/2/30 5/3/31 8/4/32
f 13/1/33 14/2/34 10/3/35 9/4/36
f 14/1/37 15/2/38 11/3/39 10/4/40
f 15/1/41 16/2/42 12/3/43 11/4/44
f 16/1/45 13/2/46 9/3/47 12/4/48
f 17/1/49 18/2/50 14/3/51 13/4/52
f 18/1/53 19/2/54 15/3/55 14/4/56
f 19/1/57 20/2/58 16/3/59 15/4/60
f 20/1/61 17/2/62 13/3/63 16/4/64
f 21/1/65 22/2/66 18/3/67 17/4/68
f 22/1/69 23/2/70 19/3/71 18/4/72
f 23/1/73 24/2/74 20/3/75 19/4/76
f 24/1/77 21/2/78 17/3/79 20/4/80
f 25/1/81 26/2/82 22/3/83 21/4/84
f 26/1/85 27/2/86 23/3/87 22/4/88
f 27/1/89 28/2/90 24/3/91 23/4/92
f 28/1/93 25/2/94 21/3/95 24/4/96
f 29/1/97 30/2/98 26/3/99 25/4/100
f 30/1/101 31/2/102 27/3/103 26/4/104
f 31/1/105 32/2/106 28/3/107 27/4/108
f 32/1/109 29/2/110 25/3/111 28/4/112
f 1/1/113 2/2/114 30/3/115 29/4/116
f 2/1/117 3/2/118 31/3/119 30/4/120
f 3/1/121 4/2/122 32/3/123 31/4/124
f 4/1/125 1/2/126 29/3/127 32/4/128
t crease 2/1/0 1 5 4.7
t crease 2/1/0 5 9 4.7
t crease 2/1/0 9 13 4.7
t crease 2/1/0 13 17 4.7
t crease 2/1/0 17 21 4.7
t crease 2/1/0 21 25 4.7
t crease 2/1/0 25 29 4.7
t crease 2/1/0 29 1 4.7

61
test.cc
View File

@@ -7,14 +7,16 @@
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes) static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes, bool triangulate = true)
{ {
std::cout << "# of shapes : " << shapes.size() << std::endl;
for (size_t i = 0; i < shapes.size(); i++) { for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str()); printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
printf("shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size()); printf("shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
assert((shapes[i].mesh.indices.size() % 3) == 0); if (triangulate)
{
assert((shapes[i].mesh.indices.size() % 3) == 0);
}
for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) { for (size_t f = 0; f < shapes[i].mesh.indices.size(); f++) {
printf(" idx[%ld] = %d\n", f, shapes[i].mesh.indices[f]); printf(" idx[%ld] = %d\n", f, shapes[i].mesh.indices[f]);
} }
@@ -28,6 +30,50 @@ static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes)
shapes[i].mesh.positions[3*v+2]); shapes[i].mesh.positions[3*v+2]);
} }
printf("shape[%ld].numFaces: %ld\n", i, shapes[i].mesh.numVertices.size());
for (size_t v = 0; v < shapes[i].mesh.numVertices.size(); v++) {
printf(" numVerts[%ld] = %ld\n", v,
(long) shapes[i].mesh.numVertices[v]);
}
printf("shape[%ld].numTags: %ld\n", i, shapes[i].mesh.tags.size());
for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) {
printf(" tag[%ld] = %s ", t, shapes[i].mesh.tags[t].name.c_str());
printf(" ints: [");
for (int j = 0; j < shapes[i].mesh.tags[t].intValues.size(); ++j)
{
printf("%ld", (long) shapes[i].mesh.tags[t].intValues[j]);
if (j < (shapes[i].mesh.tags[t].intValues.size()-1))
{
printf(", ");
}
}
printf("]");
printf(" floats: [");
for (int j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j)
{
printf("%f", shapes[i].mesh.tags[t].floatValues[j]);
if (j < (shapes[i].mesh.tags[t].floatValues.size()-1))
{
printf(", ");
}
}
printf("]");
printf(" strings: [");
for (int j = 0; j < shapes[i].mesh.tags[t].stringValues.size(); ++j)
{
printf("%s", shapes[i].mesh.tags[t].stringValues[j].c_str());
if (j < (shapes[i].mesh.tags[t].stringValues.size()-1))
{
printf(", ");
}
}
printf("]");
printf("\n");
}
printf("shape[%ld].material.name = %s\n", i, shapes[i].material.name.c_str()); printf("shape[%ld].material.name = %s\n", i, shapes[i].material.name.c_str());
printf(" material.Ka = (%f, %f ,%f)\n", shapes[i].material.ambient[0], shapes[i].material.ambient[1], shapes[i].material.ambient[2]); printf(" material.Ka = (%f, %f ,%f)\n", shapes[i].material.ambient[0], shapes[i].material.ambient[1], shapes[i].material.ambient[2]);
printf(" material.Kd = (%f, %f ,%f)\n", shapes[i].material.diffuse[0], shapes[i].material.diffuse[1], shapes[i].material.diffuse[2]); printf(" material.Kd = (%f, %f ,%f)\n", shapes[i].material.diffuse[0], shapes[i].material.diffuse[1], shapes[i].material.diffuse[2]);
@@ -54,19 +100,20 @@ static void PrintInfo(const std::vector<tinyobj::shape_t>& shapes)
static bool static bool
TestLoadObj( TestLoadObj(
const char* filename, const char* filename,
const char* basepath = NULL) const char* basepath = NULL,
bool triangulate = true)
{ {
std::cout << "Loading " << filename << std::endl; std::cout << "Loading " << filename << std::endl;
std::vector<tinyobj::shape_t> shapes; std::vector<tinyobj::shape_t> shapes;
std::string err = tinyobj::LoadObj(shapes, filename, basepath); std::string err = tinyobj::LoadObj(shapes, filename, basepath, triangulate);
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
return false; return false;
} }
PrintInfo(shapes); PrintInfo(shapes, triangulate);
return true; return true;
} }
@@ -174,7 +221,6 @@ main(
int argc, int argc,
char **argv) char **argv)
{ {
if (argc > 1) { if (argc > 1) {
const char* basepath = NULL; const char* basepath = NULL;
if (argc > 2) { if (argc > 2) {
@@ -185,6 +231,7 @@ main(
assert(true == TestLoadObj("cornell_box.obj")); assert(true == TestLoadObj("cornell_box.obj"));
assert(true == TestLoadObj("cube.obj")); assert(true == TestLoadObj("cube.obj"));
assert(true == TestStreamLoadObj()); assert(true == TestStreamLoadObj());
assert(true == TestLoadObj("catmark_torus_creases0.obj", NULL, false));
} }
return 0; return 0;

View File

@@ -38,6 +38,14 @@ struct vertex_index {
vertex_index(int vidx, int vtidx, int vnidx) : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}; vertex_index(int vidx, int vtidx, int vnidx) : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {};
}; };
struct tag_sizes {
tag_sizes() : num_ints(0), num_floats(0), num_strings(0) {}
int num_ints;
int num_floats;
int num_strings;
};
// for std::map // for std::map
static inline bool operator<(const vertex_index& a, const vertex_index& b) static inline bool operator<(const vertex_index& a, const vertex_index& b)
{ {
@@ -122,6 +130,30 @@ static inline void parseFloat3(
} }
static tag_sizes parseTagTriple(const char* & token)
{
tag_sizes ts;
ts.num_ints = atoi(token);
token += strcspn(token, "/ \t\r");
if (token[0] != '/') {
return ts;
}
token++;
ts.num_floats = atoi(token);
token += strcspn(token, "/ \t\r");
if (token[0] != '/') {
return ts;
}
token++;
ts.num_strings = atoi(token);
token += strcspn(token, "/ \t\r") + 1;
return ts;
}
// Parse triples: i, i/j/k, i//k, i/j // Parse triples: i, i/j/k, i//k, i/j
static vertex_index parseTriple( static vertex_index parseTriple(
const char* &token, const char* &token,
@@ -184,13 +216,13 @@ updateVertex(
positions.push_back(in_positions[3*i.v_idx+1]); positions.push_back(in_positions[3*i.v_idx+1]);
positions.push_back(in_positions[3*i.v_idx+2]); positions.push_back(in_positions[3*i.v_idx+2]);
if (i.vn_idx >= 0) { if (i.vn_idx >= 0 && (i.vn_idx * 3 + 2) < in_normals.size() ) {
normals.push_back(in_normals[3*i.vn_idx+0]); normals.push_back(in_normals[3*i.vn_idx+0]);
normals.push_back(in_normals[3*i.vn_idx+1]); normals.push_back(in_normals[3*i.vn_idx+1]);
normals.push_back(in_normals[3*i.vn_idx+2]); normals.push_back(in_normals[3*i.vn_idx+2]);
} }
if (i.vt_idx >= 0) { if (i.vt_idx >= 0 && (i.vt_idx * 2 +1) < in_texcoords.size()) {
texcoords.push_back(in_texcoords[2*i.vt_idx+0]); texcoords.push_back(in_texcoords[2*i.vt_idx+0]);
texcoords.push_back(in_texcoords[2*i.vt_idx+1]); texcoords.push_back(in_texcoords[2*i.vt_idx+1]);
} }
@@ -228,9 +260,11 @@ exportFaceGroupToShape(
const std::vector<float> &in_normals, const std::vector<float> &in_normals,
const std::vector<float> &in_texcoords, const std::vector<float> &in_texcoords,
const std::vector<std::vector<vertex_index> >& faceGroup, const std::vector<std::vector<vertex_index> >& faceGroup,
std::vector<tag_t>& tags,
const material_t &material, const material_t &material,
const std::string &name, const std::string &name,
const bool is_material_seted) const bool is_material_seted,
const bool triangulate)
{ {
if (faceGroup.empty()) { if (faceGroup.empty()) {
return false; return false;
@@ -247,26 +281,38 @@ exportFaceGroupToShape(
for (size_t i = 0; i < faceGroup.size(); i++) { for (size_t i = 0; i < faceGroup.size(); i++) {
const std::vector<vertex_index>& face = faceGroup[i]; const std::vector<vertex_index>& face = faceGroup[i];
vertex_index i0 = face[0];
vertex_index i1(-1);
vertex_index i2 = face[1];
size_t npolys = face.size(); size_t npolys = face.size();
// Polygon -> triangle fan conversion if (triangulate) {
for (size_t k = 2; k < npolys; k++) { vertex_index i0 = face[0];
i1 = i2; vertex_index i1(-1);
i2 = face[k]; vertex_index i2 = face[1];
unsigned int v0 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i0); // Polygon -> triangle fan conversion
unsigned int v1 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i1); for (size_t k = 2; k < npolys; k++) {
unsigned int v2 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i2); i1 = i2;
i2 = face[k];
indices.push_back(v0); unsigned int v0 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i0);
indices.push_back(v1); unsigned int v1 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i1);
indices.push_back(v2); unsigned int v2 = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, i2);
indices.push_back(v0);
indices.push_back(v1);
indices.push_back(v2);
shape.mesh.numVertices.push_back(3);
}
} }
else
{
for (size_t k = 0; k < npolys; k++) {
unsigned int v = updateVertex(vertexCache, positions, normals, texcoords, in_positions, in_normals, in_texcoords, face[k]);
indices.push_back(v);
shape.mesh.numVertices.push_back(npolys);
}
}
} }
// //
@@ -277,6 +323,7 @@ exportFaceGroupToShape(
shape.mesh.normals.swap(normals); shape.mesh.normals.swap(normals);
shape.mesh.texcoords.swap(texcoords); shape.mesh.texcoords.swap(texcoords);
shape.mesh.indices.swap(indices); shape.mesh.indices.swap(indices);
shape.mesh.tags.swap(tags);
if(is_material_seted) { if(is_material_seted) {
shape.material = material; shape.material = material;
@@ -499,7 +546,8 @@ std::string
LoadObj( LoadObj(
std::vector<shape_t>& shapes, std::vector<shape_t>& shapes,
const char* filename, const char* filename,
const char* mtl_basepath) const char* mtl_basepath,
bool triangulate)
{ {
shapes.clear(); shapes.clear();
@@ -518,19 +566,22 @@ LoadObj(
} }
MaterialFileReader matFileReader( basePath ); MaterialFileReader matFileReader( basePath );
return LoadObj(shapes, ifs, matFileReader); return LoadObj(shapes, ifs, matFileReader, triangulate);
} }
std::string LoadObj( std::string LoadObj(
std::vector<shape_t>& shapes, std::vector<shape_t>& shapes,
std::istream& inStream, std::istream& inStream,
MaterialReader& readMatFn) MaterialReader& readMatFn,
bool triangulate)
{ {
std::stringstream err; std::stringstream err;
std::vector<float> v; std::vector<float> v;
std::vector<float> vn; std::vector<float> vn;
std::vector<float> vt; std::vector<float> vt;
std::vector<tag_t> tags;
std::vector<std::vector<vertex_index> > faceGroup; std::vector<std::vector<vertex_index> > faceGroup;
std::string name; std::string name;
@@ -656,7 +707,7 @@ std::string LoadObj(
// flush previous face group. // flush previous face group.
shape_t shape; shape_t shape;
bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name, is_material_seted); bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, tags, material, name, is_material_seted, triangulate);
if (ret) { if (ret) {
shapes.push_back(shape); shapes.push_back(shape);
} }
@@ -688,7 +739,7 @@ std::string LoadObj(
// flush previous face group. // flush previous face group.
shape_t shape; shape_t shape;
bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name, is_material_seted); bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, tags, material, name, is_material_seted, triangulate);
if (ret) { if (ret) {
shapes.push_back(shape); shapes.push_back(shape);
} }
@@ -706,11 +757,51 @@ std::string LoadObj(
continue; continue;
} }
if (token[0] == 't' && isSpace(token[1])) {
tag_t tag;
char namebuf[4096];
token += 2;
sscanf(token, "%s", namebuf);
tag.name = std::string(namebuf);
token += tag.name.size() + 1;
tag_sizes ts = parseTagTriple(token);
tag.intValues.resize(ts.num_ints);
for(int i = 0; i < ts.num_ints; ++i)
{
tag.intValues[i] = atoi(token);
token += strcspn(token, "/ \t\r") + 1;
}
tag.floatValues.resize(ts.num_floats);
for(int i = 0; i < ts.num_floats; ++i)
{
tag.floatValues[i] = parseFloat(token);
token += strcspn(token, "/ \t\r") + 1;
}
tag.stringValues.resize(ts.num_strings);
for(int i = 0; i < ts.num_strings; ++i)
{
char stringValueBuffer[4096];
sscanf(token, "%s", stringValueBuffer);
tag.stringValues[i] = stringValueBuffer;
token += tag.stringValues[i].size() + 1;
}
tags.push_back(tag);
}
// Ignore unknown command. // Ignore unknown command.
} }
shape_t shape; shape_t shape;
bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, material, name, is_material_seted); bool ret = exportFaceGroupToShape(shape, v, vn, vt, faceGroup, tags, material, name, is_material_seted, triangulate);
if (ret) { if (ret) {
shapes.push_back(shape); shapes.push_back(shape);
} }

View File

@@ -34,12 +34,23 @@ typedef struct
std::map<std::string, std::string> unknown_parameter; std::map<std::string, std::string> unknown_parameter;
} material_t; } material_t;
typedef struct
{
std::string name;
std::vector<int> intValues;
std::vector<float> floatValues;
std::vector<std::string> stringValues;
} tag_t;
typedef struct typedef struct
{ {
std::vector<float> positions; std::vector<float> positions;
std::vector<float> normals; std::vector<float> normals;
std::vector<float> texcoords; std::vector<float> texcoords;
std::vector<unsigned int> indices; std::vector<unsigned int> indices;
std::vector<unsigned char> numVertices; //Is it worth it 255 faces
std::vector<tag_t> tags;
} mesh_t; } mesh_t;
typedef struct typedef struct
@@ -82,7 +93,9 @@ class MaterialFileReader:
std::string LoadObj( std::string LoadObj(
std::vector<shape_t>& shapes, // [output] std::vector<shape_t>& shapes, // [output]
const char* filename, const char* filename,
const char* mtl_basepath = NULL); const char* mtl_basepath = NULL,
bool triangulate = true
);
/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve /// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve
/// std::istream for materials. /// std::istream for materials.
@@ -90,7 +103,8 @@ std::string LoadObj(
std::string LoadObj( std::string LoadObj(
std::vector<shape_t>& shapes, // [output] std::vector<shape_t>& shapes, // [output]
std::istream& inStream, std::istream& inStream,
MaterialReader& readMatFn); MaterialReader& readMatFn,
bool triangulate = true);
/// Loads materials into std::map /// Loads materials into std::map
/// Returns an empty string if successful /// Returns an empty string if successful