Click here to Skip to main content
15,891,933 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Been playing around with a 3D example and having trouble getting the rotation to be cumulative. The example is just a 3D box. I am trying to add ArcBall rotation to it via a quaternion and mouse click points. It works well with the exception of the Box resetting on the next click. I am no DirectX expert and do not fully understand matrix manipulation. I think what I need to do is set the rotated matrix as the current world matrix so that the succeeding matrix manipulation will become cumulative. Although I may be way off? But if so how do I do this? The Microsoft on line docs are pretty vague and it is kind of driving me nuts. Hopefully someone can help me out.

This is the Mouse Down event
C#
if (e.Button == MouseButtons.Left)
{

    HalfWidth = this.ClientRectangle.Width / 2.0f;
    HalfHeight = this.ClientRectangle.Height / 2.0f;

    MouseDownX = (e.X - HalfWidth) / HalfWidth;
    MouseDownY = (HalfHeight - e.Y) / HalfHeight;

    mouseroll = true;
}

This is the Mouse Move event
C#
float curX = (e.X - HalfWidth) / HalfWidth;
float curY = (HalfHeight - e.Y) / HalfHeight;


// Rotate on Right Mouse Button Drag
LastWorldRotation = WorldRotation;
WorldRotation = ComputeRotation(MouseDownX, MouseDownY, curX, curY); // We Compute the New World Rotation


This is the Compute rotation function

C#
public static Quaternion ComputeRotation(float p1x, float p1y, float p2x, float p2y)
     {
         Vector3 axis;  // axis of rotation
         Vector3 p1;
         Vector3 p2;
         Vector3 d;
         float phi;     // how much to rotate about the axis
         float t;

         if ((p1x == p2x) && (p1y == p2y))
         {
             // Zero rotation
             return new Quaternion(0, 0, 0, 1.0f);
         }

         //
         // First, figure out z-coordinates for projection of P1 and P2 to ball
         //
         p1 = new Vector3(p1x, p1y, p_ProjectToSphere(TRACKBALLSIZE, p1x, p1y));
         p2 = new Vector3(p2x, p2y, p_ProjectToSphere(TRACKBALLSIZE, p2x, p2y));

         //
         // Now, we want the cross product of P1 and P2
         //
         axis = Vector3.Cross(p1, p2);

         //
         // Figure out how much to rotate around that axis.
         //
         d = p1 - p2;
         t = d.Length() / (2.0f * TRACKBALLSIZE);

         //
         // Avoid problems with out-of-control values...
         //
         if (t > 1.0f) t = 1.0f;
         if (t < -1.0f) t = -1.0f;
         phi = 2.0f * (float)System.Math.Asin(t);


         return Quaternion.RotationAxis(axis, phi);
     }

     private static float p_ProjectToSphere(float r, float x, float y)
     {
         float d, t, z;

         d = (float)System.Math.Sqrt(x * x + y * y);

         if (d < r * 0.70710678118654752440)
         {
             // Inside sphere
             z = (float)System.Math.Sqrt(r * r - d * d);
         }
         else
         {
             // On hyperbola
             t = (float)(r / 1.41421356237309504880);
             z = t * t / d;
         }

         return -z;
     }


And this is my Render function

C#
private void Render()
       {
           d3dDevice.Clear(ClearFlags.Target | ClearFlags.ZBuffer,
                            Color.White, 1.0f, 0);


           d3dDevice.BeginScene();

           rotation_matrix = Matrix.RotationQuaternion(WorldRotation);

           world_matrix = Matrix.Identity;

           translation_matrix = Matrix.Translation(0.0f, 0.0f, 5.0f);

           world_matrix = rotation_matrix * translation_matrix;


           d3dDevice.SetTransform(TransformType.World, world_matrix);
           d3dDevice.SetTransform(TransformType.View, world_matrix);
           d3dDevice.SetTransform(TransformType.Projection, world_matrix);

    //       d3dDevice.Transform.World = world_matrix
           d3dDevice.Transform.World = Matrix.Identity;

           d3dDevice.Transform.Projection = Matrix.PerspectiveFovLH(Geometry.DegreeToRadian(45.0f), (float)this.ClientSize.Width / this.ClientSize.Height, 0.1f, 100.0f);

           d3dDevice.VertexFormat = Vertex.FVF_Flags;
           d3dDevice.SetStreamSource(0, vertexBuffer, 0);

           d3dDevice.SetTexture(0, texture);

           d3dDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
           d3dDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 4, 2);
           d3dDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 8, 2);
           d3dDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 12, 2);
           d3dDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 16, 2);
           d3dDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 20, 2);

           d3dDevice.EndScene();

           d3dDevice.Present();

       }
Posted

1 solution

I found the problem. After playing around with it what happens is the rotation calculation is referencing the screen coordinates. Because of this it causes any subsequent selections to reset the matrix. I guess what I need to do is somehow reference the matrix instead of the screen axis. From what I have read about it I can just create a Vector transform to reference the matrix position.
Vector4 transformedReference = Vector4.Transform(WorldViewVector4, world_matrix);


Then I just need to convert my screen coordinates to world space using Vector3.Unproject. This way each rotation will be successive.
I am still trying to figure out how to use vector3.Unproject but I am sure I can figure it out.
Thanks for all the help! Not sure what I would have done without taking the time to post on this on this site with all the help I have gotten! Cheers!!!!!!!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900