Search Unity

[SOLVED] Increasingly inaccurate results of ScreenPointToRay() as transform size increase (Choppy)

Discussion in 'Scripting' started by CarterG81, Mar 8, 2017.

  1. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,737
    ========
    SOLVED
    ========

    Near Clipping on Camera was set to 0.1
    Changing it to any other value (1, 10, 100) fixed this.

    Upon posting this problem, within minutes the solution came to me.
    Leaving this here for future reference.
    Thank you!​



    -------------------------
    I am using S̶c̶r̶e̶e̶n̶T̶o̶W̶o̶r̶l̶d̶P̶o̶i̶n̶t̶ ScreenToRayPoint to convert from the player's mouse cursor to world coordinates in a flat 3D world.

    Asking THIS QUESTION and I eventually found out (assumed) it seems to be a floating point limitation. However, this is a pretty big problem when it really shouldn't be: it begins to become inaccurate very quickly. Almost immediately actually: in the 3-4 digit transform range.

    ------------------------------------------------
    A Short Synopsis
    -------------------------------------------------

    • When the Player (Camera) is at Transform 0,0,0 all is well. Very accurate ScreenToWorldPoint().
      The slightest change in mouse position will result in a change in world position. #Winning
    • When far out, such as when the Player/Camera is at Transform.position.x = 30,000, it is completely unusable.
    Here is an example where the world position of the player/camera is at
    Vector3 (-30000, 0, 0)

    The Y (0) is perfectly smooth.​
    • However the X (-30,000) is very inaccurate.
      Moving the mouse doesn't even move the object, until it leaps in a big chunk.​
    • This problem begins to show up almost immediately though. Quick testing shows it to be very problematic at just -4000 position.​
    • However it seems much better at -3000 (which is also 4 digits) so I am wondering if I was wrong in assuming this is about floating point precision transforms? Although the math could just be complex enough that it begins to become inaccurate at higher numbers (but same digits).​
    I am raycasting to the terrain (flat ground; square colliders).

    Code (csharp):
    1. Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    2. RaycastHit hit;
    3. if (Physics.Raycast(ray, out hit, 10000, LayerMask.GetMask("Ground")))
    4. {
    5.     myCursorObject.transform.position = hit.point;
    6. }
    The object (green circle) is a 3D object located in 3D worldspace.



    The mouse cursor is obviously in 2D screenspace.
    The camera is perspective. Vector3 (0,3450,-1750) relative to the player; rotation (60); Near 0.1; Far 999999

    This forces me to keep the Player/Camera at 0,0,0 & move the world around them. (requiring a lot of extra work).

    I was hoping that I'm just missing something obvious, or could get help in creating a better method than ScreenPointToRay? The math involved isn't the easiest thing for me to understand.

    If I am correct in my understanding, then I am surprised this isn't a bigger problem (more readily found through googling). Hopefully though I am just doing something obviously wrong.​
     
    Last edited: Mar 8, 2017
  2. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,737
    I swore I had tried this using ScreenToWorldPoint() rather than ScreenPointToRay. I think I ran into the same problem. Corrected the title to reflect my code doesn't actually use ScreenToWorldPoint().

    Although I can't confirm it definitely, but I believe that even at -800 position I begin to see a very miniscule level of inaccuracy. It's only very close to 0,0,0 that it is incredibly accurate (no jittering).
     
  3. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,737
    While posting this problem, the solution began so obvious: Camera settings. Specifically, that Near/Far clipping.

    I changed the Near clipping and wallah! No more jittery results at large transform sizes.
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    6,702
    Single precision floating point, IEEE-754-1985 implementation:
    https://en.wikipedia.org/wiki/Single-precision_floating-point_format

    This float is defined as having:

    1 sign bit
    8 exponent bits (the 'floating' part)
    23 mantissa bits (or fraction)

    Basically we have the mantissa, which is the "sig value" portion of your number (from science/math class? It's the portion of your number without leading or trailing zeros... the sig value of 23,000,000,000 is 23, hence saying 23 billion). That is excluding the leading 1... because binary sig values ALWAYS have a leading 1 (the only non-zero symbol in binary), we can implicitly assume there is a leading 1... giving us actually 24 bits of sig value range stored in 23 bits.

    The exponent, or floating portion of the float, moves the decimal point over this mantissa to give us fractional values. Like scientific notation:
    23 * 10^9 = 23 billion
    The 9 is the exponent, the 23 is the mantissa.

    This sig value range is where your issue lies.

    24 bits of sig value sounds like a lot... but that's binary.

    24 bits binary really is only 2^24 = 8,388,608. So you only get 7 digits of precision, and really 7 digits isn't guaranteed since 9,123,456 can't be represented here. So REALLY you're only guaranteed 6 digits of precision.

    30,000 with some fractions on it... only offers you a measily 1 fracitonal digit (1/10) before you start hitting your sig-value ceiling.

    Now some relative maths can resolve this, fiddling with settings may resolve some localized issues. But be well aware, out here you're going to get all sorts of issues, and it's best to stay much closer to the origin. It all comes down to the fact that as you perform the maths lesser sig values fall off. If the math works out that those sig values round out (like a maths that does like 0.5 times an even number bringing it out of fractional territory 0.5 * 100 = 500... no data lossed, where as 0.125 * 373 = 46.625, if you're only allowed 3 sig values you lose data). So basically if your settings are complimentary out here, you will have fewer issues.
     
    Last edited: Mar 8, 2017
  5. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,737
    I'm well aware that I may eventually need to have the world revolve around the player (with some sort of streaming world system). However, I have fought back that beast, at least for this day!

    Although I cannot wait for the day when Unity expands their transform floating point limitations so this (and things like Kerbal Space Program) aren't even an issue we have to deal with anymore.

    I know very little about Camera Settings (Near Clipping) and so I don't at all understand why a setting of Near=0.1 would cause this problem the further out I go. Makes sense, given how I was casting rays from the camera to the ground.However any other value fixes it entirely... so as long as the problem is fixed, at least I don't have to worry about it (until later).

    Having to totally revamp how I load my large open world by having to refractor a lot of code & create a new streaming system was just too much for me at this point in development. I am trying to finish alpha, but felt like this (along with typical gamedev stuff) just puts me in perpetual alpha. So much work just trying to get a few systems in the game... ugh!

    While I understand floating point precision, your post flew way above my head with so much mathematical jargon. As odd as it is, I love programming but hate complex math. Not so much because I'm bad at it, but more along the lines that I haven't had any real math courses for about 15 years or so? So my ignorance / rustiness goes a long way to make it difficult for me to think through some of the math involved in gamedev.
     
  6. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,737
    I planned on writing a tutorial on how to create (and network) large open worlds, such as those we see in GTA/Skyrim/SurvivalGenre. So eventually I would need to tackle a streaming system of some kind.

    I think that once I get around to creating said tutorial for others, I will update my project to include the "Farnsworth" style of systems where the universe revolves around the player (in addition to the world being streamed in, only chunks at a time over the network).

    The only problem I have with this is that my simulation for NPC's uses Unity (ex. physics & AI) and thus I will have to implement even more systems to handle this stuff or separate my simulation entirely from Unity (...ugh...)

    The less work I have to do to get my game done, the better. So hopefully I can avoid this for as long as possible.
    It helps that my levels have gotten potentially smaller though. Originally they were small enough to remain within Unity's floating point limit (and used Y-axis stacking for multiple levels).

    potato chips.png

    It's actually through stacking like Jenga/Pringles that I am able to avoid having to stream in my large world in the first place. That's a lot less work for the game.

    So it's nice to know that I won't have to do this because of my ScreenToWorld conversion math. Maybe I can get away with not having to do it at all... At the very least, I can write a partial tutorial covering some of the systems, even if not all of them (such as using your own physics for the simulation, independent of Unity).
     
    lordofduct likes this.
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    6,702
    I feel ya on that.

    Having to explain to my artist that we just can't do certain things without massive amounts of work gets him like "yeah, but... I mean you've said why... but why not?"

    He often loves trying to push me to waste weeks of work on something to only have the results be exactly what I predicted and he finally like "ok...... I get it now."

    LOL!
     
    CarterG81 likes this.
  8. mountainstream

    mountainstream

    Joined:
    Apr 15, 2019
    Posts:
    98
    Thanks for this. You saved my bacon.
     
    CarterG81 likes this.
  9. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,737
    My pleasure!