Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: RenderTexture and OpenGL example  (Read 10191 times)

0 Members and 1 Guest are viewing this topic.

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
RenderTexture and OpenGL example
« on: March 31, 2012, 04:37:07 pm »
Well I'm just trying to extend the OpenGL example with having it render the OpenGL specific stuff to a render texture to then be copied to the output window.

I can verify that the render texture have correct OpenGL states and that stuff are "rendered" to it. I randomize a clear color every frame and the render texture get that color. It is also copied to the window as I can see the effect. Removing the copy gives me a black screen with the example text. What doesn't work is the actual geometry. No cube is rendered to the render texture. I don't understand why? Am I missing something?

I know I have succeeded with this before but just this case where I am trying to only extend the OpenGL example I can't get it to work. What am I missing?


////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#include <iostream>


////////////////////////////////////////////////////////////
/// Entry point of application
///
/// \return Application exit code
///
////////////////////////////////////////////////////////////
int main()
{
    // Create the main window
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Deferred OpenGL", sf::Style::Default, sf::ContextSettings(32));
    window.setVerticalSyncEnabled(true);
       
        sf::RenderTexture geometryBuffer;
        geometryBuffer.create(800, 600, true);
        sf::Sprite geometrySprite(geometryBuffer.getTexture());
       
        window.setActive();

    // Create a sprite for the background
    sf::Texture backgroundTexture;
    if (!backgroundTexture.loadFromFile("resources/background.jpg"))
        return EXIT_FAILURE;
    sf::Sprite background(backgroundTexture);

    // Load an OpenGL texture.
    // We could directly use a sf::Texture as an OpenGL texture (with its Bind() member function),
    // but here we want more control on it (generate mipmaps, ...) so we create a new one from an image
    GLuint texture = 0;
    {
        sf::Image image;
        if (!image.loadFromFile("resources/texture.jpg"))
            return EXIT_FAILURE;
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
        gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, image.getWidth(), image.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, image.getPixelsPtr());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    }
       
        // window.setActive();
        geometryBuffer.setActive();

    // Enable Z-buffer read and write
    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);
    glClearDepth(1.f);
        glClearColor(0.f, 0.f, 0.f, 0.f);

    // Setup a perspective projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90.f, 800.f/600.f, 1.f, 100.f);

    // Bind our texture
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texture);
    glColor4f(1.f, 1.f, 1.f, 1.f);

    // Create a clock for measuring the time elapsed
    sf::Clock clock;

    // Start game loop
    while (window.isOpen())
    {
        // Process events
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close window : exit
            if (event.type == sf::Event::Closed)
                window.close();

            // Escape key : exit
            if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
                window.close();

            // Adjust the viewport when the window is resized
            if (event.type == sf::Event::Resized)
                        {
                                // window.setActive();
                                geometryBuffer.setActive();
                glViewport(0, 0, event.size.width, event.size.height);
                        }
        }

        // Draw the background
        window.pushGLStates();
        window.draw(background);
        window.popGLStates();

        // Activate the window before using OpenGL commands.
        // This is useless here because we have only one window which is
        // always the active one, but don't forget it if you use multiple windows
                // window.setActive();
        geometryBuffer.setActive();

        // Clear the depth buffer
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Apply some transformations
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0, 0, -5.f);
        glRotatef(clock.getElapsedTime().asSeconds() * 50.f, 1.f, 0.f, 0.f);
        glRotatef(clock.getElapsedTime().asSeconds() * 30.f, 0.f, 1.f, 0.f);
        glRotatef(clock.getElapsedTime().asSeconds() * 90.f, 0.f, 0.f, 1.f);

        // Draw a cube
        float size = 1.f;
        glBegin(GL_QUADS);

            glTexCoord2f(0, 0); glVertex3f(-size, -size, -size);
            glTexCoord2f(0, 1); glVertex3f(-size,  size, -size);
            glTexCoord2f(1, 1); glVertex3f( size,  size, -size);
            glTexCoord2f(1, 0); glVertex3f( size, -size, -size);

            glTexCoord2f(0, 0); glVertex3f(-size, -size, size);
            glTexCoord2f(0, 1); glVertex3f(-size,  size, size);
            glTexCoord2f(1, 1); glVertex3f( size,  size, size);
            glTexCoord2f(1, 0); glVertex3f( size, -size, size);

            glTexCoord2f(0, 0); glVertex3f(-size, -size, -size);
            glTexCoord2f(0, 1); glVertex3f(-size,  size, -size);
            glTexCoord2f(1, 1); glVertex3f(-size,  size,  size);
            glTexCoord2f(1, 0); glVertex3f(-size, -size,  size);

            glTexCoord2f(0, 0); glVertex3f(size, -size, -size);
            glTexCoord2f(0, 1); glVertex3f(size,  size, -size);
            glTexCoord2f(1, 1); glVertex3f(size,  size,  size);
            glTexCoord2f(1, 0); glVertex3f(size, -size,  size);

            glTexCoord2f(0, 1); glVertex3f(-size, -size,  size);
            glTexCoord2f(0, 0); glVertex3f(-size, -size, -size);
            glTexCoord2f(1, 0); glVertex3f( size, -size, -size);
            glTexCoord2f(1, 1); glVertex3f( size, -size,  size);

            glTexCoord2f(0, 1); glVertex3f(-size, size,  size);
            glTexCoord2f(0, 0); glVertex3f(-size, size, -size);
            glTexCoord2f(1, 0); glVertex3f( size, size, -size);
            glTexCoord2f(1, 1); glVertex3f( size, size,  size);

        glEnd();
               
                geometryBuffer.display();

        // Draw some text on top of our OpenGL object
        window.pushGLStates();
                window.draw(geometrySprite);
        sf::Text text("SFML / OpenGL demo");
        text.setColor(sf::Color(255, 255, 255, 170));
        text.setPosition(250.f, 450.f);
        window.draw(text);
        window.popGLStates();

        // Finally, display the rendered frame on screen
        window.display();
               
                std::cout << sf::err();
    }

    // Don't forget to destroy our texture
    glDeleteTextures(1, &texture);

    return EXIT_SUCCESS;
}
 

Also you are aware of that the projection matrix aspect ratio is wrong?

Update: Remade the example and if I uncomment the activation of the window and comment the geometry buffer activation it works like I would expect it to do. (Though the clear hides the background but it is expected so not weird)

Second Update: Tried with rendering a test sprite to the render texture and it works just like it should so rendering to the texture works. Just not opengl geometry? But SFML uses that behind the scene so what is missing?
« Last Edit: March 31, 2012, 05:51:03 pm by Groogy »
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Re: RenderTexture and OpenGL example
« Reply #1 on: March 31, 2012, 06:02:56 pm »
I solved it. I don't know if you count it as a bug but it feels like it since render targets handles views and so on. But the proper viewport had not been set on the render texture. I had to explicitly set it even without the window being resized or anything like that. Shouldn't the render texture do that by itself as it internally handles views?

Also I noticed I have to recreate the entire context when the window is resized. Is it possible to somehow resize a render texture without having to recreate the context? Or can you copy one context over to another when you recreate a render texture? It would make it a lot easier to work with.
« Last Edit: March 31, 2012, 06:15:26 pm by Groogy »
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture and OpenGL example
« Reply #2 on: March 31, 2012, 06:55:54 pm »
Quote
But the proper viewport had not been set on the render texture. I had to explicitly set it even without the window being resized or anything like that.
I've never experienced such a problem. Can you show me your code, so that I'm sure to understand your problem 100%?

Quote
Also I noticed I have to recreate the entire context when the window is resized. Is it possible to somehow resize a render texture without having to recreate the context? Or can you copy one context over to another when you recreate a render texture?
I don't think so.
« Last Edit: March 31, 2012, 08:07:25 pm by Laurent »
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Re: RenderTexture and OpenGL example
« Reply #3 on: March 31, 2012, 07:19:07 pm »
Quote
But the proper viewport had not been set on the render texture. I had to explicitly set it even without the window being resized or anything like that.
I've never experienced such a problem. Can you show me your code, so that I'm sure to understand your problem 100%?

The code above demonstrates it. If you resize the window you can see that the cube appears as the viewport is set to a correct one. I think that if you don't draw any SFML drawables the viewport is not set.
« Last Edit: March 31, 2012, 08:07:19 pm by Laurent »
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture and OpenGL example
« Reply #4 on: March 31, 2012, 08:09:46 pm »
Oh, I remember now. It's a recent modification: now the SFML states don't pollute the user's ones anymore. So if you need to setup a viewport, you must do it yourself. Don't rely on anything that SFML could setup internally; it's now completely contained between the push/popGlStates.
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Re: RenderTexture and OpenGL example
« Reply #5 on: March 31, 2012, 08:36:45 pm »
Aaah okay. Well it's just that it feel inconsistent as the window example didn't need to set it's own viewport? You should probably add a call to glViewport to the OpenGL example just to be extra clear that you should not expect SFML render targets to do any OpenGL stuff for you.

Reason I tried this is because I got a message from a guy where he tried to adapt the OpenGL example to my MultipleRenderTextures class. He probably had the same problem. I finally got it working and will put out a separate example called deferred_opengl
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture and OpenGL example
« Reply #6 on: March 31, 2012, 09:29:53 pm »
Quote
Well it's just that it feel inconsistent as the window example didn't need to set it's own viewport?
I think that by default, the viewport is correctly set for windows.
Laurent Gomila - SFML developer

Groogy

  • Hero Member
  • *****
  • Posts: 1469
    • MSN Messenger - groogy@groogy.se
    • View Profile
    • http://www.groogy.se
    • Email
Re: RenderTexture and OpenGL example
« Reply #7 on: March 31, 2012, 10:02:20 pm »
Quote
Well it's just that it feel inconsistent as the window example didn't need to set it's own viewport?
I think that by default, the viewport is correctly set for windows.

By default in OpenGL? Because I don't know really cause every tutorial I see no matter what opengl interface they always set the viewport manually. Maybe it's just a good practise to set it manually.

If it is that it is set on default by SFML then I feel it becomes inconsistent ^^
« Last Edit: March 31, 2012, 10:03:59 pm by Groogy »
Developer and Maker of rbSFML and Programmer at Paradox Development Studio

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture and OpenGL example
« Reply #8 on: March 31, 2012, 10:12:08 pm »
sf::Window doesn't set anything by default, it just creates the OpenGL context.

I couldn't find more general information, but at least on Windows this is the intended behaviour:
http://msdn.microsoft.com/en-us/library/dd374202(v=vs.85).aspx
Quote
When an OpenGL context is first attached to a window, width and height are set to the dimensions of that window.
Laurent Gomila - SFML developer

ActionBoy

  • Newbie
  • *
  • Posts: 36
    • View Profile
Re: RenderTexture and OpenGL example
« Reply #9 on: June 10, 2012, 10:51:08 pm »
Well I'm just trying to extend the OpenGL example with having it render the OpenGL specific stuff to a render texture to then be copied to the output window.

I can verify that the render texture have correct OpenGL states and that stuff are "rendered" to it. I randomize a clear color every frame and the render texture get that color. It is also copied to the window as I can see the effect. Removing the copy gives me a black screen with the example text. What doesn't work is the actual geometry. No cube is rendered to the render texture. I don't understand why? Am I missing something?

I know I have succeeded with this before but just this case where I am trying to only extend the OpenGL example I can't get it to work. What am I missing?


////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics.hpp>
#include <SFML/OpenGL.hpp>
#include <iostream>


////////////////////////////////////////////////////////////
/// Entry point of application
///
/// \return Application exit code
///
////////////////////////////////////////////////////////////
int main()
{
    // Create the main window
    sf::RenderWindow window(sf::VideoMode(800, 600), "SFML Deferred OpenGL", sf::Style::Default, sf::ContextSettings(32));
    window.setVerticalSyncEnabled(true);
       
        sf::RenderTexture geometryBuffer;
        geometryBuffer.create(800, 600, true);
        sf::Sprite geometrySprite(geometryBuffer.getTexture());
       
        window.setActive();

    // Create a sprite for the background
    sf::Texture backgroundTexture;
    if (!backgroundTexture.loadFromFile("resources/background.jpg"))
        return EXIT_FAILURE;
    sf::Sprite background(backgroundTexture);

    // Load an OpenGL texture.
    // We could directly use a sf::Texture as an OpenGL texture (with its Bind() member function),
    // but here we want more control on it (generate mipmaps, ...) so we create a new one from an image
    GLuint texture = 0;
    {
        sf::Image image;
        if (!image.loadFromFile("resources/texture.jpg"))
            return EXIT_FAILURE;
        glGenTextures(1, &texture);
        glBindTexture(GL_TEXTURE_2D, texture);
        gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, image.getWidth(), image.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, image.getPixelsPtr());
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    }
       
        // window.setActive();
        geometryBuffer.setActive();

    // Enable Z-buffer read and write
    glEnable(GL_DEPTH_TEST);
    glDepthMask(GL_TRUE);
    glClearDepth(1.f);
        glClearColor(0.f, 0.f, 0.f, 0.f);

    // Setup a perspective projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90.f, 800.f/600.f, 1.f, 100.f);

    // Bind our texture
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texture);
    glColor4f(1.f, 1.f, 1.f, 1.f);

    // Create a clock for measuring the time elapsed
    sf::Clock clock;

    // Start game loop
    while (window.isOpen())
    {
        // Process events
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close window : exit
            if (event.type == sf::Event::Closed)
                window.close();

            // Escape key : exit
            if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
                window.close();

            // Adjust the viewport when the window is resized
            if (event.type == sf::Event::Resized)
                        {
                                // window.setActive();
                                geometryBuffer.setActive();
                glViewport(0, 0, event.size.width, event.size.height);
                        }
        }

        // Draw the background
        window.pushGLStates();
        window.draw(background);
        window.popGLStates();

        // Activate the window before using OpenGL commands.
        // This is useless here because we have only one window which is
        // always the active one, but don't forget it if you use multiple windows
                // window.setActive();
        geometryBuffer.setActive();

        // Clear the depth buffer
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Apply some transformations
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(0, 0, -5.f);
        glRotatef(clock.getElapsedTime().asSeconds() * 50.f, 1.f, 0.f, 0.f);
        glRotatef(clock.getElapsedTime().asSeconds() * 30.f, 0.f, 1.f, 0.f);
        glRotatef(clock.getElapsedTime().asSeconds() * 90.f, 0.f, 0.f, 1.f);

        // Draw a cube
        float size = 1.f;
        glBegin(GL_QUADS);

            glTexCoord2f(0, 0); glVertex3f(-size, -size, -size);
            glTexCoord2f(0, 1); glVertex3f(-size,  size, -size);
            glTexCoord2f(1, 1); glVertex3f( size,  size, -size);
            glTexCoord2f(1, 0); glVertex3f( size, -size, -size);

            glTexCoord2f(0, 0); glVertex3f(-size, -size, size);
            glTexCoord2f(0, 1); glVertex3f(-size,  size, size);
            glTexCoord2f(1, 1); glVertex3f( size,  size, size);
            glTexCoord2f(1, 0); glVertex3f( size, -size, size);

            glTexCoord2f(0, 0); glVertex3f(-size, -size, -size);
            glTexCoord2f(0, 1); glVertex3f(-size,  size, -size);
            glTexCoord2f(1, 1); glVertex3f(-size,  size,  size);
            glTexCoord2f(1, 0); glVertex3f(-size, -size,  size);

            glTexCoord2f(0, 0); glVertex3f(size, -size, -size);
            glTexCoord2f(0, 1); glVertex3f(size,  size, -size);
            glTexCoord2f(1, 1); glVertex3f(size,  size,  size);
            glTexCoord2f(1, 0); glVertex3f(size, -size,  size);

            glTexCoord2f(0, 1); glVertex3f(-size, -size,  size);
            glTexCoord2f(0, 0); glVertex3f(-size, -size, -size);
            glTexCoord2f(1, 0); glVertex3f( size, -size, -size);
            glTexCoord2f(1, 1); glVertex3f( size, -size,  size);

            glTexCoord2f(0, 1); glVertex3f(-size, size,  size);
            glTexCoord2f(0, 0); glVertex3f(-size, size, -size);
            glTexCoord2f(1, 0); glVertex3f( size, size, -size);
            glTexCoord2f(1, 1); glVertex3f( size, size,  size);

        glEnd();
               
                geometryBuffer.display();

        // Draw some text on top of our OpenGL object
        window.pushGLStates();
                window.draw(geometrySprite);
        sf::Text text("SFML / OpenGL demo");
        text.setColor(sf::Color(255, 255, 255, 170));
        text.setPosition(250.f, 450.f);
        window.draw(text);
        window.popGLStates();

        // Finally, display the rendered frame on screen
        window.display();
               
                std::cout << sf::err();
    }

    // Don't forget to destroy our texture
    glDeleteTextures(1, &texture);

    return EXIT_SUCCESS;
}
 

Also you are aware of that the projection matrix aspect ratio is wrong?

Update: Remade the example and if I uncomment the activation of the window and comment the geometry buffer activation it works like I would expect it to do. (Though the clear hides the background but it is expected so not weird)

Second Update: Tried with rendering a test sprite to the render texture and it works just like it should so rendering to the texture works. Just not opengl geometry? But SFML uses that behind the scene so what is missing?

I can't get this to work. I switched:
Code: [Select]
       
// window.setActive();
 geometryBuffer.setActive();
to
Code: [Select]
       
 window.setActive();
// geometryBuffer.setActive();

But still no opengl geometri. What have I missed?