[open/new] OpenGLDriver > TargetTexture/FBO & Stencil Buffer

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.
Squareys
Posts: 18
Joined: Tue Mar 11, 2014 8:09 pm
Location: Konstanz, Germany

[open/new] OpenGLDriver > TargetTexture/FBO & Stencil Buffer

Post by Squareys »

Hello Irrlicht community!


I recently wanted to add some shaders to a FrameBufferObject/RenderTargetTexture for post-processing purposes. That actually works fine, with the exception of the beautiful stencil shadows disapearing and the complete scene gets alot darker. (Basically the issue stated in this sadly completely ignored thread: http://irrlicht.sourceforge.net/forum/v ... w=previous )

I created a simplified code example of the issue, based on "Tutorial 08: SpecialFX" and slightly modified code provided in an answer of ( http://irrlicht.sourceforge.net/forum/v ... =4&t=49629 ).

Full code of "main.cpp":

Code: Select all

/** Example 008 SpecialFX (modified for bug display)
 
This tutorials describes how to do special effects. It shows how to use stencil
buffer shadows, the particle system, billboards, dynamic light, and the water
surface scene node.
 
We start like in some tutorials before. Please note that this time, the
'shadows' flag in createDevice() is set to true, for we want to have a dynamic
shadow casted from an animated character. If this example runs too slow,
set it to false. The Irrlicht Engine checks if your hardware doesn't support
the stencil buffer, and disables shadows by itself, but just in case the demo
runs slow on your hardware.
*/
 
#include <irrlicht.h>
#include <iostream>
#include "driverChoice.h"
 
using namespace irr;
 
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
 
 
//! This is a helper class that is used to render a whole screen rectangle
class CScreenQuadSceneNode : public scene::ISceneNode{
      core::aabbox3df aabb;               //An axis aligned bounding box. Actually not needed.
      video::SMaterial material;            //The material used to render the Scene Node
       video::S3DVertex2TCoords vertices[4];    //The vertices of the Scene Node.
                                    //Normally we wouldn't need more
                                    //than one set of UV coordinates.
                                    //But if we are to use the builtin materials, this is necesary
 
public:
       CScreenQuadSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id)
       :ISceneNode(parent,mgr,id)
       {
            f32 shiftX,shiftY;
            core::dimension2d<u32> currentResolution;
 
            /** Here we initialize the vertices of the screen Aligned quad **/
 
            currentResolution = mgr->getVideoDriver()->getScreenSize();
 
            aabb.reset(0,0,0);
 
            shiftX = 0.5/currentResolution.Width;   //This small shift is necesary to compensate the texture sampling bias
            shiftY = 0.5/currentResolution.Height;   //It avoids that our effect becomes too blurry.
 
            vertices[0] = video::S3DVertex2TCoords(
                  -1.0f,-1.0f,0.0f,
                  0.0f,0.0f,-1.0f,
                  video::SColor(255,255,255,255),
                  shiftX,1.0f+shiftY,
                  shiftX,1.0f+shiftY);
 
            vertices[1] = video::S3DVertex2TCoords(
                  1.0f,-1.0,0.0f,
                  0.0f,0.0f,-1.0f,
                  video::SColor(255,255,255,255),
                  1.0f+shiftX,1.0f+shiftY,
                  1.0f+shiftX,1.0f+shiftY);
 
            vertices[2] = video::S3DVertex2TCoords(
                  -1.0f,1.0,0.0f,
                  0.0f,0.0f,-1.0f,
                  video::SColor(255,255,255,255),
                  shiftX,shiftY,
                  shiftX,shiftY);
 
            vertices[3] = video::S3DVertex2TCoords(
                  1.0f,1.0f,0.0f,
                  0.0f,0.0f,-1.0f,
                  video::SColor(255,255,255,255),
                  1.0f+shiftX,shiftY,
                  1.0f+shiftX,shiftY);
 
            /**Now we proceed to initialize the appropriate settings for the material we are going to use
            We can alter these later, but for the time being, initializing then here will do no harm*/
 
            material.Lighting = false;                     //No need for lighting.
            material.MaterialType = video::EMT_LIGHTMAP_ADD;   //This will add both first and second textures :)
            material.BackfaceCulling=false;                  //not needed, but simplifies things
            setAutomaticCulling(scene::EAC_OFF);            //We don't need this scene
            material.setFlag(video::EMF_TRILINEAR_FILTER, false);
            material.setFlag(video::EMF_ANISOTROPIC_FILTER, false);
            material.setFlag(video::EMF_FOG_ENABLE, false);
            material.setFlag(video::EMF_LIGHTING, false);
 
      }
 
       ~CScreenQuadSceneNode()
       {
      }
 
      const core::aabbox3df& getBoundingBox() const
      {
         return aabb;
      }
 
       void OnRegisterSceneNode()
       {
         //This method is empty because it is best for us to render this scene node manually.
         //So, it is never really rendered on its own, if we don't tell it to do so.
      }
 
       void render()
       {
         video::IVideoDriver* drv = getSceneManager()->getVideoDriver();
         core::matrix4 proj;
          u16 indices[] = {0,1,2,3,1,2};
          //A triangle list
 
         drv->setMaterial(material);
 
         drv->setTransform(video::ETS_PROJECTION, core::IdentityMatrix);
         drv->setTransform(video::ETS_VIEW, core::IdentityMatrix);
         drv->setTransform(video::ETS_WORLD, core::IdentityMatrix);
 
         drv->drawIndexedTriangleList(&vertices[0],4,&indices[0],2);
      }
 
       u32 getMaterialCount()
       {
         return 1;   //There is only one material
      }
 
      video::SMaterial& getMaterial(irr::u32 i)
      {
            return material;//We always return the same material, so there is no need for more.
      }
 
};
 
int main()
{
    /*
    Create device and exit if creation failed. We make the stencil flag
    optional to avoid slow screen modes for runs without shadows.
    */
    core::dimension2d<u32> screenDimensions = core::dimension2d<u32>(640, 480);
 
    IrrlichtDevice *device =
        createDevice(video::EDT_OPENGL, screenDimensions,
        16, false, true);
 
    if (device == 0)
        return 1; // could not create selected driver.
 
    video::IVideoDriver* driver = device->getVideoDriver();
    scene::ISceneManager* smgr = device->getSceneManager();
 
    /*
    For our environment, we load a .3ds file. It is a small room I modelled
    with Anim8or and exported into the 3ds format because the Irrlicht
    Engine does not support the .an8 format. I am a very bad 3d graphic
    artist, and so the texture mapping is not very nice in this model.
    Luckily I am a better programmer than artist, and so the Irrlicht
    Engine is able to create a cool texture mapping for me: Just use the
    mesh manipulator and create a planar texture mapping for the mesh. If
    you want to see the mapping I made with Anim8or, uncomment this line. I
    also did not figure out how to set the material right in Anim8or, it
    has a specular light color which I don't really like. I'll switch it
    off too with this code.
    */
 
    scene::IAnimatedMesh* mesh = smgr->getMesh("../../media/room.3ds");
 
    smgr->getMeshManipulator()->makePlanarTextureMapping(mesh->getMesh(0), 0.004f);
 
    scene::ISceneNode* node = 0;
 
    node = smgr->addAnimatedMeshSceneNode(mesh);
    node->setMaterialTexture(0, driver->getTexture("../../media/wall.jpg"));
    node->getMaterial(0).SpecularColor.set(0,0,0,0);
 
    /*
    Now, for the first special effect: Animated water. It works like this:
    The WaterSurfaceSceneNode takes a mesh as input and makes it wave like
    a water surface. And if we let this scene node use a nice material like
    the EMT_REFLECTION_2_LAYER, it looks really cool. We are doing this
    with the next few lines of code. As input mesh, we create a hill plane
    mesh, without hills. But any other mesh could be used for this, you
    could even use the room.3ds (which would look really strange) if you
    want to.
    */
 
    mesh = smgr->addHillPlaneMesh( "myHill",
        core::dimension2d<f32>(20,20),
        core::dimension2d<u32>(40,40), 0, 0,
        core::dimension2d<f32>(0,0),
        core::dimension2d<f32>(10,10));
 
    node = smgr->addWaterSurfaceSceneNode(mesh->getMesh(0), 3.0f, 300.0f, 30.0f);
    node->setPosition(core::vector3df(0,7,0));
 
    node->setMaterialTexture(0, driver->getTexture("../../media/stones.jpg"));
    node->setMaterialTexture(1, driver->getTexture("../../media/water.jpg"));
 
    node->setMaterialType(video::EMT_REFLECTION_2_LAYER);
 
    /*
    The second special effect is very basic, I bet you saw it already in
    some Irrlicht Engine demos: A transparent billboard combined with a
    dynamic light. We simply create a light scene node, let it fly around,
    and to make it look more cool, we attach a billboard scene node to it.
    */
 
    // create light
 
    node = smgr->addLightSceneNode(0, core::vector3df(0,0,0),
        video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 800.0f);
    scene::ISceneNodeAnimator* anim = 0;
    anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f);
    node->addAnimator(anim);
    anim->drop();
 
    // attach billboard to light
 
    node = smgr->addBillboardSceneNode(node, core::dimension2d<f32>(50, 50));
    node->setMaterialFlag(video::EMF_LIGHTING, false);
    node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
    node->setMaterialTexture(0, driver->getTexture("../../media/particlewhite.bmp"));
 
    /*
    The next special effect is a lot more interesting: A particle system.
    The particle system in the Irrlicht Engine is quite modular and
    extensible, but yet easy to use. There is a particle system scene node
    into which you can put a particle emitter, which makes particles come out
    of nothing. These emitters are quite flexible and usually have lots of
    parameters like direction, amount, and color of the particles they
    create.
 
    There are different emitters, for example a point emitter which lets
    particles pop out at a fixed point. If the particle emitters available
    in the engine are not enough for you, you can easily create your own
    ones, you'll simply have to create a class derived from the
    IParticleEmitter interface and attach it to the particle system using
    setEmitter(). In this example we create a box particle emitter, which
    creates particles randomly inside a box. The parameters define the box,
    direction of the particles, minimal and maximal new particles per
    second, color, and minimal and maximal lifetime of the particles.
 
    Because only with emitters particle system would be a little bit
    boring, there are particle affectors which modify particles while
    they fly around. Affectors can be added to a particle system for
    simulating additional effects like gravity or wind.
    The particle affector we use in this example is an affector which
    modifies the color of the particles: It lets them fade out. Like the
    particle emitters, additional particle affectors can also be
    implemented by you, simply derive a class from IParticleAffector and
    add it with addAffector().
 
    After we set a nice material to the particle system, we have a cool
    looking camp fire. By adjusting material, texture, particle emitter,
    and affector parameters, it is also easily possible to create smoke,
    rain, explosions, snow, and so on.
    */
 
    // create a particle system
 
    scene::IParticleSystemSceneNode* ps =
        smgr->addParticleSystemSceneNode(false);
 
    if (ps)
    {
        scene::IParticleEmitter* em = ps->createBoxEmitter(
            core::aabbox3d<f32>(-7,0,-7,7,1,7), // emitter size
            core::vector3df(0.0f,0.06f,0.0f),   // initial direction
            80,100,                             // emit rate
            video::SColor(0,255,255,255),       // darkest color
            video::SColor(0,255,255,255),       // brightest color
            800,2000,0,                         // min and max age, angle
            core::dimension2df(10.f,10.f),         // min size
            core::dimension2df(20.f,20.f));        // max size
 
        ps->setEmitter(em); // this grabs the emitter
        em->drop(); // so we can drop it here without deleting it
 
        scene::IParticleAffector* paf = ps->createFadeOutParticleAffector();
 
        ps->addAffector(paf); // same goes for the affector
        paf->drop();
 
        ps->setPosition(core::vector3df(-70,60,40));
        ps->setScale(core::vector3df(2,2,2));
        ps->setMaterialFlag(video::EMF_LIGHTING, false);
        ps->setMaterialFlag(video::EMF_ZWRITE_ENABLE, false);
        ps->setMaterialTexture(0, driver->getTexture("../../media/fire.bmp"));
        ps->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
    }
 
    /*
    Next we add a volumetric light node, which adds a glowing fake area light to
    the scene. Like with the billboards and particle systems we also assign a
    texture for the desired effect, though this time we'll use a texture animator
    to create the illusion of a magical glowing area effect.
    */
    scene::IVolumeLightSceneNode * n = smgr->addVolumeLightSceneNode(0, -1,
                32,                              // Subdivisions on U axis
                32,                              // Subdivisions on V axis
                video::SColor(0, 255, 255, 255), // foot color
                video::SColor(0, 0, 0, 0));      // tail color
 
    if (n)
    {
        n->setScale(core::vector3df(56.0f, 56.0f, 56.0f));
        n->setPosition(core::vector3df(-120,50,40));
 
        // load textures for animation
        core::array<video::ITexture*> textures;
        for (s32 g=7; g > 0; --g)
        {
            core::stringc tmp;
            tmp = "../../media/portal";
            tmp += g;
            tmp += ".bmp";
            video::ITexture* t = driver->getTexture( tmp.c_str() );
            textures.push_back(t);
        }
 
        // create texture animator
        scene::ISceneNodeAnimator* glow = smgr->createTextureAnimator(textures, 150);
 
        // add the animator
        n->addAnimator(glow);
 
        // drop the animator because it was created with a create() function
        glow->drop();
    }
 
    /*
    As our last special effect, we want a dynamic shadow be casted from an
    animated character. For this we load a DirectX .x model and place it
    into our world. For creating the shadow, we simply need to call
    addShadowVolumeSceneNode(). The color of shadows is only adjustable
    globally for all shadows, by calling ISceneManager::setShadowColor().
    Voila, here is our dynamic shadow.
 
    Because the character is a little bit too small for this scene, we make
    it bigger using setScale(). And because the character is lighted by a
    dynamic light, we need to normalize the normals to make the lighting on
    it correct. This is always necessary if the scale of a dynamic lighted
    model is not (1,1,1). Otherwise it would get too dark or too bright
    because the normals will be scaled too.
    */
 
    // add animated character
 
    mesh = smgr->getMesh("../../media/dwarf.x");
    scene::IAnimatedMeshSceneNode* anode = 0;
 
    anode = smgr->addAnimatedMeshSceneNode(mesh);
    anode->setPosition(core::vector3df(-50,20,-60));
    anode->setAnimationSpeed(15);
 
    // add shadow
    anode->addShadowVolumeSceneNode();
    smgr->setShadowColor(video::SColor(150,0,0,0));
 
    // make the model a little bit bigger and normalize its normals
    // because of the scaling, for correct lighting
    anode->setScale(core::vector3df(2,2,2));
    anode->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
 
    /*
    Finally we simply have to draw everything, that's all.
    */
 
    scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
    camera->setPosition(core::vector3df(-50,50,-150));
    camera->setFarValue(10000.0f); // this increase a shadow visible range.
 
    // disable mouse cursor
    //device->getCursorControl()->setVisible(false);
 
    // create target texture / fbo
    video::ITexture* renderTexture = driver->addRenderTargetTexture(screenDimensions);
 
    // create the big quad to render the target texture to
    CScreenQuadSceneNode* quad = new CScreenQuadSceneNode(NULL, smgr, -1);
    quad->getMaterial(0).setTexture(0, renderTexture);
 
 
    s32 lastFPS = -1;
 
    while(device->run())
    if (device->isWindowActive())
    {
        driver->beginScene(true, true, 0);
 
        driver->setRenderTarget(renderTexture, true, true, video::SColor(255, 255, 255, 255));
        smgr->drawAll();
 
        driver->setRenderTarget(0, false, false, video::SColor(255, 255, 255, 255));
        quad->render();
 
        driver->endScene();
 
        const s32 fps = driver->getFPS();
 
        if (lastFPS != fps)
        {
            core::stringw str = L"Irrlicht Engine - SpecialFX example [";
            str += driver->getName();
            str += "] FPS:";
            str += fps;
 
            device->setWindowCaption(str.c_str());
            lastFPS = fps;
        }
    }
 
    device->drop();
 
    return 0;
}
 
/*
**/
 
 
To compile, just use the makefile of the example, or replace the source of the example with the above.

What is supposed to happen: Everything renders exactly the same as in the example without modification (as if never rendered to a texture).
What happens: Stencil shadows are not rendered.

Possible bugsources: (1.) Stencil buffer is not correctly attached when creating the frame buffer. (2.) StencilBuffer is overriden when rendering the FBO to the screen. Or (3.) I am missing something obvious.

Other stuff:

Microsoft Windows 7 Home Premium Edition Service Pack 1 (Build 7601)
WGL_extensions: WGL_ARB_buffer_region WGL_ARB_create_context WGL_ARB_create_context_profile WGL_ARB_create_context_robustness WGL_ARB_extensions_string WGL_ARB_make_current_read WGL_ARB_multisample WGL_ARB_pbuffer WGL_ARB_pixel_format WGL_ARB_pixel_format_float WGL_ARB_render_texture WGL_ATI_pixel_format_float WGL_EXT_create_context_es_profile WGL_EXT_create_context_es2_profile WGL_EXT_extensions_string WGL_EXT_framebuffer_sRGB WGL_EXT_pixel_format_packed_float WGL_EXT_swap_control WGL_EXT_swap_control_tear WGL_NVX_DX_interop WGL_NV_DX_interop WGL_NV_DX_interop2 WGL_NV_delay_before_swap WGL_NV_float_buffer WGL_NV_multisample_coverage WGL_NV_render_depth_texture WGL_NV_render_texture_rectangle
Using renderer: OpenGL 4.4.0
GeForce GT 435M/PCIe/SSE2: NVIDIA Corporation
OpenGL driver version is 1.2 or better.


I will try to fix this myself aswell, since this is rather important to me, therefore any hints are welcome.


Greetings, Squareys
Last edited by Squareys on Wed Mar 12, 2014 11:30 pm, edited 1 time in total.
Squareys @ facebook > https://www.facebook.com/Squareys
Squareys @ twitter > https://twitter.com/squareys

VhiteRabbit @ facebook > https://facebook.com/vhiterabbit
VhiteRabbit @ twitter > https://twitter.com/vhiterabbitvr
Squareys
Posts: 18
Joined: Tue Mar 11, 2014 8:09 pm
Location: Konstanz, Germany

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by Squareys »

I should add that I am using Irrlicht from the svn repository trunk, revision 4717.
The bug appears in 1.8.1 aswell, though, probably always existed.
Squareys @ facebook > https://www.facebook.com/Squareys
Squareys @ twitter > https://twitter.com/squareys

VhiteRabbit @ facebook > https://facebook.com/vhiterabbit
VhiteRabbit @ twitter > https://twitter.com/vhiterabbitvr
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by hendu »

I'm not sure of the trunk, but in 1.7 days RTTs did not have stencils attached. I have it patched in my tree to optionally enable them, decided at RTT creation time.

I don't use stencil shadows though, and from the code it's clear nobody tested them with RTTs, so there may be other parts in need of changes in addition to that.
Squareys
Posts: 18
Joined: Tue Mar 11, 2014 8:09 pm
Location: Konstanz, Germany

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by Squareys »

Actually, diving into the code, Stencil for FBOs is all there, implemeted as COpenGLFBODepthTexture.

BUT:
[corrected] COpenGLDriver::addRenderTargetTexture uses COpenGLFBOTexture, and attaches a COpenGLFBODepthTexture, created via createDepthTexture(), which does NOT set the useStencil paramter in the constructor of COpenGLFBODepthTexture, therefore leaves it at default false.


Suggestions by experienced Irrlicht Engine coders, how to correctly make this paramter available? One could theoretically just set it to whatever the device paramters have the use stencil flag set to...
Last edited by Squareys on Wed Mar 12, 2014 1:51 pm, edited 1 time in total.
Squareys @ facebook > https://www.facebook.com/Squareys
Squareys @ twitter > https://twitter.com/squareys

VhiteRabbit @ facebook > https://facebook.com/vhiterabbit
VhiteRabbit @ twitter > https://twitter.com/vhiterabbitvr
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by Nadro »

In my opinion addRenderTarget interface should be more flexible eg. stencil parameter should be available. I think that it will be nice to add class called eg. IRenderTarget, which would store ITexture data - array of color, depth and stencil textures. I'll try to do something in this case when I'll finish current tasks.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Squareys
Posts: 18
Joined: Tue Mar 11, 2014 8:09 pm
Location: Konstanz, Germany

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by Squareys »

Okay, great. Is there anything I can do meanwhile?

It seems, stencil shadows still don't work, even with the stencil buffer attatched. I would probably give it a try to find the reason for that.
Squareys @ facebook > https://www.facebook.com/Squareys
Squareys @ twitter > https://twitter.com/squareys

VhiteRabbit @ facebook > https://facebook.com/vhiterabbit
VhiteRabbit @ twitter > https://twitter.com/vhiterabbitvr
Squareys
Posts: 18
Joined: Tue Mar 11, 2014 8:09 pm
Location: Konstanz, Germany

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by Squareys »

I got it to work :)

Here's an image of the stencil buffers working on RTTs ;)

Image
( linked from https://www.facebook.com/VhiteRabbit , I put it there. )


Solution:

First of all, createDepthTexture() needs an additional parameter Params.Stencilbuffer in two places.
Also, for some reason, in the constructor of COpenGLFBODepthTexture, stencil and depth buffers are created as textures instead of renderbuffers when using stencil. When not using stencil, the depth buffer is created as renderbuffer. When the framebuffer object extension is not defined (GL_EXT_framebuffer_object preprocessor symbol), not even the depth buffer will created, when stencil is not enabled.

Since I don't have a huge amount of experience with ogl: Did I understand correctly that rendering to texture without framebufferobjects does not really work? If I understood this correctly, I would rewrite the constructor to use renderbuffers instead of textures and prepare a patch.
Last edited by Squareys on Thu Mar 13, 2014 12:02 pm, edited 1 time in total.
Squareys @ facebook > https://www.facebook.com/Squareys
Squareys @ twitter > https://twitter.com/squareys

VhiteRabbit @ facebook > https://facebook.com/vhiterabbit
VhiteRabbit @ twitter > https://twitter.com/vhiterabbitvr
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by hendu »

What are you using that does not support FBOs? They are GL 1.5 level tech.
Squareys
Posts: 18
Joined: Tue Mar 11, 2014 8:09 pm
Location: Konstanz, Germany

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by Squareys »

I don't know, I didn't write the code for the depth and stencil texture attachments ;) I will take that as an encouragment to do a clean fix and create a patch.

Where or to whom do I submit patches?
Squareys @ facebook > https://www.facebook.com/Squareys
Squareys @ twitter > https://twitter.com/squareys

VhiteRabbit @ facebook > https://facebook.com/vhiterabbit
VhiteRabbit @ twitter > https://twitter.com/vhiterabbitvr
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by hendu »

I mean, if you use any recent card + driver, something is broken in them if you do not have FBOs. What card, driver?

The existing irr code is correct.
Squareys
Posts: 18
Joined: Tue Mar 11, 2014 8:09 pm
Location: Konstanz, Germany

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by Squareys »

The existing code ist not correct. And I think you are confusing renderbuffers with framebufferobjects.

Give me 30 minutes and I will explain why in detail.

By the way: In my first post, card and driver are listet. You just need to read. Also, from the screenshot you can tell, that it actually works with my hardware, as soon as I fixed the code.
Last edited by Squareys on Thu Mar 13, 2014 12:40 pm, edited 1 time in total.
Squareys @ facebook > https://www.facebook.com/Squareys
Squareys @ twitter > https://twitter.com/squareys

VhiteRabbit @ facebook > https://facebook.com/vhiterabbit
VhiteRabbit @ twitter > https://twitter.com/vhiterabbitvr
Squareys
Posts: 18
Joined: Tue Mar 11, 2014 8:09 pm
Location: Konstanz, Germany

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by Squareys »

Here is the explanation:

The following code was taken from the the file source/irrlicht/COpenGLTexture.cpp in the newest revision of trunk (4718) and begins at line 913.

Code: Select all

 
COpenGLFBODepthTexture::COpenGLFBODepthTexture(
        const core::dimension2d<u32>& size,
        const io::path& name,
        COpenGLDriver* driver,
        bool useStencil)
    : COpenGLTexture(name, driver), DepthRenderBuffer(0),
    StencilRenderBuffer(0), UseStencil(useStencil)
{
#ifdef _DEBUG
    setDebugName("COpenGLTextureFBO_Depth");
#endif
 
    ImageSize = size;
    TextureSize = size;
    InternalFormat = GL_RGBA;
    PixelFormat = GL_RGBA;
    PixelType = GL_UNSIGNED_BYTE;
    HasMipMaps = false;
 


Up to here everything is fine. I do want to note, though, that useStencil was never anything but default false, the flag was simply never used, probably never tested and therefore any bugs in the next section were never found.

Code: Select all

 
    if (useStencil)
    {
        glGenTextures(1, &DepthRenderBuffer);
        glBindTexture(GL_TEXTURE_2D, DepthRenderBuffer);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
#ifdef GL_EXT_packed_depth_stencil
        if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_packed_depth_stencil))
        {
            // generate packed depth stencil texture
            glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_EXT, ImageSize.Width,
                ImageSize.Height, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0);
            StencilRenderBuffer = DepthRenderBuffer; // stencil is packed with depth
        }
        else // generate separate stencil and depth textures
#endif
        {
            // generate depth texture
            glTexImage2D(GL_TEXTURE_2D, 0, Driver->getZBufferBits(), ImageSize.Width,
                ImageSize.Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
 
            // generate stencil texture
            glGenTextures(1, &StencilRenderBuffer);
            glBindTexture(GL_TEXTURE_2D, StencilRenderBuffer);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_STENCIL_INDEX, ImageSize.Width,
                ImageSize.Height, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, 0);
        }
    }
 


Okay, great, now we definitely have one or maybe two textures (if packed was not available) for depth and stencil buffer attachments. Note, that nothing was attached via glFramebufferTexture2D. And will not be in the future (if you don't believe me, look for your self and tell me, where, and then you'll believe me ;) ). This is to 100% a bug.

Code: Select all

 
#ifdef GL_EXT_framebuffer_object
    else
    {
        // generate depth buffer
        Driver->extGlGenRenderbuffers(1, &DepthRenderBuffer);
        Driver->extGlBindRenderbuffer(GL_RENDERBUFFER_EXT, DepthRenderBuffer);
        Driver->extGlRenderbufferStorage(GL_RENDERBUFFER_EXT,
                Driver->getZBufferBits(), ImageSize.Width,
                ImageSize.Height);
    }
#endif
}
 
Ah, so this code says: "If we have framebuffer objects extension, we can use renderbuffers aswell, yay!"
But we only use them, if we don't need the stencilbuffer? Sure, this code works, if you don't use the stencil buffer, but it is neither clean, nor does it work, when using the stencil buffer. If you still believe this code is correct, please reason, I want to know why.
Squareys @ facebook > https://www.facebook.com/Squareys
Squareys @ twitter > https://twitter.com/squareys

VhiteRabbit @ facebook > https://facebook.com/vhiterabbit
VhiteRabbit @ twitter > https://twitter.com/vhiterabbitvr
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by hendu »

Sorry, I did miss you listed the hw in the first post.

However, I use RTT stencils heavily without issue, on multiple platforms. The attaching is done in the attach() function, for both stenciled and non-stenciled cases.
Squareys
Posts: 18
Joined: Tue Mar 11, 2014 8:09 pm
Location: Konstanz, Germany

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by Squareys »

Indeed they are. Sorry about that.

Still, the stencil attachment cannot be used, because "createDepthTexture()" always creates the COpenGLFBODepthTexture with useStencil to default false.

On the other issue, why does Irrlicht use renderbuffers in one case and textures in the other, or at least try to, if they are available?
Squareys @ facebook > https://www.facebook.com/Squareys
Squareys @ twitter > https://twitter.com/squareys

VhiteRabbit @ facebook > https://facebook.com/vhiterabbit
VhiteRabbit @ twitter > https://twitter.com/vhiterabbitvr
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: [open/new] OpenGLDriver > TargetTexture/FBO & Stencil Bu

Post by hendu »

Yes, the useStencil param is not exposed currently, though I have a patch to do so. http://sourceforge.net/p/irrlicht/patches/227/
Probably won't apply to trunk, being two years old.
On the other issue, why does Irrlicht use renderbuffers in one case and textures in the other, or at least try to, if they are available?
Either an artifact of history, or perhaps a packed renderbuffer is not possible. If you feel like archeology, you can go diving in SVN history ;)
Post Reply