How to use the stencil buffer to increment a value each time a fragment is drawn ?

Hi! I want to increment the value of a stencil buffer each time a fragment is drawn and then read that value, but I don’t know how to do that.

Read Stencil in the GL wiki.

Pay particular attention to glStencilOp with GL_INCR or GL_INCR_WRAP. Note: If you don’t need 2-sided stencil, you can just call the stencil APIs without the “Separate” suffix.

As to reading, where do you want to read it to? If CPU, consider if there’s an alternative that would avoid the readback and just use the stencil buffer on the GPU side.

I tried this :


#include "../../../include/odfaeg/Graphics/oitRenderComponent.h"
#include "glCheck.h"
#include <memory.h>
using namespace sf;
using namespace std;
namespace odfaeg {
    namespace graphic {
        OITRenderComponent::OITRenderComponent (RenderWindow& window, int layer, std::string expression, sf::ContextSettings settings) :
            HeavyComponent(window, math::Vec3f(window.getView().getPosition().x, window.getView().getPosition().y, layer),
                          math::Vec3f(window.getView().getSize().x, window.getView().getSize().y, 0),
                          math::Vec3f(window.getView().getSize().x + window.getView().getSize().x * 0.5f, window.getView().getPosition().y + window.getView().getSize().y * 0.5f, layer)),
            view(window.getView()),
            expression(expression) {
            update = false;
            sf::Vector3i resolution ((int) window.getSize().x, (int) window.getSize().y, window.getView().getSize().z);
            settings.depthBits = 32;
            settings.stencilBits = 32;
            glCheck(glStencilFunc(GL_ALWAYS, 0, 0xFF));
            glCheck(glStencilOp(GL_INCR, GL_INCR, GL_INCR));
            depthBuffer.create(resolution.x, resolution.y,settings);
            settings.stencilBits = 0;
            frontBuffer.create(resolution.x, resolution.y,settings);
            settings.depthBits = 0;
            averageBlendEqPart1.create(resolution.x, resolution.y,settings);
            averageBlendEqPart2.create(resolution.x, resolution.y,settings);
            alpha.create(resolution.x, resolution.y,settings);
            frameBuffer.create(resolution.x, resolution.y,settings);

            frontBuffer.setView(window.getView());
            depthBuffer.setView(window.getView());
            frameBuffer.setView(window.getView());
            averageBlendEqPart1.setView(window.getView());
            averageBlendEqPart2.setView(window.getView());
            frontBufferSprite = Sprite (frontBuffer.getTexture(), math::Vec3f(0, 0, 0), math::Vec3f(window.getView().getSize().x, window.getView().getSize().y, 0), IntRect(0, 0, window.getView().getSize().x, window.getView().getSize().y));
            depthBufferSprite = Sprite (depthBuffer.getTexture(), math::Vec3f(0, 0, 0), math::Vec3f(window.getView().getSize().x, window.getView().getSize().y, 0), IntRect(0, 0, window.getView().getSize().x, window.getView().getSize().y));
            frameBufferSprite = Sprite(frameBuffer.getTexture(), math::Vec3f(0, 0, 0), math::Vec3f(window.getView().getSize().x, window.getView().getSize().y, 0), IntRect(0, 0, window.getView().getSize().x, window.getView().getSize().y));
            blendEqPart1 = Sprite (averageBlendEqPart1.getTexture(), math::Vec3f(0, 0, 0), math::Vec3f(window.getView().getSize().x, window.getView().getSize().y, 0), IntRect(0, 0, window.getView().getSize().x, window.getView().getSize().y));
            blendEqPart2 = Sprite (averageBlendEqPart2.getTexture(), math::Vec3f(0, 0, 0), math::Vec3f(window.getView().getSize().x, window.getView().getSize().y, 0), IntRect(0, 0, window.getView().getSize().x, window.getView().getSize().y));
            alphaSprite = Sprite (alpha.getTexture(), math::Vec3f(0, 0, 0), math::Vec3f(window.getView().getSize().x, window.getView().getSize().y, 0), IntRect(0, 0, window.getView().getSize().x, window.getView().getSize().y));
            stencilSprite = Sprite(stencilBuffer,math::Vec3f(0, 0, 0), math::Vec3f(window.getView().getSize().x, window.getView().getSize().y, 0), IntRect(0, 0, window.getView().getSize().x, window.getView().getSize().y));
            core::FastDelegate<bool> signal (&OITRenderComponent::needToUpdate, this);
            core::FastDelegate<void> slot (&OITRenderComponent::drawNextFrame, this);
            core::Command cmd(signal, slot);
            getListener().connect("UPDATE", cmd);
            if (Shader::isAvailable()) {
                const std::string  vertexShader =
                "#version 130 
"
                "out mat4 projMat;"
                "void main () {"
                    "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
                    "gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;"
                    "gl_FrontColor = gl_Color;"
                    "projMat = gl_ProjectionMatrix;"
                "}";
                const std::string  simpleVertexShader =
                "#version 130 
"
                "void main () {"
                    "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
                    "gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;"
                    "gl_FrontColor = gl_Color;"
                "}";
                const std::string addSrcColorFragShader =
                "#version 130 
"
                "in mat4 projMat;"
                "uniform vec3 resolution;"
                "uniform sampler2D frontBuffer;"
                "uniform sampler2D depthBuffer;"
                "uniform sampler2D texture;"
                "uniform float haveTexture;"
                "void main() {"
                    "vec2 position = (gl_FragCoord.xy / resolution.xy);"
                    "vec4 front_color = texture2D(frontBuffer, position);"
                    "vec4 texel = texture2D(texture, gl_TexCoord[0].xy);"
                    "vec4 colors[2];"
                    "colors[1] = texel * gl_Color;"
                    "colors[0] = gl_Color;"
                    "bool b = (haveTexture > 0.9);"
                    "vec4 color = colors[int(b)];"
                    "gl_FragColor = vec4(color.rgb * (1 - front_color.a), color.a * (1-front_color.a));"
                "}";
                const std::string addDstColorFragShader =
                "#version 130 
"
                "in mat4 projMat;"
                "uniform vec3 resolution;"
                "uniform sampler2D frontBuffer;"
                "uniform sampler2D depthBuffer;"
                "uniform sampler2D texture;"
                "uniform float haveTexture;"
                "void main() {"
                    "vec2 position = (gl_FragCoord.xy / resolution.xy);"
                    "vec4 front_color = texture2D(frontBuffer, position);"
                    "vec4 texel = texture2D(texture, gl_TexCoord[0].xy);"
                    "vec4 colors[2];"
                    "colors[1] = texel * gl_Color;"
                    "colors[0] = gl_Color;"
                    "bool b = (haveTexture > 0.9);"
                    "vec4 color = colors[int(b)];"
                    "gl_FragColor = vec4(front_color.rgb * front_color.a, front_color.a);"
                "}";
                const std::string avgFragShader =
                "#version 130 
"
                "in mat4 projMat;"
                "uniform sampler2D texture;"
                "uniform vec2 resolution;"
                "void main() {"
                    "vec2 position = (gl_FragCoord.xy / resolution.xy);"
                    "vec4 color = texture2D(texture, gl_TexCoord[0].xy);"
                    "/*if (color == vec4(1, 1, 1, 1)) {"
                        "gl_FragColor = vec4(1, 1, 1, 1);"
                    "} else {*/"
                        "gl_FragColor = vec4(color.r / 2, color.g / 2, color.b / 2, color.a);"
                    "/*}*/"
                "}";
                const std::string setAlphaFragShader =
                "#version 130 
"
                "uniform vec3 resolution;"
                "uniform sampler2D texture;"
                "uniform sampler2D frameBuffer;"
                "void main() {"
                    "vec2 position = (gl_FragCoord.xy / resolution.xy);"
                    "float alpha = texture2D(texture, gl_TexCoord[0].xy).a;"
                    "vec4 color = texture2D(frameBuffer, position);"
                    "gl_FragColor = vec4(color.rgb, alpha);"
                "}";
                const std::string depthGenFragShader =
                "#version 130 
"
                "in mat4 projMat;"
                "uniform sampler2D texture;"
                "uniform float haveTexture;"
                "void main () {"
                    "vec4 texel = texture2D(texture, gl_TexCoord[0].xy);"
                    "vec4 colors[2];"
                    "colors[1] = texel * gl_Color;"
                    "colors[0] = gl_Color;"
                    "bool b = (haveTexture > 0.9);"
                    "vec4 color = colors[int(b)];"
                    "float z = (gl_FragCoord.w != 1.f) ? (inverse(projMat) * vec4(0, 0, 0, gl_FragCoord.w)).w : gl_FragCoord.z;"
                    "gl_FragColor = vec4(0, 0, z, color.a);"
                "}";
                const std::string frameBufferGenFragShader =
                "#version 130 
"
                "uniform sampler2D depthBuffer;"
                "uniform sampler2D texture;"
                "uniform vec3 resolution;"
                "uniform float haveTexture;"
                "in mat4 projMat;"
                "void main () {"
                    "vec2 position = ( gl_FragCoord.xy / resolution.xy );"
                    "vec4 max = texture2D(depthBuffer, position);"
                    "vec4 texel = texture2D(texture, gl_TexCoord[0].xy);"
                    "vec4 colors[2];"
                    "colors[1] = texel * gl_Color;"
                    "colors[0] = gl_Color;"
                    "bool b = (haveTexture > 0.9);"
                    "vec4 color = colors[int(b)];"
                    "float z = (gl_FragCoord.w != 1.f) ? (inverse(projMat) * vec4(0, 0, 0, gl_FragCoord.w)).w : gl_FragCoord.z;"
                    "colors[1] = color;"
                    "colors[0] = vec4(0, 0, 0, 0);"
                    "b = (z < max.z);"
                    "gl_FragColor = colors[int(b)];"
                "}";
                if (!depthBufferGenerator.loadFromMemory(vertexShader, depthGenFragShader))
                    throw core::Erreur(50, "Failed to load depth buffer generator shader", 0);
                if (!frameBufferGenerator.loadFromMemory(vertexShader, frameBufferGenFragShader))
                    throw core::Erreur(51, "Failed to load frame buffer generator shader", 0);
                if (!computeAvgShader.loadFromMemory(simpleVertexShader, avgFragShader)) {
                    throw core::Erreur(51, "Failed to load compute avg shader", 0);
                }
                setAlphaShader.loadFromMemory(simpleVertexShader, setAlphaFragShader);

                if (!addSrcColorShader.loadFromMemory(vertexShader,addSrcColorFragShader)) {
                    throw core::Erreur(51, "Failed to load add src color shader", 0);
                }
                if (!addDstColorShader.loadFromMemory(vertexShader,addDstColorFragShader)) {
                    throw core::Erreur(51, "Failed to load add dst color shader", 0);
                }
                addSrcColorShader.setParameter("resolution",resolution.x, resolution.y, resolution.z);
                addSrcColorShader.setParameter("frontBuffer", frontBuffer.getTexture());
                addDstColorShader.setParameter("depthBuffer", depthBuffer.getTexture());
                addSrcColorShader.setParameter("texture", Shader::CurrentTexture);
                addDstColorShader.setParameter("resolution",resolution.x, resolution.y, resolution.z);
                addDstColorShader.setParameter("frontBuffer", frontBuffer.getTexture());
                addDstColorShader.setParameter("depthBuffer", depthBuffer.getTexture());
                addDstColorShader.setParameter("texture", Shader::CurrentTexture);
                setAlphaShader.setParameter("resolution", resolution.x, resolution.y, resolution.z);
                setAlphaShader.setParameter("frameBuffer", frameBuffer.getTexture());
                setAlphaShader.setParameter("texture", Shader::CurrentTexture);
                    //throw core::Erreur(52, "Failed to load specular texture generator shader", 0);
                /*if (!bumpTextureGenerator->loadFromMemory(vertexShader, bumpGenFragShader))
                    throw core::Erreur(53, "Failed to load bump texture generator shader", 0);
                if (!refractionTextureGenerator->loadFromMemory(vertexShader, refractionGenFragShader))
                    throw core::Erreur(54, "Failed to load refraction texture generator shader", 0);*/
                frameBufferGenerator.setParameter("resolution",resolution.x, resolution.y, resolution.z);
                frameBufferGenerator.setParameter("depthBuffer", depthBuffer.getTexture());
                frameBufferGenerator.setParameter("texture", Shader::CurrentTexture);
                depthBufferGenerator.setParameter("texture", Shader::CurrentTexture);
                computeAvgShader.setParameter("texture", Shader::CurrentTexture);
                computeAvgShader.setParameter("depthBuffer", depthBuffer.getTexture());
                computeAvgShader.setParameter("resolution", resolution.x, resolution.y, resolution.z);
                //specularTextureGenerator->setParameter("specularTexture",specularTexture->getTexture());
                backgroundColor = sf::Color::Transparent;
            } else {
                throw core::Erreur(55, "Shader not supported!", 0);
            }
        }
        void OITRenderComponent::pushEvent(sf::Event event, RenderWindow& rw) {
            if (event.type == sf::Event::Resized && &getWindow() == &rw && isAutoResized()) {
                std::cout<<"recompute size"<<std::endl;
                recomputeSize();
                getListener().pushEvent(event);
                getView().reset(physic::BoundingBox(getView().getViewport().getPosition().x, getView().getViewport().getPosition().y, getView().getViewport().getPosition().z, event.size.width, event.size.height, getView().getViewport().getDepth()));
            }
        }
        bool OITRenderComponent::needToUpdate() {
            return update;
        }
        void OITRenderComponent::changeVisibleEntities(Entity* toRemove, Entity* toAdd, EntityManager* em) {
            bool removed;
            em->removeAnimatedVisibleEntity(toRemove, visibleEntities, view, removed);
            if (removed) {
                em->insertAnimatedVisibleEntity(toAdd, visibleEntities, view);
                loadEntitiesOnComponent(visibleEntities);
                update = true;
            }
        }
        std::string OITRenderComponent::getExpression() {
            return expression;
        }
        void OITRenderComponent::setBackgroundColor(sf::Color color) {
            this->backgroundColor = color;
        }
        void OITRenderComponent::clear() {
             frameBuffer.clear(backgroundColor);
             depthBuffer.clear(sf::Color::Transparent);
             frontBuffer.clear(sf::Color::Transparent);
             averageBlendEqPart1.clear(sf::Color::Transparent);
             averageBlendEqPart2.clear(sf::Color::Transparent);
             alpha.clear(sf::Color::Transparent);
        }
        Sprite& OITRenderComponent::getAvgBlendEqPart1() {
            return blendEqPart1;
        }
        Sprite& OITRenderComponent::getAvgBlendEqPart2() {
            return blendEqPart2;
        }
        Sprite& OITRenderComponent::getFrameBufferSprite () {
            return frameBufferSprite;
        }
        Sprite& OITRenderComponent::getDepthBufferSprite() {
            return depthBufferSprite;
        }
        Sprite& OITRenderComponent::getFrontBufferSprite() {
            return frontBufferSprite;
        }
        Sprite& OITRenderComponent::getAlphaSprite() {
            return alphaSprite;
        }
        Sprite& OITRenderComponent::getStencilSprite() {
            return stencilSprite;
        }
        const Texture& OITRenderComponent::getDepthBufferTexture() {
            return depthBuffer.getTexture();
        }
        const Texture& OITRenderComponent::getFrameBufferTexture() {
            return frameBuffer.getTexture();
        }
        const Texture& OITRenderComponent::getFrontBufferTexture() {
            return frontBuffer.getTexture();
        }
        bool OITRenderComponent::loadEntitiesOnComponent(std::vector<Entity*> vEntities)
        {

            batcher.clear();
            for (unsigned int i = 0; i < vEntities.size(); i++) {
                if ( vEntities[i]->isLeaf()) {
                    for (unsigned int j = 0; j <  vEntities[i]->getFaces().size(); j++) {
                         batcher.addFace( vEntities[i]->getFaces()[j]);
                    }
                }
            }
            m_instances = batcher.getInstances();
            visibleEntities = vEntities;
            update = true;
            return true;
        }
        void OITRenderComponent::setView(View view) {
            this->view = view;
            frameBuffer.setView(view);
            depthBuffer.setView(view);
            frontBuffer.setView(view);
            averageBlendEqPart1.setView(view);
            averageBlendEqPart2.setView(view);
            alpha.setView(view);
        }
        void OITRenderComponent::setExpression(std::string expression) {
            update = true;
            this->expression = expression;
        }
        void OITRenderComponent::drawNextFrame() {
            update = false;
            currentStates.blendMode = sf::BlendNone;
            for (unsigned int i = 0; i < m_instances.size(); i++) {
                 if (m_instances[i].getMaterial().getTexture() == nullptr)
                    depthBufferGenerator.setParameter("haveTexture", 0);
                 else
                    depthBufferGenerator.setParameter("haveTexture", 1);

                 currentStates.shader=&depthBufferGenerator;
                 currentStates.texture=m_instances[i].getMaterial().getTexture();
                 depthBuffer.draw(m_instances[i].getAllVertices(),currentStates);
                 currentStates.shader=nullptr;
                 frontBuffer.draw(m_instances[i].getAllVertices(), currentStates);
            }
            unsigned int size = view.getSize().x * view.getSize().y;
            unsigned char* datas = new unsigned char[size];
            glCheck(glReadPixels(0, 0, view.getSize().x, view.getSize().y,GL_STENCIL_INDEX,GL_UNSIGNED_BYTE,datas));
            unsigned char* texDatas = new unsigned char[size * 4];
            for (unsigned int i = 0; i < size; i++) {
                texDatas[i] = datas[i];
                if ((int) texDatas[i] > 0)
                    std::cout<<"stencil data : "<<(int) texDatas[i]<<std::endl;
                texDatas[i*4+1] = 0;
                texDatas[i*4+2] = 0;
                texDatas[i*4+3] = 0;
            }
            //stencilBuffer.loadFromMemory(texDatas,view.getSize().x * view.getSize().y);
           /* frontBuffer.display();
            frontBufferSprite.setCenter(view.getPosition());
            frameBuffer.draw(frontBufferSprite, currentStates);
            currentStates.shader=&frameBufferGenerator;
            currentStates.blendMode=sf::BlendMode(sf::BlendMode::Factor::OneMinusDstAlpha, sf::BlendMode::Factor::DstAlpha, sf::BlendMode::Equation::Add, sf::BlendMode::Factor::OneMinusDstAlpha, sf::BlendMode::Factor::One, sf::BlendMode::Equation::Add);
            for (unsigned int i = 0; i < m_instances.size(); i++) {
                if (m_instances[i].getMaterial().getTexture() == nullptr)
                    frameBufferGenerator.setParameter("haveTexture", 0);
                 else
                    frameBufferGenerator.setParameter("haveTexture", 1);
                currentStates.texture = m_instances[i].getMaterial().getTexture();
                frameBuffer.draw(m_instances[i].getAllVertices(), currentStates);
            }*/
            /*averageBlendEqPart1.draw(frontBufferSprite, currentStates);
            averageBlendEqPart2.draw(frontBufferSprite, currentStates);*/
            currentStates.shader=&addSrcColorShader;
            currentStates.blendMode=sf::BlendAdd/*Mode(sf::BlendMode::Factor::One, sf::BlendMode::Factor::One, sf::BlendMode::Equation::Add, sf::BlendMode::Factor::OneMinusDstAlpha, sf::BlendMode::Factor::One, sf::BlendMode::Equation::Add)*/;
            for (unsigned int i = 0; i < m_instances.size(); i++) {
                if (m_instances[i].getMaterial().getTexture() == nullptr)
                    addSrcColorShader.setParameter("haveTexture", 0);
                else
                    addSrcColorShader.setParameter("haveTexture", 1);
                currentStates.texture = m_instances[i].getMaterial().getTexture();
                averageBlendEqPart1.draw(m_instances[i].getAllVertices(), currentStates);
            }
            currentStates.shader=&addDstColorShader;
            for (unsigned int i = 0; i < m_instances.size(); i++) {
                if (m_instances[i].getMaterial().getTexture() == nullptr)
                    addDstColorShader.setParameter("haveTexture", 0);
                else
                    addDstColorShader.setParameter("haveTexture", 1);
                currentStates.texture = m_instances[i].getMaterial().getTexture();
                averageBlendEqPart2.draw(m_instances[i].getAllVertices(), currentStates);
            }

            currentStates.blendMode = sf::BlendMode(sf::BlendMode::Factor::Zero,sf::BlendMode::Factor::Zero,sf::BlendMode::Equation::Add, sf::BlendMode::Factor::OneMinusDstAlpha, sf::BlendMode::Factor::One, sf::BlendMode::Equation::Add);
            currentStates.shader = nullptr;
            alpha.draw(frontBufferSprite, currentStates);
            currentStates.shader=&frameBufferGenerator;
            for (unsigned int i = 0; i < m_instances.size(); i++) {
                if (m_instances[i].getMaterial().getTexture() == nullptr)
                    frameBufferGenerator.setParameter("haveTexture", 0);
                else
                    frameBufferGenerator.setParameter("haveTexture", 1);
                currentStates.texture = m_instances[i].getMaterial().getTexture();
                alpha.draw(m_instances[i].getAllVertices(), currentStates);
            }
            alpha.display();
            alphaSprite.setCenter(view.getPosition());
            currentStates.blendMode=sf::BlendNone;
            currentStates.shader = &computeAvgShader;
            averageBlendEqPart1.display();
            blendEqPart1.setCenter(view.getPosition());
            averageBlendEqPart1.draw(blendEqPart1, currentStates);
            averageBlendEqPart2.display();
            blendEqPart2.setCenter(view.getPosition());
            averageBlendEqPart2.draw(blendEqPart2, currentStates);
            currentStates.shader = nullptr;
            currentStates.blendMode=sf::BlendAdd/*Mode(sf::BlendMode::Factor::One, sf::BlendMode::Factor::One, sf::BlendMode::Equation::Add, sf::BlendMode::Factor::OneMinusDstAlpha, sf::BlendMode::Factor::One, sf::BlendMode::Equation::Add)*/;
            frameBuffer.draw(blendEqPart1, currentStates);
            frameBuffer.draw(blendEqPart2, currentStates);
            //currentStates.blendMode = sf::BlendNone;
            /*currentStates.shader = &setAlphaShader;
            frameBuffer.draw(alphaSprite, currentStates);*/
            for (unsigned int i = 0; i < drawables.size(); i++) {
                frameBuffer.draw(drawables[i].first.get(), drawables[i].second);
            }
            averageBlendEqPart1.display();
            averageBlendEqPart2.display();
            frontBuffer.display();
            depthBuffer.display();
            frameBuffer.display();
        }
        std::vector<Entity*> OITRenderComponent::getEntities() {
            return visibleEntities;
        }
        void OITRenderComponent::draw(Drawable& drawable, RenderStates states) {
            update = true;
            drawables.push_back(std::make_pair(std::ref(drawable), states));
        }
        void OITRenderComponent::draw(RenderTarget& target, RenderStates states) {
            frameBufferSprite.setCenter(target.getView().getPosition());
            target.draw(frameBufferSprite, states);
            drawables.clear();
        }

        View& OITRenderComponent::getView() {
            return view;
        }
        int OITRenderComponent::getLayer() {
            return getPosition().z;
        }
        void OITRenderComponent::updateParticleSystems() {
            for (unsigned int i = 0; i < visibleEntities.size(); i++) {
                if (dynamic_cast<physic::ParticleSystem*>(visibleEntities[i]) != nullptr) {
                    static_cast<physic::ParticleSystem*>(visibleEntities[i])->update();
                }
            }
            loadEntitiesOnComponent(visibleEntities);
            update = true;
        }
    }
}

But I the readPixel function gives me an invalid gl operations and all stencil values are kept to 0.
I need to pass the stencil values to the GPU so I need to use stencil buffer on the GPU side.
I want to pass stencil values to a shader.

As I mentioned in the other thread, use GL_DEPTH24_STENCIL8 to get both a depth buffer and stencil buffer.

You can read it back using glReadPixels using GL_UNSIGNED_INT_24_8.

Consulting the spec, you can as you found out read GL_STENCIL_INDEX textures in the shader. For reading the stencil from GL_DEPTH_STENCIL textures, use GL_DEPTH_STENCIL_TEXTURE_MODE = GL_STENCIL_INDEX (from ARB_stencil_texturing).