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

Author Topic: Vanishing Circle Problem  (Read 9933 times)

0 Members and 1 Guest are viewing this topic.

scross

  • Newbie
  • *
  • Posts: 14
    • View Profile
Vanishing Circle Problem
« on: April 27, 2010, 02:23:08 pm »
I have a problem in which I have 3 circles with radii of greatly varying magnitude, however the smallest of the circles does not appear, but it does flash occasionally. The context here is a gravity simulator, where the 3 circles represent the Sun, Earth and Moon and the values for the radii are therefore approximately 6.955E8, 6.3781E6 and 1.737E3 metres respectively. The moon is the circle which is not visible (yes, I'm at the correct zoom to see it) and if I make the radius of the moon 10* larger it appears as a rather skewed circle. The radius of the sun is therefore about 100,000 * the radius of the moon, and I would guess this is the source of problem. So I'm asking the question to verify if this is the case, and if so to ask why. It'd also be useful if you could suggest a way around the problem. Finally, since I'm likely to switch the graphical part of the simulator to use 3D (with Ogre3D) some time in the future, can I expect similar problems then?

As a side note, I'm obviously aware that it's certainly not possible to see the sun and the moon on the same image, since one is so much larger than the other. Indeed, it isn't even possible to see the sun and the earth together. However, I'd like the user to be able to zoom in to get an idea of the difference in magnitudes between the solar system bodies.

Ashenwraith

  • Sr. Member
  • ****
  • Posts: 270
    • View Profile
Vanishing Circle Problem
« Reply #1 on: April 28, 2010, 06:29:25 am »
This is not a math test, you have to provide code in a simplified example if you want real help.

I think the problem is your scale is messed up. If you are using 2D graphics to draw the sun and the moon you should scale down and round. There are only so many pixels on the screen no matter what the physics suggest. What you see with your eyes is very limited.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Vanishing Circle Problem
« Reply #2 on: April 28, 2010, 01:08:23 pm »
SFML, OpenGL and your graphics card use single precision floating point numbers. So both very big and very small numbers are likely to produce this kind of artifacts.
Laurent Gomila - SFML developer

scross

  • Newbie
  • *
  • Posts: 14
    • View Profile
Vanishing Circle Problem
« Reply #3 on: April 28, 2010, 01:51:56 pm »
Quote
This is not a math test, you have to provide code in a simplified example if you want real help.


The following code demonstrates the problem:

Code: [Select]
#include <SFML/Graphics.hpp>
int main(){
sf::RenderWindow App(sf::VideoMode(1024, 768, 32), "2D Gravity Simulator");

double sunRadius = 6.955E8;
double earthRadius = 6.3781E6;
double moonRadius = 1.737E3;

sf::Vector2f sunPos(0.0, 0.0);
sf::Vector2f earthPos(1.49682955E11, 0.0);
sf::Vector2f moonPos(1.50067354E11, 0.0);

sf::Vector2f sunHalfSize(sunRadius, sunRadius);
sf::Vector2f earthHalfSize(earthRadius, earthRadius);
sf::Vector2f moonHalfSize(moonRadius, moonRadius);

sf::View view(sunPos, sunHalfSize);
    App.SetView(view);

    while (App.IsOpened()){
    App.Clear();

sf::Event Event;
while (App.GetEvent(Event)){
            if(Event.Type == sf::Event::Closed){
App.Close();
}
if(App.GetInput().IsKeyDown(sf::Key::S)){
view.SetHalfSize(sunHalfSize);
view.SetCenter(sunPos);
}else if(App.GetInput().IsKeyDown(sf::Key::E)){
view.SetHalfSize(earthHalfSize);
view.SetCenter(earthPos);
}else if(App.GetInput().IsKeyDown(sf::Key::M)){
view.SetHalfSize(moonHalfSize);
view.SetCenter(moonPos);
}
}

App.Draw(sf::Shape::Circle(sunPos, sunRadius, sf::Color(255.0, 0.0, 0.0)));
App.Draw(sf::Shape::Circle(earthPos, earthRadius, sf::Color(0.0, 255.0, 0.0)));
App.Draw(sf::Shape::Circle(moonPos, moonRadius, sf::Color(0.0, 0.0, 255.0)));
        App.Display();
    }

    return 0;
}


You press 'S' to zoom in on the sun, 'E' to zoom in on the Earth and 'M' for the moon. You should notice that the sun and the earth appear correctly, while the moon does not appear at all. However, if you move the moon so that it is closer to the origin (the sun) then you will find it starts to appear correctly. You can also increase its size, which will make it be shown correctly.

Quote
I think the problem is your scale is messed up. If you are using 2D graphics to draw the sun and the moon you should scale down and round. There are only so many pixels on the screen no matter what the physics suggest. What you see with your eyes is very limited.


The problem doesn't have anything to do with pixels on the screen, if that's what you're saying, since the program zooms in to each of the circles. Rather, the problem has to do with how the circles are stored in OpenGL.

Quote
SFML, OpenGL and your graphics card use single precision floating point numbers. So both very big and very small numbers are likely to produce this kind of artifacts.


Ok, I wasn't aware of this, thank you. I've worked out what's going on: the problem is the addition of the small radius of the moon with the large distance between the sun and the moon. Single precision floating point can only deal with around 7 decimal places in base 10, whereas the difference between the values would be 8 decimal places, thus the value of the radius of the moon is simply truncated from the result. This means that all the points of the circle are drawn in the same place and hence no circle appears.

As for how to solve this, I may have to scale up the moon as I zoom in on it. Any other potential solutions?

scross

  • Newbie
  • *
  • Posts: 14
    • View Profile
Vanishing Circle Problem
« Reply #4 on: April 30, 2010, 01:49:56 pm »
Ok, I've realised that there is a very simple solution to this, and that is to translate the circle to the centre of the screen. This is basically what sf::View does, however it only uses single precision floating point numbers, so you have to replace this with a similar mechanism for higher precision numbers. In fact, is there any good reason for sf::View not using higher precision to translate the coordinates?

Indeed, why shouldn't all of SFML use higher precision floating point numbers? Of course it's understandable that the hardware and/or graphics libraries (OpenGL) may only be able to deal with single precision, but this may change in future. Quite usefully, the Vector2 class can be specified with a template parameter that allows the use of double precision components, but the view class is still limited to single precision.

Anyway, I've adapted the code quite simply to make it work as follows:

Code: [Select]
int main(){
sf::RenderWindow App(sf::VideoMode(1024, 768, 32), "2D Gravity Simulator");

double sunRadius = 6.955E8;
double earthRadius = 6.3781E6;
double moonRadius = 1.737E3;

double sunX = 0.0, sunY = 0.0;
double earthX = 1.49682955E11, earthY = 0.0;
double moonX = 1.50067354E11, moonY = 0.0;

sf::Vector2f sunHalfSize(sunRadius, sunRadius);
sf::Vector2f earthHalfSize(earthRadius, earthRadius);
sf::Vector2f moonHalfSize(moonRadius, moonRadius);

sf::Vector2f startPos(0.0, 0.0);
sf::View view(startPos, sunHalfSize);
    App.SetView(view);

    double pX = 0.0, pY = 0.0;

    while (App.IsOpened()){
    App.Clear();

sf::Event Event;
while (App.GetEvent(Event)){
            if(Event.Type == sf::Event::Closed){
App.Close();
}
if(App.GetInput().IsKeyDown(sf::Key::S)){
view.SetHalfSize(sunHalfSize);
pX = sunX;
pY = sunY;
}else if(App.GetInput().IsKeyDown(sf::Key::E)){
view.SetHalfSize(earthHalfSize);
pX = earthX;
pY = earthY;
}else if(App.GetInput().IsKeyDown(sf::Key::M)){
view.SetHalfSize(moonHalfSize);
pX = moonX;
pY = moonY;
}
}

App.Draw(sf::Shape::Circle(sunX - pX, sunY - pY, sunRadius, sf::Color(255.0, 0.0, 0.0)));
App.Draw(sf::Shape::Circle(earthX - pX, earthY - pY, earthRadius, sf::Color(0.0, 255.0, 0.0)));
App.Draw(sf::Shape::Circle(moonX - pX, moonY - pY, moonRadius, sf::Color(0.0, 0.0, 255.0)));
        App.Display();
    }

    return 0;
}

nulloid

  • Full Member
  • ***
  • Posts: 134
    • View Profile
Vanishing Circle Problem
« Reply #5 on: April 30, 2010, 03:51:57 pm »
Quote from: "scross"
In fact, is there any good reason for sf::View not using higher precision to translate the coordinates?


Uhhh.... speed?

scross

  • Newbie
  • *
  • Posts: 14
    • View Profile
Vanishing Circle Problem
« Reply #6 on: April 30, 2010, 04:00:30 pm »
On x86, which is the architecture most used (if you have an AMD or Intel processor, you're almost certainly on x86), all floating point operations are on an internal 80 bit value, which is larger than both single and double precision. So effectively both single precision (32 bits) and double precision (64 bits) numbers are converted to an 80 bit value, such that neither precision is faster than the other. Of course, if you're storing a large number of floating point values, doubles do have a space impact.

This is all summarised nicely here: http://stackoverflow.com/questions/417568/float-vs-double-performance

nulloid

  • Full Member
  • ***
  • Posts: 134
    • View Profile
Vanishing Circle Problem
« Reply #7 on: April 30, 2010, 04:41:21 pm »
Oh... I see. I didn't know that. Thanks :)
On the other hand, there is the last post:
Quote
There are still some cases where floats are prefered however - with OpenGL coding for example it's far more common to use the GLFloat datatype (generally mapped directly to 16 bit float) as it is more efficient on most GPU's than GLDouble

and some comments:
Quote
Maybe due to higher data throughput? If you have a matrix of numbers (z-buffer etc.), the data size becomes more important, and avoiding conversions between float and double speeds up handling. My guess. – Lucero Apr 16 '09 at 19:34

Quote
Undoubtedly throughput. Also given the specialised context there is unlikely anything visible to be gained from using doubles over floats so why waste the memory - especially as it is in shorter supply on GPUs than CPUs – Cruachan Apr 16 '09 at 20:59

I still think speed is a major factor. What do you say? (Just asking, not offending you ;))

scross

  • Newbie
  • *
  • Posts: 14
    • View Profile
Vanishing Circle Problem
« Reply #8 on: April 30, 2010, 04:45:51 pm »
Quote
I still think speed is a major factor. What do you say?


On the GPU, yes, single precision will be faster, but on the CPU there won't be a difference. What I'm suggesting is that SFML (on the CPU) should use double precision, even though the GPU may use single precision (hopefully future GPUs would have good support for higher precision). My point is that virtually nothing is lost by this approach, whereas it would help avoid problems like the one mentioned above.

scross

  • Newbie
  • *
  • Posts: 14
    • View Profile
Vanishing Circle Problem
« Reply #9 on: April 30, 2010, 04:49:43 pm »
As a side note, the value I was using for the moon is incorrect, and the moon is in fact 1.737E6 metres (i.e. 1000 * my previous value :) )

nulloid

  • Full Member
  • ***
  • Posts: 134
    • View Profile
Vanishing Circle Problem
« Reply #10 on: April 30, 2010, 04:57:23 pm »
Quote from: "scross"
What I'm suggesting is that SFML (on the CPU) should use double precision, even though the GPU may use single precision (hopefully future GPUs would have good support for higher precision). My point is that virtually nothing is lost by this approach, whereas it would help avoid problems like the one mentioned above.

And, if I understand it correctly, the amount of conversion between CPU and GPU is the same when using single-precision and double-precision?

scross

  • Newbie
  • *
  • Posts: 14
    • View Profile
Vanishing Circle Problem
« Reply #11 on: April 30, 2010, 05:05:16 pm »
Quote from: "nulloid"
Quote from: "scross"
What I'm suggesting is that SFML (on the CPU) should use double precision, even though the GPU may use single precision (hopefully future GPUs would have good support for higher precision). My point is that virtually nothing is lost by this approach, whereas it would help avoid problems like the one mentioned above.

And, if I understand it correctly, the amount of conversion between CPU and GPU is the same when using single-precision and double-precision?


You won't have to do any extra conversions and the conversion time from double to float will be negligible in most cases (every floating point operation involves two conversions to and from the internal format anyway, regardless of precision).

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Vanishing Circle Problem
« Reply #12 on: April 30, 2010, 07:54:13 pm »
OpenGL uses single precision, and it's not going to change. It would be useless to support double precision in SFML.
Laurent Gomila - SFML developer

scross

  • Newbie
  • *
  • Posts: 14
    • View Profile
Vanishing Circle Problem
« Reply #13 on: April 30, 2010, 08:13:35 pm »
Quote from: "Laurent"
OpenGL uses single precision, and it's not going to change. It would be useless to support double precision in SFML.


Yes, ok, OpenGL uses single precision and this won't change. However it is worth providing a double precision version of sf::View, since this would avoid introducing error when points are translated to the centre of the screen. Once  the shapes are translated and resized by the view, there is absolutely no need for double precision, but as you can see with my problem it is valuable up until that point.

Anyway, if you were to do this, it is obviously a very low priority thing :)
It's pretty easy to throw together a custom double precision view, which I am doing now.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Vanishing Circle Problem
« Reply #14 on: April 30, 2010, 08:31:31 pm »
What you don't seem to realize is that SFML doesn't do anything, views and transformations are (almost) entirely done on the GPU through OpenGL.

You can't write a true double precision view.
Laurent Gomila - SFML developer