How to obtain REAL reflections with RenderToTexture (example 13)

A forum to store posts deemed exceptionally wise and useful
Post Reply
Noiecity
Posts: 163
Joined: Wed Aug 23, 2023 7:22 pm
Contact:

How to obtain REAL reflections with RenderToTexture (example 13)

Post by Noiecity »

Image

Using example 13 from the official irrlicht documentation, by modifying some variables a little, you can obtain realistic reflections of the environment in real time (applying the changes), and with a very good performance.



The modified code in question looks like this:

Code: Select all

/** Example 013 Render To Texture

This tutorial shows how to render to a texture using Irrlicht. Render to
texture is a feature where everything which would usually be rendered to 
the screen is instead written to a (special) texture. This can be used to 
create nice special effects.
In addition, this tutorial shows how to enable specular highlights.

In the beginning, everything as usual. Include the needed headers, ask the user
for the rendering driver, create the Irrlicht device:
*/

#include <irrlicht.h>
#include "driverChoice.h"
#include "exampleHelper.h"

using namespace irr;

#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif

int main()
{
	// ask user for driver
	video::E_DRIVER_TYPE driverType=driverChoiceConsole();
	if (driverType==video::EDT_COUNT)
		return 1;

	// create device and exit if creation failed

	IrrlichtDevice *device =
		createDevice(driverType, core::dimension2d<u32>(800, 600),
		16, true, 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();

	const io::path mediaPath = getExampleMediaPath();
	
	/*
	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(mediaPath + "faerie.md2"));

	if (fairy)
	{
		fairy->setMaterialTexture(0,
				driver->getTexture(mediaPath + "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
	smgr->addLightSceneNode(0, core::vector3df(-15,5,-105),
			video::SColorf(1.0f, 1.0f, 1.0f));

	// set ambient light
	smgr->setAmbientLight(video::SColor(1,1,3,14));
	
	/*
	The next is just some standard stuff: Add a test cube and let it rotate
	to make the scene more interesting. The user defined camera and cursor
	setup is made later on, right before the render loop.
	*/

	// create test cube
	scene::IAnimatedMesh* mesh = smgr->getMesh(mediaPath + "test1.obj");
	for (u32 j = 0; j < mesh->getMeshBufferCount(); ++j)
	{
		scene::IMeshBuffer* buffer = mesh->getMeshBuffer(j);
		video::E_VERTEX_TYPE vertexType = buffer->getVertexType();

		if (vertexType == video::EVT_2TCOORDS)
		{
			video::S3DVertex2TCoords* vertices = (video::S3DVertex2TCoords*)buffer->getVertices();
			u32 vertexCount = buffer->getVertexCount();

			for (u32 i = 0; i < vertexCount; ++i)
			{
				vertices[i].TCoords2.X = 1.0f - vertices[i].TCoords2.X; 
			}
		}
	}
	scene::IAnimatedMeshSceneNode* cube = smgr->addAnimatedMeshSceneNode(mesh);
	cube->setScale(core::vector3df(12.0f, 12.0f, 12.0f));
	cube->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
	// let the cube rotate and set some light settings
	scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(
		core::vector3df(0.3f, 0.3f,0));

	cube->setPosition(core::vector3df(-100,0,-100));
	cube->setMaterialType(video::EMT_REFLECTION_2_LAYER);
	cube->setMaterialFlag(video::EMF_LIGHTING, false); // disable dynamic lighting
	cube->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 to define our
	new rendertarget. The rendertarget will need one texture to receive
	the result you would otherwise see on screen and one texture
	which is used as depth-buffer. 

	(Note: If you worked with older Irrlicht versions (before 1.9) you might be 
	used to only create a rendertarget texture and no explicit rendertarget. While
	that's still possible, it's no longer recommended.)
	
	The rendertarget textures are not like standard textures, but need to be created
	first. To create them, we call IVideoDriver::addRenderTargetTexture()
	and specify the size of the texture and the type. 
	For depth-maps you can use types ECF_D16, ECF_D32 or ECF_D24S8. When ECF_D24S8 
	you can also use a stencil-buffer. 

	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::IRenderTarget* renderTarget = 0;
	scene::ICameraSceneNode* fixedCam = 0;
	// add a nice skybox

	driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);

	smgr->addSkyBoxSceneNode(
		driver->getTexture("../../media/irrlicht2_up.jpg"),
		driver->getTexture("../../media/irrlicht2_dn.jpg"),
		driver->getTexture("../../media/irrlicht2_lf.jpg"),
		driver->getTexture("../../media/irrlicht2_rt.jpg"),
		driver->getTexture("../../media/irrlicht2_ft.jpg"),
		driver->getTexture("../../media/irrlicht2_bk.jpg"));

	driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
	if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET))
	{
		const core::dimension2d<u32> rtDim(256, 256);	// always use same size for render target texture and it's depth-buffer
		video::ITexture* renderTargetTex = driver->addRenderTargetTexture(rtDim, "RTT1", video::ECF_A8R8G8B8);
		video::ITexture* renderTargetDepth = driver->addRenderTargetTexture(rtDim, "DepthStencil", video::ECF_D16); 

		renderTarget = driver->addRenderTarget();
		renderTarget->setTexture(renderTargetTex, renderTargetDepth);
		cube->setMaterialTexture(1, renderTargetTex); // set material of cube to render target

		// add fixed camera
		fixedCam = smgr->addCameraSceneNode(0, core::vector3df(cube->getPosition()),
			core::vector3df(-10,10,-100));

		fixedCam->setFOV(1.3f);
		
	}
	else
	{
		// create problem text
		gui::IGUISkin* skin = env->getSkin();
		gui::IGUIFont* font = env->getFont(mediaPath + "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));
	}
	
	// add fps camera
	scene::ICameraSceneNode* fpsCamera = smgr->addCameraSceneNodeFPS();
	fpsCamera->setPosition(core::vector3df(-50,50,-150));
	
	
	// disable mouse cursor
	device->getCursorControl()->setVisible(false);

	/*
	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 visibility of the test cube, because it has the
	render target texture applied to it. That's it, wasn't too complicated
	I hope. :)
	*/

	int lastFPS = -1;

	while(device->run())
	if (device->isWindowActive())
	{
		driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0));
		
		if (renderTarget)
		{
			// draw scene into render target
			
			// set render target
			driver->setRenderTargetEx(renderTarget, video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(0,0,0,255));

			// make cube invisible and set fixed camera as active camera
			cube->setVisible(false);
			smgr->setActiveCamera(fixedCam);
			fixedCam->setTarget(core::vector3df(fpsCamera->getPosition()));

			// draw whole scene into render buffer
			smgr->drawAll();

			// set back old render target (the screen)
			driver->setRenderTargetEx(0, 0);

			// make the cube visible and set the user controlled camera as active one
			cube->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;
		}
	}

	device->drop(); // drop device
	return 0;
}

/*
**/
The code still needs to add the update of the position of the camera positioned on the model, as soon as the model changes its position. It is also necessary to add specific conditions to verify if the model loaded correctly. The example works with relative and absolute position.

The files used (it is only the model and a texture) can be found in this post:
viewtopic.php?t=53047
**
If you are looking for people with whom to develop your game, even to try functionalities, I can help you, free. CC0 man.

Image
**
Post Reply