DirectX C#.net Quaternion ArcBall累积旋转 [英] DirectX C# .net Quaternion ArcBall Cumulative rotation

查看:63
本文介绍了DirectX C#.net Quaternion ArcBall累积旋转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一直在玩3D示例并且难以让轮换累积起来。这个例子只是一个3D盒子。我试图通过四元数和鼠标点击添加ArcBall旋转。它适用于下一次单击时Box重置的例外情况。我不是DirectX专家,也不完全理解矩阵操作。我认为我需要做的是将旋转的矩阵设置为当前的世界矩阵,以便随后的矩阵操作变得累积。虽然我可能会离开?但如果是这样,我该怎么做?微软的在线文档相当模糊,这让我感到疯狂。希望有人可以帮助我。



这是Mouse Down事件

  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 ;
}



这是Mouse Move事件

  float  curX =(eX  -  HalfWidth)/ HalfWidth; 
float curY =(HalfHeight-e.Y)/ HalfHeight;


// 旋转鼠标右键拖动
LastWorldRotation = WorldRotation;
WorldRotation = ComputeRotation(MouseDownX,MouseDownY,curX,curY); // 我们计算新世界轮换





这是计算轮换功能



  public   static  Quaternion ComputeRotation( float  p1x, float  p1y, float  p2x, float  p2y)
{
Vector3轴; // 旋转轴
Vector3 p1;
Vector3 p2;
Vector3 d;
float phi; // 围绕轴旋转多少
浮动 t;

if ((p1x == p2x)&&(p1y == p2y))
{
// 零旋转
返回 new 四元数( 0 0 0 1 .0f);
}

//
// 首先,计算出P1和P2投影到球的z坐标
//
p1 = new Vector3(p1x ,p1y,p_ProjectToSphere(TRACKBALLSIZE,p1x,p1y));
p2 = new Vector3(p2x,p2y,p_ProjectToSphere(TRACKBALLSIZE,p2x,p2y));

//
// 现在,我们想要P1和P2的叉积
//
轴= Vector3.Cross(p1,p2);

//
// 计算绕该轴旋转多少。
//
d = p1 - p2;
t = d.Length()/( 2 .0f * TRACKBALLSIZE);

//
// 避免失控值出现问题......
//
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
{
// 内部球体
z =( float )System.Math.Sqrt(r * r - d * d);
}
其他
{
// < span class =code-comment>在双曲线上
t =( float )(r / 1 41421356237309504880 );
z = t * t / d;
}

return -z;
}





这是我的渲染功能



  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();

}

解决方案

我发现了问题。在玩弄它之后发生的事情是旋转计算是参考屏幕坐标。因此,它会导致任何后续选择重置矩阵。我想我需要做的是以某种方式引用矩阵而不是屏幕轴。从我读到的内容我可以创建一个Vector变换来引用矩阵位置。

 Vector4 transformedReference = Vector4.Transform(WorldViewVector4,world_matrix); 





然后我只需要使用Vector3.Unproject将我的屏幕坐标转换为世界空间。这样每次轮换都是连续的。

我还在试图弄清楚如何使用vector3.Unproject,但我相信我能搞清楚。

谢谢大家帮忙!不知道如果没有花时间在这个网站上发布我已经得到的所有帮助,我会做什么!干杯!!!!!!!


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

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

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

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

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();

       }

解决方案

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!!!!!!!


这篇关于DirectX C#.net Quaternion ArcBall累积旋转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆