Render To Texture Without Updating Default Window

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
kkrizka
Posts: 70
Joined: Sun Sep 30, 2007 3:10 am

Render To Texture Without Updating Default Window

Post by kkrizka »

Hi all,

I am using the render-to-texture to generate an image of a scene and pass it to a different toolkit to display as an image. The rendering seems to work fain, but I have one more problem. The rendering has to be done between beginScene and endScene, which is fain. But endScene then copies my texture to the default screen, which means that the texture will be displayed for a bit before I overdraw it with the actual camera. I do not want this to happen. So my question is, is there to run endScene without having the final result being copied to the default screen?

I should also mention that since I am using another toolkit to display the rendered texture (it also requests updates of the texture), the render-to-texture method will be called outside of my main scene rendering loop, so I cannot use it's endScene to finish everything.
Cheers,
Karol Krizka

http://www.krizka.net
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

When using the RTT feature properly, the texture shouldn't be visible on the screen. At least that was my impression. Could you show the relevant code (your RTT render loop and the main render loop, including texture creation calls etc.)? Maybe there's something to optimize.
kkrizka
Posts: 70
Joined: Sun Sep 30, 2007 3:10 am

Post by kkrizka »

Sorry about the late reply, but I've got sidetracked on another project. So I hope someone here will be still willing to help me. :)

Anyways, I've modified the RTT example from irrlicht and split it into two beginScenes, so it simulates what I have in my application. When you run it with OpenGL driver (at least on Linux), there is a fast flicker and you see the texture being rendered to in the lower left corner. I should point out that this works on DirectX9.

Code: Select all

#include <irrlicht.h>

#include <iostream>



using namespace irr;



#pragma comment(lib, "Irrlicht.lib")



int main()

{

	// let user select driver type



	video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;



	printf("Please select the driver you want for this example:\n"\

		" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\

		" (d) Software Renderer\n (e) Burning's Software Renderer\n"\

		" (f) NullDevice\n (otherKey) exit\n\n");



	char i;

	std::cin >> i;



	switch(i)

	{

		case 'a': driverType = video::EDT_DIRECT3D9;break;

		case 'b': driverType = video::EDT_DIRECT3D8;break;

		case 'c': driverType = video::EDT_OPENGL;   break;

		case 'd': driverType = video::EDT_SOFTWARE; break;

		case 'e': driverType = video::EDT_BURNINGSVIDEO;break;

		case 'f': driverType = video::EDT_NULL;     break;

		default: return 1;

	}	



	// create device and exit if creation failed



	IrrlichtDevice *device =

		createDevice(driverType, core::dimension2d<s32>(640, 480),

		16, false, false);



	if (device == 0)

		return 1; // could not create selected driver.



	video::IVideoDriver* driver = device->getVideoDriver();

	scene::ISceneManager* smgr = device->getSceneManager();

	gui::IGUIEnvironment* env = device->getGUIEnvironment();

	

	/*

	Now, we load an animated mesh to be displayed. As in most examples,

	we'll take the fairy md2 model. The difference here: We set the shininess

	of the model to a value other than 0 which is the default value. This

	enables specular highlights on the model if dynamic lighting is on.

	The value influences the size of the highlights.

	*/



	// load and display animated fairy mesh



	scene::IAnimatedMeshSceneNode* fairy = smgr->addAnimatedMeshSceneNode(

		smgr->getMesh("../../media/faerie.md2"));



	if (fairy)

	{

		fairy->setMaterialTexture(0, driver->getTexture("../../media/faerie2.bmp")); // set diffuse texture

		fairy->setMaterialFlag(video::EMF_LIGHTING, true); // enable dynamic lighting

		fairy->getMaterial(0).Shininess = 20.0f; // set size of specular highlights

		fairy->setPosition(core::vector3df(-10,0,-100));

		fairy->setMD2Animation ( scene::EMAT_STAND );

	}

	

	/*

	To make specular highlights appear on the model, we need a dynamic light in the scene.

	We add one directly in vicinity of the model. In addition, to make the model not that 

	dark, we set the ambient light to gray. 

	*/



	// add white light

	scene::ILightSceneNode* light = smgr->addLightSceneNode(0,

		core::vector3df(-15,5,-105), video::SColorf(1.0f, 1.0f, 1.0f));



	// set ambient light

	smgr->setAmbientLight(video::SColor(0,60,60,60));

	

	/*

	The next is just some standard stuff: Add a user controlled camera to the scene, disable

	mouse cursor, and add a test cube and let it rotate to make the scene more interesting.

	*/



	// add fps camera

	scene::ICameraSceneNode* fpsCamera = smgr->addCameraSceneNodeFPS();

	fpsCamera->setPosition(core::vector3df(-50,50,-150));



	// disable mouse cursor

	device->getCursorControl()->setVisible(false);



	// create test cube

	scene::ISceneNode* test = smgr->addCubeSceneNode(60);



	// let the cube rotate and set some light settings

	scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(

		core::vector3df(0.3f, 0.3f,0));



	test->setPosition(core::vector3df(-100,0,-100));

	test->setMaterialFlag(video::EMF_LIGHTING, false); // disable dynamic lighting

	test->addAnimator(anim);

	anim->drop();



	// set window caption

	device->setWindowCaption(L"Irrlicht Engine - Render to Texture and Specular Highlights example");

	

	/*

	To test out the render to texture feature, we need a render target texture. These are not 

	like standard textures, but need to be created first. To create one, we call 

	IVideoDriver::createRenderTargetTexture() and specify the size of the texture. Please

	don't use sizes bigger than the frame buffer for this, because the render target shares

	the zbuffer with the frame buffer. And because we want to render the scene not from the

	user camera into the texture, we add another, fixed camera to the scene. But before we

	do all this, we check if the current running driver is able to render to textures. If 

	it is not, we simply display a warning text.

	*/



	// create render target

	video::ITexture* rt = 0;

	scene::ICameraSceneNode* fixedCam = 0;

	



	if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET))

	{

		rt = driver->createRenderTargetTexture(core::dimension2d<s32>(256,256));

		test->setMaterialTexture(0, rt); // set material of cube to render target



		// add fixed camera

		fixedCam = smgr->addCameraSceneNode(0, core::vector3df(10,10,-80),

			core::vector3df(-10,10,-100));

	}

	else

	{

		// create problem text

		gui::IGUISkin* skin = env->getSkin();

		gui::IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");

		if (font)

			skin->setFont(font);



		gui::IGUIStaticText* text = env->addStaticText(

			L"Your hardware or this renderer is not able to use the "\

			L"render to texture feature. RTT Disabled.",

			core::rect<s32>(150,20,470,60));



		text->setOverrideColor(video::SColor(100,255,255,255));

	}

	

	/*

	Nearly finished. Now we need to draw everything. Every frame, we draw the scene twice.

	Once from the fixed camera into the render target texture and once as usual. When rendering

	into the render target, we need to disable the visibilty of the test cube, because it has

	the render target texture applied to it.

	That's, wasn't quite complicated I hope. :)

	*/



	int lastFPS = -1;



	while(device->run())

	if (device->isWindowActive())

	{



		if (rt)

		{

			// draw scene into render target

			

			// set render target texture

			driver->setRenderTarget(rt, true, true, video::SColor(0,0,0,255));     

			driver->beginScene(true, true, 0);





			// make cube invisible and set fixed camera as active camera

			test->setVisible(false);

			smgr->setActiveCamera(fixedCam);



			// draw whole scene into render buffer

			smgr->drawAll();                 

		// draw scene normally

		smgr->drawAll(); 

		env->drawAll();



		driver->endScene();





			// set back old render target

			// The buffer might have been distorted, so clear it

			driver->setRenderTarget(0, true, true, 0);      

			driver->beginScene(true, true, 0);



			// make the cube visible and set the user controlled camera as active one

			test->setVisible(true);

			smgr->setActiveCamera(fpsCamera);

		}

		

		// draw scene normally

		smgr->drawAll(); 

		env->drawAll();



		driver->endScene();



		// display frames per second in window title

		int fps = driver->getFPS();

		if (lastFPS != fps)

		{

			core::stringw str = L"Irrlicht Engine - Render to Texture and Specular Highlights example";

			str += " FPS:";

			str += fps;



			device->setWindowCaption(str.c_str());

			lastFPS = fps;

		}

	}



	if (rt)

		rt->drop(); // drop render target because we created if with a create() method



	device->drop(); // drop device

	return 0;

}
Cheers,
Karol Krizka

http://www.krizka.net
FreakNigh
Posts: 122
Joined: Thu Oct 19, 2006 7:31 am
Location: Orlando FL, USA
Contact:

Post by FreakNigh »

Code: Select all

	device->getFileSystem()->addZipFileArchive("media/map-20kdm2.pk3");
	IAnimatedMesh* mesh2 = smgr->getMesh("20kdm2.bsp");
	ISceneNode* node2 = 0;
	if (mesh2)
		node2 = smgr->addOctTreeSceneNode(mesh2->getMesh(0), 0, -1, 128);
	if (node2)
		node2->setPosition(vector3df(-1300,-144,-1249));
add that into the render example and you'll get garbage in your rendered texture.
FreakNigh
Posts: 122
Joined: Thu Oct 19, 2006 7:31 am
Location: Orlando FL, USA
Contact:

Post by FreakNigh »

Using multiple begin / end scenes is what is causing the flickering.
kkrizka
Posts: 70
Joined: Sun Sep 30, 2007 3:10 am

Post by kkrizka »

FreakNigh wrote:Using multiple begin / end scenes is what is causing the flickering.
Yes, that is what I noticed too (actually, it is the presence of just the endScene that is causing it). But I'm wondering if there is a way to use multiple endScenes without the flicker. hybrid mentioned in the post above that it should be possible, as far as he knows.

Also the first begin/end scene calls are called while the render target is a texture, so I don't think that in theory the screen should be updated at all.
Cheers,
Karol Krizka

http://www.krizka.net
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

It could be a problem with lack of FBO support. Since we use a texture instead, it might cause a flicker because of framebuffer clear calls. I'll try to check this when I fix the RTT locking, maybe we can also enhance the buffer usage for non-FBO RTTs-
kkrizka
Posts: 70
Joined: Sun Sep 30, 2007 3:10 am

Post by kkrizka »

hybrid wrote:It could be a problem with lack of FBO support. Since we use a texture instead, it might cause a flicker because of framebuffer clear calls. I'll try to check this when I fix the RTT locking, maybe we can also enhance the buffer usage for non-FBO RTTs-
Yeah, I'm starting to think that this might have something to do with the lack of some extension on the computer because I tested this on my laptop with an Intel video card. But now I got the chance to try it out with an Nvidia card and did not have the problem with seeing the texture being rendered to the screen.

Here are some more information on the cards, as given by Irrlicht:

Code: Select all

Linux 2.6.24-19-generic #1 SMP Fri Jul 11 23:41:49 UTC 2008 i686
Using renderer: OpenGL 1.4
Mesa DRI Intel(R) 965GM 4.1.3002 x86/MMX/SSE2: Tungsten Graphics, Inc
OpenGL driver version is 1.2 or better.
GLSL not available.

Code: Select all

Linux 2.6.18-53.1.21.el5 #1 SMP Tue May 20 10:08:35 EDT 2008 i686
Using renderer: OpenGL 2.1.2
GeForce FX 5500/AGP/SSE2: NVIDIA Corporation
OpenGL driver version is 1.2 or better.
GLSL version: 1.3

But I did have one more problem (with nvidia) with flicker on operations that took a bit longer, but I managed to solve it. I just had to make sure that I did not clear the backbuffer of the screen render target when I set it. Basically I changed

Code: Select all

      Device->getVideoDriver()->setRenderTarget(0);
to

Code: Select all

      Device->getVideoDriver()->setRenderTarget(0,false,true);
Cheers,
Karol Krizka

http://www.krizka.net
FreakNigh
Posts: 122
Joined: Thu Oct 19, 2006 7:31 am
Location: Orlando FL, USA
Contact:

Post by FreakNigh »

incase you haven't noticed..

Code: Select all

         // draw whole scene into render buffer

         smgr->drawAll();                 

      // draw scene normally

      smgr->drawAll(); 
kkrizka
Posts: 70
Joined: Sun Sep 30, 2007 3:10 am

Post by kkrizka »

I think I've found what could be causing the problem. When I call endScene() after drawing to the RTT, it calls glXSwapBuffers which updates the screen with the backbuffer. But on my Intel card, I'm guessing that the backbuffer is being shared with my render texture, so when I draw to it the texture and call endScene, it becomes flipped to the display.

But then if I call glXSwapBuffers only if a RTT is not set, then there is no flicker.

Would this be considered as a bug in Irrlicht?
Cheers,
Karol Krizka

http://www.krizka.net
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

I'll have to check this on my Intel card. Anyway, moving it to bug forum won't hurt...
Post Reply