Game Development Community

Beta 5 rendering issues - Porting fxForceField

by Jaimi McEntire · in Torque 3D Professional · 08/25/2009 (4:32 pm) · 6 replies

I'm porting one of my older resources to T3D - fxForceField (it's kind of cool - you can shoot through it, but you can't walk through it). Actually, I'm rewriting it - I used the "RenderMeshExample" class as a base.

I've created a yellow texture two different ways - one a very dull yellow (for additive blending) and one a bright yellow with alpha. I've created two different materials. In both cases, the materials render green instead of yellow (T3D sees them as yellow - the screenshot has the material editor up). Both versions incorrectly show the sky on top of the partially occluded geometry - for example, the mountains behind the force field have sky on them. The LerpAlpha is a complete mess - it has some strange moire pattern going on, which I've seen before and believe related to fogging (SWAG).


edit: Bad pics removed. Please see the later messages

#1
08/25/2009 (5:26 pm)
The RenderMeshExample render code seems designed for opaque geometry. You need to do some additional work if your material is translucent. A good place to look for reference is TSMesh::innerRender(), which does exactly that.
#2
08/25/2009 (7:22 pm)
Thanks, how could I have missed that? I appreciate the response.
#3
08/25/2009 (9:37 pm)
I'm missing something - I just can't get anything to render when I'm using RenderPassManager::RIT_Translucent;

I've gone through the code for GroundPlane (which looks like it is setup for materials and translucent rendering) but then I found it doesn't work either if you set a translucent material, so I followed your advice and initialized everything the way tsMesh::InnerRender did, and the result is the same -- nothing renders. :(

If anyone can look and see what I'm doing wrong... I'd appreciate it. :)

bool fxForceField::prepRenderImage( SceneState *state, const U32 stateKey, 
                                         const U32 startZone, const bool modifyBaseZoneState)
{
   // Do a little prep work if needed
   if ( mVertexBuffer.isNull() )
      createGeometry();

   // Make sure we haven't already been processed by this state
   if ( isLastState( state, stateKey ) )
      return false;

   // Update our state
   setLastState(state, stateKey);

   // If we are actually rendered then create and submit our RenderInst
   if ( state->isObjectRendered( this ) ) 
   {
      // Get a handy pointer to our RenderPassmanager
      RenderPassManager *renderPass = state->getRenderPass();

      // Allocate an MeshRenderInst so that we can submit it to the RenderPassManager
      MeshRenderInst *ri = renderPass->allocInst<MeshRenderInst>();

      // Set our RenderInst as a standard mesh render
      //ri->type = RenderPassManager::RIT_Mesh;
      ri->type = RenderPassManager::RIT_Translucent;
      ri->translucentSort = true;
 
      // Calculate our sorting point
      const Box3F& rBox = getRenderWorldBox();
      ri->sortDistSq = rBox.getSqDistanceToPoint( state->getCameraPosition() );      

      // Set up our transforms
      MatrixF objectToWorld = getRenderTransform();
      objectToWorld.scale( getScale() );

      ri->objectToWorld = renderPass->allocXform( objectToWorld );
      ri->worldToCamera = renderPass->allocXform( GFX->getWorldMatrix() );
      ri->projection    = renderPass->allocXform( GFX->getProjectionMatrix() );

      // Let the light manager fill the RIs light vector with the current best lights
      LightManager* lm = NULL;
      if ( state->getSceneManager() )
      {
         lm = state->getSceneManager()->getLightManager();
         if ( lm && !state->isShadowPass() )
         {
            lm->setupLights( this, getWorldSphere() );

            lm->getBestLights( ri->lights, 8 );
         }
      }

      // Make sure we have an up-to-date backbuffer in case
      // our Material would like to make use of it
      ri->backBuffTex = GFX->getSfxBackBuffer();

      // Set our Material
      if ( mMaterialInst )
         ri->matInst = mMaterialInst;
      else
         ri->matInst = MATMGR->getWarningMatInstance();

      // Set up our vertex buffer and primitive buffer
      ri->vertBuff = &mVertexBuffer;
      ri->primBuff = &mPrimitiveBuffer;

      ri->prim = renderPass->allocPrim();
      ri->prim->type = GFXTriangleList;
      ri->prim->minIndex = 0;
      ri->prim->startIndex = 0;
      ri->prim->numPrimitives = 12;
      ri->prim->startVertex = 0;
      ri->prim->numVertices = 36;
      ri->visibility             = 1.0f;
      // We sort by the vertex buffer
      ri->defaultKey = (U32)ri->vertBuff; // Not 64bit safe!
      ri->defaultKey2 = 0;

      // Submit our RenderInst to the RenderPassManager
      state->getRenderPass()->addInst( ri );

      // Give the light manager a chance to reset the lights
      if ( lm )
         lm->resetLights();
   }

   return false;
}

#4
08/25/2009 (10:44 pm)
It looks right at first glance...

My only idea is to get a really simple scene with only your object in it then put a breakpoint when it goes to actually process the render instances ( so there should be only yours or maybe a shadow or sky one ).

I'd put a breakpoint in renderTranslucentMgr.cpp line 180

Either something wrong in the render instance that maybe you can spot there, or, something wrong with the material itself.
#5
08/26/2009 (12:40 am)
@James - Thanks, you put me on the right track.

The problem is a bug in RenderTranslucentMgr. Down around line 235, the following line:

GFX->drawPrimitive( passRI->primBuffIndex );

Needs to be changed to:

// draw it
              if ( passRI->prim )
                 GFX->drawPrimitive( *passRI->prim );
              else
                 GFX->drawPrimitive( passRI->primBuffIndex );

#6
08/26/2009 (1:25 am)
One more note - Glow doesn't work on translucent meshes. However, this is easy to fix. In renderBinManager.h, change the getMaterial function to look like this:
/// Utility function, gets the material from the RenderInst if available, otherwise, return NULL
inline BaseMatInstance* RenderBinManager::getMaterial(RenderInst* inst) const
{
   if (inst->type == RenderPassManager::RIT_Mesh || inst->type == RenderPassManager::RIT_Interior || inst->type == RenderPassManager::RIT_Translucent)
      return static_cast<MeshRenderInst*>(inst)->matInst;         

   return NULL;      
}

Here is fxForceField in action:

www.aztica.com/images/fxForceField.jpg
Update: T3D is pretty cool - Here is fxForceField with a non-translucent material. You could actually build stuff out of it, and turn it on and off on the fly. I'm thinking about adding different primitive types - cylinder, sphere, cone, etc.

www.aztica.com/images/fxForceField2.jpg