Game Development Community

T3D 1.2 LOD imposter bug fix

by Dave Wagner · in Torque 3D Professional · 06/18/2012 (1:27 pm) · 1 replies

So I was adjusting the imposters for our trees in the forest which had two geometry LODs and then switched to the imposter for the third LOD. I had everything working great with no popping but when I reloaded the level the trees starting popping in and out of LOD levels, sometimes disappearing all together. If I saved each tree back out using the shape editor the popping would go away, until I reloaded the level. I figured that the shape editor was doing something that wasn't being done during the initial load of the level.

To make a long story short, the follow change fixed the problem.

Change the function in tsShapeEdit.cpp from:
S32 TSShape::addImposter(const String& cachePath, S32 size, S32 numEquatorSteps,
                        S32 numPolarSteps, S32 dl, S32 dim, bool includePoles, F32 polarAngle)
{
   // Check if the desired size is already in use
   bool isNewDetail = false;
   S32 detIndex = findDetailBySize( size );

   if ( detIndex >= 0 )
   {
      // Size is in use. If the detail is already an imposter, we can just change
      // the settings, otherwise quit
      if ( details[detIndex].subShapeNum >= 0 )
      {
         Con::errorf( "TSShape::addImposter: A non-billboard detail already "
            "exists at size %d", size );
         return -1;
      }
   }
   else
   {
      // Size is not in use. If an imposter already exists, change its size, otherwise
      // create a new detail
      for ( detIndex = 0; detIndex < details.size(); ++detIndex )
      {
         if ( details[detIndex].subShapeNum < 0 )
         {
            // Change the imposter detail size
            setDetailSize( details[detIndex].size, size );
            break;
         }
      }
      if ( detIndex == details.size() )
      {
         isNewDetail = true;
         detIndex = addDetail( "bbDetail", size, -1 );
      }
   }

   // Now set the billboard properties.
   Detail &detail = details[detIndex];

   // In prior to DTS version 26 we would pack the autobillboard
   // into this single 32bit value.  This was prone to overflows
   // of parameters caused random bugs.
   //
   // Set the old autobillboard properties var to zero.
   detail.objectDetailNum = 0;
   
   // We now use the new vars.
   detail.bbEquatorSteps = numEquatorSteps;
   detail.bbPolarSteps = numPolarSteps;
   detail.bbPolarAngle = polarAngle;
   detail.bbDetailLevel = dl;
   detail.bbDimension = dim;
   detail.bbIncludePoles = includePoles;

   // Rebuild billboard details or force an update of the modified detail
   if ( isNewDetail )
   {
      // Add NULL meshes for this detail
      for ( S32 iObj = 0; iObj < objects.size(); ++iObj )
      {
         if ( detIndex < objects[iObj].numMeshes )
         {
            objects[iObj].numMeshes++;
            meshes.insert( objects[iObj].startMeshIndex + detIndex, NULL );
            for (S32 j = iObj + 1; j < objects.size(); ++j )
               objects[j].startMeshIndex++;
         }
      }

      // Could be dedicated server.
      if ( GFXDevice::devicePresent() )
         setupBillboardDetails( cachePath );

      while ( detailCollisionAccelerators.size() < details.size() )
         detailCollisionAccelerators.push_back( NULL );
   }
   else
   {
      if ( billboardDetails.size() && GFXDevice::devicePresent() )
      {
         delete billboardDetails[detIndex];
         billboardDetails[detIndex] = new TSLastDetail(
                                          this,
                                          cachePath,
                                          detail.bbEquatorSteps,
                                          detail.bbPolarSteps,
                                          detail.bbPolarAngle,
                                          detail.bbIncludePoles,
                                          detail.bbDetailLevel,
                                          detail.bbDimension );

         billboardDetails[detIndex]->update( true );
      }
   }

   return detIndex;
}

To:
S32 TSShape::addImposter(const String& cachePath, S32 size, S32 numEquatorSteps,
                        S32 numPolarSteps, S32 dl, S32 dim, bool includePoles, F32 polarAngle)
{
   // Check if the desired size is already in use
   bool isNewDetail = false;
   S32 detIndex = findDetailBySize( size );

   if ( detIndex >= 0 )
   {
      // Size is in use. If the detail is already an imposter, we can just change
      // the settings, otherwise quit
      if ( details[detIndex].subShapeNum >= 0 )
      {
         Con::errorf( "TSShape::addImposter: A non-billboard detail already "
            "exists at size %d", size );
         return -1;
      }
   }
   else
   {
      // Size is not in use. If an imposter already exists, change its size, otherwise
      // create a new detail
      for ( detIndex = 0; detIndex < details.size(); ++detIndex )
      {
         if ( details[detIndex].subShapeNum < 0 )
         {
            // Change the imposter detail size
            setDetailSize( details[detIndex].size, size );
            break;
         }
      }
      if ( detIndex == details.size() )
      {
         isNewDetail = true;
         detIndex = addDetail( "bbDetail", size, -1 );
      }
   }

   // Now set the billboard properties.
   Detail &detail = details[detIndex];

   // In prior to DTS version 26 we would pack the autobillboard
   // into this single 32bit value.  This was prone to overflows
   // of parameters caused random bugs.
   //
   // Set the old autobillboard properties var to zero.
   detail.objectDetailNum = 0;
   
   // We now use the new vars.
   detail.bbEquatorSteps = numEquatorSteps;
   detail.bbPolarSteps = numPolarSteps;
   detail.bbPolarAngle = polarAngle;
   detail.bbDetailLevel = dl;
   detail.bbDimension = dim;
   detail.bbIncludePoles = includePoles;
   detail.polyCount = 2;

   // Rebuild billboard details or force an update of the modified detail
   if ( isNewDetail )
   {
      // Add NULL meshes for this detail
      for ( S32 iObj = 0; iObj < objects.size(); ++iObj )
      {
         if ( detIndex < objects[iObj].numMeshes )
         {
            objects[iObj].numMeshes++;
            meshes.insert( objects[iObj].startMeshIndex + detIndex, NULL );
            for (S32 j = iObj + 1; j < objects.size(); ++j )
               objects[j].startMeshIndex++;
         }
      }

      // Could be dedicated server.
      if ( GFXDevice::devicePresent() )
         setupBillboardDetails( cachePath );

      while ( detailCollisionAccelerators.size() < details.size() )
         detailCollisionAccelerators.push_back( NULL );
   }
   else
   {
      if ( billboardDetails.size() && GFXDevice::devicePresent() )
      {
         delete billboardDetails[detIndex];
         billboardDetails[detIndex] = new TSLastDetail(
                                          this,
                                          cachePath,
                                          detail.bbEquatorSteps,
                                          detail.bbPolarSteps,
                                          detail.bbPolarAngle,
                                          detail.bbIncludePoles,
                                          detail.bbDetailLevel,
                                          detail.bbDimension );

         billboardDetails[detIndex]->update( true );
      }
   }

   // Re-initialize the shape
   init();

   return detIndex;
}