触摸和去

Windows Phone 议案和 3D 视图

Charles Petzold

下载代码示例

Charles PetzoldWindows Phone 7.1 引入的新议案类是一个好的工具,对于程序员需要知道如何电话面向在三维的空间。运动类将信息从传感器 (加速度计、 磁强计和陀螺仪) 相结合和也来平滑数据并使其可方便的形式。

当 Windows Phone 程序了解的电话在 3D 空间中的定位时,电话可以进入一个 3D 世界提供一个门户网站。这项设施有应用程序映射、 虚拟现实、 增强的现实,当然,游戏,但可能还有些应用程序,有没有未受孕。这绝对是你要像你编码的技能一样行使你的想象力的领域。

运动数据

我想要只专注于获取电话,而不是速度或加速度,这也可从运动类的方向。传感器提供的 MotionReading 结构,和方向的信息是可用的态度属性中。"态度"一词来自飞行动力学,它指示在 3D 空间中的一架飞机的方向 — — 从海拔高度的不同,这是地球以上的高度。这个词有时也用于矢量几何。

这个态度属性是类型 AttitudeReading,另一种结构,用于定义描述三维方向的五个属性:

  • 偏航角的浮点类型,以弧度表示的角
  • 浮点类型,以弧度表示的角的音调
  • 辊的浮点类型,以弧度表示的角
  • 新华社中定义的类型矩阵,4 × 4 矩阵类型的 RotationMatrix
  • 四元数的类型四元数,新华社在定义的类型

偏航,音调和卷也飞行动力学中使用的术语和他们正在即通常所指的欧拉角。偏航指示罗盘方向平面的鼻子所面临的诸多,因此飞机转右或左,偏航更改。随着鼻子攀爬的间距更改或向下俯冲。左和右平面银行作为卷的更改。直观显示这些公约电话,它有助于想像到你前面电话和到你后面的三个标准按钮的顶部的"飞天"你像魔毯在手机上坐上这款手机的屏幕。

一个叫做 YawPitchRoll 包含在可下载的代码,这篇文章的小程序可能也有助于直观显示这些角度。(像这篇文章中的所有程序,它需要向 Microsoft.Devices.Sensors 和 Microsoft.Xna.Framework 的程序集的引用。)如中所示图 1,该程序显示的值转换为度,这三个角度,它还象征着它们的值以图形方式。


图 1 YawPitchRoll 显示

指向北像一个指南针,简单线条显示偏航而沥青和卷都显示为似乎滚向地球的固体球。当电话坐在了屏幕和手机指向北方的顶部水平表上时,所有三个角度有零值。

如你向上和向下倾斜手机的顶部,您可以从 90 ° 更改间距,当手机-90 ° 到直立时手机的顶部向下指。同样,您可以更改卷从 90 °-90 ° 到倒腾的左、 右的电话。

当电话显示朝下,南偏航角点。摊位就值范围从 90 ° 到 180 °,和到-180 °-90 °。在 YawPitchRoll 程序中,这些值是空心的红色-概述的球的象征。值的卷继续采取从 90 度到-90 ° 的值。

旋转角度

虽然我们花费我们整个的生活在一个三维的宇宙,我们很多人掌握很穷直观的三维旋转。因此,直观显示和使用在 3D 空间中旋转,颇具挑战性。偏航,摊位和辊似乎充分说明您在 3D 空间中旋转,但他们变成尴尬实际编程中。

程序员更喜欢使用替代的方式来描述 3D 旋转:

  • 一个单一的角度描述围绕 3D 矢量 (轴/角度旋转) 旋转
  • 旋转矩阵 (全 3D 矩阵变换的子集)
  • 四元数,复杂平面的 2D 旋转 3D 模拟

这些窗体可全部之间转换对方,因为我演示中的章节 7 及 8 条"3D 编程 Windows 的"我的书 (微软出版社,2008年)。四元数是从一个方向顺利迁移到另一种特别有用,因为它适合线性插值。

运动类提供 3D 旋转旋转矩阵和四元数,但我会只专注的 AttitudeReading 结构的 RotationMatrix 属性。这是新华社矩阵值,这是一个标准的 4 × 4 变换矩阵,但该矩阵表示只旋转。它具有无缩放和没有翻译。M14、 较老的 M24、 M34、 M41、 M42 和 M43 字段是所有 0,且 M44 字段为 1。

当使用此旋转矩阵,角度的改变将非常有用。此列中的前一部分中,描述如何从加速度计和指南针传感器可用的三维向量是相对于 3D 坐标系强加于地理的电话。不过,在处理时的旋转矩阵,您真的需要直观显示两个不同 3D 坐标系,另一个用于手机和其他地球:

  • 这款手机的 3D 的坐标系统中积极 Y 指向顶部的 (在纵向模式),电话 X 点右和积极正面 Z 出来屏幕。
  • 在地球的三维坐标系统中,积极 Y 点往北,积极 X 点东和来自于大地的正 Z。

当电话坐在了屏幕的水平表面上和北指向顶部,RotationMatrix 的值是恒等矩阵。否则,它描述了地球旋转与手机中,是相反的方式描述的欧拉角的旋转。

要说明这点,我写了一个叫做 MotionMatrix 的小程序。显示 (显示在图 2) 仅包含数字值:横倾、 沥青和卷值,全矩阵和旋转的轴/角形式表示的 3 × 3 旋转矩阵子集。

The MotionMatrix Display
图 2 MotionMatrix 显示

当你第一次开始玩这个程序时,你立即的直觉可能是电话的方向,使所有欧拉角均为零。不过,倒在底部的轴矢量都疯掉了,因为几乎没有旋转,因此轴值可以为几乎任何东西。简单的轮换平静显示。中的截图图 2 显示顶部的手机指向北方,但升高约 45 °。这是的螺距值的报告,以及轴/角度旋转显示 46 ° 非常密切值。

但请注意,旋转轴:它大约是 (– 1,0,0),这是座标轴指向左边的电话。新华社轴/角度旋转遵守右侧的规则:中轴的方向指向你的右手的拇指 (这是,左边的电话在这种情况下)。曲线的你的手指然后显示正旋转的方向。这意味着旋转对面俯仰角度。它告诉我们电话必须是旋转-45 °,地球的对齐。

MotionMatrix 和新华社

它似乎合理的利用从运动类的旋转矩阵用于查看 3D 对象的电话。但不正常的做法是 — — 凡 3D 对象的旋转与显示,或许用鼠标或手指 — — 这里会相对于 3D 对象旋转了显示屏 (从概念上讲,反正)。

这个实验,我从 archive3d 下载古董电话的 3D 模型。净的 Web 站点 (特别是 bit.ly/GSNTi3),然后转换为使用转换器工具从欧特克的新华社友好 FBX 格式的 3DS 格式。创建显示逐步更好的方法显示此对象的四个 Visual Studio 项目。(其实,我就很有点说错和后来才创建这些四个项目,以掩盖这一事实 !)为了减少您的源代码下载时间,所有四个项目引用相同的 3D 模型文件。

四个项目的第一个被称为 View3DPhonePlain,这是刚才的静态视图的对象 ; 图 3 显示相关的代码。此程序将加载在模型中,定义了一个世界转换,缩放的模型下很多,并且定义了一个简单的相机。(显然多余的字段变量指定将使感不久。)

图 3 View3DPhonePlain 程序

public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    Model model;
    Matrix scaleMatrix, worldMatrix, lookatMatrix,
           viewMatrix, projectionMatrix;
    ...
protected override void LoadContent()
    {
        model = this.Content.Load<Model>(“Phone Retro Caesar N170910”);
        foreach (ModelMesh mesh in model.Meshes)
            foreach (BasicEffect effect in mesh.Effects)
                effect.EnableDefaultLighting();
        // World matrix
        scaleMatrix = Matrix.CreateScale(0.0001f);
        worldMatrix = scaleMatrix;
        // View matrix
        lookatMatrix = Matrix.CreateLookAt(new Vector3(0, 0, 10f),
                                                       Vector3.Zero,
                                                       Vector3.Up);
        viewMatrix = lookatMatrix;
        // Projection matrix
        float aspectRatio = 
            graphics.GraphicsDevice.Viewport.AspectRatio;
        projectionMatrix =
            Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4,
                                                aspectRatio,
                                                1f, 100.0f);
    }
    ...
protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        model.Draw(worldMatrix, viewMatrix, projectionMatrix);
        base.Draw(gameTime);
    }
}

在 3D 图形系统中像新华社,模型受到一系列的矩阵转换到显示的路上。 世界变换应用第一,而且这江镇在 3D 空间中的模型。 相机是应用于连续两次转换的组合:该视图转换帐户的位置和方向的相机,而投影变换处理透视效果,还会将剪辑的所有坐标都标准化。

图 4 模型在新华社的外观的显示默认景观模式,和它很多我们或许可以预期。

The View3DPhonePlain Display
图 4 View3DPhonePlain 显示

下一步是名为 View3DPhoneReoriented 的项目。 我想要切换到纵向模式,以便在新华社内使用的三维坐标都相同,使用的传感器的三维坐标系统。 这是一个简单的问题,将几个语句添加到游戏衍生的构造函数:

graphics.IsFullScreen = true;
   graphics.PreferredBackBufferWidth = 480;
   graphics.PreferredBackBufferHeight = 800;

我也想要重新定位在手机本身。 如前所述,运动类所提供的 3D 旋转矩阵是恒等矩阵时电话正坐在了屏幕的表和北指向顶部。 3D 电话要显示在该位置有电话时并未想怎样? 我想要找电话的顶部,如果从上面看所以我只是添加的世界变换绕 X 轴旋转:

worldMatrix *= Matrix.CreateRotationX(MathHelper.PiOver2);

结果将显示在图 5

The View3DPhone­Reoriented Display
图 5 View3DPhone­调整显示的方向

相机看起来有点太接近该对象在这一点上,但这并没有打扰我,因为我知道当我成立为法团的旋转矩阵,我会能够旋转的电话要在视图中得到这一切一点。 (3D 光线和阴影的敏锐查看器可能会注意到的方法,我使用的,但让我天真 traipse 沿着这条路第一概念存在缺陷,然后我要修理东西。

现在让我们把从运动类的旋转矩阵。

从概念上讲,3D 对象应似乎仍停留在空间中,固定和移动电话应允许您查看对象从不同的方向。 当然,经验不像"现实生活"因为你永远不能移动电话要看对象。 对象始终是有研究显示,但在 3D 空间中显示的方向为您提供了不同的意见,它。

要实现此效果,我们需要适用对象实现地球的坐标系统中,此对象的概念上存在从手机的坐标系旋转矩阵。

我们应该能够达到这种效果只需通过在世界变换的计算中包括从运动类的 RotationMatrix 对象。 View3DPhoneWorldMotion 项目执行此操作。 它包括在其构造函数中创建运动传感器、 启动它在 OnActivated 重写并停止它在 OnDeactivated 重写的代码。 我然后移动计算的世界变换到更新改写,如中所示图 6

图 6 中 View3DPhoneWorldMotion 的更新替代

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == 
      ButtonState.Pressed)
        this.Exit();
    worldMatrix = scaleMatrix * 
      Matrix.CreateRotationX(MathHelper.PiOver2);
    if (motion != null && motion.IsDataValid)
        worldMatrix *= motion.CurrentValue.Attitude.RotationMatrix;
    base.Update(gameTime);
}

在此程序中,当您在 3D 空间中移动手机的定位您查看 3D 对象从所有不同的方向。 其效果是非常顺利和 — — 我必须承认 — — 非常酷。

移旋转

然而,越多我演奏了与此版本的程序,就越觉得出事了。

通过对世界变换应用的旋转矩阵,3D 对象有效地旋转与相机,不仅与光源。 在某些情况下,这将是正确的。 例如,如果要实现一个触摸界面,所以你可以转身的 3D 图像用你的手指,在世界变换应用旋转矩阵将适当。

但对此程序范例很大的不同。 我想要电话显示要像,相对于 3D 对象,将移动,这意味着此对象应保持固定与光源的移动相机。 从运动传感器的旋转矩阵需要应用于视图转换,而不是世界变换。

最后版本的程序 — — 称为 View3DPhone­CameraMotion — — 回复原始版本的世界变换的计算:

worldMatrix = scaleMatrix;

即使应用初始旋转是个错误,因为它暗示光即将从电话中,而不从上面。 新的更新方法所示图 7

图 7 中 View3DPhoneCameraMotion 的更新替代

protected override void Update(GameTime gameTime)
{
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == 
      ButtonState.Pressed)
        this.Exit();
    if (motion != null && motion.IsDataValid)
        viewMatrix = Matrix.CreateRotationX(MathHelper.PiOver2) *
                        motion.CurrentValue.Attitude.RotationMatrix *
                        lookatMatrix;
    else
        viewMatrix = Matrix.CreateRotationX(MathHelper.PiOver2) *
                        lookatMatrix;
    base.Update(gameTime);
}

你真的需要试用此程序在电话中得到充分的效果,但中的图像图 8 显示了一个可能的视图。

One View in View3DPhoneCameraMotion
图 8 个视图中 View3DPhoneCameraMotion

Charles Petzold 是 MSDN 杂志长期贡献和 Windows 8 的当前正在更新他的经典著作"编程 Windows"(微软出版社,1998年)。 他的网站是 charlespetzold.com

由于下面的技术专家,检讨这篇文章: Donn Morse