Adjacency to index buffer from trimesh

hey everyone!

I would like to generate an index buffer with adjacency information to send to a geometry shader for silhouette extraction (along the lines of openGL cookbook and P. Rideout’s blog). I have an .obj file loaded with the objLoader into a trimesh and… that’s about it at the moment. building the shader looks to be no problem. so my request is for some help generating that index buffer.

here is a screenshot of the foundation.

textured plane: check.
cel shaded bird from .obj file (complete with randomized, bird-like hopping behavior): check.
wouldn’t it be great to help me check off stylized bold outlines?

throw me a bone, anyone?

Hi,

a TriMesh, by default, is not really suitable for that kind of thing. It only supports GL_TRIANGLES, meaning that for each triangle there are 3 indices in the index buffer. There is no adjacency information available, because this is not stored in an OBJ file, anyway.

The way I see it you have 2 options:

  1. Create your own mesh from scratch.
  2. Parse the TriMesh one triangle at a time and try to reconstruct adjacency info from it. If two triangles share two vertices, you know they are adjacent to each other. Then build a new index buffer and set the primitive type to GL_TRIANGLES_ADJACENCY.

-Paul

Thanks @paul.houx !

I see. I found something to get me started with option 1: a VBOmeshAdjacency loader that takes an obj file…

for option 2, how can I access the triangles of the trimesh? I think I have seen a method for calculating those shared edges given a vector of faces.

You can call TriMesh::getNumTriangles and then iterate through, calling TriMesh::getTriangleVertices for each triangle ID. You can also call TriMesh::getIndices, which will return a std::vector<uint32_t>, representing the indices of the mesh. You can index into this vector using the triangle ID from above.

thank you so much. this is so helpful!

ok, so I have extracted some stuff from the objLoader and from a Rideout example to build a parser that returns a vector of indices with adjacency information (happy to share it with anyone that wants it… setting up my github now!).

from here, is it best to construct a vbomesh in cinder? or is there a way to replace the trimesh primitive type with GL_TRIANGLES_ADJACENCY and the indices with my new ones? either way, I can’t figure out how to build a new index buffer at the moment or what to associate it with.

Hi,

as far as I know (and I briefly checked Cinder’s source code), a TriMesh only supports GL_TRIANGLES, so you won’t be able to change its primitive type to GL_TRIANGLES_ADJACENCY. Doing so would cause most of its utility functions to stop working correctly. But you can relatively easily create a VboMesh using the positions, normals, texcoords etc. from the TriMesh and the index buffer with adjacency you created from parsing.

See this VboMesh constructor, for example. See also the bufferAttrib method and this sample.

-Paul

yes!!!

the picking FBO sample was one I had overlooked. the construction method there was super helpful. so the overall process goes like this (for anyone interested):

extract vertices from ‘v’ tags in the obj file and the indices from the ‘f’ tags of the same file. both go into std::vectors.
make a new vector mapping the vertices from the index vector:

    std::vector<vec3> verts=mAdjCalc.mVals.mVertices;
    std::vector<GLuint> inds=mAdjCalc.mVals.mVertIndices;
    std::vector<vec3> indexedVerts;
    for(auto idx:inds)
    {
        indexedVerts.push_back(verts[idx]);
    }

run the adjacency calculation from the glsl 4.0 cookbook: https://github.com/daw42/glslcookbook/blob/master/ingredients/vbomeshadj.cpp#L17

finally create the vbomesh:

    layout.usage( GL_STATIC_DRAW ).attrib( geom::POSITION, 3 );
    mVBOMesh=gl::VboMesh::create(indexedVerts.size(),GL_TRIANGLES_ADJACENCY,{ layout } );
    mVBOMesh->bufferAttrib( geom::POSITION, indexedVerts.size() * sizeof( vec3 ), indexedVerts.data() );

the geometry shader from the same book works nicely. the result without texture (I haven’t incorporated this into the main program yet):

big thanks to @paul.houx and @mike for help on this one!

3 Likes

Congratulations! Perhaps we should add this adjacency stuff to Cinder, might come in handy. A gl::VboMeshAdj that takes a TriMesh, gl::VboMesh or even a geom::Source as input, for instance.

1 Like

for sure, I would be happy to contribute there! I actually tried to cobble together something from the trimesh and vbomesh sources at first but got a little lost.

Hi @mettrelapaix,

Congratulations on solving this difficult problem. I’ve been Googling and hammering away for many hours trying to come up with a similar solution for shape2d outlines in Cinder PoScene.

I’ve created a post describing the problem I’m having and how far I’ve gotten solving it: Outline shape2d VboMesh with stroke in PoScene.

Do you have a Cinder project demonstrating your solution that you’d be willing to share? I read through your post and the logic and code snippets make sense but I’m not sure how to put it all together, especially integrating the adjacency calculation code and it’s dependencies from the glsl 4.0 cookbook into my Cinder project.

Many thanks for any help on this.

Kind regards,

Ken