Postprocessing Example

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Postprocessing Example

Post by mongoose7 »

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;
}
 
Max Power
Posts: 98
Joined: Wed Mar 14, 2012 10:09 am

Re: Postprocessing Example

Post by Max Power »

Hi, thanks for posting this. I want to do some postprocessing myself and found your example. Haven't read it yet and I've got one question before getting started. Will this work with stereoscopic 3D? Or will I get a flat picture when using NVidia 3D-vision?
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Postprocessing Example

Post by Vectrotek »

Thanks! very useful.
Post Reply