Custom rendering order with no need for a z buffer

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
Munger
Posts: 28
Joined: Sun Mar 04, 2007 11:39 am
Location: Tokyo

Custom rendering order with no need for a z buffer

Post by Munger »

The application I'm working on is composed of layers going back into the screen. Imagine an old parallax scrolling game for example. Each layer can have little 2D tiles over it though, so at the moment I'm suffering from z-fighting. I could offset the tiles slightly above the layer they are on, but that won't completely solve the problem entirely and since I know the order I want to draw everything in, I'd like to call the render method of each scene node individually.

I tried a straight-forward approach and it just rendered the background color. Then I looked through the Irrlicht source and realized I hadn't added the camera to my custom rendering loop. So I copied that in (along with anything else that seemed relevant), but I still just get the background color.

So how would I go about specifying the render order of my objects? I'd really prefer not to use actual z-differences to get the effect, and it seems like a simple thing to ask. I know in straight OpenGL or DirectX it would be really straight-forward.

My original loop (ripped pretty much straight from the examples) was:

Code: Select all

driver->beginScene(true, true, video::SColor(255,128,0,0));
smgr->drawAll();
env->drawAll();
driver->endScene();
The current (non-working) version is:

Code: Select all

driver->beginScene(true, true, video::SColor(255,128,0,0));
if ( driver )
{
	core::matrix4 identity;
	driver->setTransform ( video::ETS_PROJECTION, identity );
	driver->setTransform ( video::ETS_VIEW, identity );
	driver->setTransform ( video::ETS_WORLD, identity );
	driver->setTransform ( video::ETS_TEXTURE_0, identity );
	driver->setTransform ( video::ETS_TEXTURE_1, identity );
	driver->setTransform ( video::ETS_TEXTURE_2, identity );
	driver->setTransform ( video::ETS_TEXTURE_3, identity );
}
smgr->getActiveCamera()->OnRegisterSceneNode();
smgr->getActiveCamera()->render();
controller->GetTarget()->GetSection()->Render();
env->drawAll();
driver->endScene();
I also notice in the source code that regular scene nodes are sorted according to material before rendering.
fmx

Post by fmx »

I'm sure there's better ways of achieving what you want, but to render nodes manually, just set their visibility to false and render them in whatever order you want at a later time:

Code: Select all

node1->setVisibility(false);
node2->setVisibility(false);

...

node2->render();
node1->render();
I can't remember the exact syntax, but something like that
Munger
Posts: 28
Joined: Sun Mar 04, 2007 11:39 am
Location: Tokyo

Post by Munger »

That makes a lot of sense. I'll give it try.
Munger
Posts: 28
Joined: Sun Mar 04, 2007 11:39 am
Location: Tokyo

Post by Munger »

It's not working like that. I suspect it's because the 'CurrentRendertime' of the SceneManager is no longer what it needs to be for the mesh's 'render' method to work. It's going to be caught in this section of CMeshSceneNode.cpp:

Code: Select all

video::IMaterialRenderer* rnd = driver->getMaterialRenderer(material.MaterialType);
bool transparent = (rnd && rnd->isTransparent());

// only render transparent buffer if this is the transparent render pass
// and solid only in solid pass
if (transparent == isTransparentPass) 
{
	driver->setMaterial(material);
	driver->drawMeshBuffer(mb);
}
It'll skip over the 'drawMeshBufferCall'. I'll try recreating the important parts of the render method and call driver->drawMeshBuffer(mb) myself.
Munger
Posts: 28
Joined: Sun Mar 04, 2007 11:39 am
Location: Tokyo

Post by Munger »

Now I'm getting somewhere. The geometry is there, but it's black. I'll keep at it :-)

Here's the code I'm using (you'll notice it's quite similar to the render method of CMeshSceneNode):

Code: Select all

void GTRenderable::RenderToDevice(IVideoDriver *driver, IMeshSceneNode *node)
{
	IMesh* mesh = node->getMesh();
	driver->setTransform(video::ETS_WORLD, node->getAbsoluteTransformation());
	for (unsigned int i=0; i<mesh->getMeshBufferCount(); ++i)
	{
		scene::IMeshBuffer* mb = mesh->getMeshBuffer(i);
		if (mb)
		{
			const video::SMaterial& material = mb->getMaterial();
			driver->setMaterial(material);
			driver->drawMeshBuffer(mb);
		}
	}
}
Munger
Posts: 28
Joined: Sun Mar 04, 2007 11:39 am
Location: Tokyo

Post by Munger »

OK. I'm back in business the problem with the last code chunk was with the material. I was ignoring the read-only material flag - incorrectly. They updated (and functional) line is:

Code: Select all

const video::SMaterial& material = node->isReadOnlyMaterials() ? mb->getMaterial() : node->getMaterial(i);
Thanks fmx for getting me going in a better direction.
Munger
Posts: 28
Joined: Sun Mar 04, 2007 11:39 am
Location: Tokyo

Post by Munger »

And one last thing for anyone else trying to do the same thing, you'll need to call updateAbsolutePosition() on the node manually since that gets called as part of the rendering process normally.
fmx

Post by fmx »

good to hear you got it working :)
Mikhail9
Posts: 54
Joined: Mon Jun 29, 2009 8:41 am

Post by Mikhail9 »

After a lot of time digging in the forum trying to figure out why my shadows quit working when my mini-map was on the screen, I discovered they worked when I set the map node as invisible in order to completely prevent the first render pass from drawing it. Apparently, it's presence close to the camera fools the stencil buffer shadow system into thinking no shadows need to be drawn.

Then I discovered my manual node->render() call after drawAll() wasn't actually doing anything. After much digging through the Irrlicht source code, I discovered your post about calling node->updateAbsolutePosition() and it fixed the problem. That function normally gets called as part of OnAnimate() in the drawAll() call. Why it needs called again when nothing has changed is somewhat of mystery to me.

Anyway, thanks for following up by posting your solution. I wouldn't have thought to try that, at least not for many more hours.
Post Reply