Game Development Community

Triangle Strip Assembly

by Derk Adams · in Torque Game Engine · 05/04/2005 (1:41 pm) · 16 replies

Greetings,

I will be really surprised if I get a response to this as it is pretty deep in the engine.

I am working in "TSMesh::assemble" with the "leaveAsMultipleStrips" option. I would like to map the strip to the skeletal node it is attached to (-1 if there is not a node).

The results of the operation go into "ToolVector primitives;" which is run through during rendering as such:
for (S32 i=0; i<primitives.size(); i++) {
	  TSDrawPrimitive & draw = primitives[i];         
	  AssertFatal(draw.matIndex & TSDrawPrimitive::Indexed,                  
	    "TSMesh::render: rendering of non-indexed meshes no longer supported");         
	  S32 drawType = getDrawType(draw.matIndex>>30);         
	  glDrawElements(drawType,draw.numElements,GL_UNSIGNED_SHORT,&indices[draw.start]);
	}

I would like to have an array that contains the skeletal node for each strip so I can manipulate the results based on body part.

I have no idea where to start. Anyone have any suggestions?

Thanks.

#1
05/04/2005 (2:08 pm)
Derk: I follow you so far, but could you explain exactly what you are going to do with and how you would like to access the array?

There are a number of methods and scopes you could implement, so the real question is what exactly do you want this data to do, and where are you going to be accessing it from?

Brandon.
#2
05/04/2005 (2:43 pm)
Brandon,

You got it.

I have duplicated the "TSMesh::render" function and called it "TSMesh::renderDamage." I have modified the code around the rendering to be:
bool oldlighting=glIsEnabled(GL_LIGHTING);      
    glDisable(GL_LIGHTING);      
	bool old2dtex=glIsEnabled(GL_TEXTURE_2D);      
	glDisable(GL_TEXTURE_2D);      
	F32 oldcolor[4];      
	glGetFloatv(GL_CURRENT_COLOR,oldcolor);      
	glCullFace(GL_BACK);      
	glPolygonMode (GL_BACK, GL_FILL);      
	glDepthFunc(GL_LEQUAL);      
	glColor4f(0.0f,0.0f,0.0f,0.5f);
	bool oldblend=glIsEnabled(GL_BLEND);      
	glEnable(GL_BLEND);
	for (S32 i=0; i<primitives.size(); i++) {
	  TSDrawPrimitive & draw = primitives[i];         
	  AssertFatal(draw.matIndex & TSDrawPrimitive::Indexed,                  
	    "TSMesh::render: rendering of non-indexed meshes no longer supported");         
	  S32 drawType = getDrawType(draw.matIndex>>30);         
	  glDrawElements(drawType,draw.numElements,GL_UNSIGNED_SHORT,&indices[draw.start]);
	}
	if (!oldblend) glDisable(GL_BLEND);
    glColor4fv(oldcolor);      
	if (old2dtex) glEnable(GL_TEXTURE_2D);      
	glDepthFunc(GL_LEQUAL);      
	glColor3f(1.0f,1.0f,1.0f);      
	glCullFace(GL_BACK);      
	glPolygonMode (GL_BACK, GL_FILL);      
	if (oldlighting) glEnable(GL_LIGHTING);
You'll notice the glColor4f function that I plan on pulling into the for statement. I will modify the alpha value to show damage level for the part. This will add a black layer blended with the texture layer that goes from nothing (no damage) to black (destroyed).

I don't have a problem getting the damage value to this function. I just don't have the location information of the triangle strip to compare to.

I would like to do something like:
for (S32 i=0; i<primitives.size(); i++) {
  S32 node = add info here;
  glColor4f(0.0f,0.0f,0.0f,TSShapeInstance::smRenderData.damageValue[node]);
...

I call the function in:
void TSShapeInstance::MeshObjectInstance::render(S32 objectDetail, TSMaterialList * materials)
{
   if (visible>0.01f)
   {
      TSMesh * mesh = getMesh(objectDetail);
      if (mesh)
      {
         MatrixF * transform = getTransform();
         if (transform != TSShapeInstance::smRenderData.currentTransform)
         {
            if (TSShapeInstance::smRenderData.currentTransform)
               glPopMatrix();
            if (transform)
            {
               glPushMatrix();
               dglMultMatrix(transform);
            }
            TSShapeInstance::smRenderData.currentTransform = transform;
         }
         if (visible>0.99f)
         {
            if (TSShapeInstance::smRenderData.balloonShape)
            {
               glPushMatrix();
               F32 & bv = TSShapeInstance::smRenderData.balloonValue;
               glScalef(bv,bv,bv);
            }
            mesh->render(frame,matFrame,materials);
            if (TSShapeInstance::smRenderData.balloonShape)
               glPopMatrix();
         }
         else
         {
            mesh->setFade(visible);
            mesh->render(frame,matFrame,materials);
            mesh->clearFade();
         }
// add conditional structure
            mesh->renderDamage(frame,matFrame,materials);
// 
      }
   }
}
Is this enough info?

Thanks.
#3
05/04/2005 (3:07 pm)
That's pretty good info, but where is the damage for each node stored?

In the code sample you would like to get working you entered:

glColor4f(0.0f,0.0f,0.0f,TSShapeInstance::smRenderData.damageValue[node]);

I'm wondering if you have already stored info into the damageValue[node] variable?

If you have, then you have already isolated the section of the model that has taken damage, and stored the value. If you could, post that section of code and I'll see if I can help ya.

B--
#4
05/04/2005 (3:14 pm)
Brandon,

No, damage values (TSShapeInstance::smRenderData.damageValue[node]) are coming from Torque Script. The body mesh is a single mesh made up of triangle strips. I need a way to know which strip is attached to which node.

Example for one of my models:

Strip 0-4, 27-31, 163-166 is the right arm
Strip 99-104, 227-237 is the head

I have that info by coloring the strips manually and looking at the model in the game. I need an automatic way to do this during model assembly, as they are different for every model.

Thanks.
#5
05/04/2005 (3:34 pm)
Ahh.. Ok, so you are really looking for a way to find out which strips are in each node, and then add these strips to the array of nodes.. Hmm. That is a tough one. If you had to do it that way I would think you would have to tag the sections when creating the models. That does not sound fun. You might want to consider using whatever is creating the damage to cast an area ray and grab the mesh sections that way. I think that would also blend into the model better. If you change the whole arm section black for example you would have some hard polygon lines that would not look natural. But if you grabbed the sections of mesh on the fly from the area effect of the damage, then it would blend better.

I'm sure you know this, but there is a damage decal system built in for the player models. I'm guessing you don't want to use the existing system.

Anyway, let me know if you need help getting the collision areas of the mesh affected by the damage stored.


B--
#6
05/04/2005 (3:50 pm)
Brandon,

A couple of concepts that might help. My characters are Mechs, so hard damage lines aren't a problem. The character is a single mesh as I have been unable to get Milkshape to export a segmented model without trashing the animations. I already have a damage detection system in place, I just need to show the damage on the model.

That is why I focused on the nodes. Since the nodes animate the triangle strips, I assume that the information is already in there somewhere, I just need to pull it out.

I am looking to say:
The right arm has taken 40% damage.
The arm node damage alpha is 0.4.
Run through all the triangle strips
   if it is attached to the arm node
      draw the damage layer at 0.4 alpha.

The character decal system didn't work for me because it sticks it on the bounding box, not the character mesh. It looks really dumb to have a bullet hole floating next to the arm instead of on it.

Thanks.

Any other takers?
#7
05/04/2005 (4:36 pm)
Ok, so your trying to get the vertex list in TSMesh::smWeightList into triangle strips? Am I understanding what your trying to do?

B--
#8
05/04/2005 (5:12 pm)
Brandon,

Nope, as in my first post.
Quote:
I am working in "TSMesh::assemble" with the "leaveAsMultipleStrips" option. I would like to map the strip to the skeletal node it is attached to (-1 if there is not a node).

Thanks.
#9
05/04/2005 (5:37 pm)
Exactly: I was suggesting the possibility of using the weight list from the bones during the mesh load to compare with the tri strips to figure out which ones belong to each node.

It was just a thought though... I'm not sure if it would work, I was just throwing some ideas at you.

B--
#10
05/04/2005 (5:56 pm)
A strip may be mapped to many different bones. You're going to have to calculate the color info per-vert and render it that way (probably as an additive/multiplicative pass).

The leaveAsMultipleStrips stuff is just related to how the strips are optimized - no relationship to the bones or any other model info.
#11
05/04/2005 (6:27 pm)
Ben,

My models do not have strips that map to more than one bone, so even just running through all the bones and getting the last one would work for me.

I'm not set on the "leaveAsMultipleStrips", I just traced "primatives" to that point.

Any suggestions? Or, if I have to go to the vertex level, can you suggest an example resource that operates at that level?

Thanks.
#12
05/05/2005 (2:13 pm)
I too am interested in vertex-level operations in Torque, since I'll need those in the near future, but my quick attempts at finding an entry point to manipulate the shape's geometry have failed so far...
#13
05/05/2005 (5:01 pm)
Greetings,

Hopefully, Ben is still around for this :)

Ok, I have dove a little deeper into the rendering code and here is what I have found:

1. A file is read in TSShape::read.
2. The shape is assembled in TSSShape::assembleShape.
3. The mesh is assembled in TSMesh::assembleMesh
4. The skin triangles are assembled in TSSkinMesh::assemble. This is skipped for non-skinned shapes.
5. The mesh triangles are assembled in TSMesh::assemble.

The skin has the bone and node data. Since this is lacking from the mesh data (default render), I was unable to reach any of it.

I have figured out how to call the render using the skin instead of just the mesh so I have access to: weight, vertexIndex, boneIndex, nodesIndex, etc.

Using my sample animated character I have the following:
From the Mesh: verts, norms, and tverts all have 1079 entries. However the indices have 1368. Also, primitives has 313 entries
From the Skin: weight, vertexIndex, boneIndex all have 1079 (although the values in weights are all zeros). The nodesIndex holds 14 entries.

So the issue now is:
1. The render code runs through the "primitives."
2. The boneIndex has the information I want, but it is tied to vertex number.
3. How do I get the vertex information from the current primitive to compare to the boneIndex?

I was thinking that each triangle is composed of three vertexes, but 3 * 313 = 939, not 1079. So I guess that I don't quite understand the structure of the triangle strips in primitives.

Another note: each vertex is only assigned to a single bone, so I only need to select one vertex per triangle to be able to look up the bone.

Also, I am a little curious about the numbers because my model has 18 skeletal nodes (although only 15 are actually animated).

Thanks.
#14
05/05/2005 (5:05 pm)
Oh, just tried something new.

primitives[i].start returns a number that is in the range of indices (i.e. to 1368).

So, how does indices relate to verts?

Thanks.
#15
05/06/2005 (5:34 am)
Damn, I'm good :)

Got it.

primitives[i].start points to the indicies which contains pointers to the verts. So:

primitives[i].start] = index start point
indices[primitives[i].start] = vert of start point
boneIndex[indices[primitives[i].start]] = bone of vert of start point

The bone value in my character was 14 because the mesh was only attached to 14 of the 18 nodes. Unused attachment (not animation) nodes are not included in the boneIndex.

So I'm off to add the script hooks to color each bone individually.

Thanks.
#16
05/06/2005 (11:34 pm)
Glad you got it solved! Sorry about my absence, I got sucked into Psychonauts... Excellent game. Also, working hard on terrain. :)