Расположение и ориентирование твердых тел

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

Вращение объекта можно представить в трех видах: набора углов Эйлера1 (значения вращения по х, у и z), вращательной матрицы преобразования или кватерниона. Хотя это и может заставить некоторых из вас съежиться, но я выбираю кватернионы для представления вращения тела. Основная причина заключается в том, что кватернионы численно устойчивы и с ними легче работать, чем с остальными методами.

Для тех из вас, кого не устраивает использование кватернионов, позвольте мне бегло рассказать о принципе их работы. Кватернион (или, если быть точным, единичный кватернион) является набором из четырех значений, определяющих вектор и скаляр. Компоненты вектора определяются как х, у, z и скаляр w. Тройка х, у, z может быть обозначена v; w может быть обозначен как s. Итак, существует два способа задания кватерниона

q = [s, v]

q = [w, [х, у, z]]

В Direct3D кватернион хранится в объекте D3DXQUATERNION, который использует обозначения х, у, z, w.

typedef struct D3DXQUATERNION {

FLOAT x; FLOAT y; FLOAT z; FLOAT w; } D3DXQUATERNION;

1. Угол Эйлера - угол между плоскостями параллелепипеда и мировым центром координат. - Примеч. науч. ред.

Как вы можете видеть на рис. 7.6, компоненты х, у, z определяют направляющий вектор. Этот направляющий вектор, v, представляет собой ось вращения.

Рис. 7.6. Векторный компонент (у = x, у, z) кватерниона определяет ось вращения

Угол вращения, заданный в радианах, хранящийся в компонентах кватерниона, х, у, z) вычисляется из следующего соотношения:

q = [тлг = соБ(д/2), xyz = sin(q/2)xyz ]

По-русски, все вычисления разделяются на вычисление компоненты \у, содержащей косинус угла вращения ^ деленное на два) и единичного вектора х, у, z, масштабированного на синус угла вращения ^ деленное на два). В виде кода это будет выглядеть так:

q = [cos(Angle/2.0f), normalized(x,y,z)*sin(Angle/2.0f)]

Говоря другими словами, предположим, вы хотите создать кватернион, представляющий вращение на 45 градусов (0.785 радиан) вокруг оси у. Вы создаете вектор, сонаправленный с положительной осью у, и устанавливаете его амплитуду равной синусу половины угла. После этого вы устанавливаете компоненту \у в косинус половины угла.

// Экземпляр используемого кватерниона В3ВХО_иАТЕ1Ш1(да quatRotation;

// Создать вектор, представляющий ось вращения БЗОХУЕСТСЖЗ vecAxis = В3ВХ¥ЕСТСЖ3(0.0^ 1.0^ 0.0Л;

// Нормализовать его, чтобы установить амплитуду D3DXVec3Normalize(&vecAxis, &vecAxis);

Расположение и ориентирование твердых тел

/ / Масштабировать вектор на синус половины угла vecAxis *= ^^^^(0.785 /

// Сохранить вектор в кватернионе quatRotation.x = vecAxis.x,• quatRotation.у = vecAxis.y,• quatRotation.z = vecAxis.z,•

// Вычислить компоненту w, используя косинус половины угла quatRotation.w = (float)cos(0.785f / 2.0^;

Для единичного кватерниона, какой вы будете использовать, выполняется соотношение (х2 + у2 + 22 + \у2 = 1), означающее, что сумма квадратов всех составляющих должна равняться единице. Если она не равна единице, тогда кватернион не единичной длины, и он должен быть нормализован перед использованием. При использовании БкейЗБ можно очень легко нормализовать кватернион, используя функцию В3ВХрш1еггцопКогтаН2е. Например, для нормализации кватерниона, хранящегося в quatOrientation, вы можете использовать следующий код:

D3DXQuaternionNormalize(&quatOrientation, &quatOrientation) ;

Ну и куда все это нас ведет? После определения оси и угла поворота вы можете использовать кватернион для преобразования точек твердого тела. Все правильно; кватернион занимает место повседневно используемых матриц преобразования и углов Эйлера! Ну, в каком то смысле.

Т. к. фактически БкесЛЗБ не работает с преобразованиями кватернионов (пока!), вам необходимо привести кватернион к вращательной матрице преобразование, которую может использовать БкесЛЗБ. Вы можете выполнить это преобразования при помощи функции D3DXMatrixRotationQuaternion, как показано тут. (Заметьте, что я транспонирую результирующую матрицу, потому что кватернионы используют правосторонние, а я в этой книге левосторонние преобразования.)

// quatOrientation = кватернион с установленными вращательными значениями

D3DXMATRIX matOrientation,•

D3DXMatrixRotationQuaternion(&matOrientation, \ &quatOrientation);

// Конвертировать преобразование в левостороннее D3DXMatrixTranspose(&matOrientation, &matOrientation);

Зачем я раскрывал вам секреты единичных кватернионов, если, в конце концов, мы будем использовать вращательные матрицы преобразования? На самом деле матрица преобразования является вторичным объектом, используемым для преобразования точек ограничивающего параллелепипеда вашего твердого тела

(и еще для нескольких вещей). Под словом вторичная я подразумеваю то, что хотя ориентация тела и хранится в кватернионе, все преобразования выполняются с помощью матрицы.

Вот мы и там, откуда начали, только теперь вы знаете, как работают кватернионы, и поэтому будете использовать их для представления ориентации твердых тел. После вычисления кватерниона, используемого для ориентирования твердого тела и сохранения глобальных координат в векторе положения, вы можете преобразовать локальные точки вашего твердого тела в координаты трехмерного мира.

// vecLocalPoints[] = массив точек тела в локальном пространстве

// vecWorldPoints[] = массив точек тела в глобальном пространстве

// quatOrientation = кватернион, содержащий вращение тела

// vecPosition = положение твердого тела

// Создать матрицу преобразования из кватерниона D3DXMATRIX matOrientation,•

D3DXMatrixRotationQuaternion(&matOrientation, \ &quatOrientation);

// Преобразовать все восемь точек тела for(DWORD і=0;і<8;і++) {

// Ориентировать, используя матрицу преобразования D3DXVec3Transform(&vecWorldPoints[i], \

&vecLocalPoints[i], \

&matOrientation) ;

// Переместить точки, используя вектор vecWorldPoints[i] += vecPosition,• }

Теперь каждая точка корректно ориентирована в мировом пространстве в соответствии с заданными трехмерными координатами и значениями вращения. Все это хорошо, но на самом деле ничего не происходит - тело остается на месте. Вам необходимо начать трясти этого щенка и заставить тело двигаться!

Создание твердого тела || Оглавление || Обработка движения твердых тел