0
\$\begingroup\$

I have a simple scrolling camera positioned 2000 units about the 3D 'floor' that moves forward by 1 unit every frame and looks down on the floor at a point that also moves forward by 1 unit every frame in the same direction.

I am then drawing a sphere where the mouse coordinate ray (unprojected from near plane to far plane) is intersecting the plane parallel to the floor plane but at height 2000 (the same plane that the camera position is). I am using this technique to acheive this:

http://msdn.microsoft.com/en-GB/library/bb203905(v=xnagamestudio.40).aspx

The intended behavior is for the camera to be looking down at a scrolling world and the sphere to exist on the 2000 height plane with its center where the mouse is pointed at.

This works fine for about 30 seconds, but then I notice that the sphere starts jittering forwards and backwards after a while, this increases with time. The scroll direction is only in the -z direction (forward) so it seems related to the growth in total scroll amount. I am thinking this might be a precision problem. I debugged the first three sphere location calculations and got these results:

z = -466.2891f
z = -465.2905f
z = -464.3159f

I then paused again when it started jittering and got these results:

z = 3848.743f
z = 3849.764f
z = 3850.956f

I am guessing the jittering starts as the Z number goes into the thousands and worsens as it goes into 10,000 e.t.c. The levels of the game won't extend past 10 minutes so my solution doesn't need to work past a certain Z value but the current solution doesn't work past 30 seconds.

I cannot change to double precision as I am using the XNA built in structs which all use floats. I also want to avoid scaling everything down as I don't want to rescale all the assets in the game. Is this another solution to this problem?

EDIT:

The game is fixed time step and I changed the code to make the scrolling every frame a constant amount.

I have done some further debugging and I noticed that if I do the following conversion:

screen coords -> world coords -> screen coords. All using XNA inbuilt methods. I see that the ranges of the delta between initial screen coords and output screen coords gets larger over time. This means to me that the drawing code is likely correct and it might be something to do with the conversion code or the camera itself. I have fixed the mouse cursor position to the middle of the screen and I have checked that the scrolling logic works correctly. It does a simple addition of z:-1 every frame.

The calculation of the viewMatrix:

I don't think this is the culprit but the code was as follows:

        lookingAt = scrollPosition;
        position = new Vector3(lookingAt.X, 
            lookingAt.Y + (float)Math.Cos(angle) * distance,
            lookingAt.Z + distance * (float)Math.Sin(angle));
        viewDirty = true;

        viewMatrix = Matrix.CreateLookAt(position, lookingAt,
            new Vector3(0.0f, 1.0f, 0.0f));
  • scrollPosition: the total scroll location e.g. x:0, y: 0, z: -240
  • angle: The angle that the camera is rotated around the x axis (set to 25 degrees). 0 degrees would be a straight down top-down view.
  • distance: The distance of the camera position from the scrollPosition. (set to 2500f)

The conversion of the screen coords (Mouse) to the world coords.

yPlane is set to 1000f (height of the sphere).

    private Vector3 convertScreenToWorldCoordinateFlat(Vector2 position, float yPlane)
    {
        Vector3 nearsource = new Vector3(position.X, position.Y, 0f);
        Vector3 farsource = new Vector3(position.X, position.Y, 1f);

        Vector3 nearPoint = Carriers.device.Viewport.Unproject(nearsource, CameraSystem.projectionMatrix, CameraSystem.viewMatrix, world);

        Vector3 farPoint = Carriers.device.Viewport.Unproject(farsource, CameraSystem.projectionMatrix, CameraSystem.viewMatrix, world);
        Vector3 direction = farPoint - nearPoint;
        direction.Normalize();
        Ray pickRay = new Ray(nearPoint, direction);
        float? maybe = pickRay.Intersects(new Plane(new Vector3(-1, yPlane, 0), new Vector3(1, yPlane, 0), new Vector3(0, yPlane, -1)));
        float f = maybe.HasValue ? maybe.Value : 0;
        return nearPoint + direction * f;
    }

This code was mostly copied from the MSDN tutorial except I am intersection with a plane at height 1000f.

\$\endgroup\$
2
  • \$\begingroup\$ Before thinking about scaling, go ahead and debug the issue deeper, the numbers you use are pretty normal, hard to say without seeing the code though, but the numbers look ok. I suspect a bug in your moving code or maybe the getting-the-current-time-code. In addition to your logging, also print out the elapsed time, the velocity, change in position etc. \$\endgroup\$ Commented Jun 16, 2013 at 15:40
  • \$\begingroup\$ edited to add further debugging findings. \$\endgroup\$
    – Jkh2
    Commented Jun 16, 2013 at 16:23

1 Answer 1

0
\$\begingroup\$

I solved this problem by making everything relative to the camera position. The camera view and projection matrices don't ever change. The scroll is added to the world transformation instead of the camera position/lookat. This means that since everything on the screen is relatively close to the origin (where the camera is looking). The precision of the float is kept high as the value of the float never goes into the 1000's meaning the precision of the fractional component is never below 3 numbers.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .