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

Author Topic: wobbling lines when render window size changes (SFML2)  (Read 5508 times)

0 Members and 1 Guest are viewing this topic.

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
wobbling lines when render window size changes (SFML2)
« on: February 05, 2010, 03:05:13 pm »
I'm using branches/sfml2 revision 1369 and I noticed that when creating and drawing lines with sf::Shape::Line the final position of those lines seems to be dependent on the size of the render window. In addition there seem to be issues with the visibility of diagonal (angular/beveled/sloped?) lines when their thickness is too small.

When running my demo application (see next post for code) you'll notice the following:
- the window size randomly changes all the time (intended)
- the blue rectangle always remains on the very same spot (intended)
- the red horizontal and vertical lines are "wobbling" despite the fact that their positions are not changed in the code (bad)
- the red diagonal line is not visible at all (bad)

As I can't imagine any use for positions of lines being dependent on the render window size I'd really appreciate if at least the first issue will get fixed.

Please note that the second issue was already mentioned here:
http://www.sfml-dev.org/forum/viewtopic.php?t=1828

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
wobbling lines when render window size changes (SFML2)
« Reply #1 on: February 05, 2010, 03:06:56 pm »
Code: [Select]
// small SFML demo written by T.T.H. on 4. Feb. 2010 to demonstrate:
// 1. line position "wobbling" based on render window size
// 2. line thickness "invisibility" with diagonal lines
//    (already mentioned here: http://www.sfml-dev.org/forum/viewtopic.php?t=1828 )
//
// forum post:
// http://www.sfml-dev.org/forum/viewtopic.php?t=2145
//
// I'm using:
// - branches/sfml2 revision 1369 being statically linked
// - Visual C++ .NET 2003 (compiler version 7.1.6030, "Professional" edition)
// - German Windows XP SP3 32 Bit
// - NVIDIA Quadro NVS 285 (some onboard thingie with some default driver)

#include <SFML/Graphics.hpp>

int myrand(int max)
{
  return (int) ((float) max * (rand() / (RAND_MAX + 1.0)));
}

int main(int argc, char** argv)
{
  // create render window
  sf::RenderWindow MyRenderWindow(sf::VideoMode(300, 300), "My SFML Window");

  // create image
  sf::Image MyImage;
  MyImage.Create(200, 200, sf::Color(0, 0, 255, 255));
 
  // create sprite
  sf::Sprite MySprite(MyImage);
  MySprite.SetPosition(50.0f, 50.0f);

  // create lines
  float X(50.0f);
  float Y(50.0f);
  float Length(200.0f);
  sf::Shape MyLineHorizontal(sf::Shape::Line(X, Y, X + Length, Y         , 1.0f, sf::Color(255, 0, 0)));
  sf::Shape MyLineVertical  (sf::Shape::Line(X, Y, X         , Y + Length, 1.0f, sf::Color(255, 0, 0)));
  sf::Shape MyLineDiagonal  (sf::Shape::Line(X, Y, X + Length, Y + Length, 1.0f, sf::Color(255, 0, 0)));

  // the big loop
  srand((unsigned int) time(NULL));
  bool Running(true);
  while (Running)
  {
    // randomly set render window size
    MyRenderWindow.SetSize(300 + myrand(50), 300 + myrand(50));

    // update view of window to avoid wicked streching and enforce pixel precision
    MyRenderWindow.SetView(sf::View(sf::FloatRect(0, 0, (float) MyRenderWindow.GetWidth(), (float) MyRenderWindow.GetHeight())));

    // clear window
    MyRenderWindow.Clear(sf::Color(0, 255, 0));

    // draw sprite
    MyRenderWindow.Draw(MySprite);

    // draw lines
    MyRenderWindow.Draw(MyLineHorizontal);
    MyRenderWindow.Draw(MyLineVertical);
    MyRenderWindow.Draw(MyLineDiagonal);
   
    // display window
    MyRenderWindow.Display();

    // process events
    sf::Event MyEvent;
    while (MyRenderWindow.GetEvent(MyEvent))
    {
      // window closed
      if (MyEvent.Type == sf::Event::Closed) Running = false;

      // escape key pressed
      if ((MyEvent.Type == sf::Event::KeyPressed) && (MyEvent.Key.Code == sf::Key::Escape)) Running = false;
    }
  }

  return EXIT_SUCCESS;
}

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
wobbling lines when render window size changes (SFML2)
« Reply #2 on: February 05, 2010, 03:47:58 pm »
Dude, you should update to the latest revision before spending so much time writing test code, I fixed it in revision 1390 :wink:

But your feedback was not useless, I tested your code and it confirms that the fix works well.

By the way, this is the kind of code that I love: I copied, compiled, ran it and wrote my answer in 30 sec :mrgreen:
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
wobbling lines when render window size changes (SFML2)
« Reply #3 on: February 05, 2010, 05:09:24 pm »
D'OH

I remember I checked the log on 2. February.
You made revision 1390 on 3. February.
I stumbled about the issue on 4. February.

Regarding the sample code: I know that if one gives you simple, obvious, working sample code you're usually pretty fast with fixing bugs. So I really polished it up - and it worked - a bit wicked in the temporal order or events but it worked  :D

Anyway, my weekend is like only 2 minutes ahead, so I'll update to the latest revision and test it at Monday. By the way, what exactly do you mean with...

Quote from: "commit message of 1390"
New try for pixel-perfect rendering -- waiting for feedbacks

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
wobbling lines when render window size changes (SFML2)
« Reply #4 on: February 05, 2010, 05:26:18 pm »
Quote
Regarding the sample code: I know that if one gives you simple, obvious, working sample code you're usually pretty fast with fixing bugs. So I really polished it up - and it worked - a bit wicked in the temporal order or events but it worked

:lol:

Quote
By the way, what exactly do you mean with...

Quote from: "commit message of 1390"
New try for pixel-perfect rendering -- waiting for feedbacks

Well, it's like my 10th attempt at getting pixel-perfect rendering, so I wasn't very positive about this new modification. On top of that, this modification consists mainly in getting rid of everything that was trying to make the rendering better. Too beautiful to work.
However, it passed all my tests (which consists of all the code samples of people that once complained about rendering), that's why I commited it.

It actually works and solves all the remaining bugs, but it won't produce a perfect result with coordinates not aligned with pixels (i.e. integer coordinates, if you don't play with views).
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
wobbling lines when render window size changes (SFML2)
« Reply #5 on: February 08, 2010, 11:28:12 am »
I just updated to branches/sfml2 revision 1392 and tried it out (with VS2003).

The good news:
- no more line "wobbling" when the render window is resized
- the diagonal line is visible with exactly one pixel width (non-antialiased)
- the diagonal line is exactly where I want it to be (same position and size as the rectangle)

The bad news:
- the horizontal line is one pixel "too far up"
- the vertical line is one pixel "too far left"

When putting the following code in my former example...
Code: [Select]
int main(int argc, char** argv)
{
  // create render window
  sf::RenderWindow MyRenderWindow(sf::VideoMode(300, 300), "My SFML Window");

  // position
  float X(1.0f);
  float Y(1.0f);
  float Length(200.0f);

  // create image
  sf::Image MyImage;
  MyImage.Create((int) Length, (int) Length, sf::Color(0, 0, 255, 255));
 
  // create sprite
  sf::Sprite MySprite(MyImage);
  MySprite.SetPosition(X, Y);

  // create lines
  sf::Shape MyLineHorizontal(sf::Shape::Line(X, Y, X + Length, Y         , 1.0f, sf::Color(255, 0, 0)));
  sf::Shape MyLineVertical  (sf::Shape::Line(X, Y, X         , Y + Length, 1.0f, sf::Color(255, 0, 0)));
  sf::Shape MyLineDiagonal  (sf::Shape::Line(X, Y, X + Length, Y + Length, 1.0f, sf::Color(255, 0, 0)));

  // the big loop
  /* -- SNIP -- */

...you can see that the top left corner of the blue rectangle is at 1/1 but the horizontal line starts at 1/0 and the vertical line starts at 0/1 despite the fact that all drawables in my examples are positioned at 1/1. Maybe it's a rounding issue?

Regarding code size: when I develop new features for a project the code gets bigger at first and then the code gets smaller again and at the end of the day I have to refrain from judging myself by the sheer amount of new code because "good code" even means "simple and short code, doing exactly what was required, nothing more and nothing less". A funny quote I did recently read in an online resume was "my contribution to the project's code size was -40.000 lines of code".

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
wobbling lines when render window size changes (SFML2)
« Reply #6 on: February 08, 2010, 12:11:51 pm »
Quote
The bad news:
- the horizontal line is one pixel "too far up"
- the vertical line is one pixel "too far left"

This is a very particular situation.
Let's take the example of your horizontal line at Y = 1. With a thickness of 1, it will extend from Y = 0.5 to Y = 1.5. In other words, it is located exactly between the center of pixel 0 and the center of pixel 1, and due to strict rounding rules, OpenGL chooses to draw it on pixel 0. You can easily confirm this by adding a very small amount to the Y coordinate (like 0.01): it is enough to make it appear at pixel 1 ;)

If my explanations are not clear enough I can try to draw a picture to show you what happens.
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
wobbling lines when render window size changes (SFML2)
« Reply #7 on: February 08, 2010, 01:10:36 pm »
Your explanation is clear, thanks. My answer is "GNAAGNAAGNAAWHATAMESS". Those rounding issues in 3D interfaces can get really annoying.

I could "fix" it like this in my demo project:
Code: [Select]
 // position
  // note: +0.001 because of OpenGL rounding issues regarding lines
  float X(1.001f);
  float Y(1.001f);


Some related issue: when "zooming" the view of the render window the lines become "un-pixel-precise" again:

Code: [Select]
   MyRenderWindow.SetView(sf::View(sf::FloatRect(0, 0, (float) MyRenderWindow.GetWidth() / 3.0f, (float) MyRenderWindow.GetHeight() / 3.0f)));


Notice the / 3.0f in the code and the missing pixel in the top left corner of the three pixel thick lines. This even happens without the +0.001f trick.

Anyway. Since I only need horizontal and vertical lines in my current project I will now simply use one pixel thick rectangles instead of one pixel thick lines: so far I did not notice any of those aforementioned issues when using rectangles instead of lines.

Nevertheless thanks for your help!

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
wobbling lines when render window size changes (SFML2)
« Reply #8 on: February 08, 2010, 01:21:33 pm »
Quote
I could "fix" it like this in my demo project:
Code: [Select]
 // position
  // note: +0.001 because of OpenGL rounding issues regarding lines
  float X(1.001f);
  float Y(1.001f);

Well, you really need to fix it because your code is wrong ;)
What you want is a line that is drawn between Y = 1 and Y = 2, not between 0.5 and 1.5. Given that the line coordinates represent its center, what you want is really 1.5, not 1.0.

Quote
Some related issue: when "zooming" the view of the render window the lines become "un-pixel-precise" again:

This is intended. One consequence of my last modification is that pixel-perfect rendering now requires the objects coordinates to be aligned with pixels. Basically, when you use decimal coordinates for your objects and/or your view, anything can happen and I'm not responsible for that ;)
If you're wondering why I removed the automatic rounding that happened before my last modification, this is because it caused a bug: objects moving/rotating/scaling slowly were crappy, the rounding stuff removed all the smoothness.

Quote
Anyway. Since I only need horizontal and vertical lines in my current project I will now simply use one pixel thick rectangles instead of one pixel thick lines: so far I did not notice any of those aforementioned issues when using rectangles instead of lines.

You don't need to do that, just remember that lines coordinates are their center, and you will have the exact same results as rectangles.
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
wobbling lines when render window size changes (SFML2)
« Reply #9 on: February 08, 2010, 03:02:55 pm »
Quote from: "Laurent"
What you want is a line that is drawn between Y = 1 and Y = 2, not between 0.5 and 1.5. Given that the line coordinates represent its center, what you want is really 1.5, not 1.0.

Ok. But that +0.5 is only for lines, right?

Quote from: "Laurent"
[...] now requires the objects coordinates to be aligned with pixels. Basically, when you use decimal coordinates for your objects and/or your view, anything can happen and I'm not responsible for that ;)

That is something I don't understand yet.

Quote from: "Laurent"
You don't need to do that, just remember that lines coordinates are their center, and you will have the exact same results as rectangles.

When adding 0.5 to the position of the line while there is no zoom in the view it looks like I want it to look. But when the zoom changes it doesn't. Try the following code and make the lines matched on the rectangle with different values for the Zoom variable: 0.5f, 1.0f, 4.0f

Code: [Select]
int main(int argc, char** argv)
{
  // create render window
  sf::RenderWindow MyRenderWindow(sf::VideoMode(900, 900), "My SFML Window");

  // position
  float X(1.0f);
  float Y(1.0f);
  float Length(200.0f);
  float Zoom(4.0f); // <-- change this 0.5f, 1.0f, 4.0f

  // create image
  sf::Image MyImage;
  MyImage.Create((int) Length, (int) Length, sf::Color(0, 0, 255, 255));
  MyImage.SetSmooth(false);
 
  // create sprite
  sf::Sprite MySprite(MyImage);
  MySprite.SetPosition(X, Y);

  // line position adaption
  X += 0.5f;
  Y += 0.5f;

  // create lines
  sf::Shape MyLineHorizontal(sf::Shape::Line(X, Y, X + Length, Y         , 1.0f, sf::Color(255, 0, 0)));
  sf::Shape MyLineVertical  (sf::Shape::Line(X, Y, X         , Y + Length, 1.0f, sf::Color(255, 0, 0)));
  sf::Shape MyLineDiagonal  (sf::Shape::Line(X, Y, X + Length, Y + Length, 1.0f, sf::Color(255, 0, 0)));

  // the big loop
  srand((unsigned int) time(NULL));
  bool Running(true);
  while (Running)
  {
    // randomly set render window size
    // ### MyRenderWindow.SetSize(300 + myrand(50), 300 + myrand(50));

    // update view of window to avoid wicked streching and enforce pixel precision
    MyRenderWindow.SetView(sf::View(sf::FloatRect(0, 0, (float) MyRenderWindow.GetWidth() / Zoom, (float) MyRenderWindow.GetHeight() / Zoom)));

    // clear window
    MyRenderWindow.Clear(sf::Color(0, 255, 0));

    // draw sprite
    MyRenderWindow.Draw(MySprite);

    // draw lines
    MyRenderWindow.Draw(MyLineHorizontal);
    MyRenderWindow.Draw(MyLineVertical);
    MyRenderWindow.Draw(MyLineDiagonal);
   
    // display window
    MyRenderWindow.Display();

    // process events
    sf::Event MyEvent;
    while (MyRenderWindow.GetEvent(MyEvent))
    {
      // window closed
      if (MyEvent.Type == sf::Event::Closed) Running = false;

      // escape key pressed
      if ((MyEvent.Type == sf::Event::KeyPressed) && (MyEvent.Key.Code == sf::Key::Escape)) Running = false;
    }

    // sleep
    _sleep(100);
  }

  return EXIT_SUCCESS;
}

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
wobbling lines when render window size changes (SFML2)
« Reply #10 on: February 08, 2010, 10:49:25 pm »
Quote
Ok. But that +0.5 is only for lines, right?

That 0.5 is thickness/2 which is added on each side of the line. So yes, it is only for lines.

Quote
That is something I don't understand yet.

I'm just saying that pixel perfect rendering requires that you don't mess too much with decimal coordinates ;)
To be more precise, coordinates must match pixels of the RenderTarget. In most situations this simply means using integer coordinates.

Quote
When adding 0.5 to the position of the line while there is no zoom in the view it looks like I want it to look. But when the zoom changes it doesn't. Try the following code and make the lines matched on the rectangle with different values for the Zoom variable: 0.5f, 1.0f, 4.0f

This is because you add 0.5 to each coordinate of each line. You just need to add it to Y for the horizontal line and to X for the vertical line.
Laurent Gomila - SFML developer

T.T.H.

  • Full Member
  • ***
  • Posts: 112
    • View Profile
wobbling lines when render window size changes (SFML2)
« Reply #11 on: February 09, 2010, 11:17:10 am »
Quote from: "Laurent"
This is because you add 0.5 to each coordinate of each line. You just need to add it to Y for the horizontal line and to X for the vertical line.

Ah, ok, now I understood it. Seems to work fine now.

Thanks again, your help is greatly appreciated.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
wobbling lines when render window size changes (SFML2)
« Reply #12 on: February 09, 2010, 11:19:15 am »
You're welcome, I love demonstrating that the new code works flawlessly :lol:
Laurent Gomila - SFML developer