This commit is contained in:
Syoyo Fujita
2016-07-25 22:46:30 +09:00
parent 5826f1e149
commit 22883def8d
5 changed files with 370 additions and 170 deletions

View File

@@ -4,19 +4,19 @@
#define TINYOBJLOADER_IMPLEMENTATION #define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h" #include "tiny_obj_loader.h"
#include <cassert>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cassert> #include <fstream>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <fstream>
#ifdef _WIN32 #ifdef _WIN32
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#include <windows.h>
#include <mmsystem.h> #include <mmsystem.h>
#include <windows.h>
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -30,7 +30,7 @@ extern "C" {
#endif #endif
class timerutil { class timerutil {
public: public:
#ifdef _WIN32 #ifdef _WIN32
typedef DWORD time_t; typedef DWORD time_t;
@@ -58,7 +58,8 @@ public:
static_cast<time_t>((tv[1].tv_usec - tv[0].tv_usec) / 1000); static_cast<time_t>((tv[1].tv_usec - tv[0].tv_usec) / 1000);
} }
time_t usec() { time_t usec() {
return this->sec() * 1000000 + static_cast<time_t>(tv[1].tv_usec - tv[0].tv_usec); return this->sec() * 1000000 +
static_cast<time_t>(tv[1].tv_usec - tv[0].tv_usec);
} }
time_t current() { time_t current() {
struct timeval t; struct timeval t;
@@ -66,7 +67,7 @@ public:
return static_cast<time_t>(t.tv_sec * 1000 + t.tv_usec); return static_cast<time_t>(t.tv_sec * 1000 + t.tv_usec);
} }
#else // C timer #else // C timer
// using namespace std; // using namespace std;
typedef clock_t time_t; typedef clock_t time_t;
@@ -81,7 +82,7 @@ public:
#endif #endif
#endif #endif
private: private:
#ifdef _WIN32 #ifdef _WIN32
DWORD t_[2]; DWORD t_[2];
#else #else
@@ -94,96 +95,103 @@ private:
#endif #endif
}; };
static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj::shape_t>& shapes, const std::vector<tinyobj::material_t>& materials) static void PrintInfo(const tinyobj::attrib_t& attrib,
{ const std::vector<tinyobj::shape_t>& shapes,
const std::vector<tinyobj::material_t>& materials) {
std::cout << "# of vertices : " << (attrib.vertices.size() / 3) << std::endl; std::cout << "# of vertices : " << (attrib.vertices.size() / 3) << std::endl;
std::cout << "# of normals : " << (attrib.normals.size() / 3) << std::endl; std::cout << "# of normals : " << (attrib.normals.size() / 3) << std::endl;
std::cout << "# of texcoords : " << (attrib.texcoords.size() / 2) << std::endl; std::cout << "# of texcoords : " << (attrib.texcoords.size() / 2)
<< std::endl;
std::cout << "# of shapes : " << shapes.size() << std::endl; std::cout << "# of shapes : " << shapes.size() << std::endl;
std::cout << "# of materials : " << materials.size() << std::endl; std::cout << "# of materials : " << materials.size() << std::endl;
for (size_t v = 0; v < attrib.vertices.size() / 3; v++) { for (size_t v = 0; v < attrib.vertices.size() / 3; v++) {
printf(" v[%ld] = (%f, %f, %f)\n", static_cast<long>(v), printf(" v[%ld] = (%f, %f, %f)\n", static_cast<long>(v),
static_cast<const double>(attrib.vertices[3*v+0]), static_cast<const double>(attrib.vertices[3 * v + 0]),
static_cast<const double>(attrib.vertices[3*v+1]), static_cast<const double>(attrib.vertices[3 * v + 1]),
static_cast<const double>(attrib.vertices[3*v+2])); static_cast<const double>(attrib.vertices[3 * v + 2]));
} }
for (size_t v = 0; v < attrib.normals.size() / 3; v++) { for (size_t v = 0; v < attrib.normals.size() / 3; v++) {
printf(" n[%ld] = (%f, %f, %f)\n", static_cast<long>(v), printf(" n[%ld] = (%f, %f, %f)\n", static_cast<long>(v),
static_cast<const double>(attrib.normals[3*v+0]), static_cast<const double>(attrib.normals[3 * v + 0]),
static_cast<const double>(attrib.normals[3*v+1]), static_cast<const double>(attrib.normals[3 * v + 1]),
static_cast<const double>(attrib.normals[3*v+2])); static_cast<const double>(attrib.normals[3 * v + 2]));
} }
for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) { for (size_t v = 0; v < attrib.texcoords.size() / 2; v++) {
printf(" uv[%ld] = (%f, %f)\n", static_cast<long>(v), printf(" uv[%ld] = (%f, %f)\n", static_cast<long>(v),
static_cast<const double>(attrib.texcoords[2*v+0]), static_cast<const double>(attrib.texcoords[2 * v + 0]),
static_cast<const double>(attrib.texcoords[2*v+1])); static_cast<const double>(attrib.texcoords[2 * v + 1]));
} }
// For each shape // For each shape
for (size_t i = 0; i < shapes.size(); i++) { for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", static_cast<long>(i), shapes[i].name.c_str()); printf("shape[%ld].name = %s\n", static_cast<long>(i),
printf("Size of shape[%ld].indices: %lu\n", static_cast<long>(i), static_cast<unsigned long>(shapes[i].mesh.indices.size())); shapes[i].name.c_str());
printf("Size of shape[%ld].indices: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].mesh.indices.size()));
size_t index_offset = 0; size_t index_offset = 0;
assert(shapes[i].mesh.num_face_vertices.size() == shapes[i].mesh.material_ids.size()); assert(shapes[i].mesh.num_face_vertices.size() ==
shapes[i].mesh.material_ids.size());
printf("shape[%ld].num_faces: %lu\n", static_cast<long>(i), static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size())); printf("shape[%ld].num_faces: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].mesh.num_face_vertices.size()));
// For each face // For each face
for (size_t f = 0; f < shapes[i].mesh.num_face_vertices.size(); f++) { for (size_t f = 0; f < shapes[i].mesh.num_face_vertices.size(); f++) {
size_t fnum = shapes[i].mesh.num_face_vertices[f]; size_t fnum = shapes[i].mesh.num_face_vertices[f];
printf(" face[%ld].fnum = %ld\n", static_cast<long>(f), static_cast<unsigned long>(fnum)); printf(" face[%ld].fnum = %ld\n", static_cast<long>(f),
static_cast<unsigned long>(fnum));
// For each vertex in the face // For each vertex in the face
for (size_t v = 0; v < fnum; v++) { for (size_t v = 0; v < fnum; v++) {
tinyobj::index_t idx = shapes[i].mesh.indices[index_offset + v]; tinyobj::index_t idx = shapes[i].mesh.indices[index_offset + v];
printf(" face[%ld].v[%ld].idx = %d/%d/%d\n", static_cast<long>(f), static_cast<long>(v), idx.vertex_index, idx.normal_index, idx.texcoord_index); printf(" face[%ld].v[%ld].idx = %d/%d/%d\n", static_cast<long>(f),
} static_cast<long>(v), idx.vertex_index, idx.normal_index,
idx.texcoord_index);
}
printf(" face[%ld].material_id = %d\n", static_cast<long>(f), shapes[i].mesh.material_ids[f]); printf(" face[%ld].material_id = %d\n", static_cast<long>(f),
shapes[i].mesh.material_ids[f]);
index_offset += fnum; index_offset += fnum;
} }
printf("shape[%ld].num_tags: %lu\n", static_cast<long>(i), static_cast<unsigned long>(shapes[i].mesh.tags.size())); printf("shape[%ld].num_tags: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].mesh.tags.size()));
for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) { for (size_t t = 0; t < shapes[i].mesh.tags.size(); t++) {
printf(" tag[%ld] = %s ", static_cast<long>(t), shapes[i].mesh.tags[t].name.c_str()); printf(" tag[%ld] = %s ", static_cast<long>(t),
shapes[i].mesh.tags[t].name.c_str());
printf(" ints: ["); printf(" ints: [");
for (size_t j = 0; j < shapes[i].mesh.tags[t].intValues.size(); ++j) for (size_t j = 0; j < shapes[i].mesh.tags[t].intValues.size(); ++j) {
{ printf("%ld", static_cast<long>(shapes[i].mesh.tags[t].intValues[j]));
printf("%ld", static_cast<long>(shapes[i].mesh.tags[t].intValues[j])); if (j < (shapes[i].mesh.tags[t].intValues.size() - 1)) {
if (j < (shapes[i].mesh.tags[t].intValues.size()-1)) printf(", ");
{ }
printf(", ");
}
} }
printf("]"); printf("]");
printf(" floats: ["); printf(" floats: [");
for (size_t j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j) for (size_t j = 0; j < shapes[i].mesh.tags[t].floatValues.size(); ++j) {
{ printf("%f", static_cast<const double>(
printf("%f", static_cast<const double>(shapes[i].mesh.tags[t].floatValues[j])); shapes[i].mesh.tags[t].floatValues[j]));
if (j < (shapes[i].mesh.tags[t].floatValues.size()-1)) if (j < (shapes[i].mesh.tags[t].floatValues.size() - 1)) {
{ printf(", ");
printf(", "); }
}
} }
printf("]"); printf("]");
printf(" strings: ["); printf(" strings: [");
for (size_t j = 0; j < shapes[i].mesh.tags[t].stringValues.size(); ++j) for (size_t j = 0; j < shapes[i].mesh.tags[t].stringValues.size(); ++j) {
{ printf("%s", shapes[i].mesh.tags[t].stringValues[j].c_str());
printf("%s", shapes[i].mesh.tags[t].stringValues[j].c_str()); if (j < (shapes[i].mesh.tags[t].stringValues.size() - 1)) {
if (j < (shapes[i].mesh.tags[t].stringValues.size()-1)) printf(", ");
{ }
printf(", ");
}
} }
printf("]"); printf("]");
printf("\n"); printf("\n");
@@ -191,25 +199,59 @@ static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj
} }
for (size_t i = 0; i < materials.size(); i++) { for (size_t i = 0; i < materials.size(); i++) {
printf("material[%ld].name = %s\n", static_cast<long>(i), materials[i].name.c_str()); printf("material[%ld].name = %s\n", static_cast<long>(i),
printf(" material.Ka = (%f, %f ,%f)\n", static_cast<const double>(materials[i].ambient[0]), static_cast<const double>(materials[i].ambient[1]), static_cast<const double>(materials[i].ambient[2])); materials[i].name.c_str());
printf(" material.Kd = (%f, %f ,%f)\n", static_cast<const double>(materials[i].diffuse[0]), static_cast<const double>(materials[i].diffuse[1]), static_cast<const double>(materials[i].diffuse[2])); printf(" material.Ka = (%f, %f ,%f)\n",
printf(" material.Ks = (%f, %f ,%f)\n", static_cast<const double>(materials[i].specular[0]), static_cast<const double>(materials[i].specular[1]), static_cast<const double>(materials[i].specular[2])); static_cast<const double>(materials[i].ambient[0]),
printf(" material.Tr = (%f, %f ,%f)\n", static_cast<const double>(materials[i].transmittance[0]), static_cast<const double>(materials[i].transmittance[1]), static_cast<const double>(materials[i].transmittance[2])); static_cast<const double>(materials[i].ambient[1]),
printf(" material.Ke = (%f, %f ,%f)\n", static_cast<const double>(materials[i].emission[0]), static_cast<const double>(materials[i].emission[1]), static_cast<const double>(materials[i].emission[2])); static_cast<const double>(materials[i].ambient[2]));
printf(" material.Ns = %f\n", static_cast<const double>(materials[i].shininess)); printf(" material.Kd = (%f, %f ,%f)\n",
static_cast<const double>(materials[i].diffuse[0]),
static_cast<const double>(materials[i].diffuse[1]),
static_cast<const double>(materials[i].diffuse[2]));
printf(" material.Ks = (%f, %f ,%f)\n",
static_cast<const double>(materials[i].specular[0]),
static_cast<const double>(materials[i].specular[1]),
static_cast<const double>(materials[i].specular[2]));
printf(" material.Tr = (%f, %f ,%f)\n",
static_cast<const double>(materials[i].transmittance[0]),
static_cast<const double>(materials[i].transmittance[1]),
static_cast<const double>(materials[i].transmittance[2]));
printf(" material.Ke = (%f, %f ,%f)\n",
static_cast<const double>(materials[i].emission[0]),
static_cast<const double>(materials[i].emission[1]),
static_cast<const double>(materials[i].emission[2]));
printf(" material.Ns = %f\n",
static_cast<const double>(materials[i].shininess));
printf(" material.Ni = %f\n", static_cast<const double>(materials[i].ior)); printf(" material.Ni = %f\n", static_cast<const double>(materials[i].ior));
printf(" material.dissolve = %f\n", static_cast<const double>(materials[i].dissolve)); printf(" material.dissolve = %f\n",
printf(" material.illum = %d\n", materials[i].illum); static_cast<const double>(materials[i].dissolve));
printf(" material.illum = %d\n", materials[i].illum);
printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str()); printf(" material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str()); printf(" material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str()); printf(" material.map_Ks = %s\n", materials[i].specular_texname.c_str());
printf(" material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str()); printf(" material.map_Ns = %s\n",
materials[i].specular_highlight_texname.c_str());
printf(" material.map_bump = %s\n", materials[i].bump_texname.c_str()); printf(" material.map_bump = %s\n", materials[i].bump_texname.c_str());
printf(" material.map_d = %s\n", materials[i].alpha_texname.c_str()); printf(" material.map_d = %s\n", materials[i].alpha_texname.c_str());
printf(" material.disp = %s\n", materials[i].displacement_texname.c_str()); printf(" material.disp = %s\n", materials[i].displacement_texname.c_str());
std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin()); printf(" <<PBR>>\n");
std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end()); printf(" material.Pr = %f\n", materials[i].roughness);
printf(" material.Pm = %f\n", materials[i].metallic);
printf(" material.Ps = %f\n", materials[i].sheen);
printf(" material.Pc = %f\n", materials[i].clearcoat_thickness);
printf(" material.Pcr = %f\n", materials[i].clearcoat_thickness);
printf(" material.aniso = %f\n", materials[i].anisotropy);
printf(" material.anisor = %f\n", materials[i].anisotropy_rotation);
printf(" material.map_Ke = %s\n", materials[i].emissive_texname.c_str());
printf(" material.map_Pr = %s\n", materials[i].roughness_texname.c_str());
printf(" material.map_Pm = %s\n", materials[i].metallic_texname.c_str());
printf(" material.map_Ps = %s\n", materials[i].sheen_texname.c_str());
printf(" material.norm = %s\n", materials[i].normal_texname.c_str());
std::map<std::string, std::string>::const_iterator it(
materials[i].unknown_parameter.begin());
std::map<std::string, std::string>::const_iterator itEnd(
materials[i].unknown_parameter.end());
for (; it != itEnd; it++) { for (; it != itEnd; it++) {
printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str()); printf(" material.%s = %s\n", it->first.c_str(), it->second.c_str());
@@ -218,12 +260,8 @@ static void PrintInfo(const tinyobj::attrib_t &attrib, const std::vector<tinyobj
} }
} }
static bool static bool TestLoadObj(const char* filename, const char* basepath = NULL,
TestLoadObj( bool triangulate = true) {
const char* filename,
const char* basepath = NULL,
bool triangulate = true)
{
std::cout << "Loading " << filename << std::endl; std::cout << "Loading " << filename << std::endl;
tinyobj::attrib_t attrib; tinyobj::attrib_t attrib;
@@ -233,7 +271,8 @@ TestLoadObj(
timerutil t; timerutil t;
t.start(); t.start();
std::string err; std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, basepath, triangulate); bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename,
basepath, triangulate);
t.end(); t.end();
printf("Parsing time: %lu [msecs]\n", t.msec()); printf("Parsing time: %lu [msecs]\n", t.msec());
@@ -251,102 +290,96 @@ TestLoadObj(
return true; return true;
} }
static bool TestStreamLoadObj() {
static bool
TestStreamLoadObj()
{
std::cout << "Stream Loading " << std::endl; std::cout << "Stream Loading " << std::endl;
std::stringstream objStream; std::stringstream objStream;
objStream objStream << "mtllib cube.mtl\n"
<< "mtllib cube.mtl\n" "\n"
"\n" "v 0.000000 2.000000 2.000000\n"
"v 0.000000 2.000000 2.000000\n" "v 0.000000 0.000000 2.000000\n"
"v 0.000000 0.000000 2.000000\n" "v 2.000000 0.000000 2.000000\n"
"v 2.000000 0.000000 2.000000\n" "v 2.000000 2.000000 2.000000\n"
"v 2.000000 2.000000 2.000000\n" "v 0.000000 2.000000 0.000000\n"
"v 0.000000 2.000000 0.000000\n" "v 0.000000 0.000000 0.000000\n"
"v 0.000000 0.000000 0.000000\n" "v 2.000000 0.000000 0.000000\n"
"v 2.000000 0.000000 0.000000\n" "v 2.000000 2.000000 0.000000\n"
"v 2.000000 2.000000 0.000000\n" "# 8 vertices\n"
"# 8 vertices\n" "\n"
"\n" "g front cube\n"
"g front cube\n" "usemtl white\n"
"usemtl white\n" "f 1 2 3 4\n"
"f 1 2 3 4\n" "g back cube\n"
"g back cube\n" "# expects white material\n"
"# expects white material\n" "f 8 7 6 5\n"
"f 8 7 6 5\n" "g right cube\n"
"g right cube\n" "usemtl red\n"
"usemtl red\n" "f 4 3 7 8\n"
"f 4 3 7 8\n" "g top cube\n"
"g top cube\n" "usemtl white\n"
"usemtl white\n" "f 5 1 4 8\n"
"f 5 1 4 8\n" "g left cube\n"
"g left cube\n" "usemtl green\n"
"usemtl green\n" "f 5 6 2 1\n"
"f 5 6 2 1\n" "g bottom cube\n"
"g bottom cube\n" "usemtl white\n"
"usemtl white\n" "f 2 6 7 3\n"
"f 2 6 7 3\n" "# 6 elements";
"# 6 elements";
std::string matStream( std::string matStream(
"newmtl white\n" "newmtl white\n"
"Ka 0 0 0\n" "Ka 0 0 0\n"
"Kd 1 1 1\n" "Kd 1 1 1\n"
"Ks 0 0 0\n" "Ks 0 0 0\n"
"\n" "\n"
"newmtl red\n" "newmtl red\n"
"Ka 0 0 0\n" "Ka 0 0 0\n"
"Kd 1 0 0\n" "Kd 1 0 0\n"
"Ks 0 0 0\n" "Ks 0 0 0\n"
"\n" "\n"
"newmtl green\n" "newmtl green\n"
"Ka 0 0 0\n" "Ka 0 0 0\n"
"Kd 0 1 0\n" "Kd 0 1 0\n"
"Ks 0 0 0\n" "Ks 0 0 0\n"
"\n" "\n"
"newmtl blue\n" "newmtl blue\n"
"Ka 0 0 0\n" "Ka 0 0 0\n"
"Kd 0 0 1\n" "Kd 0 0 1\n"
"Ks 0 0 0\n" "Ks 0 0 0\n"
"\n" "\n"
"newmtl light\n" "newmtl light\n"
"Ka 20 20 20\n" "Ka 20 20 20\n"
"Kd 1 1 1\n" "Kd 1 1 1\n"
"Ks 0 0 0"); "Ks 0 0 0");
using namespace tinyobj; using namespace tinyobj;
class MaterialStringStreamReader: class MaterialStringStreamReader : public MaterialReader {
public MaterialReader public:
{ MaterialStringStreamReader(const std::string& matSStream)
public: : m_matSStream(matSStream) {}
MaterialStringStreamReader(const std::string& matSStream): m_matSStream(matSStream) {} virtual ~MaterialStringStreamReader() {}
virtual ~MaterialStringStreamReader() {} virtual bool operator()(const std::string& matId,
virtual bool operator() ( std::vector<material_t>* materials,
const std::string& matId, std::map<std::string, int>* matMap,
std::vector<material_t>* materials, std::string* err) {
std::map<std::string, int>* matMap, (void)matId;
std::string* err) (void)err;
{ LoadMtl(matMap, materials, &m_matSStream);
(void)matId; return true;
(void)err; }
LoadMtl(matMap, materials, &m_matSStream);
return true;
}
private: private:
std::stringstream m_matSStream; std::stringstream m_matSStream;
}; };
MaterialStringStreamReader matSSReader(matStream); MaterialStringStreamReader matSSReader(matStream);
tinyobj::attrib_t attrib; tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes; std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials; std::vector<tinyobj::material_t> materials;
std::string err; std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, &objStream, &matSSReader); bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, &objStream,
&matSSReader);
if (!err.empty()) { if (!err.empty()) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
} }
@@ -356,15 +389,11 @@ std::string matStream(
} }
PrintInfo(attrib, shapes, materials); PrintInfo(attrib, shapes, materials);
return true; return true;
} }
int int main(int argc, char** argv) {
main(
int argc,
char **argv)
{
if (argc > 1) { if (argc > 1) {
const char* basepath = "models/"; const char* basepath = "models/";
if (argc > 2) { if (argc > 2) {
@@ -372,10 +401,11 @@ main(
} }
assert(true == TestLoadObj(argv[1], basepath)); assert(true == TestLoadObj(argv[1], basepath));
} else { } else {
//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("models/catmark_torus_creases0.obj", "models/", false)); assert(true ==
TestLoadObj("models/catmark_torus_creases0.obj", "models/", false));
} }
return 0; return 0;

19
models/pbr-mat-ext.mtl Normal file
View File

@@ -0,0 +1,19 @@
# .MTL with PBR extension.
newmtl pbr
Ka 0 0 0
Kd 1 1 1
Ks 0 0 0
Ke 0.1 0.1 0.1
Pr 0.2
Pm 0.3
Ps 0.4
Pc 0.5
Pcr 0.6
aniso 0.7
anisor 0.8
map_Pr roughness.tex
map_Pm metallic.tex
map_Ps sheen.tex
map_Ke emissive.tex
norm normalmap.tex

10
models/pbr-mat-ext.obj Normal file
View File

@@ -0,0 +1,10 @@
mtllib pbr-mat-ext.mtl
o floor
usemtl pbr
v 552.8 0.0 0.0
v 0.0 0.0 0.0
v 0.0 0.0 559.2
v 549.6 0.0 559.2
f 1 2 3 4

View File

@@ -293,7 +293,7 @@ std::string matStream(
return true; return true;
} }
const char* gMtlBasePath = "../models"; const char* gMtlBasePath = "../models/";
TEST_CASE("cornell_box", "[Loader]") { TEST_CASE("cornell_box", "[Loader]") {
@@ -319,6 +319,34 @@ TEST_CASE("catmark_torus_creases0", "[Loader]") {
REQUIRE(8 == shapes[0].mesh.tags.size()); REQUIRE(8 == shapes[0].mesh.tags.size());
} }
TEST_CASE("pbr", "[Loader]") {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string err;
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "../models/pbr-mat-ext.obj", gMtlBasePath, /*triangulate*/false);
if (!err.empty()) {
std::cerr << err << std::endl;
}
REQUIRE(true == ret);
REQUIRE(1 == materials.size());
REQUIRE(0.2 == Approx(materials[0].roughness));
REQUIRE(0.3 == Approx(materials[0].metallic));
REQUIRE(0.4 == Approx(materials[0].sheen));
REQUIRE(0.5 == Approx(materials[0].clearcoat_thickness));
REQUIRE(0.6 == Approx(materials[0].clearcoat_roughness));
REQUIRE(0.7 == Approx(materials[0].anisotropy));
REQUIRE(0.8 == Approx(materials[0].anisotropy_rotation));
REQUIRE(0 == materials[0].roughness_texname.compare("roughness.tex"));
REQUIRE(0 == materials[0].metallic_texname.compare("metallic.tex"));
REQUIRE(0 == materials[0].sheen_texname.compare("sheen.tex"));
REQUIRE(0 == materials[0].emissive_texname.compare("emissive.tex"));
REQUIRE(0 == materials[0].normal_texname.compare("normalmap.tex"));
}
TEST_CASE("stream_load", "[Stream]") { TEST_CASE("stream_load", "[Stream]") {
REQUIRE(true == TestStreamLoadObj()); REQUIRE(true == TestStreamLoadObj());
} }

View File

@@ -91,6 +91,22 @@ typedef struct {
std::string bump_texname; // map_bump, bump std::string bump_texname; // map_bump, bump
std::string displacement_texname; // disp std::string displacement_texname; // disp
std::string alpha_texname; // map_d std::string alpha_texname; // map_d
// PBR extension
// http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
float roughness; // [0, 1] default 0
float metallic; // [0, 1] default 0
float sheen; // [0, 1] default 0
float clearcoat_thickness; // [0, 1] default 0
float clearcoat_roughness; // [0, 1] default 0
float anisotropy; // aniso. [0, 1] default 0
float anisotropy_rotation; // anisor. [0, 1] default 0
std::string roughness_texname; // map_Pr
std::string metallic_texname; // map_Pm
std::string sheen_texname; // map_Ps
std::string emissive_texname; // map_Ke
std::string normal_texname; // norm. For normal mapping.
std::map<std::string, std::string> unknown_parameter; std::map<std::string, std::string> unknown_parameter;
} material_t; } material_t;
@@ -156,7 +172,6 @@ typedef struct callback_t_ {
mtllib_cb(NULL), mtllib_cb(NULL),
group_cb(NULL), group_cb(NULL),
object_cb(NULL) {} object_cb(NULL) {}
} callback_t; } callback_t;
class MaterialReader { class MaterialReader {
@@ -563,6 +578,20 @@ static void InitMaterial(material_t *material) {
material->dissolve = 1.f; material->dissolve = 1.f;
material->shininess = 1.f; material->shininess = 1.f;
material->ior = 1.f; material->ior = 1.f;
material->roughness = 0.f;
material->metallic = 0.f;
material->sheen = 0.f;
material->clearcoat_thickness = 0.f;
material->clearcoat_roughness = 0.f;
material->anisotropy_rotation = 0.f;
material->anisotropy = 0.f;
material->roughness_texname = "";
material->metallic_texname = "";
material->sheen_texname = "";
material->emissive_texname = "";
material->normal_texname = "";
material->unknown_parameter.clear(); material->unknown_parameter.clear();
} }
@@ -779,6 +808,55 @@ void LoadMtl(std::map<std::string, int> *material_map,
continue; continue;
} }
// PBR: roughness
if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) {
token += 2;
material.roughness = parseFloat(&token);
continue;
}
// PBR: metallic
if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) {
token += 2;
material.metallic = parseFloat(&token);
continue;
}
// PBR: sheen
if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) {
token += 2;
material.sheen = parseFloat(&token);
continue;
}
// PBR: clearcoat thickness
if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) {
token += 2;
material.clearcoat_thickness = parseFloat(&token);
continue;
}
// PBR: clearcoat roughness
if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) {
token += 4;
material.clearcoat_roughness = parseFloat(&token);
continue;
}
// PBR: anisotropy
if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) {
token += 6;
material.anisotropy = parseFloat(&token);
continue;
}
// PBR: anisotropy rotation
if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) {
token += 7;
material.anisotropy_rotation = parseFloat(&token);
continue;
}
// ambient texture // ambient texture
if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) {
token += 7; token += 7;
@@ -835,6 +913,41 @@ void LoadMtl(std::map<std::string, int> *material_map,
continue; continue;
} }
// PBR: roughness texture
if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) {
token += 7;
material.roughness_texname = token;
continue;
}
// PBR: metallic texture
if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) {
token += 7;
material.metallic_texname = token;
continue;
}
// PBR: sheen texture
if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) {
token += 7;
material.sheen_texname = token;
continue;
}
// PBR: emissive texture
if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) {
token += 7;
material.emissive_texname = token;
continue;
}
// PBR: normal map texture
if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) {
token += 5;
material.normal_texname = token;
continue;
}
// unknown parameter // unknown parameter
const char *_space = strchr(token, ' '); const char *_space = strchr(token, ' ');
if (!_space) { if (!_space) {