MultiRenderTarget : different clear colors

What it says on the tin: a place to discuss proposed new features.
Post Reply
User avatar
Archangel
Greenskin
Posts: 101
Joined: Sun Dec 19, 2004 6:02 pm
Location: Nantes, France
Contact:

MultiRenderTarget : different clear colors

Post by Archangel »

Hi!

I have two RenderTargets that are bound in a MultiRenderTarget.
Today, I needed to clear them with two different colors (color1 for the first, color2 for the second).

I searched a little and found out that the Viewport class (which takes care of clearing the background) is not "multi render target aware".
So I tried a few things and eventually got something working!

The idea is to create an additional viewport for each of the two render targets, and use them to clear the RTs independently (before content is rendered, using a render target listener on the MRT) :

Code: Select all

class SceneRenderTargetListener : public Ogre::RenderTargetListener
{
public :

    void preRenderTargetUpdate( const Ogre::RenderTargetEvent& mEvent )
    {
        // Clear the FIRST render target (color1)
        pRenderSystem->_setViewport(pRenderTarget1->getViewport(0));
        pRenderSystem->clearFrameBuffer(Ogre::FBT_COLOUR | Ogre::FBT_DEPTH, color1);

        // Clear the SECOND render target (color2)
        pRenderSystem->_setViewport(pRenderTarget2->getViewport(0));
        pRenderSystem->clearFrameBuffer(Ogre::FBT_COLOUR | Ogre::FBT_DEPTH, color2);
    }
};
Creation of the render targets :

Code: Select all

// Create the two render targets
pRenderTarget1 = Ogre::TextureManager::getSingleton().createManual(
    "Target1", "General", Ogre::TEX_TYPE_2D, 1024, 1024, 0, Ogre::PF_A8R8G8B8, Ogre::TU_RENDERTARGET
)->getBuffer()->getRenderTarget();

pRenderTarget2 = Ogre::TextureManager::getSingleton().createManual(
    "Target2", "General", Ogre::TEX_TYPE_2D, 1024, 1024, 0, Ogre::PF_A8R8G8B8, Ogre::TU_RENDERTARGET
)->getBuffer()->getRenderTarget();

// Viewports for clearing
pRenderTarget1->addViewport(NULL);
pRenderTarget2->addViewport(NULL);

// Multi render target
pMRT_ = pRenderSystem->createMultiRenderTarget("Scene_MRT");
pMRT->addListener(new SceneRenderTargetListener());
pMRT->bindSurface(0, pRenderTarget1);
pMRT->bindSurface(1, pRenderTarget2);

// ... and its viewport
pViewport = pMRT->addViewport(pMainCamera);
pViewport->setClearEveryFrame(false);
I haven't measured any performance impact, so it seems to be quite efficient.

But it's not very handy... Actually I'd prefer to write something like :

Code: Select all

pViewport->setBackgroundColor(0, color1);
pViewport->setBackgroundColor(1, color1);
Internally, the viewport would store all the colors in an array.
Then in SceneManager::_renderScene() :

Code: Select all

// Clear the viewport if required
if (mCurrentViewport->getClearEveryFrame())
{
    MultiRenderTarget* mrt = dynamic_cast<MultiRenderTarget*>(mCurrentViewport->getTarget());
    if (mrt)
    {
        // This viewport's target is a multi render target : clear each bound targets
        const MultiRenderTarget::BoundSurfaceList& rtList = mrt->getBoundSurfaceList();

        MultiRenderTarget::BoundSurfaceList::const_iterator iter;
        for (iter = rtList.begin(), int i = 0; iter != rtList.end(); ++iter, ++i)
        {
            Viewport* vp = (*iter)->addViewport(NULL, SOME_MAGIC_Z_VALUE);

            mDestRenderSystem->setViewport(vp);
            mDestRenderSystem->clearFrameBuffer(
                mCurrentViewport->getClearBuffers(i),
                mCurrentViewport->getBackgroundColour(i)
            );

            (*iter)->removeViewport(SOME_MAGIC_Z_VALUE);
        }
        
        mDestRenderSystem->setViewport(mCurrentViewport);
    }
    else
    {
        // This viewport's target is a simple render target : just clear it
        mDestRenderSystem->clearFrameBuffer(
            mCurrentViewport->getClearBuffers(),
            mCurrentViewport->getBackgroundColour()
        );
    }
}
What do you think ?
Of course, SOME_MAGIC_Z_VALUE is to be defined... (this viewport indexing system is not very handy, if you ask me).

NOTE : this is untested code!
Arch. / Kalith
SimonW
Gnoblar
Posts: 21
Joined: Wed Aug 12, 2009 3:39 pm
Location: Vienna, Austria

Re: MultiRenderTarget : different clear colors

Post by SimonW »

I was just facing a (maybe) slightly different problem; I'm using a GBuffer to access depth and normal values in a compositor. And that's also where I clear my mrt that acts as the GBuffer. I'll explain my approach with some code:

Code: Select all

compositor SSAO/GBuffer
{
	technique
	{
		// GBuffer enconding: --------------------------------------------------
		// mrt0: rgba --> unused in this sample
		// mrt1: xyz --> normals, w --> normalized lieanar depth [-1, 1]
		// mrt2: xyz --> position in view space
		// ---------------------------------------------------------------------
		
		texture mrt target_width target_height PF_R8G8B8A8 PF_R8G8B8A8 PF_R8G8B8A8 chain_scope

		target mrt
		{
			input none
			shadows off
			
			pass clear {}
			
			pass render_quad
			{
				material SSAO/ClearGBuffer
			}			

			pass render_scene {}
		}
	}
}

Code: Select all

fragment_program SSAO/ClearGBuffer_fp cg
{
	source ClearGBuffer.cg
	entry_point ClearGBuffer_fp
	profiles ps_2_x arbfp1
}

material SSAO/ClearGBuffer
{
	technique
	{
		pass
		{
			depth_write off

			fragment_program_ref SSAO/ClearGBuffer_fp {}
		}
	}
}

Code: Select all

void ClearGBuffer_fp
(
	out float4 oColor0 : COLOR0,
	out float4 oColor1 : COLOR1,
	out float4 oColor2 : COLOR2
)
{
	oColor0 = float4(0, 0, 0, 0);	// rgba
	oColor1 = float4(0.5, 0.5, 0.5, 1);	// normal + liear depth [0..1]
	oColor2 = float4(0, 0, 0, 0);	// position in view space + unused
}
Rendering to the GBuffer and all its magic is based on the deffered shading sample, that comes with ogre.

So, what does that code do:
The mrt is created, a general clear pass is executed and an full screen quad with my clear material is rendered. This material writes my clear values to the different layers of the mrt. It is important to note, that depth writing is deactivated for the clear material. This allows the later reder_scene pass to overwrite the buffers where needed.

I don't know if this code is applicable for your problem. The nice thing about is, that it neatly integrates with an existing GBuffer/deffered shading/compositor approach (at least in my case it does). Since I'm not going after performance right now, I don't know how much it costs compared to the viewport approach. Any suggestions on that?

regards, Simon
User avatar
Archangel
Greenskin
Posts: 101
Joined: Sun Dec 19, 2004 6:02 pm
Location: Nantes, France
Contact:

Re: MultiRenderTarget : different clear colors

Post by Archangel »

This is surely possible (and I actually didn't think about it), but I was mainly interested in a convenient programmatical solution.
That said, isn't clearing via shaders slower than with the fixed pipeline ?
Arch. / Kalith
nbeato
Gnome
Posts: 372
Joined: Thu Dec 20, 2007 1:00 am
Location: Florida
x 3
Contact:

Re: MultiRenderTarget : different clear colors

Post by nbeato »

For what it is worth, I cleared a MRT the same way (with a shader). The shaders are pretty straightforward and low instruction count, so I didn't think there would be a difference. It was about 5 minutes of work to set up, but programmatically, I think it is easier to maintain that way. I'd be curious to know if there is a noticeable framerate issue. I haven't seen anything unacceptably slow yet, so I haven't worried about it. If anything, I'm trying to say that I assumed it would not be slower (at least noticeably slower after scene rendering and post processing).
Post Reply