Game Development Community

Getting triangles and indicies from TSMesh

by Brett Fattori · in Torque Game Engine · 01/02/2004 (8:42 pm) · 9 replies

Is there a way to get the triangle mesh (and indicies) from TSMesh, TSShapeInstance, or something like that? Right now, I see that TGE takes care of all the rendering for you... It sets up the object/sub-objects, animates them, and then sends the VB(s) to OpenGL. It would be nice to be able to access the mesh, and its indicies, directly. However, the optimizations of tri-strips and the like are causing me headaches.

I'll be honest.. I'm working on a stencil shadow implementation, and I'm stuck at the point of generating edge lists. If I access TSMesh and grab its primitive and index lists, am I guaranteed that the indicies will line up with verts in the primitives? Where can I look, within the engine, to get an example of this? I've been pouring over TSShapeInstance->render() and TSMesh->fillVB() but I don't know if/think I'm in the right place.

Any help from y'all master coders would be mucho appreciated.

- Brett

#1
01/05/2004 (12:04 pm)
Yes, you can cycle through the primitives. If you look at the render functions, they should give you good examples on how to do it. If you need to cycle through each triangle, here's some example code taken from my shader work:

for (U32 objIndex = 0; objIndex < objects.size(); objIndex++)
   {
      TSObject * obj = &objects[objIndex];

      for (S32 meshIndex = 0; meshIndex < obj->numMeshes; meshIndex++)
      {
         TSMesh * mesh = meshes[obj->startMeshIndex+meshIndex];
         //do some checking here if it's a skinmesh, i.e.:
         TSSkinMesh* sMesh = dynamic_cast<TSSkinMesh*>(mesh);
         ToolVector<Point3F>* vertexList = &mesh->verts;
         if (sMesh)
         {
            //if it's a skin mesh, use the "initial" data
            vertexList = &sMesh->initialVerts;
         }

         if (!mesh)
            continue;

         //make sure we have vertices...
         S32 numVerts = vertexList->size();
         if (!numVerts)
            continue;

         //make sure there are some primitives...
         S32 numPrims = mesh->primitives.size();
         if (!numPrims)
            continue;

         //make sure we have some indices...
         S32 numIndices = mesh->indices.size();
         if (!numIndices)
            continue;

         for (S32 primIndex = 0; primIndex < numPrims; primIndex++)
         {
            S16 start = mesh->primitives[primIndex].start;
            S16 numElements = mesh->primitives[primIndex].numElements;

            if ( (mesh->primitives[primIndex].matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles)
            {
               for (S16 triIndex = 0; triIndex < numElements; triIndex+=3)
               {
                  U32 triStart = start + triIndex;

                  //DO STUFF HERE
                  //each triangle will start at index triStart
                  //and the other vertices are the 2 following this
                  //use triStart to lookup into the indices to lookup
                  //into the vertices.  i.e. verts[indices[triIndex]]
                  
               }
            }
            else
            {
               U16 idx0 = mesh->indices[start + 0];
               U16 idx1;
               U16 idx2 = mesh->indices[start + 1];
               U16 * nextIdx = &idx1;
               for (S32 triIndex=2; triIndex < numElements; triIndex++)
               {
                  *nextIdx = idx2;
      //            nextIdx = (j%2)==0 ? &idx0 : &idx1;
                  nextIdx = (U16*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);
                  idx2 = mesh->indices[start + triIndex];
                  if (idx0 == idx1 || idx0 == idx2 || idx1 == idx2)
                     continue;

                   //DO STUFF HERE
                   //idx0, idx1, idx2 will be used to lookup indices
                   //for lookup into the vertices.
                   //i.e. verts[indices[idx0]]


               }
            }
         }
         //next mesh!
      }
   }

Hope that helps.
#2
01/05/2004 (3:39 pm)
Thanks Chris.. as usual, you are helpful.

- Brett
#3
04/27/2004 (12:59 pm)
How would i find the number of triangles for a whole shape?

i tried looping through the meshes, then the meshes prims, then adding up the .numelements, but it was giving ridiculously highnumbers.. :S
#4
06/01/2004 (12:42 pm)
There is a polycount method on the TSMesh class. It will give you a count of all the polys in a mesh... Just remember that an object can consist of many sub-objects.

- Brett
#5
06/01/2004 (1:23 pm)
This is great, I was looking for something similar :D How about accessing to textures? I guess it will be much more complex... I would like to give bump mapping a try, but I don't know how to find a texture and alter its pixels... Anyway, this thread is a nice clue!

Uh... just wondering... Would it be possible to use this way of accesing the mesh to create something like an 'automatic LOD' :m I saw that gluBuild2DMipmaps() creates mipmap levels from a certain image... Would it be possible to create different LOD levels merging near mesh vertices and storing the new shape like a normal LOD loaded from a file?
#6
11/01/2005 (9:28 pm)
@Joakim: What is 'transforms' in the following code:
transforms->mulP(v1);
transforms->mulP(v2);
transforms->mulP(v3);

Is it the render transform for the object?
#7
11/03/2005 (6:10 am)
Ok, sorry I haven't had the time to update this thread, and BTW I removed the prev. threads which did not give anything to the discussion.

I did get it to work though, as I might hav said my goal were to create a ray-polygon (used for picking in the RTS kit) collision handler, and to check the polygons for collision I had to get the geometry data as triangles and this is how I did it.

I start by looping through the meshes (in a class derived from ShapeBase) and find submeshes, and get a pointer to the mesh (referring to the pointer as 'mesh' which is a tsMesh pointer as this:

TSMesh *mesh = getShape()->meshes[mesh_index];

then I get the node transform, this is (if I did understand it right the "offset transform" from the parrent, like in any scenegraph system)

MatrixF *transforms = mShapeInstance->mNodeTransforms.address();

then just for the ease of my work I create some placeholders for the current primitive and the three verts, in a for loop ( we will have to loop through all primitives)

for(S32 i=0; i<mesh->primitives.size(); i++) {
      TSDrawPrimitive &draw = mesh->primitives[i];
      Point3F = v1, v2, v3;

and to get the right transformed vertex data per polygon I loop through the elements and transforming the data:

for(S32 j=0; j<draw.numElements; j+=3)
{
      S32 ind = j+draw.start;

      // fetch the verts of the current triangle
      v1 = mesh->verts[mesh->indices[ind]];
      v2 = mesh->verts[mesh->indices[ind+1]];
      v3 = mesh->verts[mesh->indices[ind+2]];

      // and this is the named translation
      transforms->mulP(v1);
      transforms->mulP(v2);
      transforms->mulP(v3);
}

And if I have not forgot something (except for the actuall collision code, which I left out to save place) this is what I did, and although it seem to work great under Windows it didn't perform as well under Linux.

Anyone have any idea why that is?

is the representation different under Linux?
#8
01/11/2008 (1:03 am)
Hi!!
Does anyone know why i am not getting actual position of the vertex in the world by applying following transform?

MatrixF *transforms = mShapeInstance->mNodeTransforms.address();
...
...
transforms->mulP(v1);

Appreciate if someone can point me what is the right transform matrix to convert vertex position from a TSMesh to world.
#9
02/24/2008 (12:05 am)
@Viren? If you still need help. take a look at GetMountNodeTransform, or whatever it's called, to get an idea how to convert your local coords to world coords.