Game Development Community

Optimizing Lightning

by Chris Haigler · in Torque Game Engine · 12/30/2007 (7:59 pm) · 2 replies

I've been working on making the Lightning class render via glDrawElements() rather than individual glBegin()/gleEnd() calls. I'm using the batched decal and batched precipitation resources created by Alex Scarborough and asmaloney as examples. It's mainly a learning project (as I'm quite the OpenGL novice) but things seem to be moving in the right direction.

At the moment I've got it working (and by working I mean not crashing or rendering horribly misplaced verts everywhere) but the individual lightning bolts seem smaller than they should be and I'm not quite sure why. What's stranger, changing the width of the bolts (via the strikeWidth variable) will widen them but rather than rendering as a solid strip they render as a series of triangles. It's a bit hard to explain so here's some screenshots illustrating the problem:

Clean copy of 1.4.2 with a default Lightning object using a strikeWidth of 15

New and improved Lightning object using a strikeWidth of 15...

And this is the code I'm using. Could someone with a bit more OpenGL experience give it a once over? I'm particularly interested in the section that actually creates/sets the indices (renderLBVertIndices) which index into the vertex array. Both the decal and precipitation resources I mention above increment the vertex array and index by 4 and 6, respectively. I'm incrementing by 2 and 3 (respectively) because each segment of a lightning bolt is only an additional two vertices. On top of that, I'm almost positive something is wrong with my index array as I basically pulled and pushed the offset values until I came up with something that didn't crash. :)

[Code in next post]

#1
12/30/2007 (8:00 pm)
...
...
...
static Vector<LightningBoltVert> renderLBoltVert(__FILE__, __LINE__);
static Vector<U16> renderLBVertIndices(__FILE__, __LINE__);
static U16 vertCount = 0;

void LightningBolt::render( const Point3F &camPos )
{  
   renderLBoltVert.clear();
   renderLBVertIndices.clear();
   vertCount = 0;

   if( !startRender )
   {
      return;
   }

   if( !isFading )
   {
      generateMinorNodes();
   }

   glEnableClientState(GL_VERTEX_ARRAY);
   glEnableClientState(GL_TEXTURE_COORD_ARRAY);

   U32 i;
   for( i=0; i<mMinorNodes.size(); i++ )
   {
      if( i+1 == mMinorNodes.size() )
      {
         renderSegment( mMinorNodes[i], camPos, true );

      }
      else
      {
         renderSegment( mMinorNodes[i], camPos, false );
      }
   }

   LightningBolt *curBolt = NULL;
   for( curBolt = splitList.next( curBolt ); curBolt; curBolt = splitList.next( curBolt ) )
   {
      if( isFading )
      {
         curBolt->isFading = true;
      }
      curBolt->render( camPos );
   }

   if ( vertCount )
   {
      glVertexPointer( 3, GL_FLOAT, sizeof( LightningBoltVert ), &(renderLBoltVert[0].vert) );
      glTexCoordPointer( 2, GL_FLOAT, sizeof( LightningBoltVert ), &(renderLBoltVert[0].texCoord) );
      
      glDrawElements( GL_TRIANGLE_STRIP, renderLBVertIndices.size(), GL_UNSIGNED_SHORT, renderLBVertIndices.address() );
   }

   glDisableClientState(GL_VERTEX_ARRAY);
   glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}

void LightningBolt::renderSegment( NodeManager &segment, const Point3F &camPos, bool renderLastPoint )
{
   F32 totalLen = 0;
   for( int i=0; i<segment.numNodes; i++ )
   {
      Point3F  curPoint = segment.nodeList[i].point;

      Point3F  nextPoint;
      Point3F  segDir;

      if( i == (segment.numNodes-1) )
      {
         if( renderLastPoint )
         {
            segDir = curPoint - segment.nodeList[i-1].point;
         }
         else
         {
            continue;
         }
      }
      else
      {
         nextPoint = segment.nodeList[i+1].point;
         segDir = nextPoint - curPoint;
      }
      totalLen = segDir.len();
      segDir.normalizeSafe();

      Point3F dirFromCam = curPoint - camPos;
      Point3F crossVec;
      mCross(dirFromCam, segDir, &crossVec);
      crossVec.normalize();
      crossVec *= width * 0.5;

      renderLBoltVert.increment(2);
      renderLBVertIndices.increment(3);
      LightningBoltVert *verts = &(renderLBoltVert[vertCount * 2]);
      U16 *ind = &(renderLBVertIndices[vertCount * 3]);

      verts[0].vert = curPoint - crossVec;
      verts[0].texCoord.set(i, 1.0f);
      ind[0] = vertCount * 2;
      ind[2] = vertCount * 2;

      verts[1].vert = curPoint + crossVec;
      verts[1].texCoord.set(i, 0.0f);
      ind[1] = vertCount * 2 + 1;

     vertCount++;
   }
}

Thanks for any help!
#2
01/01/2008 (11:55 am)
I'm still working through this issue but haven't made a great deal of progress. It's obvious from the screenshots I'm missing a few verts. Either they're not being indexed properly or they're simply not being added to the vertex array. I'll keep plugging at it. The performance increase seems fairly modest but any improvement is good. :)