ObjLoad and Texture


#1

Hi,

I try to load and .obj and its .mtl via cinder but I have some problem.

Textures are not shown when I render the scene and I also have some rendering problems.

This is how I load the obj:

      std::string obj = "/Users/thewoz/Research/LIBRARIES/TEST/Cinder/samples/_opengl/ObjLoader2/AcrimSat/AcrimSat_FINAL_2013.obj";
      std::string mtl = "/Users/thewoz/Research/LIBRARIES/TEST/Cinder/samples/_opengl/ObjLoader2/AcrimSat/acrimsat_final_2013.mtl";

      ObjLoader loader(loadFile(obj), loadFile(mtl));
      
      mMesh = TriMesh::create(loader);
      
      if(!loader.getAvailableAttribs().count(geom::NORMAL)) mMesh->recalculateNormals();
      
      auto lambertShader = gl::getStockShader(gl::ShaderDef().color().lambert());
      mBatch = gl::Batch::create( *mMesh, lambertShader );

and this is how I render it:

    gl::enableDepthWrite();
	gl::enableDepthRead();
	
	gl::clear(Color(0.0f, 0.1f, 0.2f));

	gl::setMatrices(mCam);

	gl::pushMatrices();
  
    mBatch->draw();
  
	gl::popMatrices();

This are the differences between cinder and the same file open with Cheetah 3D

How you can see the textures are missing and there are also some rendering issue.

What I’m doing wrong?

Here my obj and code https://files.fm/u/qzcdefhh


#2

Try adding .texture() to the stock shader. That should fix it, but only if ObjLoader supports materials and textures (it’s been a while since I used it, so I’m not sure if it does).


#3

This is the result with

gl::getStockShader(gl::ShaderDef().color().texture().lambert());

same with

gl::getStockShader(gl::ShaderDef().texture().lambert());
gl::getStockShader(gl::ShaderDef().texture());


#4

You’re not binding a texture before you draw. ObjLoader doesn’t load the textures for you, you’ll need to load and bind them yourself.


#5

I’m sorry but I did not expect this behavior.
I thought that by passing to the ObjLoader the mtl file, the library also load ad bind the textures.
How can I do it manually?


#6

Hi,

support for loading models in Cinder has always been rather limited. I know it’s not an excuse, but since there are so many 3D file formats and proper support always requires elaborate data structures, you’d almost need a full-fledged engine backend to do it properly. That is why most users rely on third-party libraries like Assimp or glTF to load models, materials, textures and animations.

Unfortunately, Cinder’s ObjLoader does not extract texture information from the .mtl file. If you look at the source code, you’ll notice it ignores “map_Kd” and similar statements. It would be relatively easy to add a std::string to the Material class which contains the filename. You could then at least use loader.getGroups() to retrieve all groups, followed by iterating over group.mFaces to retrieve all faces, followed by face.mMaterial to get to the material. But as you can see, you’d have to dive pretty deep into the data structure to get your list of textures. The OBJ file format isn’t exactly optimised for easy access. But then again, that goes for most 3D file formats. You’d also have to write your own shaders to actually use the textures, because Cinder’s stock shaders have no support for e.g. normal mapping, light mapping, bump mapping, parallax occlusion mapping, etc.

I’d recommend looking at the Cinder-Assimp block to load your models instead. I haven’t used it myself (I rely on a concoction of my own that is not ready for a public release), but it looks like it’s still being maintained. As a bonus, you get full support for animations and there is even some documentation :slight_smile: If you’re feeling more adventurous, there is also the glTF block for Cinder. More blocks can be found via this awesome link.

-Paul


#7

I know, but I think that a full support, at least to the obj format, would be a good thing for the library. Maybe it would be nice to have in the documentation the support status of the obj and mtl format in Cinder.

This is exactly what I tried to do. However it would be necessary to change the various classes. Especially the material struct.

This is the real problem. Additionally shaders depend a lot on how the entire data structure is implemented. Moreover write shaders is not my strong one.

I have seen this Cinder-Assimp block and it seems to be still alive. Obviously it is not very documented and I would not like to start coding with something that might die from one moment to the next. By the way I have some code that I use to load a model via Assimp which is based on another data structure and could hardly be reused.

Unfortunately I do not think I have enough skills to try something so advanced.

I’m really undecided about what to do.

  1. If you try to implement a loader just for the obj and mtl format separated by Cinder.

  2. Extend the support for the obj and mtl format directly into Cinder. But that would mean putting hands on into the Cinder’s class and stock shaders.

  3. Or continue to develop my code to load the models through Assimp.


#8

You could copy the ObjLoader class files, rename them slightly and add them to your project. That way, you can tinker with it however much you like.


#9

As usual, paul is totally right that you will wind up loading your 3d data in a custom way most of the time, but the few times where performance isn’t a concern (read: i was too lazy to bother), i’ve gotten decent mileage out of tiny obj loader