Поиск на сайте: Расширенный поиск


Новые программы oszone.net Читать ленту новостей RSS
Программа для автоматической смены обоев на рабочем столе компьютера. BioniX Wallpaper предоставляет пользователю возмож...
Программа для запуска на одном компьютере нескольких виртуальных операционных систем. VirtualBox - это удобный и функцио...
AutoHotkey - программа позволяет создавать горячие клавиши. А также переназначить команды, которые вводятся с клавиатуры...
CheMax - очень большая база данных с кодами для игр. База CheMax является прямой наследницей базы программы ChEaTs, кото...
iCash – это программа, которая позволяет вам отслеживать все ваши доходы, расходы, кредиты, долги, а также банковские оп...
OSzone.net Microsoft Разработка приложений Windows Phone Класс Motion в Windows Phone и трехмерные представления RSS

Класс Motion в Windows Phone и трехмерные представления

Текущий рейтинг: 5 (проголосовало 1)
 Посетителей: 590 | Просмотров: 682 (сегодня 0)  Шрифт: - +

Новый класс Motion, введенный в Windows Phone 7.1, — прекрасный инструмент для программистов, которым нужно знать, как смартфон ориентирован в трехмерном пространстве. Класс Motion комбинирует информацию от датчиков (акселерометра, магнитометра и гироскопа), а также сглаживает эти данные и делает их доступными в удобных формах.

Когда программе Windows Phone известна ориентация смартфона в трехмерном пространстве, смартфон может предоставить ей портал в трехмерный мир. Эта возможность широко используется в поддержке карт, виртуальной и дополненной реальности, а также, разумеется, игр, но вполне вероятно, что некоторые области применения пока просто не придуманы. Это явно та сфера, где стоит прилагать не только навыки в кодировании, но и воображение.

Данные Motion

Я хочу сосредоточиться исключительно на получении информации об ориентации смартфона, а не на скорости перемещения или ускорении, данные о которых тоже доступны от класса Motion. Датчик предоставляет структуру MotionReading, и информация об ориентации хранится в свойстве Attitude. Слово «attitude» (пространственное положение, или угол тангажа) взято из механики полетов, где это значение указывает ориентацию самолета в трехмерном пространстве; оно отличается от высоты полета (altitude), которая определяет абсолютную высоту над уровнем моря. Этот термин также иногда применяется в векторной геометрии.

Свойство Attitude имеет тип AttitudeReading — это другая структура, которая определяет пять свойств, описывающих ориентацию в трехмерном пространстве:

  • Yaw типа float (угол в радианах);
  • Pitch типа float (угол в радианах);
  • Roll типа float (угол в радианах);
  • RotationMatrix типа Matrix (тип матрицы 4 × 4, определенный в XNA);
  • Quaternion типа Quaternion (тип, определенный в XNA).

Yaw, Pitch и Roll тоже являются терминами в механике полетов, и их часто называют углами Эйлера. Yaw указывает направление по компасу, в котором смотрим нос самолета, поэтому, когда самолет поворачивает вправо или влево, отклонение от горизонтальной оси, или рысканье (yaw), меняется. Pitch изменяется, когда нос самолета задирается вверх при подъеме или опускается вниз при снижении. Roll изменяется, когда самолет накреняется влево (banks left) и вправо. Чтобы визуализировать эти значения относительно смартфона, полезно представить «полет» на смартфоне как на волшебном ковре-самолете, где вы сидите на экране смартфона, его верхняя часть смотрит вперед, а три стандартные кнопки находятся сзади от вас.

Небольшая программа YawPitchRoll, включенная в пакет для скачивания к этой статье, поможет в визуализации этих углов. (Как и все программы в этой статье, она требует ссылок на сборки Microsoft.Devices.Sensors и Microsoft.Xna.Framework.) Как показано на рис. 1, эта программа отображает значения этих трех углов, преобразованных в градусы, и обозначает эти значения в символьном виде.

*
Рис. 1. Экран YawPitchRoll

Yaw отображается простой линией, указывающей на север подобно компасу, тогда как Pitch и Roll визуализируются закрашенными шариками, которые словно катятся к земле. Когда смартфон лежит на ровном столе с экраном вверх, а его верхняя часть смотрит на север, все три угла имеют нулевые значения.

Наклоняя верхнюю часть смартфона вверх и вниз, вы можете менять Pitch от 90° (верхняя часть смотрит прямо вверх) до –90° (верхняя часть указывает строго вниз). Аналогично можно менять Roll от 90° до –90°, поворачивая смартфон вправо и влево.

Когда экран смартфона смотрит вниз, угол Yaw указывает на юг. Pitch принимает значения от 90° до 180° и от –90° до –180°. В программе YawPitchRoll эти значения обозначены символы полого шарика с красными границами. Значения Roll по прежнему варьируются в диапазоне от 90° до –90°.

Вращение в трехмерном пространстве

Хотя мы живем в трехмерной вселенной, многие из нас очень плохо представляют вращение в трехмерном пространстве. Соответственно визуализация и операции вращения в трехмерном пространстве могут оказаться весьма затруднительными. Yaw, Pitch и Roll адекватно описывают вращение в таком пространстве, но оказываются довольно неудобными в программировании на практике.

Программисты гораздо больше предпочитают работать с альтернативными способами описания трехмерных вращений:

  • единственным углом, описывающим вращение вокруг трехмерного вектора (вращение оси/угла);
  • матрицей вращения (подмножество полного преобразования трехмерной матрицы);
  • кватернионом — трехмерным аналогом двухмерного вращения в плоскости комплексной переменной (complex plane).

Эти формы можно взаимно преобразовывать, как я демонстрировал в главах 7 и 8 моей книги «3D Programming for Windows» (Microsoft Press, 2008). Кватернион особенно удобен для плавного перемещения из одной ориентации в другую, так как он пригоден для линейной интерполяции.

Класс Motion поддерживает трехмерное вращение с помощью матрицы вращения и кватерниона, но я сосредоточусь исключительно на свойстве RotationMatrix структуры AttitudeReading. Это значение XNA Matrix, которая является стандартной матрицей преобразования 4 × 4, но представляет только вращение. В ней нет масштабирования и трансляции. Поля M14, M24, M34, M41, M42 и M43 — все равны 0, а поле M44 равно 1.

При работе с этой матрицей вращения будет полезно изменение в перспективе. В предыдущей статье из этой рубрики я описал, каким образом трехмерный вектор, доступный от классов датчиков Accelerometer и Compass, является относительным системе трехмерных координат и налагается на географическое положение смартфона. Однако, работая с матрицей вращения, вам на самом деле нужно визуализировать две разные системы трехмерных координат: одну — для смартфона, а другую — для Земли:

  • в системе трехмерных координат смартфона положительная ось Y указывает в его верхнюю часть (в портретном режиме), положительная ось X — вправо, а положительная ось Z исходит из экрана;
  • в системе трехмерных координат Земли положительная ось Y указывает на север, положительная ось X — на восток, а положительная ось Z исходит из земли.

Когда смартфон находится на ровной поверхности с экраном вверх и его верхняя часть указывает на север, значение RotationMatrix равно матрице тождественности, или единичной матрице (identity matrix). В ином случае оно описывает, как Земля поворачивается относительно смартфона, что противоположно поворачиванию, описываемому углами Эйлера.

Чтобы проиллюстрировать это, я написал небольшую программу MotionMatrix. Ее экран (рис. 2) отображает только числовые значения: Yaw, Pitch и Roll, матрицу вращения 3 × 3 (подмножество полной матрицы) и поворот, выраженный в виде значений по осям и угла.

*
Рис. 2. Экран MotionMatrix

Когда вы впервые начинаете экспериментировать с этой программой, тут же возникает инстинктивное желание сориентировать смартфон так, что все углы Эйлера были нулевыми. Однако вектор осей внизу начинает сходить с ума, потому что вращения почти нет, а значит, значение оси может быть практически любым. Простые вращательные движения успокаивают смартфон. На экранном снимке на рис. 2 верхняя часть смартфона указывает на север, но задрана вверх под углом около 45°. Именно об этом и сообщает значение Pitch, а матрица вращения показывает очень близкое значение — 46°.

Но обратите внимание на ось вращения: она примерно (–1, 0, 0), что является осью координат, которая указывает влево от смартфона. Матрицы вращения XNA следуют правилу правой руки: указывайте большим пальцем правой руки в направлении оси (т. е. в данном случае — влево от смартфона). Тогда кривая, описываемая вашими пальцами, будет показывает направление положительного вращения. То есть поворот противоположен углу Pitch. Это говорит нам о том, что смартфон нужно повернуть на –45°, чтобы выровнять его относительно Земли.

MotionMatrix и XNA

Для просмотра трехмерных объектов (далее 3D-объектов) на смартфоне вроде бы логично использовать матрицу вращения от класса Motion. Но вместо обычного подхода (где 3D-объект вращается относительно дисплея, возможно, мышью или пальцем) здесь будет вращаться дисплей относительно 3D-объекта (концептуально, разумеется).

Для экспериментов я скачал с веб-сайта archive3d.net трехмерную модель антикварного телефона (ссылка на саму модель: bit.ly/GSNTi3), а затем преобразовал формат 3DS в FBX, понятный XNA, с помощью конвертера от Autodesk. Я создал четыре проекта Visual Studio, которые по порядку отражают все более эффективные способы визуализации этого объекта. (На самом деле я довольно долго барахтался во мраке и лишь потом создал эти четыре проекта, чтобы завуалировать этот факт!) Чтобы не перегружать пакет для скачивания, все четыре проекта ссылаются на один и тот же файл с трехмерной моделью.

Первый из четырех проектов называется 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();
        // Матрица мировых координат
        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);
    }
}

В трехмерной графической системе наподобие XNA модели подвергаются сериям матричных преобразований на пути к экрану. Первым применяется преобразование мировых координат, и это приводи к размещению модели в трехмерном пространстве. Камера является комбинацией двух преобразований, применяемых последовательно: преобразование вида камеры (view transform) отвечает за расположение и ориентацию камеры, тогда как преобразование проекции (projection transform) обрабатывает эффекты перспективы и нормализует все координаты для отсечения.

На рис. 4 показано, как выглядит модель в альбомном режиме XNA по умолчанию, и это весьма близко к тому, что мы могли бы ожидать.

*
Рис. 4. Экран View3DPhonePlain

Следующий шаг — проект View3DPhoneReoriented. Я хотел переключиться в портретный режим, чтобы трехмерные координаты, используемые в XNA, соответствовали системе трехмерных координат, применяемой датчиками. Для этого достаточно добавить несколько выражений в конструктор объекта, производного от Game:

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

Мне также нужно было переориентировать сам смартфон. Как я уже упоминал, матрица вращения в трехмерном пространстве, предоставляемая классом Motion, является матрицей тождественности (identity matrix), когда смартфон находится на столе экраном вверх, а его верхняя часть указывает на север. Как должен выглядеть трехмерный телефон, когда смартфон находится в таком положении? Я хотел смотреть на верхняя часть телефона так, словно я вижу его сверху, поэтому я просто добавил вращение по оси X в преобразование мировых координат:

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

Результат представлен на рис. 5.

*
Рис. 5. Экран View3DPhone Reoriented

Камера смотрит слишком близко на объект с этой точки, но это меня не беспокоило — я знал, что когда введу матрицу вращения, я смогу слегка повернуть телефон, чтобы все встало на свои места. (Специалист по трехмерной графике мог бы заметить концептуальный промах в используемом мной подходе, но дайте мне наивно дойти до конца по этому пути, а уж потом я все поправлю.)

Теперь включаем матрицу вращения от класса Motion.

С концептуальной точки зрения, 3D-объект должен выглядеть фиксированным в пространстве, и перемещение смартфона должно позволять рассматривать объект с разных сторон. Конечно, на практике вы никогда не сможете сместить смартфон так, чтобы «отвернуться» от объекта. Объект всегда присутствует на экране, но ориентация дисплея в трехмерном пространстве дает разные представления этого объекта.

Чтобы добиться этого эффекта, нужно применить матрицу к объекту, которая обеспечила бы его вращение и перевод из системы координат смартфона в систему координат Земли, где концептуально этот объект и существует.

Мы должны достичь этого простым включением объекта RotationMatrix от класса Motion в вычисление преобразования мировых координат. Именно это и делается в проекте View3DPhoneWorldMotion. Он включает код для создания датчика Motion в своем конструкторе, его запуска в переопределенной версии OnActivated и остановки в переопределенной версии OnDeactivated. Затем я переместил вычисление преобразования мировых координат в переопределенную версию Update, как показано на рис. 6.

Рис. 6. Переопределенная версия Update в 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-объекта, а это означает, что объект должен быть фиксированным относительно источника света. Матрицу вращения от датчика Motion следует применять к преобразованию вида камеры, а не к преобразованию мировых координат.

Для финальной версии программы — View3DPhone CameraMotion — я восстановил вычисление преобразования мировых координат в исходное состояние:

worldMatrix = scaleMatrix;

Даже применение изначального вращения было ошибкой, так как это подразумевало, что источник света располагается за смартфоном, а не сверху. Новый метод Update показан на рис. 7.

Рис. 7. Переопределенная версия Update в 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 показывает одно из возможных представлений.

*
Рис. 8. Одно из представлений в View3DPhoneCameraMotion

Автор: Чарльз Петцольд  •  Иcточник: MSDN Magazine  •  Опубликована: 19.10.2012
Нашли ошибку в тексте? Сообщите о ней автору: выделите мышкой и нажмите CTRL + ENTER
Теги:   Windows Phone.


Оценить статью:
Вверх
Комментарии посетителей
Комментарии отключены. С вопросами по статьям обращайтесь в форум.