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

Author Topic: RenderTexture won't clear properly  (Read 32633 times)

0 Members and 1 Guest are viewing this topic.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture won't clear properly
« Reply #30 on: March 04, 2013, 09:01:15 am »
So can you now try the same kind of minimal app, but which uses sf::RenderTexture? (shouldn't be hard to do, the equivalent calls are written in the comments)
Laurent Gomila - SFML developer

ZackTheHuman

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: RenderTexture won't clear properly
« Reply #31 on: March 04, 2013, 09:44:33 am »
Here is the minimal application that uses RenderTexture that I tried:

#include <memory>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>

int main()
{
    sf::VideoMode videoMode(640, 480, 32);
    sf::RenderWindow window(videoMode, "RenderTexture Test");

    sf::RenderTexture renderTexture;

    renderTexture.create(32, 32);

    bool exit = false;

    while(!exit) {
        sf::Event e;
        while(window.pollEvent(e)) {
            if(e.type == sf::Event::Closed) {
                exit = true;
            }
        }

        window.clear(sf::Color::Black);

        renderTexture.clear(sf::Color(255, 255, 255, 255));
        renderTexture.display();

        sf::Sprite s(renderTexture.getTexture());
        window.draw(s);

        window.display();
    }

    return 0;
}

It produces similar behavior as the "plain" OpenGL application -- a window is displayed with a 32x32 white square in the top left corner.
« Last Edit: March 04, 2013, 10:02:39 am by ZackTheHuman »
Project Hikari Dev Blog: http://hikari.zackthehuman.com/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture won't clear properly
« Reply #32 on: March 04, 2013, 10:04:27 am »
So it works after all ;)

Now you must find what's different in your code, that produces your problem.
Laurent Gomila - SFML developer

ZackTheHuman

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: RenderTexture won't clear properly
« Reply #33 on: March 04, 2013, 10:19:38 am »
No, I think there is an issue with SFML and my graphics card. Here is a sample program does not work correctly:
#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow window(sf::VideoMode(500, 500), "Test");
    window.setFramerateLimit(60);

    sf::RenderTexture rt;
    rt.create(500, 500);

    sf::RectangleShape rs;
    rs.setSize(sf::Vector2f(20, 20));
    rs.setPosition(0.f, 0.f);
    rs.setFillColor(sf::Color::Red);

    sf::Sprite sprite;
    sprite.setTexture(rt.getTexture(), true);

    while(window.isOpen())
    {
        sf::Event event;
        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }

        rs.setPosition(static_cast<sf::Vector2f>(sf::Mouse::getPosition(window)));

        rt.clear();
        rt.draw(rs);
        rt.display();

        window.clear();
        window.draw(sprite);
        window.display();
    }
}

Here is what I see when I move my mouse across the screen with this program:



There should only be one red square located where my mouse cursor is, but instead there is a trail. Now, it seems to actually be clearing a region close to where the repaints are happening, which seems strange.

I have a simple and strange "fix" for this; draw a transparent quad over the entire screen and things are cleared properly. Here's a "fixed" version of the sample program above:

#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow window(sf::VideoMode(500, 500), "Test");
    window.setFramerateLimit(60);

    sf::RenderTexture rt;
    rt.create(500, 500);

    sf::RectangleShape rs;
    rs.setSize(sf::Vector2f(20, 20));
    rs.setPosition(0.f, 0.f);
    rs.setFillColor(sf::Color::Red);

    sf::Sprite sprite(rt.getTexture());

    sf::RectangleShape screenClearer;
    screenClearer.setSize(sf::Vector2f(500, 500));
    screenClearer.setPosition(0.f, 0.f);
    screenClearer.setFillColor(sf::Color::Transparent);

    while(window.isOpen())
    {
        sf::Event event;
        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }

        rs.setPosition(static_cast<sf::Vector2f>(sf::Mouse::getPosition(window)));

        rt.clear();
        rt.draw(rs);
        rt.draw(screenClearer);
        rt.display();

        window.clear();
        window.draw(sprite);
        window.display();
    }
}
« Last Edit: March 04, 2013, 10:26:50 am by ZackTheHuman »
Project Hikari Dev Blog: http://hikari.zackthehuman.com/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture won't clear properly
« Reply #34 on: March 04, 2013, 10:25:47 am »
Are your SFML 2 and graphics drivers up-to-date?
Laurent Gomila - SFML developer

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10848
    • View Profile
    • development blog
    • Email
Re: RenderTexture won't clear properly
« Reply #35 on: March 04, 2013, 10:53:08 am »
Although I hadn't experienced the problem at the time I've written the example, I do now.
Then again I got a new PC with a slightly different graphics card, but the drivers are up to date and I'm obviously using SFML 2. It btw doesn't matter if I used VS or MinGW, debug or release...

Not sure what this could be, also the "fix" works.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

ZackTheHuman

  • Newbie
  • *
  • Posts: 33
    • View Profile
Re: RenderTexture won't clear properly
« Reply #36 on: March 04, 2013, 10:55:38 am »
I just pulled the latest revision from GitHub and my drivers are up-to-date (I double checked :P).
Project Hikari Dev Blog: http://hikari.zackthehuman.com/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture won't clear properly
« Reply #37 on: March 04, 2013, 11:00:21 am »
I'm sorry I can't investigate myself, so if you want  this bug to be fixed you'll have to spend some time on it.

What I would do, is to translate your minimal app to OpenGL-only code (since the one that I already wrote doesn't show the problem), make sure that it still produces the error of course, and then compare it with the FBO sample that works.
Laurent Gomila - SFML developer

Suskive

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: RenderTexture won't clear properly
« Reply #38 on: March 04, 2013, 11:51:03 pm »

I have a simple and strange "fix" for this; draw a transparent quad over the entire screen and things are cleared properly. Here's a "fixed" version of the sample program above:


thanks a lot for the trick.

exafi

  • Newbie
  • *
  • Posts: 41
    • View Profile
Re: RenderTexture won't clear properly
« Reply #39 on: July 03, 2013, 05:48:58 pm »

    RenderTexture.clear(sf::Color(255,255,255,0));

the_mean_marine

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: RenderTexture won't clear properly
« Reply #40 on: December 27, 2013, 11:01:29 am »
I've recently run in to this bug while trying to implement post-effect shaders without copying the contents of the window and I believe that I may have come across some additional information which may help quash this bug.

When running with a shader on, renderTexture.clear() appears to be working as intended but when the shader is switched off the problem appears again. While the previous work-around of drawing a transparent shape over the entire renderTexture works I've found another work-around which may help narrow down where the problem lies. If you call window.resetGLStates() at any point in the rendering loop the problem disappears. Looking at the source for RenderTarget::resetGLStates I've tried using all of the OpenGL calls there in my code after calling window.setActive() and it doesn't seem to have any effect. So it must be one of the other parts of resetGLStates() that is correcting the problem. It also seems weird that the call is to the window and not the renderTexture to fix the problem. I tried calling it on the renderTexture but it had no effect.

So far this seems to only be affecting ATI cards. I'm running Win 7 x64 with a Radeon 7970. My graphics card drivers are Catalyst 13.12 and I'm using the pre-compiled SFML 2.1 libs statically linked. My compiler is VS2012 x64 and the problem appears in both debug and release builds. There are no error messages sent to the console window and I've broken the shader program before and the error messages were sent to the console so the error output is working.

I've attached a piece of sample code below which demonstrates the problem on my machine. The shader, the original work-around, and my work around are all toggleable from within the program by using the F1, F2, and F3 keys respectively.

// Includes
#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>
#include <iostream>


int main()
{
        // Constants
        const int windowWidth = 800, windowHeight = 600;
        const float ballWidth = 50.0f, ballHeight = 50.0f;
        sf::Vector2f ballVelocity(-300.0f,-300.0f);

        // Toggles
        bool ShaderEnabled = false;
        bool hackOneEnabled = false;
        bool hackTwoEnabled = false;
       
        // Fragment Shader Code
        const std::string fragmentShader = \
    "uniform sampler2D texture;" \
        "void main()" \
    "{" \
    "    gl_FragColor = texture2D(texture, gl_TexCoord[0].xy) * vec4(1.0, 0.0, 0.0, 1.0);" \
    "}";

        // Create Main Window
    sf::RenderWindow window(sf::VideoMode(windowWidth, windowHeight), "RenderTexture Issue Demo");
        window.setVerticalSyncEnabled(true);

        // Load Shader
        sf::Shader Shader;
        if (!Shader.loadFromMemory(fragmentShader, sf::Shader::Fragment))
        {
                std::cout << "ERROR: Unable to load shader" << std::endl;
                std::cout << "Press any key to continue..." << std::endl;
                std::cin.get();
        return EXIT_FAILURE;
        }

        // Create RenderTexture
        sf::RenderTexture renderTexture;
        renderTexture.create(windowWidth,windowHeight);

        // Create Sprite for the RenderTexture
        sf::Sprite renderSprite;
        renderSprite.setTexture(renderTexture.getTexture());

        // Create Ball
        sf::RectangleShape ball(sf::Vector2f(ballWidth,ballHeight));
        ball.setOrigin(sf::Vector2f(ballWidth * 0.5f, ballHeight * 0.5f));
        ball.setPosition(sf::Vector2f(0.5f * windowWidth, 0.5f * windowHeight));
        ball.setFillColor(sf::Color::White);

        // Create Transparent Shape with the same size as the window
        sf::RectangleShape screenClearer;
    screenClearer.setSize(sf::Vector2f(windowWidth, windowHeight));
    screenClearer.setFillColor(sf::Color::Transparent);
   
        // Time and Timers Initialisation
        sf::Clock frameTimer;
        sf::Time lastFrameTime;
        const sf::Time physicsTimeStep = sf::microseconds(10);

        // Main Loop
        while (window.isOpen())
    {
                // Simulation Timing
                lastFrameTime += frameTimer.restart();

                // Clamp the maximum frame time to prevent self-perpetuating slowdowns
                if (lastFrameTime.asMilliseconds() > 250)
                        lastFrameTime = sf::milliseconds(250);

                while (lastFrameTime >= physicsTimeStep)
                {
                        // Move Ball
                        ball.move(ballVelocity * physicsTimeStep.asSeconds());
                               
                        // Check Wall Colisions
                        if ((ball.getPosition().x - 0.5f * ballWidth) < 0)
                        {
                                ballVelocity.x = std::abs(ballVelocity.x);
                        }
                        if ((ball.getPosition().x + 0.5f * ballWidth) > windowWidth)
                        {
                                ballVelocity.x = -std::abs(ballVelocity.x);
                        }
                        if (((ball.getPosition().y - 0.5f * ballHeight) < 0) || ((ball.getPosition().y + 0.5f * ballHeight) > windowHeight))
                                ballVelocity.y = -ballVelocity.y;

                        // Advance Simulation Step
                        lastFrameTime -= physicsTimeStep;
                }

                // Render
                renderTexture.clear();
                renderTexture.draw(ball);
               
                // Hack to fix bug where the renderTexture doesn't clear
                if (hackOneEnabled)
                        renderTexture.draw(screenClearer);             
               
                renderTexture.display();
               
                // Alternative hack to fix aforementioned bug.
                // It doesn't seem to matter when this happens as long as it happens at least once per loop.
                if (hackTwoEnabled)
                        window.resetGLStates();                                

                window.clear();

                if (ShaderEnabled)
                        window.draw(renderSprite, &Shader);
                else
                        window.draw(renderSprite);
       
                window.display();
               
                // Event Handler
        sf::Event event;
        while (window.pollEvent(event))
        {
                        switch(event.type)
                        {
                                case sf::Event::Closed:
                                        window.close();
                                        break;
                                case sf::Event::KeyPressed:
                                {
                                        // Toggle Shader
                                        if (event.key.code == sf::Keyboard::F1)
                                                ShaderEnabled = !ShaderEnabled;
                                        // Toggle first RenderTexture clearing hack (Transparent texture over screen)
                                        if (event.key.code ==sf::Keyboard::F2)
                                                hackOneEnabled = !hackOneEnabled;
                                        // Toggle second RenderTexture clearing hack (window.resetGLStates())
                                        if (event.key.code ==sf::Keyboard::F3)
                                                hackTwoEnabled = !hackTwoEnabled;
                                        break;
                                }
                        }
        }
    }
    return EXIT_SUCCESS;
}

nathanchere

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: RenderTexture won't clear properly
« Reply #41 on: April 28, 2014, 06:45:31 am »
This is the results of running your code:


I am running the AMD Catalyst 12.8 drivers, which is the current version.

I get the same results using the SFML 2.0 RC.
Graphicscard is also an AMD, but its a 6950.

When it occured within my project i thought it were my fault, but it seems to be a more general problem.

Just my two cents, I still get the same issue with SFML 2.1. I get the red square ghosting, but the FBO teapot demo works fine. Happens consistently on both systems I've tried (one with an Nvidia quadro 3000m and Win7, one with ATI Firepro M3900 and Win8). Issue doesn't occur when writing direct to window, only when using RenderTexture. It seems inconsistent in a multi-monitor scenario, ie the ghosting appears much worse on the non-primary displays.

Is it fair to say this is still an ongoing issue? I don't mind digging in to work out why it's happening as long as it isn't already resolved and I've just missed the relevant post(s).

nathanchere

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: RenderTexture won't clear properly
« Reply #42 on: April 28, 2014, 09:10:13 am »
OK here's what I've got. It's using SFML.Net but I think it gets the point across.

Spike source code:
https://github.com/nathanchere/Spikes_SfmlRenderTexture

Compiled version if you just want to see the shiny:
https://dl.dropboxusercontent.com/u/14432582/sfmlRenderTextureSpike.7z

Main code for the really lazy:
        private void RenderWorking()
        {
            window.Clear(Color.Black);

            textureOne.Clear(Color.White);
            textureOne.Display();

            var renderSprite = new Sprite(textureOne.Texture);

            // Note #2
            // renderSprite.Position = new Vector2f(Mouse.GetPosition(window).X, Mouse.GetPosition(window).Y);

            renderSprite.Draw(window, RenderStates.Default);

            // Note #1
            // window.Display();
        }

        private void RenderBuggy()
        {
            shapeTwo.Position = new Vector2f(Mouse.GetPosition(window).X, Mouse.GetPosition(window).Y);

            textureTwo.Clear();
            textureTwo.Draw(shapeTwo);
            textureTwo.Display();

            window.Clear();
            var renderSprite = new Sprite(textureTwo.Texture);
            window.Draw(renderSprite);
        }

        private void RenderMoreBuggy()
        {
            textureThree.Clear(new Color(
                (byte) (DateTime.Now.Millisecond%128),
                (byte) (DateTime.Now.Millisecond%64),
                (byte) (DateTime.Now.Millisecond%255)
            ));
            textureThree.Display();

            shapeThree.Position = new Vector2f(Mouse.GetPosition(window).X, Mouse.GetPosition(window).Y);
            shapeThree.Rotation = 0.36f*DateTime.Now.Millisecond;
            textureThree.Draw(shapeThree);            

            window.Clear();
            var renderSprite = new Sprite(textureThree.Texture);
            window.Draw(renderSprite);
        }

 

So basically RenderWorking is doing the white-square-in-corner thing, RenderBuggy is the red-square-following-mouse thing,  and RenderMoreBuggy is intended to display the issue better.

Use: press 1 2 and 3 to toggle render mode, Space to toggle displaying text over the top.

Huh? What's the point of the text? Read on...

Observations:

 
  • the white square test works fine, although it's a bad test. Gives a false positive that it's working OK because nothing is changing or moving
  • Uncomment the window.Display() call at Note #1 and you reproduce the flickering someone mentioned earlier in the thread - make sure you're not calling Display on the main render target multiple times in a row?
  • the red square demo replicates the expected buggy result. Main difference with this and the white square demo is that the whole drawing area is a RenderTexture, not just the white square, and there is movement
  • The third demo tries to better highlight how RenderTexture regions which aren't being drawn over do not get updated, even when you use Clear()

The interesting part for me is the main loop:

while (window.IsOpen())
            {
                window.DispatchEvents();
                Render();
               
                if(DisplayText) window.Draw(Text); // Note #3

                window.Display();
            }
 

Render() calls whichever one of the three afore described functions is currently selected. Behaviour is as already described. When drawing text is enabled, suddenly the buggy drawing goes away.

Example:
 


I'm now more inclined to believe yes it really is a bug and not just people "doing it wrong".

{edit} disregard; issue identified will be fixed in SFML 2.2.
« Last Edit: May 01, 2014, 06:38:22 am by nathanchere »

nathanchere

  • Newbie
  • *
  • Posts: 7
    • View Profile
    • Email
Re: RenderTexture won't clear properly
« Reply #43 on: April 28, 2014, 09:26:51 am »
One last thing... for anyone still looking for a workaround (C#; adapt for C++ or whatever accordingly):

// do all your drawing
// etc..
// right before display:

Shape shittyHack = new RectangleShape(new Vector2f(0,0)){ FillColor = new Color(0,0,0,0) };
Window.Draw(shittyHack);

// and now you may...

Window.Display();
 

I don't normally like playing with C++ code these days but if I can get SFML building at home I'll look into exactly why this is happening and hopefully not require a fake Draw() to make sure the entire RenderTexture is drawn.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: RenderTexture won't clear properly
« Reply #44 on: April 28, 2014, 09:59:00 am »
Thanks a lot for your investigations. You should open a new task on the tracker, since all RenderTexture tasks were closed.
Laurent Gomila - SFML developer