My displacement shader is not working.

#1

Hi! I would like to re-use the fragments of my previous frame to generate the new one, so I coded a displacement shader.

But it doesn’t work, how can I get view coordinates of gl_FragPos and then transform it to the other frame coordinates ?


const std::string transfFragVertexShader =
                R"(#version 130
                out mat4 newViewMatrix;
                out mat4 projMat;
                void main() {
                    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
                    gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
                    gl_FrontColor = gl_Color;
                    newViewMatrix = gl_ModelViewMatrix;
                    projMat = gl_ProjectionMatrix;
                })";
                const std::string transfFragFragmentShader =
                R"(#version 130
                uniform mat4 oldViewMatrix;
                in mat4 newViewMatrix;
                in mat4 projMat;
                uniform vec3 resolution;
                uniform sampler2D oldFrameBuffer;
                void main() {
                    vec4 oldFragPos = inverse(projMat) * gl_FragCoord;
                    oldFragPos /= oldFragPos.w;
                    oldFragPos = inverse(newViewMatrix) * oldViewMatrix * oldFragPos;
                    oldFragPos /= oldFragPos.w;
                    oldFragPos = oldFragPos * projMat;
                    vec2 position = (resolution.xy / oldFragPos.xy);
                    gl_FragColor = texture2D(oldFrameBuffer, position);
                })";

#2

Tried this but not work too.


 const std::string transfFragFragmentShader =
                R"(#version 130
                uniform mat4 oldViewMatrix;
                in mat4 newViewMatrix;
                in mat4 projMat;
                uniform vec3 resolution;
                uniform sampler2D oldFrameBuffer;
                uniform vec4 viewport;
                void main() {
                    vec4 ndcPos;
                    ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1;
                    ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
                        (gl_DepthRange.far - gl_DepthRange.near);
                    ndcPos.w = 1.0;
                    vec4 clipPos = ndcPos / gl_FragCoord.w;
                    vec4 eyePos = inverse(projMat) * clipPos;
                    vec4 worldPos = inverse(newViewMatrix) * eyePos;
                    eyePos = oldViewMatrix * worldPos;
                    clipPos = (eyePos * projMat) / gl_FragCoord.w;
                    ndcPos.xy = ((2.0 * clipPos.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1;
                    ndcPos.z =  (2.0 * clipPos.z - gl_DepthRange.near - gl_DepthRange.far) /
                        (gl_DepthRange.far - gl_DepthRange.near);
                    vec4 oldFragPos;
                    oldFragPos.x = (ndcPos.x + 1) * viewport.z * 0.5 + viewport.x;
                    oldFragPos.y = (ndcPos.y + 1) * viewport.w * 0.5 + viewport.y;
                    oldFragPos.z = ndcPos.z;
                    oldFragPos.w = 1 / clipPos.w;
                    vec2 position = (resolution.xy / oldFragPos.xy);
                    gl_FragColor = texture2D(oldFrameBuffer, position);
                })";

How to pass from view pos to window pos ?

#3

Dont work too. (Black screen)


const std::string transfFragFragmentShader =
                R"(#version 130
                uniform mat4 oldViewMatrix;
                in mat4 newViewMatrix;
                in mat4 projMat;
                uniform vec3 resolution;
                uniform sampler2D oldFrameBuffer;
                uniform vec4 viewport;
                void main() {
                    vec4 ndcPos;
                    ndcPos.xy = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1;
                    ndcPos.z = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) /
                        (gl_DepthRange.far - gl_DepthRange.near);
                    ndcPos.w = 1.0;
                    vec4 clipPos = ndcPos / gl_FragCoord.w;
                    vec4 eyePos = inverse(projMat) * clipPos;
                    vec4 worldPos = inverse(newViewMatrix) * eyePos;
                    eyePos = oldViewMatrix * worldPos;
                    clipPos = eyePos * projMat;
                    clipPos.xyz /= clipPos.w;
                    vec4 oldFragPos;
                    oldFragPos.x = (clipPos.x + 1) * viewport.z * 0.5 + viewport.x;
                    oldFragPos.y = (clipPos.y + 1) * viewport.w * 0.5 + viewport.y;
                    oldFragPos.z = clipPos.z;
                    oldFragPos.w = 1 / clipPos.w;
                    vec2 position = (oldFragPos.xy / resolution.xy);
                    gl_FragColor = texture2D(oldFrameBuffer, position);
                })";

I really don’t know how to perform this.

#4

Mmmm It seems the texture is empy, when I clear my framebuffer fbo the previousframe fbo is cleared too!!!

I think that the opengl context of the previousFrame FBO stay activated so it clears both.

I’ll try to use them in a single opengl context and see if the bug persist.

#5

Ok the problem is not my shader code but the opengl context created with SFML, when I use only one context for all my FBO, my second component display something at the first draw call. But at the second draw call the texture is empty.


std::cout<<"draw previous frame!"<<std::endl;
                currentStates.blendMode = sf::BlendNone;
                currentStates.shader = nullptr;
                frameBuffer.draw(previousFrameBufferSprite, currentStates);
                frameBuffer.display();
                const Texture& text = frameBuffer.getTexture();
                Image img = text.copyToImage();
                bool found = false;
                for (unsigned int x = 0; x < img.getSize().x && !found; x++) {
                    for (unsigned int y = 0; y < img.getSize().y && !found; y++) {
                        if ((int) img.getPixel(x, y).r > 0) {
                            std::cout<<(int) img.getPixel(x, y).r<<std::endl;
                            found = true;
                        }
                    }
                }

The texture of the previous frame buffer is not empty but the texture of the framebuffer is empty at the second draw call.

And for my second component that’s doesn’t draw me nothing.

This is really strange, I suspect a bug with opengl context created with SFML.

#6

Ok I’ve found why it didn’t draw nothing it seems that if I let the depthtest enabled before drawing to the FBO (with a depth attachment) it doesn’t work.

But the shader is not working it didn’t get me the fragment of the previous frame with the previous view matrix…

#7

Ok I’m forced to activate the depthtest, because I need to have the nearest fragments.
But for the first draw the depth test never pass, it seems that every values in the depthbuffer are initialized with a very big value and even if I call glClear(GL_DEPTH_BITS), it doesn’t draw anything. The values in the depthBuffer should be initialized to 0.

For the shader, it works fine.

#8

I had to make this otherwise the depthTest doesn’t pass : (I’ve added a variable secondDraw to redraw everything at the second draw call)


if (viewUpdated || firstDraw || secondDraw) {
                depthBuffer.clear(sf::Color::Transparent);
                frontBuffer.clear(sf::Color::Transparent);
                currentStates.blendMode = BlendNone;
                for (unsigned int i = 0; i < m_newInstances.size(); i++) {
                     if (m_newInstances[i].getMaterial().getTexture() == nullptr) {
                        depthBufferGenerator.setParameter("haveTexture", 0);
                        simpleShader.setParameter("haveTexture", 0);
                     } else {
                        depthBufferGenerator.setParameter("haveTexture", 1);
                        simpleShader.setParameter("haveTexture", 1);
                     }
                     currentStates.shader=&depthBufferGenerator;
                     currentStates.texture=m_newInstances[i].getMaterial().getTexture();
                     depthBuffer.draw(m_newInstances[i].getAllVertices(),currentStates);
                     currentStates.shader = nullptr;/*&simpleShader;*/
                     frontBuffer.draw(m_newInstances[i].getAllVertices(), currentStates);
                }
                frontBuffer.display();
                frontBufferSprite.setCenter(view.getPosition());
                //simpleShader.setParameter("haveTexture", 1);
                currentStates.blendMode = sf::BlendMode(sf::BlendMode::Factor::OneMinusDstAlpha, sf::BlendMode::Factor::DstAlpha, sf::BlendMode::Add, sf::BlendMode::Factor::OneMinusDstAlpha, sf::BlendMode::Factor::One, sf::BlendMode::Equation::Add);
                frameBuffer.draw(frontBufferSprite, currentStates);
                if (twoLayers) {
                    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_newInstances.size(); i++) {
                        if (m_newInstances[i].getMaterial().getTexture() == nullptr)
                            frameBufferGenerator.setParameter("haveTexture", 0);
                         else
                            frameBufferGenerator.setParameter("haveTexture", 1);
                        currentStates.texture = m_newInstances[i].getMaterial().getTexture();
                        frameBuffer.draw(m_newInstances[i].getAllVertices(), currentStates);
                    }
                } else {

                    /*depthBuffer.bind();
                    glCheck(glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[0]));
                    glCheck(glReadBuffer(GL_COLOR_ATTACHMENT0_EXT));
                    glCheck(glReadPixels(0, view.getSize().y - (view.getPosition().y + view.getSize().y), view.getSize().x, view.getSize().y, GL_RGBA, GL_UNSIGNED_BYTE, 0));
                    glCheck(glBindBuffer(GL_PIXEL_PACK_BUFFER, pboIds[1]));
                    GLubyte* src = (GLubyte*) glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
                    unsigned int nbLayers = 0;
                    unsigned int layerValue = 0;
                    if(src) {
                        for (unsigned int i = 0; i < view.getSize().x * view.getSize().y; i++) {
                            if ((unsigned int) (src[i*4+2]) > layerValue) {
                                nbLayers++;
                                layerValue = (unsigned int) (src[i*4+2]);
                            }
                        }
                    }
                    glCheck(glUnmapBuffer(GL_PIXEL_PACK_BUFFER));
                    glCheck(glBindBuffer(GL_PIXEL_PACK_BUFFER, 0));*/
                    /*unsigned int nbLayers = 0;
                    unsigned int size = view.getSize().x * view.getSize().y * 4;
                    const sf::Uint8 * data = new unsigned char[size];
                    depthBuffer.display();
                    sf::Image img = depthBuffer.getTexture().copyToImage();
                    data = img.getPixelsPtr();
                    for (unsigned int i = 0; i < size / 4; i++) {
                        if ((float)(data[i*4+2])  > nbLayers) {
                            nbLayers++;
                        }
                        //std:cout<<"depthBufferdata "<<" i : "<<((float)(data[i*4]))<<","<<((float)(data[i*4+1]))<<","<<((float)(data[i*4+2]))<<","<<((float)(data[i*3]))<<std::endl;
                    }*/
                    unsigned int nbLayers = newBatcher.getNbLayers()-1;
                    std::cout<<"nb layers : "<<nbLayers<<std::endl;
                    for (unsigned int i = 0; i < nbLayers; i++) {
                        currentStates.shader = &frameBufferGenerator;
                        currentStates.blendMode = sf::BlendNone;
                        frontBuffer.clear(sf::Color::Transparent);
                        for (unsigned int i = 0; i < m_newInstances.size(); i++) {
                             if (m_newInstances[i].getMaterial().getTexture() == nullptr) {
                                frameBufferGenerator.setParameter("haveTexture", 0);
                             } else {
                                frameBufferGenerator.setParameter("haveTexture", 1);
                             }
                             currentStates.texture=m_newInstances[i].getMaterial().getTexture();
                             frontBuffer.draw(m_newInstances[i].getAllVertices(), currentStates);
                        }
                        frontBuffer.display();
                        frontBufferSprite.setCenter(view.getPosition());
                        currentStates.shader = &depthPeelingGenerator;
                        currentStates.texture = &depthBuffer.getTexture();
                        depthBuffer.setActive();
                        glCheck(glClear(GL_DEPTH_BUFFER_BIT));
                        for (unsigned int i = 0; i < m_newInstances.size(); i++) {
                             depthBuffer.draw(m_newInstances[i].getAllVertices(), currentStates);
                        }
                        depthBuffer.display();
                        //Problem, depthTexture is emplty!!!
                        currentStates.shader = nullptr;/*&simpleShader;
                        simpleShader.setParameter("haveTexture", 1);*/
                        currentStates.blendMode = sf::BlendMode(sf::BlendMode::Factor::OneMinusDstAlpha, sf::BlendMode::Factor::DstAlpha, sf::BlendMode::Add, sf::BlendMode::Factor::OneMinusDstAlpha, sf::BlendMode::Factor::One, sf::BlendMode::Equation::Add);
                        frameBuffer.draw(frontBufferSprite, currentStates);
                    }
                }
                /*for (unsigned int j = 0; j < m_newInstances.size(); j++) {
                    m_instances.push_back(m_newInstances[j]);
                }
                m_newInstances.clear();
                newBatcher.clear();*/
                for (unsigned int i = 0; i < drawables.size(); i++) {
                    frameBuffer.draw(drawables[i].first.get(), drawables[i].second);
                }
                frameBuffer.display();
                previousFrame.clear(backgroundColor);
                currentStates.blendMode = sf::BlendNone;
                currentStates.shader = nullptr;
                frameBufferSprite.setCenter(view.getPosition());
                previousFrame.draw(frameBufferSprite, currentStates);
                previousFrame.display();
                previousFrameBufferSprite.setCenter(view.getPosition());                //std::cout<<"view updated!"<<std::endl;
                if (!firstDraw)
                    secondDraw = false;
                firstDraw = false;
                viewUpdated = false;
            } else {
                //std::cout<<"draw previous frame!"<<std::endl;
                currentStates.blendMode = sf::BlendNone;
                currentStates.shader = nullptr;
                frameBuffer.draw(previousFrameBufferSprite, currentStates);
                frameBuffer.display();
                const Texture& text = frameBuffer.getTexture();
                Image img = text.copyToImage();
                bool found = false;
                for (unsigned int x = 0; x < img.getSize().x && !found; x++) {
                    for (unsigned int y = 0; y < img.getSize().y && !found; y++) {
                        if ((int) img.getPixel(x, y).r > 0) {
                            std::cout<<(int) img.getPixel(x, y).r<<std::endl;
                            found = true;
                        }
                    }
                }
            }