tinyobjloader / tinyobjloader Goto Github PK
View Code? Open in Web Editor NEWTiny but powerful single file wavefront obj loader
License: Other
Tiny but powerful single file wavefront obj loader
License: Other
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.
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.
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
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?
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?
There's a crash on MS compilers resulting from a missing buffer size when using sscanf_s.
All
sscanf_s(token, "%s", namebuf);
should read:
sscanf_s(token, "%s", namebuf, 4096);
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.
Adding support for parsing extra MTL attribute as suggested here.
http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr
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.
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
(available at https://github.com/syoyo/tinyobjloader /tree/475bc83ef3193198f145896abc864429ef07fdbf)
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
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
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.
I can't seem to decide e.g. from http://www.martinreddy.net/gfx/3d/OBJ.spec if spaces are allowed in .mtl
filenames, but I have some files where this is the case and they cannot be read because:
https://github.com/syoyo/tinyobjloader/blob/master/tiny_obj_loader.cc#L784-L792
uses sscanf
to read a space delimited string.
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.
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.
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
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
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
No support for texture options. If options are present, they are read in as part of the texture path.
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 👍
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.
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
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.
Simply add a
if (material_id != -1)
@tiny_obj_loader.cc:406
Thanks
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);
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
PS:
This occurred in the Viewer example which I rewrite it in openGLES1.1, and run it on the GalaxyNote2 Android phone. Hope for anyone's help ;)
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!
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.
Should loading an empty .obj file generate an error?
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.
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.
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);
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);
After this fix: #68
If a file ends with usemtl, the last exportFaceGroupToShape (https://github.com/syoyo/tinyobjloader/blob/master/tiny_obj_loader.h#L1340) returns false because the faceGroup is empty.
As a consequence, the last shape is lost.
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!
why not use strnicmp,there always get nothing
src/App.cpp: In member function ‘void App::draw(float)’:
src/App.cpp:266:35: error: ‘struct tinyobj::attrib_t’ has no member named ‘positions’
float vx = attrib.positions[3*idx.vertex_index+0];
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.
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
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 :)
First of all many thanks for sharing this nice library! I have more or less completed a basic wrapper package for R https://github.com/jefferis/readobj.
I have noticed a small bug. If the mtl file cannot be found then an empty material is added. This is because
std::ifstream matIStream(filepath.c_str());
is not checked here https://github.com/syoyo/tinyobjloader/blob/master/tiny_obj_loader.cc#L614-L627.
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.
Add more facility to load .mtl. e.g., parse diffuse texture name.
Hello,
Looking at the code I expected it to flatten out mixed triangle and quad meshes into triangle meshes. However trying to read such data, as per the usage section of the main project page, results in a garbled mess. As for a file that displays this behaviour:
http://www.sci.utah.edu/~wald/animrep/fairy/fairy.obj.tgz
e.g. f000.obj.
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?
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.
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;
Hello. Will support for Java platforms? In Java very need obj loader...
The parsed MTL filename is used directly to load the MTL file. If the OBJ file is given with a path, it will fail. Thus merge the parent path of the OBJ file and the MTL filename.
thx
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.