3D Globe Rotation Issues

I am trying to make my 3D sphere rotate when the user moves the mouse / finger across the sphere.

I can make it spin without problems, but when I try to add inertia to the sphere using the Affine2DInertiaProcessor in the Surface SDK, I get jumping problems when I quickly scan the sphere, and I don't know why ...

Here is my initialization code:

    private void InitializeManipulationProcessor()
    {
        manipulationProcessor = new Affine2DManipulationProcessor(
            Affine2DManipulations.Rotate | 
            Affine2DManipulations.TranslateX | 
            Affine2DManipulations.TranslateY,
            _eventSource);


        inertiaProcessor = new Affine2DInertiaProcessor();
        inertiaProcessor.Affine2DInertiaDelta += Inertia_OnManipulationDelta;
        inertiaProcessor.Affine2DInertiaCompleted += InertiaProcessor_Affine2DInertiaCompleted;

        manipulationProcessor.Affine2DManipulationStarted += OnManipulationStarted;
        manipulationProcessor.Affine2DManipulationDelta += Manipulation_OnManipulationDelta;
        manipulationProcessor.Affine2DManipulationCompleted += OnManipulationCompleted;
}

When the user moves his finger, here is the code to rotate the sphere:

private void Manipulation_OnManipulationDelta(object sender, Affine2DOperationDeltaEventArgs e)
    {
        Point currentPosition = e.ManipulationOrigin;
        // avoid any zero axis conditions
        if (currentPosition == _previousPosition2D)
            return;

        Track(currentPosition);

        _previousPosition2D = currentPosition;
    }

This will start ineria when the user stops moving his finger:

private void OnManipulationCompleted(object sender, Affine2DOperationCompletedEventArgs e)
{
    inertiaProcessor.InitialOrigin = e.ManipulationOrigin;
    inertiaProcessor.InitialVelocity = e.Velocity;
    inertiaProcessor.DesiredDeceleration = 0.0001;
    inertiaProcessor.Begin();
}

The rotation magic occurs in the Track method below:

    private void Track(Point currentPosition)
    {
        Vector3D currentPosition3D = ProjectToTrackball(currentPosition);

        Vector3D axis = Vector3D.CrossProduct(_previousPosition3D, currentPosition3D);
        double angle = Vector3D.AngleBetween(_previousPosition3D, currentPosition3D);

        // quaterion will throw if this happens - sometimes we can get 3D positions that
        // are very similar, so we avoid the throw by doing this check and just ignoring
        // the event 
        if (axis.Length == 0)
            return;

        Quaternion delta = new Quaternion(axis, -angle);

        // Get the current orientantion from the RotateTransform3D
        Quaternion q = new Quaternion(_rotation.Axis, _rotation.Angle);

        // Compose the delta with the previous orientation
        q *= delta;

        // Write the new orientation back to the Rotation3D
        _rotation.Axis = q.Axis;
        _rotation.Angle = q.Angle;

        _previousPosition3D = currentPosition3D;
    }

_rotation var - the AxisAngleRotation3D class used for RotateTransform3D in a 3d mesh.

, , , , , .

, , , , , , ! ...

3D- , , ZIP- ,

, , !

+3
2

, , , , - .

-, ProjectToTrackball? , , ( ) , ? , , 2D- ? ? , , 2D ?

Track. , , 3D-, 3 ( ). . , . , .

, "-angle", "angle" -, , , , ;)

EDIT: .rar.

, ProjectToTrackball ( SurfaceTrackballDecorator.cs), , .

, ( , , ), . , , , .

, , , 2 , 3D, ( ).

, 2D- 3D- . , 2D .

, , 2D- ( ), . 2D- (z = 0).

, , " ":)

, , - 3D, , .

. , .

EDIT: :)

?

private Vector3D ProjectToTrackball(Point point)
{
  double x = point.X / (ActualWidth / 2);    // Scale so bounds map to [0,0] - [2,2]
  double y = point.Y / (ActualHeight / 2);

  x = x - 1;                           // Translate 0,0 to the center
  y = 1 - y;                           // Flip so +Y is up instead of down
  double alpha = 1.0 / Math.Sqrt(x*x + y*y + 1);
  return new Vector3D(x*alpha, y*alpha, alpha);
}

, ( , ), ...

, ...

EDIT: :

  private Vector3D ProjectToTrackball(Point point)

  {
    // IMPORTANT NOTE: result should always be normalized

    double x = point.X / (ActualWidth / 2);    // Scale so bounds map to [0,0] - [2,2]

    double y = point.Y / (ActualHeight / 2);



    x = x - 1;                           // Translate 0,0 to the center

    y = 1 - y;                           // Flip so +Y is up instead of down



    double z2 = 1 - x * x - y * y;       // z^2 = 1 - x^2 - y^2
    double z =  0;

    if(z2 > 0)
      z2 = Math.Sqrt(z2); // Ok no need to normalize.
    else
    {
      // I will get rid of the discontinuity with a little trick:
      // I construct an imaginary point below the sphere.
      double length = Math.Sqrt(x * x + y * y);
      x = x / length;
      y = y / length;
      z = 1 - length;
      // Now I normalize:
      length = Math.Sqrt(x * x + y * y + z * z);
      x = x / length;
      y = y / length;
      z = z / length;
    }

    return new Vector3D(x, y, z);

  }

, , , . . .

: , , , 2D- , ProjectToTrackball NON- . , .

: OpenGL 3D.

EDIT 11/18/2009:

, , , " Z".

_ . , _rotation, .

Track:

private void Track(Point currentPosition)
{
    Vector3D currentPosition3D = ProjectToTrackball(currentPosition);

    Vector3D axis = Vector3D.CrossProduct(_previousPosition3D, currentPosition3D);
    double angle = Vector3D.AngleBetween(_previousPosition3D, currentPosition3D);

    // quaterion will throw if this happens - sometimes we can get 3D positions that
    // are very similar, so we avoid the throw by doing this check and just ignoring
    // the event 
    if (axis.Length == 0)
        return;

    Quaternion delta = new Quaternion(axis, -angle);

    // Compose the delta with the previous orientation
    _rotation *= delta;

    _previousPosition3D = currentPosition3D;
}

... - .

+1

, , , , ManipulationOrigin Manipulation_OnManipulationDelta OnManipulationCompleted?

, , , , "" , .

0

Source: https://habr.com/ru/post/1721757/


All Articles