Git Product home page Git Product logo

tinyobjloader's Introduction

tinyobjloader

PyPI version

AZ Build Status

AppVeyor Build status

Coverage Status

AUR version

Tiny but powerful single file wavefront obj loader written in C++03. No dependency except for C++ STL. It can parse over 10M polygons with moderate memory and time.

tinyobjloader is good for embedding .obj loader to your (global illumination) renderer ;-)

If you are looking for C89 version, please see https://github.com/syoyo/tinyobjloader-c .

Version notice

We recommend to use master(main) branch. Its v2.0 release candidate. Most features are now nearly robust and stable(Remaining task for release v2.0 is polishing C++ and Python API, and fix built-in triangulation code).

We have released new version v1.0.0 on 20 Aug, 2016. Old version is available as v0.9.x branch https://github.com/syoyo/tinyobjloader/tree/v0.9.x

What's new

  • 29 Jul, 2021 : Added Mapbox's earcut for robust triangulation. Also fixes triangulation bug(still there is some issue in built-in triangulation algorithm: #319).
  • 19 Feb, 2020 : The repository has been moved to https://github.com/tinyobjloader/tinyobjloader !
  • 18 May, 2019 : Python binding!(See python folder. Also see https://pypi.org/project/tinyobjloader/)
  • 14 Apr, 2019 : Bump version v2.0.0 rc0. New C++ API and python bindings!(1.x API still exists for backward compatibility)
  • 20 Aug, 2016 : Bump version v1.0.0. New data structure and API!

Requirements

  • C++03 compiler

Old version

Previous old version is available in v0.9.x branch.

Example

Rungholt

tinyobjloader can successfully load 6M triangles Rungholt scene. http://casual-effects.com/data/index.html

Use case

TinyObjLoader is successfully used in ...

New version(v1.0.x)

Old version(v0.9.x)

Features

Primitives

  • face(f)
  • lines(l)
  • points(p)
  • curve
  • 2D curve
  • surface.
  • Free form curve/surfaces

Material

  • PBR material extension for .MTL. Please see pbr-mtl.md for details.
  • Texture options
  • Unknown material attributes are returned as key-value(value is string) map.

TODO

  • Fix obj_sticker example.
  • More unit test codes.

License

TinyObjLoader is licensed under MIT license.

Third party licenses.

  • pybind11 : BSD-style license.
  • mapbox earcut.hpp: ISC License.

Usage

Installation

One option is to simply copy the header file into your project and to make sure that TINYOBJLOADER_IMPLEMENTATION is defined exactly once.

Building tinyobjloader - Using vcpkg(not recommended though)

Although it is not a recommended way, you can download and install tinyobjloader using the vcpkg dependency manager:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install tinyobjloader

The tinyobjloader port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

Data format

attrib_t contains single and linear array of vertex data(position, normal and texcoord).

attrib_t::vertices => 3 floats per vertex

       v[0]        v[1]        v[2]        v[3]               v[n-1]
  +-----------+-----------+-----------+-----------+      +-----------+
  | x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z |
  +-----------+-----------+-----------+-----------+      +-----------+

attrib_t::normals => 3 floats per vertex

       n[0]        n[1]        n[2]        n[3]               n[n-1]
  +-----------+-----------+-----------+-----------+      +-----------+
  | x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z |
  +-----------+-----------+-----------+-----------+      +-----------+

attrib_t::texcoords => 2 floats per vertex

       t[0]        t[1]        t[2]        t[3]               t[n-1]
  +-----------+-----------+-----------+-----------+      +-----------+
  |  u  |  v  |  u  |  v  |  u  |  v  |  u  |  v  | .... |  u  |  v  |
  +-----------+-----------+-----------+-----------+      +-----------+

attrib_t::colors => 3 floats per vertex(vertex color. optional)

       c[0]        c[1]        c[2]        c[3]               c[n-1]
  +-----------+-----------+-----------+-----------+      +-----------+
  | x | y | z | x | y | z | x | y | z | x | y | z | .... | x | y | z |
  +-----------+-----------+-----------+-----------+      +-----------+

Each shape_t::mesh_t does not contain vertex data but contains array index to attrib_t. See loader_example.cc for more details.


mesh_t::indices => array of vertex indices.

  +----+----+----+----+----+----+----+----+----+----+     +--------+
  | i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7 | i8 | i9 | ... | i(n-1) |
  +----+----+----+----+----+----+----+----+----+----+     +--------+

Each index has an array index to attrib_t::vertices, attrib_t::normals and attrib_t::texcoords.

mesh_t::num_face_vertices => array of the number of vertices per face(e.g. 3 = triangle, 4 = quad , 5 or more = N-gons).


  +---+---+---+        +---+
  | 3 | 4 | 3 | ...... | 3 |
  +---+---+---+        +---+
    |   |   |            |
    |   |   |            +-----------------------------------------+
    |   |   |                                                      |
    |   |   +------------------------------+                       |
    |   |                                  |                       |
    |   +------------------+               |                       |
    |                      |               |                       |
    |/                     |/              |/                      |/

 mesh_t::indices

  |    face[0]   |       face[1]     |    face[2]   |     |      face[n-1]           |
  +----+----+----+----+----+----+----+----+----+----+     +--------+--------+--------+
  | i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7 | i8 | i9 | ... | i(n-3) | i(n-2) | i(n-1) |
  +----+----+----+----+----+----+----+----+----+----+     +--------+--------+--------+

Note that when triangulate flag is true in tinyobj::LoadObj() argument, num_face_vertices are all filled with 3(triangle).

float data type

TinyObjLoader now use real_t for floating point data type. Default is float(32bit). You can enable double(64bit) precision by using TINYOBJLOADER_USE_DOUBLE define.

Robust triangulation

When you enable triangulation(default is enabled), TinyObjLoader triangulate polygons(faces with 4 or more vertices).

Built-in trinagulation code may not work well in some polygon shape.

You can define TINYOBJLOADER_USE_MAPBOX_EARCUT for robust triangulation using mapbox/earcut.hpp. This requires C++11 compiler though. And you need to copy mapbox/earcut.hpp to your project. If you have your own mapbox/earcut.hpp file incuded in your project, you can define TINYOBJLOADER_DONOT_INCLUDE_MAPBOX_EARCUT so that mapbox/earcut.hpp is not included inside of tiny_obj_loader.h.

Example code (Deprecated API)

#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
// Optional. define TINYOBJLOADER_USE_MAPBOX_EARCUT gives robust trinagulation. Requires C++11
//#define TINYOBJLOADER_USE_MAPBOX_EARCUT
#include "tiny_obj_loader.h"

std::string inputfile = "cornell_box.obj";
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, inputfile.c_str());

if (!warn.empty()) {
  std::cout << warn << std::endl;
}

if (!err.empty()) {
  std::cerr << err << std::endl;
}

if (!ret) {
  exit(1);
}

// Loop over shapes
for (size_t s = 0; s < shapes.size(); s++) {
  // Loop over faces(polygon)
  size_t index_offset = 0;
  for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) {
    size_t fv = size_t(shapes[s].mesh.num_face_vertices[f]);

    // Loop over vertices in the face.
    for (size_t v = 0; v < fv; v++) {
      // access to vertex
      tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];

      tinyobj::real_t vx = attrib.vertices[3*size_t(idx.vertex_index)+0];
      tinyobj::real_t vy = attrib.vertices[3*size_t(idx.vertex_index)+1];
      tinyobj::real_t vz = attrib.vertices[3*size_t(idx.vertex_index)+2];

      // Check if `normal_index` is zero or positive. negative = no normal data
      if (idx.normal_index >= 0) {
        tinyobj::real_t nx = attrib.normals[3*size_t(idx.normal_index)+0];
        tinyobj::real_t ny = attrib.normals[3*size_t(idx.normal_index)+1];
        tinyobj::real_t nz = attrib.normals[3*size_t(idx.normal_index)+2];
      }

      // Check if `texcoord_index` is zero or positive. negative = no texcoord data
      if (idx.texcoord_index >= 0) {
        tinyobj::real_t tx = attrib.texcoords[2*size_t(idx.texcoord_index)+0];
        tinyobj::real_t ty = attrib.texcoords[2*size_t(idx.texcoord_index)+1];
      }
      // Optional: vertex colors
      // tinyobj::real_t red   = attrib.colors[3*size_t(idx.vertex_index)+0];
      // tinyobj::real_t green = attrib.colors[3*size_t(idx.vertex_index)+1];
      // tinyobj::real_t blue  = attrib.colors[3*size_t(idx.vertex_index)+2];
    }
    index_offset += fv;

    // per-face material
    shapes[s].mesh.material_ids[f];
  }
}

Example code (New Object Oriented API)

#define TINYOBJLOADER_IMPLEMENTATION // define this in only *one* .cc
// Optional. define TINYOBJLOADER_USE_MAPBOX_EARCUT gives robust trinagulation. Requires C++11
//#define TINYOBJLOADER_USE_MAPBOX_EARCUT
#include "tiny_obj_loader.h"


std::string inputfile = "cornell_box.obj";
tinyobj::ObjReaderConfig reader_config;
reader_config.mtl_search_path = "./"; // Path to material files

tinyobj::ObjReader reader;

if (!reader.ParseFromFile(inputfile, reader_config)) {
  if (!reader.Error().empty()) {
      std::cerr << "TinyObjReader: " << reader.Error();
  }
  exit(1);
}

if (!reader.Warning().empty()) {
  std::cout << "TinyObjReader: " << reader.Warning();
}

auto& attrib = reader.GetAttrib();
auto& shapes = reader.GetShapes();
auto& materials = reader.GetMaterials();

// Loop over shapes
for (size_t s = 0; s < shapes.size(); s++) {
  // Loop over faces(polygon)
  size_t index_offset = 0;
  for (size_t f = 0; f < shapes[s].mesh.num_face_vertices.size(); f++) {
    size_t fv = size_t(shapes[s].mesh.num_face_vertices[f]);

    // Loop over vertices in the face.
    for (size_t v = 0; v < fv; v++) {
      // access to vertex
      tinyobj::index_t idx = shapes[s].mesh.indices[index_offset + v];
      tinyobj::real_t vx = attrib.vertices[3*size_t(idx.vertex_index)+0];
      tinyobj::real_t vy = attrib.vertices[3*size_t(idx.vertex_index)+1];
      tinyobj::real_t vz = attrib.vertices[3*size_t(idx.vertex_index)+2];

      // Check if `normal_index` is zero or positive. negative = no normal data
      if (idx.normal_index >= 0) {
        tinyobj::real_t nx = attrib.normals[3*size_t(idx.normal_index)+0];
        tinyobj::real_t ny = attrib.normals[3*size_t(idx.normal_index)+1];
        tinyobj::real_t nz = attrib.normals[3*size_t(idx.normal_index)+2];
      }

      // Check if `texcoord_index` is zero or positive. negative = no texcoord data
      if (idx.texcoord_index >= 0) {
        tinyobj::real_t tx = attrib.texcoords[2*size_t(idx.texcoord_index)+0];
        tinyobj::real_t ty = attrib.texcoords[2*size_t(idx.texcoord_index)+1];
      }

      // Optional: vertex colors
      // tinyobj::real_t red   = attrib.colors[3*size_t(idx.vertex_index)+0];
      // tinyobj::real_t green = attrib.colors[3*size_t(idx.vertex_index)+1];
      // tinyobj::real_t blue  = attrib.colors[3*size_t(idx.vertex_index)+2];
    }
    index_offset += fv;

    // per-face material
    shapes[s].mesh.material_ids[f];
  }
}

Optimized loader

Optimized multi-threaded .obj loader is available at experimental/ directory. If you want absolute performance to load .obj data, this optimized loader will fit your purpose. Note that the optimized loader uses C++11 thread and it does less error checks but may work most .obj data.

Here is some benchmark result. Time are measured on MacBook 12(Early 2016, Core m5 1.2GHz).

  • Rungholt scene(6M triangles)
    • old version(v0.9.x): 15500 msecs.
    • baseline(v1.0.x): 6800 msecs(2.3x faster than old version)
    • optimised: 1500 msecs(10x faster than old version, 4.5x faster than baseline)

Python binding

$ python -m pip install tinyobjloader

See python/sample.py for example use of Python binding of tinyobjloader.

CI + PyPI upload

cibuildwheels + twine upload for each git tagging event is handled in Github Actions and Cirrus CI(arm builds).

How to bump version(For developer)

  • Apply black to python files(python/sample.py)
  • Bump version in CMakeLists.txt
  • Commit and push release. Confirm C.I. build is OK.
  • Create tag starting with v(e.g. v2.1.0)
  • git push --tags
    • version settings is automatically handled in python binding through setuptools_scm.
    • cibuildwheels + pypi upload(through twine) will be automatically triggered in Github Actions + Cirrus CI.

Tests

Unit tests are provided in tests directory. See tests/README.md for details.

tinyobjloader's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tinyobjloader's Issues

Export cmake package

http://www.cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file

libraries, but also tools that could be useful as a build-utility, such as documentation generators, wrapper generators, etc.) should provide at a minimum a Config.cmake or a -config.cmake file. This file can then be used by the find_package() command in config-mode to provide information about include-directories, libraries and their dependencies, required compile-flags or locations of executables.

mtl files with both 'd' and 'Tr' set behave unexpectedly

I've noticed this with many commercial model files, which have materials defined something like:

newmtl my_material
        ... 
        d 1.0000
        Tr 0.0000
        ...

The loader will first set dissolve to 1, then overwrite it and set it to 0. The result is a material that is fully transparent even though it is intended to be fully visible.

Is it not possible to deal with this? I assume it is a model exporting problem (there really should only be either 'd' or 'Tr' and not both), but it seems to be common.

Thanks

per face material, why

Hello Syoyo,
What was the decision behind having per-face material?

Looking in the exportFaceGroupToShape function, I notice that it is assigned the same material_id for the facegroup for all faces, but I couldn't find an application that this material_id change in a shape, looks that it is all the same.

If that is need, wouldn't it be nicer to have another degree level of an hierarchy so you only store one material_id per facegroup?
I am thinking that for some renders it is not practical to assign a material to every triangle face. With your actual structure, it would be need to detect while still using the same material_id and then switch to the next one.

Could you please clarify?
Thanks!

Multiple Group Name

Hi @syoyo , great work !

As you write // @todo { multiple group name. } , do you have sth in mind ? For my project multiple group naming is essential and I'll code for it.

From my perspective; I need another struct to push child shape's.

typedef struct
{
    std::string  name;
    std::vector<shape_t>  shapes;
} object3D_t;

normal generation

It would be really great if the library could generate normals, based on the smoothing groups, if the model itself doesn't contain any normals.

issue loading mtl file with spaces in file path

Hi syoyo

while reading the obj file if it contains a mtllib directive with a file name like "Female Cyborg.mtl" the mtllib file name will incorrectly be parsed as Female (only extracts the first word before the space) this cause the MaterialFileReader to create default materials

Bad allocation Error rungholt scene

The blog post on http://swarminglogic.com/jotting/2013_10_gamedev01 lead me to this nice little library. Sadly for the rungholt scene i get an bad allocation during loading the rungholt scene from http://graphics.cs.williams.edu/data/meshes.xml

// group name
if (token[0] == 'g' && isSpace((token[1]))) {

  // flush previous face group.
  bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt,
                                    faceGroup, material, name, true);
  if (ret) {
    shapes.push_back(shape);
  }

  shape = shape_t();/// bad allocation

It might be very important to note that I get a bad allocation error with the assimp model loader library for this scene as well, so it could be very much a problem on my side, but I would appreciate any guidance to fix/solve the problem :)

Edit: OK with the release built and in release mode the library does not seem to fail (/Ox). Still it takes like 5 minutes to load the rungholt scene. What could I possibly do wrong that it takes that long as swarmlogic reported like 38 seconds.

Edit: Ok i guess the bad allocation is because the 32bit exe is running into its 2GB limit when started in debug mode from VS2013, so I think this is not a fault of tinyobjloader. I think this issue can be closed, as I do not think there is much that tinyobjloader could do against that :)

Uninitialized member warning

While building the library, the compiler reports several uninitialized variables in

struct vertex_index
in file tiny_obj_loader.h

The members

int v_idx, vt_idx, vn_idx;
are not initilaized by the default constructor
vertex_index() {}
which might lead to undefined behaviour.

Can those members be set to some kind of "uninitialized" value (-1 maybe)?
I did not look into the usage of the struct. If this case is already covered by other code, then please add default values to silence this warning.

Compiler warnings are

Member 'v_idx' was not initialized in this constructor
Member 'vn_idx' was not initialized in this constructor
Member 'vt_idx' was not initialized in this constructor

File not imported correctly

Hi,
when importing this obj I get wird results.
First to notice is the indicies count not dividable by 3 for left sphere even though only triangles are present it seems to be capped at 1999.
The position array contains 1883 values, the obj file contains 546 vertices for this object so that should be 1638 position values shouldn't it?

Im am running arch linux.
Programming in Clion with the included compiler.

skip trailing whitespace in mtl names (map_kd)

If the mtl file contains any space at the end, but before the newline, it gets added to the texture filename.

Add a line like follows to fix it:
linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1);

Problem with some OBJs with shared UV coords

This OBJ file: http://ow.ly/4mHMap (simple cube model from Maya - 8 pts, 6 faces, 14 uv coords)causes that: http://ow.ly/4mIdkx
"i" is one of the points that already cached, just with difference uv ref, since it's interconnected mesh/faces. As you can see, vertexCache already has 8 points in it, and this is going to be 9th, since std::map thinks they're differs. Which is obviously incorrect.

Upon loading this file there's 42 elements in mesh.positions, yielding 14 points instead of 8.
The reason is that code(line ~450, i reformatted the header):

static unsigned int updateVertex(std::map<vertex_index, unsigned int> &vertexCache, std::vector &positions, std::vector &normals, std::vector &texcoords, const std::vector &in_positions, const std::vector &in_normals, const std::vector &in_texcoords, const vertex_index &i)
{
const std::map<vertex_index, unsigned int>::iterator it = vertexCache.find(i);
if(it != vertexCache.end()) { return it->second; } // return vtx number if yes

Produces redundant points in mesh.positions when one of the points with the idx that already was cached, using different texture coord(for different face).
I'm afraid that proper change(with compacted UVs/references to them) will require massive rewrite of the lib.

loading blender OBJ

Hello there, amazing library you got there and I am actively using on my 3d viewport project , nice and clean and you saved me a lot of time to write a proper loader.
I just have one problem , It looks like I am not able to load obj exported from blender,
I saw both the obj you have in the repo and I the blender one they are pretty much the same having hard time pin pointing the problem . Any clue ? (obj coming from Autodesk maya works fine even high load of points).
Here's the blender obj :

mtllib cube.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
usemtl Material
s off
f 1 2 3 4
f 5 8 7 6
f 1 5 6 2
f 2 6 7 3
f 3 7 8 4
f 5 1 4 8

Keep up the great work 👍

Populate array buffer with data in attrib_t directly?

Hi

I found that in order to populate array buffer, all examples make a copy of every position, normal, etc to create a new vertex.
I was wondering if there is a way to avoid it, so we can populate array buffer directly from attrib_t? Current attrib_t contains all information for all the shapes, i have no luck in finding the boundary between shapes.

By the way, I'm new to opengl and tinyobjloader and .obj file.

Normals index buffers

Hi,
I see that you define the shape structure in this way
typedef struct {
std::vector positions;
std::vector normals;
std::vector texcoords;
std::vector indices;
std::vector material_ids; // per-mesh material ID
} mesh_t;

Which only stores the index buffer for vertices, what happen when you have more information per vertex ? for example I get from maya a face definition like this:
f 7/7/13 8/8/14 1/9/15

I assume that the extra information just gets lost?
The problem came up when I notice that using a cube I was getting a normal buffer with 24 normals and of course the index buffer was only using the first 8 elements.

Do you think it might be possible to support those extra information?
For now I am just recomputing the normals and averaging them since I don't need per face per vertex normals.

UTF-8 filepath support

If file path have non latin characters (cyrilic in my case) then function LoadObj drops error message "Cannot open file [" << filename << "]" .
Is it possible to add support of UTF-8 encoding for file paths?

Linux par parseFloat3 and parseFloat2 bug

Hi,
I had a problem with your OBJ loader on linux Ubuntu. Using your version of parseFloat3 and parseFloat2 functions the parsed values of vertices, normals and UV were wrong. I do know where was exactly the problem but if I replaced in parseFloat3 (same in parseFloat2):
x = parseFloat(token);
y = parseFloat(token);
z = parseFloat(token);

with:
std::stringstream ss;
ss << token;
ss >> x;
ss >> y;
ss >> z;

this solved my problem. I know that std::stringstream is slower than your implementation but it works, thats fine for me. I did't have any problem on Windows only on linux. I'm going to use tinyobjloader in my project: http://awesomebump.besaba.com/
Best regards,
Krzysztof Kolasinski

Give LoadObj's istream overload a default material reader implementation

LoadObj has an overload that takes a istream, however it also takes a MaterialReader* readMatFn parameter that has no default value. There is an implementation provided in tinyobjloader for this class, but it expects a filename, and opens the ifstream itself.

It is simple enough for me to build my own implementation (copy and paste the version that takes a filename, and modify a couple simple lines), but I think it would be convenient to provide a MaterialReader implementation that takes an existing istream. It would also be convenient to make the default value NULL, the way that LoadObjWithCallback already does, since LoadObj already handles the null case.

My use case is that I have built some slightly complex loading logic to find and open a file stream, and I pass that stream into my resource loaders so they can do their job. This lets me centralize search paths logic, and allows me to abstract my stream sources so that I can do automated testing without touching the filesystem.

Support for Java?

Hello. Will support for Java platforms? In Java very need obj loader...

.mtl File Location

It seems like the .mtl file needs to be in the same directory as the executable in order to work, which it should be in the same directory as the .obj file.

I am on a Mac so it might be different.

Support for multiple materials per object/group

While trying to load Crytek's Sponza model I found out that tinyobjloader does not support multiple materials per group.
I have implemented such support - but it is a bit hacky with substantially changed interface to better suit my needs(I converted obj to binary format in order to improve loading times for demo). My implementation is here sopyer@33cd9a4.

Easy fix: double->float conversion warning

I would normally give a pull request, but forking isn't working today for some reason.

tiny_obj_loader.cc line 564:

material.dissolve = 1.0 - parseFloat(token);

emits a warning in Visual Studio 2015:

tiny_obj_loader.cc(564): warning C4244: '=': conversion from 'double' to 'float', possible loss of data

Fix is simple, just add the suffix f:

material.dissolve = 1.0f - parseFloat(token);

How we use indices when vt or vn index is omitted.

Hi syoyo.
Thanks for your project. I have referred your code for my project MGRRenderer.

I have one question for it.
In updateVertex(), you have not registered the normal value to normals in case normal index is omitted such as 1//3, this is same as textures, therefore it looks that indices exist only for positions but not for normals or textcoords in mesh_t

Therefore I have no way to use glDrtawElements of OpenGLES2 when normal and textcoords do not exist.

LoadObjWithCallback() Triangulation

Does LoadObjWithCallback() triangulate non-triangles?
If it doesn't, then how can the app know how many vertices are in the face, since each index generates an independent callback?
OTOH, the function header documentation mentions:
/// 'triangulate' is optional, and used whether triangulate polygon face in .obj or not.
but the function does not have this argument at all!
There seems to be some inconsistency here.

"err" is missing in README.md

Please, add "err" at README.md:90.

bool ret = tinyobj::LoadObj(shapes, materials, inputfile.c_str());
bool ret = tinyobj::LoadObj(shapes, materials, err, inputfile.c_str());

Thanks!

map_Ns interpreted wrong; bump map support missing

The map_Ns directive in an MTL file specifies a map for the shininess parameter (aka specular exponent). See https://en.wikipedia.org/wiki/Wavefront_.obj_file#Texture_maps and http://www.fileformat.info/format/material/.

However, tinyobjloader stores it in material_t.normal_texname, indicating that it stores a normal map.
This is confusing.

As far as I know, OBJ does not actually support "real" normal maps, only the simpler variant of bump maps, using the "map_bump" or "bump" directive. Tinyobjloader does not currently support bump maps; it would be nice to have material_t.bump_texname for that purpose.

No longer able to build python module

Previously I was able to build the tinyobjloader module for Python however in the latest version of master branch I am having trouble on Windows and Linux.

This is the last commit (Aug 8, 2015) I was able to build for python 3 with compile warnings (python2 build failed):
https://github.com/syoyo/tinyobjloader/tree/d299576eac0b6400873b291fa496bf5ef876a206

Output on latest

(available at https://github.com/syoyo/tinyobjloader /tree/475bc83ef3193198f145896abc864429ef07fdbf)

Ubuntu Linux with Python 3.4.3:

python3 setup.py build
running build
running build_ext
building 'tinyobjloader' extension
creating build
creating build/temp.linux-x86_64-3.4
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -g -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -fPIC -I/usr/include/python3.4m -c main.cpp -o build/temp.linux-x86_64-3.4/main.o
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
main.cpp: In function ‘PyObject* pyLoadObj(PyObject_, PyObject_)’:
main.cpp:66:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "positions";
^
main.cpp:69:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "normals";
^
main.cpp:72:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "texcoords";
^
main.cpp:75:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "indicies";
^
main.cpp:78:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "material_ids";
^
main.cpp:108:84: error: ‘struct tinyobj::material_t’ has no member named ‘normal_texname’
PyDict_SetItemString(matobj, "normal_texname", PyUnicode_FromString((_mat).normal_texname.c_str()));
^
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

Output for python 2.7:

python setup.py build
running build
running build_ext
building 'tinyobjloader' extension
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c main.cpp -o build/temp.linux-x86_64-2.7/main.o
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
main.cpp: In function ‘PyObject* pyLoadObj(PyObject_, PyObject_)’:
main.cpp:66:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "positions";
^
main.cpp:69:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "normals";
^
main.cpp:72:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "texcoords";
^
main.cpp:75:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "indicies";
^
main.cpp:78:30: warning: deprecated conversion from string constant to ‘char_’ [-Wwrite-strings]
current_name = "material_ids";
^
main.cpp:108:84: error: ‘struct tinyobj::material_t’ has no member named ‘normal_texname’
PyDict_SetItemString(matobj, "normal_texname", PyUnicode_FromString((_mat).normal_texname.c_str()));
^
main.cpp: At global scope:
main.cpp:133:27: error: variable ‘PyModuleDef moduledef’ has initializer but incomplete type
static struct PyModuleDef moduledef = {
^
main.cpp:134:5: error: ‘PyModuleDef_HEAD_INIT’ was not declared in this scope
PyModuleDef_HEAD_INIT,
^
main.cpp: In function ‘void PyInit_tinyobjloader()’:
main.cpp:145:38: error: ‘PyModule_Create’ was not declared in this scope
return PyModule_Create(&moduledef);
^
main.cpp:145:38: error: return-statement with a value, in function returning 'void' [-fpermissive]
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

map_Kd etc

why not use strnicmp,there always get nothing

No material loaded sponza

When I try to load the crytek-sponza scene from http://graphics.cs.williams.edu/data/meshes.xml then it seems like no material is loaded.

As the main page wrote:
Feb 06, 2015 : Fix parsing multi-material object

The objects indeed have only 1 material as far as I can tell but assumed the loader can handle multi-material now it should also be able to handle one or none ;)

I expected this to work now:
auto tinyMaterialsN = shapes[i].mesh.material_ids.size();
has the value 3640

std::vectortinyobj::material_t materials;
std::string err = tinyobj::LoadObj(shapes, materials, fullpath.c_str());

materials has size == 1 with no name, no texture, nothing.

Each mesh has a different number of material_ids but all values are -1 so this definetly looks like a bug

OBJ texture coordinates can have 3 elements

According to the OBJ specification, the vt element may have up to 3 elements.
If the 3rd is missing it defaults to 0.
The current callback API only returns 2 coordinates: void (*texcoord_cb)(void *user_data, float x, float y);

NULL material path causes warning on LoadObj

When calling LoadObj without an material base path, the function returns an non-empty error string

WARN: Material file [ sphere.mtl ] not found. Created a default material..

According to the documentation

/// Returns empty string when loading .obj success.

This should not happen, also I am using size() != 0 of the return string as error checking mechanism which fails in this case where I just want to load the mesh without the material data.

Wrong number of shapes reported

The tinyobj loader reports 2 shapes for an obj file containing only 1 shape (1 object group, "o").
This used to work in earlier versions and only became an issue after updating to the latest version (Master).
I am loading only the obj file without an mtl file.

Edit: Seems I cannot seem to upload the affected mesh file, I will provide a direct link to the file in my repository
https://github.com/redagito/CG2015/blob/master/data/mesh/enemy.obj

I suspect the line 812:

usemtl Material.003

to be the cause of the problem

Edit 2: Removing the line fixed the issue, it should still be considered a bug though

how about add a optional function to normalize data?

i know it will change the origin data,but after loadobj,the data have been group,normalize is a little harder,i think do it after parse all vertex data and add a optional to normalize it or not,is it resonable?

original indexes buffer?

Hi, I have been using this library for a while and is great! now I am trying to implement skincluster deformation , aka bone deformation on the geometry,
I was already able to implement skeleton and animation out of maya into my program. Now I exported skin information per vertex out of maya.
The library due to be able to use a single index buffer for opengl (which is correct) duplicates some data, like vertex, uvs etc. The problem is that doing so I am not able to know what indexes the duplicated vertex come from so I cannot remap it to the original data.
Would it be possible to generate extra buffers mapping to original points aswell? Basically the index buffer I would get if no duplication happened? I understand that this is extra data and not always useful. What about having an overloaded function or a flag that generates that data only if requested?

Is something you think would be possible to add in?

M.

The problem when loading texture coordinate

HI,
Thanks for your project, but there is a wired problem when i using the branch normal-texcoord-indices,I want to get the normal indices and texcoord information into my program,but when i debugging, all the indices(normal,texture,position) are the same. I don't think it's the right answer of the obj file. is there anything wrong with my understand?

How to load obj as non-grouped?

Hello, I have problems with single load OBJ. Need load obj without partition. But with it I have problems. I not found in internet how unify OBJ. I have no enough memory build octree per every group, so need load obj as one part.

ifstream::getline doesn't handle non-native lf-cr-and-crlf

tinyobjloader uses ifstream::getline, which fails to handle files with different line endings, for example copied from a different operating system. The filename (mtl file or texture file) can have a \r appended, and the file fails to load.

See discussion here:
See http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf

I fixed it in my Bullet fork using the stackoverflow solution:
See https://github.com/bulletphysics/bullet3/blob/master/examples/ThirdPartyLibs/Wavefront/tiny_obj_loader.cpp#L33

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.