Postprocessing Example
Posted: Sun Apr 20, 2014 3:48 am
Here is an example to demonstrate how postprocessing works. In principle, render the scene to a texture and then render a rectangle with this texture. The code is a bit longer than this because you have to set up the shader as well. I took the screen quad from XEffects (Blindside) and he gives credit to CBAseFilter (ItIsFree). It is written for OpenGL. Type '1' for an effect and '0' to turn it off. ESC will terminate the program. You have to set IRRMEDIA (in the file) to the location of Irrlicht's media directory.
Code: Select all
//** Postprocessing Example
//**
//** This software is provided 'as-is' without any express or implied warranty.
//** Use at your own risk.
//**
#include <irrlicht.h>
#include <iostream>
// Irrlicht's 'media' directory
#define IRRMEDIA "../irrlicht-1.8.1/media/"
using namespace irr;
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
//**
//** Postprocessing code
//**
// the shader code
const c8* vs_pp =
"void main(void)\n"
"{\n"
" vec2 tCoords;\n"
" gl_Position = vec4(gl_Vertex.x, gl_Vertex.y, 0.0, 1.0);\n"
" tCoords.x = 0.5*(1.0 + gl_Vertex.x);\n"
" tCoords.y = 0.5*(1.0 + gl_Vertex.y);\n"
" gl_TexCoord[0].xy = tCoords.xy;\n"
"}\n";
const c8* ps_pp =
"uniform sampler2D render;\n"
"uniform sampler2D effect;\n"
"void main(void)\n"
"{\n"
" vec4 color1 = texture2D(render, gl_TexCoord[0].xy);\n"
" vec4 color2 = texture2D(effect, gl_TexCoord[0].xy);\n"
" vec4 final = color2.r*color1;\n"
" if (color1.r > 0.75)\n"
" final = 1.0*color1;\n"
" gl_FragColor = final;\n"
"}\n";
// the callback - called by Irrlicht before the screen quad is rendered
class PPShaderCallback : public video::IShaderConstantSetCallBack
{
public:
virtual void OnSetConstants(video::IMaterialRendererServices* services,
s32 userData)
{
video::IVideoDriver* vid = services->getVideoDriver();
// just set the textures
s32 TextureLayerID = 0;
// this is where the scne was rendered
services->setPixelShaderConstant("render", &TextureLayerID, 1);
TextureLayerID = 1;
// just a texture to create an effect
services->setPixelShaderConstant("effect", &TextureLayerID, 1);
}
};
// a class to hold our screen quad and render-target texture
class Postprocess
{
public:
Postprocess(IrrlichtDevice* device)
{
dev = device;
vid = device->getVideoDriver();
// render target
rtt = vid->addRenderTargetTexture(core::dimension2d<u32>(512, 512));
// material for screen quad
material.Wireframe = false;
material.Lighting = false;
material.ZWriteEnable = false;
// screen quad
vert[0] = video::S3DVertex(-1, -1, 0, 0, 0, 1, video::SColor(0), 0, 1);
vert[1] = video::S3DVertex(-1, 1, 0, 0, 0, 1, video::SColor(0), 0, 0);
vert[2] = video::S3DVertex( 1, 1, 0, 0, 0, 1, video::SColor(0), 1, 0);
vert[3] = video::S3DVertex( 1, -1, 0, 0, 0, 1, video::SColor(0), 1, 1);
// drawing order
index[0] = 0;
index[1] = 1;
index[2] = 2;
index[3] = 0;
index[4] = 2;
index[5] = 3;
}
~Postprocess()
{
if ((rtt))
vid->removeTexture(rtt);
dev->drop();
}
void render()
{
vid->setMaterial(material);
vid->setTransform(video::ETS_WORLD, core::matrix4());
vid->drawIndexedTriangleList(vert, 4, index, 2);
}
video::SMaterial& getMaterial()
{
return material;
}
IrrlichtDevice* dev;
video::IVideoDriver* vid;
video::ITexture* rtt;
video::SMaterial material;
video::S3DVertex vert[4];
u16 index[6];
};
//**
//** SCENE
//**
/* shader code */
const c8* vs_tex =
"uniform mat4 mWorldViewProj;\n"
"void main(void)\n"
"{\n"
" gl_Position = mWorldViewProj*gl_Vertex;\n"
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
"}\n";
const c8* ps_tex =
"uniform sampler2D myTexture;\n"
"void main(void)\n"
"{\n"
" gl_FragColor = texture2D(myTexture, vec2(gl_TexCoord[0]));\n"
"}\n";
class TextureShaderCallback : public video::IShaderConstantSetCallBack
{
public:
virtual void OnSetConstants(video::IMaterialRendererServices* services,
s32 userData)
{
video::IVideoDriver* vid = services->getVideoDriver();
core::matrix4 worldViewProj;
worldViewProj = vid->getTransform(video::ETS_PROJECTION);
worldViewProj *= vid->getTransform(video::ETS_VIEW);
worldViewProj *= vid->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant("mWorldViewProj", worldViewProj.pointer(), 16);
s32 TextureLayerID = 0;
services->setPixelShaderConstant("myTexture", &TextureLayerID, 1);
}
};
// handle keystrokes
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver() : ppEffect(0) {}
virtual bool OnEvent(const SEvent& event)
{
if (event.EventType == irr::EET_KEY_INPUT_EVENT &&
event.KeyInput.PressedDown)
switch (event.KeyInput.Key)
{
case 27: // ESC
ppEffect = -1; // signal to quit
break;
case '0': // no effect
case '1': // effect
ppEffect = event.KeyInput.Key - '0';
break;
}
return false;
}
int ppEffect;
};
int main()
{
std::cout << "main" << std::endl;
// create an OpenGL instance
IrrlichtDevice* device = createDevice(video::EDT_OPENGL,
core::dimension2d<u32>(800, 800));
if (device == 0)
{
std::cout << "Could not create an OpenGL context" << std::endl;
return 1; // could not create selected driver.
}
video::IVideoDriver* driver = device->getVideoDriver();
video::ITexture* theTex = driver->getTexture(IRRMEDIA "wall.bmp");
if (theTex == 0)
{
std::cout << "Could not create a texture from 'wall.bmp'" << std::endl;
std::cout << "Check your setting of IRRMEDIA" << std::endl;
return 2;
}
//**
//** Postprocessing code
//**
// create material
video::IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices();
if (gpu == 0)
{
std::cout << "Could not access the GPU" << std::endl;
return 3;
}
s32 ppShader;
PPShaderCallback* ppcb = new PPShaderCallback();
// create the shaders (GLSL)
ppShader = gpu->addHighLevelShaderMaterial(
vs_pp, "vertexMain", video::EVST_VS_1_1,
ps_pp, "pixelMain", video::EPST_PS_1_1,
ppcb, video::EMT_SOLID, 0, video::EGSL_DEFAULT);
if (ppShader < 0)
{
std::cout << "Could not create the postprocessing shader" << std::endl;
return 4;
}
ppcb->drop();
// instantiate the postprocessing class
Postprocess pp(device);
pp.getMaterial().MaterialType = (video::E_MATERIAL_TYPE) ppShader;
pp.getMaterial().setTexture(0, pp.rtt);
pp.getMaterial().setTexture(1, theTex);
//** End postprocessing code
MyEventReceiver receiver;
device->setEventReceiver(&receiver);
scene::ISceneManager* smgr = device->getSceneManager();
// create material
s32 texShader;
TextureShaderCallback* texcb = new TextureShaderCallback();
// create the shaders (GLSL)
texShader = gpu->addHighLevelShaderMaterial(
vs_tex, "vertexMain", video::EVST_VS_1_1,
ps_tex, "pixelMain", video::EPST_PS_1_1,
texcb, video::EMT_SOLID, 0, video::EGSL_DEFAULT);
if (texShader < 0)
{
std::cout << "Could not create the material shader" << std::endl;
return 5;
}
texcb->drop();
// create a test scene node with the shader material
scene::ISceneNode* node = smgr->addCubeSceneNode(50);
node->setPosition(core::vector3df(0,0,0));
node->setMaterialTexture(0, theTex);
node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setMaterialType((video::E_MATERIAL_TYPE) texShader);
// rotate the cube
scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(
core::vector3df(0,0.3f,0));
node->addAnimator(anim);
anim->drop();
// add a camera and disable the mouse cursor
scene::ICameraSceneNode* cam = smgr->addCameraSceneNode();
cam->setPosition(core::vector3df(-100,50,100));
cam->setTarget(core::vector3df(0,0,0));
device->getCursorControl()->setVisible(false);
// draw the scene
int lastFPS = -1;
while(device->run())
if (device->isWindowActive())
{
if (receiver.ppEffect < 0)
break; // ESC
if (receiver.ppEffect > 0)
{
// render into the texture
driver->beginScene(true, true, video::SColor(255,0,200,0));
driver->setRenderTarget(pp.rtt, true, true, video::SColor(255, 230, 200, 50));
}
else
{
// render into the frame buffer
driver->beginScene(true, true, video::SColor(255,230,200,50));
}
smgr->drawAll();
if (receiver.ppEffect > 0)
{
// get access to the render image and set the framebuffer as
// the render target
driver->setRenderTarget(0, true, true, video::SColor(0));
// and render the screen rectangle (quadrilateral) to the
// framebuffer
pp.render();
}
// that's all - swap buffers
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Postprocessing example [OpenGL] FPS: ";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
std::cout << "Postprocessing example is ending" << std::endl;
return 0;
}