openframeworks / openFrameworks

openFrameworks is a community-developed cross platform toolkit for creative coding in C++.
http://openframeworks.cc
Other
9.97k stars 2.55k forks source link

gl_FragCoord is upside down inside FBO #3353

Open kylemcdonald opened 10 years ago

kylemcdonald commented 10 years ago

FBOs are rendered upside down compared to not using an FBO, which means anything based gl_FragCoord (which is not affected by any model or view matrix transformations) gets rendered upside down.

so if you do this:

#version 120
uniform float height;
void main() {
    float y = gl_FragCoord.y / height;
    gl_FragColor = vec4(vec3(y), 1.);
}
#include "ofMain.h"
class ofApp : public ofBaseApp {
public:
    ofShader shader;
    void setup() {
        shader.setup("", "shader.fs");
    }
    void draw() {
        shader.begin();
        shader.setUniform1f("height", ofGetHeight());
        ofDrawRectangle(0, 0, ofGetWidth(), ofGetHeight());
        shader.end();
    }
};
int main() {
    ofSetupOpenGL(1280, 720, OF_WINDOW);
    ofRunApp(new ofApp());
}

you get black at top and white at bottom.

and then you stick everything inside an FBO:

...
    void draw() {
        ofFbo fbo;
        fbo.allocate(ofGetWidth(), ofGetHeight());
        fbo.begin();
        shader.begin();
        shader.setUniform1f("height", ofGetHeight());
        ofDrawRectangle(0, 0, ofGetWidth(), ofGetHeight());
        shader.end();
        fbo.end();
        fbo.draw(0, 0);
    }
};
...

you get white at top and black at bottom.

not sure if there's anything we can do about this, but i wanted to at least have an issue for it in case someone else runs into it.

ghost commented 10 years ago

Yep, same thing on Linux with catalyst driver.

bakercp commented 10 years ago

Also see here.

arturoc commented 10 years ago

there's an easy fix for this but then something else breaks :)

for 0.8.0 i reviewed all the cases in which the vflip in OF was just hardcoded to be true and instead used a flag that switches different parts of the rendering so everything looks as it should no matter if the coordinate system is flipped in y or not.

the solution that i used for fbos is flip the internal orientation matrix so when you set the orientation to be flipped in y it actually renders without the flip which makes the rendered geometry look ok. since gl_FraagCoord is not affected by the matrices this won't work for that cases.

there's a way of making this work for both the geometry and gl_FragCoord. instead of flipping the coordinates, let them as they should be:

in ofMatrixStack, line 86: https://github.com/openframeworks/openFrameworks/blob/master/libs/openFrameworks/utils/ofMatrixStack.cpp#L86

change:

bool ofMatrixStack::customMatrixNeedsFlip() const{
    return vFlipped != bool(currentFbo);
}

to

bool ofMatrixStack::customMatrixNeedsFlip() const{
    return vFlipped;
}

and then flip the texture coordinates when rendering the fbo by changing the flipTexture flag in ofFbo line 598: https://github.com/openframeworks/openFrameworks/blob/master/libs/openFrameworks/gl/ofFbo.cpp#L598 to true which will make the texture generate flipped texture coordinates when drawing it through it's draw methods.

that will render both geometry and glFragCoord the same way with fbo or not but then if you try to use the texture from the fbo to map it onto a geomtry you need to reverse the texture coordinates manually since that texture will be reversed in comparison to how images or videos are usually layed out.

i decided to flip the coordinate system instead of the texture cause that's how it worked before and it was going to break less code but it's probably more correct to do it the other way since iit's possible that the way it's now even the handedness of the coordinate system is not the same if you have an fbo binded or not. Also we can detect if a texture needs a flip in the texture coordinates through it's flipTexture flag and use the correct mapping in of3dPrimitive for example.