Game Development Community

Help needed with RenderBins

by Konrad Kiss · in Torque 3D Professional · 06/10/2009 (3:17 pm) · 17 replies

Hi. I tried to create a special renderbin which has only one object rendered into it including all its meshes. At least that's the idea.

I've taken the code from the prepass bin manager. When I add my new bin manager to renderManager.cs (to render before RenderMeshDynamicLightingMgr) all shaders that are used throw me the following:

Quote:
Error compiling shader: E_FAIL: An undetermined error occurred (80004005)
Shader shaders/common/water/waterV.hlsl: shadergen:/autogenConditioners.h(65,15): error X3003: redefinition of 'autogenCondition_55070f7a'

That's a water example, but its not related to water. As far as I can tell, the shader with the same name is being generated (since I think the chances of two different names with the same hash is negligible), but I have no idea what to look for, and why this is being generated by the new bin - it's supposed to use a differently named material, though defined just like DefaultPrePassMaterial (empty material, different name).

Any help would be greatly appreciated!

#1
06/10/2009 (4:42 pm)
The prepass bin is a little special in that it needs to generate special materials/shaders and doesn't just use the normal one that is used during diffuse rendering.

You probably don't want to use the prepass as an example as it is doing a lot of stuff that you likely do not need.
#2
06/10/2009 (11:26 pm)
Thanks James. Which RenderBin do you think would be a good a template for making a new bin?

Edit: probably RenderMeshMgr
#3
06/11/2009 (5:40 am)
Yea... if all you need to do is render a DTS... then RenderMeshMgr is where you should start.
#4
06/11/2009 (5:57 am)
Thanks Tom. I need to render a DTS to a render target.

I want to use that texture to use the outline postfx (thanks Mike J.!) on it following your directions.

This is my first time deep in render code, so I'm still somewhat lost, but it's really interesting, and things are now starting to snap in place.
#5
06/11/2009 (7:40 am)
Hmm.. I'll need to rephrase my question(s) to get a better idea, I'd lost my grip on this..

1. What is the best starting point to create a render bin that renders to a render target. I need one that I can later reference in the outline shader as a sampler (such as "#selection") - instead of #prepass? Are MatTextureTarget::registerTarget and MatTextureTarget::unregisterTarget enough to do the binding?

2. What are conditioners and unconditioners for? I know I need them, I just don't know why. I couldn't find any information on this yet.

3. Do I need to set up a new RenderInstType to render an object in a new bin that already has a RenderInstType? (its a mesh)

Sorry for being a bother guys, any help would be very much appreciated!
#6
06/11/2009 (11:14 am)
In beta 3 the best example of how to do this would be RenderGlowMgr which i completely rewrote. It derives from RenderTexTargetBinManager and renders selected MeshRenderInst which have glow on their materials.

I cut some stuff out, but this should be what you need.

The header...

#ifndef _TEXTARGETBIN_MGR_H_
#include "renderInstance/renderTexTargetBinManager.h"
#endif

class PostEffect;

class RenderGlowMgr : public RenderTexTargetBinManager
{  
   typedef RenderTexTargetBinManager Parent;

public:

   RenderGlowMgr();
   virtual ~RenderGlowMgr();

   /// Returns true if the glow post effect is
   /// enabled and the glow buffer should be updated.
   bool isGlowEnabled();

   // RenderBinManager
   virtual RenderBinManager::AddInstResult addElement( RenderInst *inst );
   virtual void render( SceneState *state );

   // ConsoleObject
   DECLARE_CONOBJECT( RenderGlowMgr );

protected:

   SimObjectPtr<PostEffect> mGlowEffect;

};
#7
06/11/2009 (11:14 am)

And the source file...

#include "platform/platform.h"
#include "renderInstance/renderGlowMgr.h"

#include "sceneGraph/sceneGraph.h"
#include "sceneGraph/sceneState.h"
#include "materials/sceneData.h"
#include "materials/matInstance.h"
#include "materials/materialFeatureTypes.h"
#include "materials/processedMaterial.h"
#include "postFx/postEffect.h"
#include "gfx/gfxTransformSaver.h"
#include "gfx/gfxDebugEvent.h"

IMPLEMENT_CONOBJECT( RenderGlowMgr );

RenderGlowMgr::RenderGlowMgr()
   : RenderTexTargetBinManager(  RenderPassManager::RIT_Mesh, 
                                 1.0f, 
                                 1.0f,
                                 GFXFormatR8G8B8A8,
                                 Point2I( 512, 512 ) )
{
   mTargetSizeType = WindowSize;
   MatTextureTarget::registerTarget( "glowbuffer", this );
}

RenderGlowMgr::~RenderGlowMgr()
{
   MatTextureTarget::unregisterTarget( "glowbuffer", this );   
}

bool RenderGlowMgr::isGlowEnabled()
{
   if ( !mGlowEffect )
      mGlowEffect = dynamic_cast<PostEffect*>( Sim::findObject( "GlowPostFx" ) );

   return mGlowEffect && mGlowEffect->isEnabled();
}

RenderBinManager::AddInstResult RenderGlowMgr::addElement( RenderInst *inst )
{
   // Skip out if we don't have the glow post 
   // effect enabled at this time.
   if ( !isGlowEnabled() )
      return RenderBinManager::arSkipped;

   // TODO: We need to get the scene state here in a more reliable
   // manner so we can skip glow in a non-diffuse render pass.
   //if ( !mParentManager->getSceneManager()->getSceneState()->isDiffusePass() )
      //return RenderBinManager::arSkipped;
      
   BaseMatInstance* matInst = getMaterial(inst);
   bool hasGlow = matInst && matInst->hasGlow();
   if ( !hasGlow )   
      return RenderBinManager::arSkipped;

   internalAddElement(inst);

   return RenderBinManager::arAdded;
}


void RenderGlowMgr::render( SceneState *state )
{
   PROFILE_SCOPE( RenderGlowMgr_Render );

   // Don't allow non-diffuse passes.
   if ( !state->isDiffusePass() )
      return;

   GFXDEBUGEVENT_SCOPE( RenderGlowMgr_Render, ColorI::GREEN );

   GFXTransformSaver saver;

   // Tell the superclass we're about to render, preserve contents
   const bool isRenderingToTarget = _onPreRender( state, true );

   // Clear all the buffers to black.
   GFX->clear( GFXClearTarget, ColorI::BLACK, 1.0f, 0);

   // init loop data
   SceneGraphData sgData;
   U32 binSize = mElementList.size();

   for( U32 j=0; j<binSize; )
   {
      MeshRenderInst *ri = static_cast<MeshRenderInst*>(mElementList[j].inst);

      // temp fix - these shouldn't submit glow ri's...
      if(ri->dynamicLight)
      {
         j++;
         continue;
      }

      setupSGData( ri, sgData );
      sgData.binType = SceneGraphData::GlowBin;

      BaseMatInstance *mat = ri->matInst;

      U32 matListEnd = j;

      while( mat->setupPass( state, sgData ) )
      {
         U32 a;
         for( a=j; a<binSize; a++ )
         {
            MeshRenderInst *passRI = static_cast<MeshRenderInst*>(mElementList[a].inst);

            if (newPassNeeded(mat, passRI))
               break;

            mat->setTransforms(*passRI->objectToWorld, *passRI->worldToCamera, *passRI->projection);
            mat->setEyePosition(*passRI->objectToWorld, state->getCameraPosition());
            mat->setBuffers(passRI->vertBuff, passRI->primBuff);

            if ( passRI->prim )
               GFX->drawPrimitive( *passRI->prim );
            else
               GFX->drawPrimitive( passRI->primBuffIndex );
         }
         matListEnd = a;
      }

      // force increment if none happened, otherwise go to end of batch
      j = ( j == matListEnd ) ? j+1 : matListEnd;
   }

   // Finish up.
   if ( isRenderingToTarget )
      _onPostRender();
}

This should get you started.
#8
06/11/2009 (11:19 am)
Quote:2. What are conditioners and unconditioners for?
Those are for writing and reading data that is encoded into a specialized format, so that your shaders don't need to know how to do it themselves.

For example there is a prepassConditioner which takes a normal and depth and then encodes the normal into a spherical format and writes 16bits of the depth into the blue channel and 16bits of the depth into the alpha channel.

There is a prepassUncondition which does the opposite.

In general you don't need to write one for your own buffers unless you have some really complex encoding to it. And even then... you don't really have to.
#9
06/11/2009 (11:35 am)
This is exactly what I need! Thank you! I'll let you know how it goes! I have lost count of the beers I owe you. :)
#10
06/11/2009 (11:48 am)
Cool, thanks Tom!
#11
06/11/2009 (11:55 am)
@Greg: Tom's right, glow really is exactly what we need. And there's no need to pass ids to meshes and such, I think the best way to go is to make a boolean in the material instance that shows whether the mesh must be selected or not! I'm in for another sleepless night! :)
#12
07/04/2009 (8:26 am)
@Tom & @Konrad, I got puzzled at one point.

In tsMesh.cpp, there's a function executed at the very end of innerRender():

state->getRenderPass()->addInst(ri);

It checks every renderBin's addElement() to see if the renderInst fits for them, is that means if I define a material for a dts, and set the material's glow to true, then the renderInst for this dts's mesh would be inserted both into meshRenderbin and glowRenderbin? And the mesh will first be drawn by meshRenderbin, then drawn again by glowRenderbin?

Is that a cpu waste, or there are some other consideration in it?
#13
07/04/2009 (8:30 am)
I think it's the fastest possible way. Tom knows a LOT more about this than I do, so I'll stay quiet and listen in. ;)
#14
07/06/2009 (2:28 am)
@Huan

It puts objects in multiple bins because objects often need to render several times. For instance when in Advanced Lighting a TSMesh can potentially go into 3 bins... RenderPrePassMgr, RenderMeshMgr, and RenderGlowMgr if it has glow enabled.

I agree it looks like a potential performance problem... but so far the binning process has not appeared in profiles.
#15
07/06/2009 (8:30 am)
Thanks for the explainations.

I just tried the glow effect, I set ForgeSoldier's 'medium' material's glow[0] to true, it looks fantarstic in advanced lighing mode, but doesn't take effects in basic lighting mode, did I miss something, or it is just the way it works.
#16
07/06/2009 (1:21 pm)
@Huan - I didn't know this... but the PostEffect system was hard coded to disable when in BL mode in beta 2 and 3. In beta 4 i hope to solve that issue and get it re-enabled so that effects like glow work in BL again.
#17
07/06/2009 (6:26 pm)
@Tom, thanks again for your patience.

And @Konrad, waiting for your new resource, good luck!