Z-buffer failing on render targets

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Z-buffer failing on render targets

Post by slavik262 »

Simply put, z-buffer tests don't work when I render to texture.

I'm extremely confused as to why this is happening. Switching from

Code: Select all

sm->drawAll();
to my post processing RenderScene() function,

Code: Select all

		vd->setRenderTarget(rts[outputRT]);
		sm->drawAll();

		//Apply post processes
		u32 sz = postProcesses.size();

		if(sz > 0)
		{
			//Flip RTs (the target becomes the source and vice versa)
			outputRT = !outputRT;
		}

		for(u32 c = 0; c < sz; c++)
		{
			postProcesses[c]->Render(rts[!outputRT], rts[outputRT]);

			//Flip RTs (the target becomes the source and vice versa)
			outputRT = !outputRT;
		}

		//Render the final image to the frame buffer
		outputRT = !outputRT;
		
		quad.SetTexture(rts[outputRT]);
		quad.Render();
instantly causes this to happen:

Image

The objects are drawing in their draw order with no regard to z-testing. The cone is farthest away, and the sphere is in the middle.

What gives?
Last edited by slavik262 on Mon Aug 09, 2010 7:27 pm, edited 4 times in total.
stefbuet
Competition winner
Posts: 495
Joined: Sun Dec 09, 2007 4:13 pm
Location: france

Post by stefbuet »

Idk what's your problem, but I know you can use a single render target as source and target like that :

Code: Select all

driver->setRenderTarget(RTT, false);
quad->setMaterialTexture(0, RTT);
quad->render();
This can save you some video memory space.

Now for your problem, I don't really see...
postProcesses[c]->Render(rts[!outputRT], rts[outputRT]); is only doing some postprocess on a quad right ?
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

Correct... I don't know what the problem is. Even after stripping out the postprocessing code (and just doing a normal render to texture, then rendering that texture on a quad), it still ignores z-testing
Lonesome Ducky
Competition winner
Posts: 1123
Joined: Sun Jun 10, 2007 11:14 pm

Post by Lonesome Ducky »

Hmm, you might have to look elsewhere in your code. I've never had z problems when I've used render targets, so I can't imagine it's just the setting render target doing it.
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

That's the weird thing though... all I have to do is swap out the code I posted with ISceneManager::drawAll() and things work perfectly again. Is there a way the z-buffer could be disabled somehow? No, I didn't change any of the material settings for those objects.

I'm also using a more recent version of the engine (I grabbed it off the Irrlicht nightly builds site on July 20). Has there been some fix in the SVN related to this since?

Anyone? This is a pretty large issue.
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

I just grabbed another build today and the problem still exists. Can anyone verify this in the current build?
porcus
Posts: 149
Joined: Sun May 27, 2007 6:24 pm
Location: Germany

Post by porcus »

I'm just guessing but maybe it's a problem with the transformation.
Try to set the transformations manually with irr::video::IVideoDriver::setTransform.
Try (just to make sure) to set all the model, view and projection matrix
before you render the stuff. Note: You should set the absolute
transformation of each node as model transformation. You can get
the view and projection matrix from your current camera.

I remember that I had some problems with post processing when
I switched the cameras before rendering the stuff manually. Setting
the transformations with setTransform solved the problem.
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

The view and projection matrices are set automatically when the scene manager calls render() on the camera scene node during ISceneManager::drawAll(). The world matrix (absolute transformation) is set by the render() calls on each scene node.

Even doing this in my quad::render function yields the same result.

Code: Select all

		void Render(ITexture* rt)
		{
			//TEMP
			matrix4 world = vd->getTransform(ETS_WORLD);
			matrix4 view = vd->getTransform(ETS_VIEW);
			matrix4 projection = vd->getTransform(ETS_PROJECTION);

			vd->setRenderTarget(rt);
			vd->setMaterial(mat);
			vd->setTransform(ETS_WORLD, core::IdentityMatrix);
			vd->setTransform(ETS_VIEW, core::IdentityMatrix);
			vd->setTransform(ETS_PROJECTION, core::IdentityMatrix);
			vd->drawIndexedTriangleList(vertices, 4, indices, 2);

			//Temp
			vd->setTransform(ETS_WORLD, world);
			vd->setTransform(ETS_VIEW, view);
			vd->setTransform(ETS_PROJECTION, projection);
		}
So it's definitely a z-test issue and not a matrix issue.

I'm compiling this with the newest DirectX SDK (June 2010).

Any new suggestions?
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

I'll create a test program that isolates the issue. In the meantime, if anyone has any ideas as to what the problem might be, let me know. Thanks!
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

I found the issue, and it blows my mind. It is...

Code: Select all

cp.WindowSize -= dimension2d<u32>(100, 100)
where cp is my IrrlichtCreationParameter struct.

I made the window a bit smaller than the screen (100 pixels each way) to make it easier to work with. Apparently since the window was no longer a size returned by IVideoModeList::getVideoModeResolution, z-buffering just stopped.

Should I post this as a bug?
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Usually, rtts create their own zbuffer. Sometimes, they share them, though. Please post a full example of how to reproduce the error here. I'll move this thread to bug forum for further investigations.
slavik262
Posts: 753
Joined: Sun Nov 22, 2009 9:25 pm
Location: Wisconsin, USA

Post by slavik262 »

Code: Select all

#include <irrlicht.h>
#pragma comment(lib, "irrlicht.lib")

using namespace irr;
using namespace io;
using namespace core;
using namespace video;
using namespace scene;

#define RENDER_TO_TEXTURE

int main(int argc, char* argv[])
{
	SIrrlichtCreationParameters cp;
	cp.Bits = 32;
	cp.AntiAlias = 4;
	cp.DriverType = EDT_DIRECT3D9;

	IrrlichtDevice* nullDevice = createDevice(EDT_NULL);
	cp.WindowSize = nullDevice->getVideoModeList()->getDesktopResolution();
	nullDevice->drop();

	//cp.WindowSize -= dimension2d<u32>(100, 100);

	IrrlichtDevice* device = createDeviceEx(cp);

	IVideoDriver* vd = device->getVideoDriver();
	ISceneManager* sm = device->getSceneManager();

	if(!vd->queryFeature(video::EVDF_RENDER_TO_TARGET))
		return 1;

#ifdef RENDER_TO_TEXTURE
	ITexture* rt = vd->addRenderTargetTexture(cp.WindowSize, "rt", ECOLOR_FORMAT::ECF_A32B32G32R32F);
	S3DVertex vertices[4];
	vertices[0].Pos.Z = vertices[1].Pos.Z = vertices[2].Pos.Z =
		vertices[3].Pos.Z = 1.0f;
	vertices[0].Pos.Y = vertices[1].Pos.Y = 1.0f;
	vertices[2].Pos.Y = vertices[3].Pos.Y = -1.0f;
	vertices[0].Pos.X = vertices[3].Pos.X = -1.0f;
	vertices[1].Pos.X = vertices[2].Pos.X = 1.0f;
	vertices[0].TCoords.Y = vertices[1].TCoords.Y = 0.0f;
	vertices[2].TCoords.Y = vertices[3].TCoords.Y = 1.0f;
	vertices[0].TCoords.X = vertices[3].TCoords.X = 1.0f;
	vertices[1].TCoords.X = vertices[2].TCoords.X = 0.0f;

	u16 indices[6] = {0, 1, 3, 1, 2, 3};

	SMaterial rtMat;
	rtMat.BackfaceCulling = false;
	rtMat.Lighting = false;
	rtMat.TextureLayer[0].TextureWrapU =
		rtMat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;

#endif

	ILightSceneNode* light = sm->addLightSceneNode(NULL, vector3df(0, 50, 0),
		SColorf(1, 1, 1), 100);
	SLight& lightData = light->getLightData();

	ICameraSceneNode* cam = sm->addCameraSceneNode(NULL, vector3df(0, 10, 0));

	const IGeometryCreator* geom = sm->getGeometryCreator();
	IMeshManipulator* manip = sm->getMeshManipulator();
	IMesh* mesh;
	ISceneNode* node;
	
	mesh = geom->createCubeMesh(vector3df(10, 10, 10));
	manip->setVertexColors(mesh, SColor(255, 0, 0, 255));
	node = sm->addMeshSceneNode(mesh, NULL, -1, vector3df(0, 0, 30));
	node->getMaterial(0).EmissiveColor = SColor(255, 0, 0, 30);
	mesh->drop();

	mesh = geom->createSphereMesh(5.0f, 32, 32);
	node = sm->addMeshSceneNode(mesh, NULL, -1, vector3df(0, 0, 50));
	node->getMaterial(0).EmissiveColor = SColor(255, 30, 30, 30);
	mesh->drop();

	mesh = geom->createConeMesh(5.0f, 10.0f, 32, SColor(255, 255, 0, 0),
		SColor(255, 255, 0, 0));
	node = sm->addMeshSceneNode(mesh, NULL, -1, vector3df(0, 0, 70));
	node->getMaterial(0).EmissiveColor = SColor(255, 30, 0, 0);
	mesh->drop();


	while(device->run())
	{
		vd->beginScene(true, true, SColor(255, 0, 0, 0))
#ifdef RENDER_TO_TEXTURE
		vd->setRenderTarget(rt);
		sm->drawAll();
		vd->setRenderTarget(NULL);
		vd->setTransform(ETS_WORLD, core::IdentityMatrix);
		vd->setTransform(ETS_VIEW, core::IdentityMatrix);
		vd->setTransform(ETS_PROJECTION, core::IdentityMatrix);
		rtMat.setTexture(0, rt);
		vd->setMaterial(rtMat);
		vd->drawIndexedTriangleList(vertices, 4, indices, 2);
#else
		sm->drawAll();
#endif
		vd->endScene()
	}

	device->drop();
	return 0;
}
The code as given will show the z-buffer working and the meshes displaying in the correct order (cube, sphere, cone).

Uncommenting line 23 (//cp.WindowSize -= dimension2d<u32>(100, 100); ) will cause the z-buffering to fail. The meshes will just be drawn in order that they were added, and the cone will show through the sphere.

A friend of mine who is a professional game programmer told me that z-buffers cannot usually be an arbitrary size, but are bound to supported resolutions of the driver and graphics card (such as those returned by IVideoModeList::getVideoModeResolution).
Post Reply