В связи с программой "Rotate3D" к нам иногда поступают вопросы о том, как сделать изображение
вращающегося трёхмерного тела.
Программа "Rotate3D" создаёт изображения "проволочных" тел, не занимаясь удалением
"невидимых" линий. Эта задача существенно сложнее. Интересующиеся могут обратиться к соответсвующей
литературе (например, к книге Е.В.Шикина и А.В.Борескова "Компьютерная графика. Динамика, реалистические
изображения."), либо использовать языки описания трёхмерных сцен типа DirectDraw или OpenGL (как в программе
"Тела").
Для понимания данной статьи желательно предварительно разобрать статьи
"Аффинные преобразования пространства" и
"Проектирование пространства на плоскость".
Для построения изображения тела обычно его поверхность разбивается на многоугольники такого размера и такой формы,
чтобы их можно было считать практически плоскими. Затем в той или иной форме создаётся "список" вершин,
линий и многоугольников, которые нужно изобразить. "Список" не обязан быть списком (или массивом) в
обычном смысле этого слова, это вполне может быть набор процедур, вычисляющих координаты вершин и всевозможную
дополнительную информацию, необходимую для построения изображения тела. Эта информация может включать, например,
такие сведения, как цвет или вектор нормали к поверхности тела. Этот "список" используется затем для
построения изображения тела.
Для построения изображения необходимо каким-то образом перейти от пространственных координат к координатам на
плоскости. Для этого обычно выбирается некоторая плоскость, на которую проектируются все точки данного тела.
Способ получения такой проекции описан в статье
"Проектирование пространства на плоскость".
Некоторую проблему создаёт тот факт, что описанный там метод хотя и даёт координаты точки, лежащей в плоскости
проекции, но это опять-таки трёхмерные координаты, а не координаты на плоскости. На практике эта проблема обычно
решается тем, что для проектирования выбирается плоскость, совпадающая с (или параллельная) одной из координатных
плоскостей, а оси координат и
на плоскости проектирования -
совпадающими с осями (или параллельными осям) пространственной системы координат.
Например, в программе "Rotate3D" плоскость проекции совпадает с плоскостью
, ось
- с осью
, ось
- с осью
; в программе "Тела"
плоскость проекции совпадает с плоскостью
, ось
- с оью
, ось
- с осью
.
Рассмотрим более общую ситуацию. Предположим, что на плоскости проекции выбрана система координат
(напомним, что в
пространстве используется система координат
), причём, точка
имеет в системе
координаты
, вектор
- координаты
, вектор
- координаты
(это
"единичные" векторы осей
и
). Тогда связь между
координатами и
можно записать в виде
системы уравнений
Как и в случае преобразований пространства, эти соотношения можно записать в матричной форме, если ввести следующие три столбца и матрицу:
Тогда рассматриваемая система запишется в виде
.
Из этой системы нужно найти и
. Некоторая трудность состоит в
том, что эта система содержит три уравнения и только две неизвестных величины. Она имеет решение только в том случае,
когда точка лежит в
плоскости проекции. Выбирая из системы любые два уравнения и решая их, получим три варианта решения:
Заметим, что все три варианта должны давать одно и то же с точностью до погрешностей вычисления; возможно осложнение, состоящее в том, что некоторые знаменатели в этих решениях могут обращаться в (с точностью до погрешностей вычисления). Вообще говоря, из трёх выражений лучше пользоваться тем, которое имеет наибольший (по модулю) знаменатель. В матричной форме эти решения можно записать в виде
Напомним, что в этих формулах точка
должна лежать в
плоскости проекции.
Здесь остаётся ещё проблема связи параметров в двух различных способах задания плоскости: с помощью точки
и двух векторов
и
с одной стороны,
и с помощью уравнения
- с другой.
Уравнение нужно для построения проекции, а точка
и векторы - для определения
двумерных координат проекции. Как известно из курса аналитической геометрии, вектор
перпендикулярен плоскости
и, следовательно, обоим упомянутым векторам. Тем же свойством обладает и векторное произведение. Поэтому можно взять
Найдя , можно затем найти , воспользовавшись тем, что плоскость проходит через точку . В результате получим следующие формулы:
Если это зачем-либо нужно (например, для нормировки вектора нормали или для изменения его направления на
противоположное), можно умножить или разделить найденные
на одно и то же число,
не равное .
Вообще говоря, имеет смысл не разбивать вычисление координат на плоскости проекции на два этапа (проектирование и
преобразование к двумерной системе координат). Вполне возможно получить выражение координат на плоскости проекции
через координаты проектируемой точки. Подчеркнём, что в следующих соотношениях
- именно проектируемая
точка, а не проекция.
То же самое с помощью определителей записывается так:
То же самое в матричной форме выглядит так:
Например, в программе "Rotate3D" для ортогональной проекции используется формула
а для параллельной (сразу после загрузки) - формула
Однако используемую здесь матрицу можно изменить в процессе работы с программой.
В программе "Тела" для получения проекции исползуется постоянное соотношение
которое соответсвует стандартной "кабинетной" проекции.
Аналогичные вычисления можно проделать и для центральной проекции. Полученное выражение является весьма длинным:
Однако с помощью определителей эти формулы можно записать сравнительно компактно:
Следующий этап построения изображения - пересчёт координат
в экранные или оконные
координаты, выраженные в пикселях. Конкретные формулы пересчёта зависят от желаемых размеров изображения и используемой
системы программирования (от этой системы может зависеть, например, положение начала экранной или оконной системы
координат и ориентация осей). Системы типа OpenGL выполняют этот пересчёт автоматически, подстраиваясь под размер окна
и разрешение экрана.
Таким образом, будем считать, что Вы сумели запрограммировать изображение неподвижного тела. Для получения эффекта
вращения осталось уже совсем немного: стирать имеющееся изображение, поворачивать тело и снова его рисовать.
Конкретные программистские приёмы замены одного изображения другим мы рассматривать не будем; для этого есть несколько
различных методов, зависящих от сложности изображения, а также имеющихся программных и аппаратных средств.
Фактически нам осталось сделать только несколько замечаний о выборе метода поворота тела. Чтобы вращение выглядело
плавным и непрерывным, смена изображения должна быть достаточно частой, а различия в последовательных положениях
тела - небольшими. Фактически можно предложить два основных варианта.
Первый метод состоит в том, что программа постоянно хранит исходное положение тела. Текущее положение тела получается
путём поворота на заданныё углы вокруг трёх различных осей (результат зависит от порядка поворотов). Для получения
нового положения тела эти углы изменяются на небольшие величины.
Этот метод даёт, как правило, эффект "хаотического" вращения. Детали вращения зависят от выбора осей и
приращений углов.
Этот метод реализован в программе "Rotate3D", причём, в качестве осей вращения выбраны оси координат
. Соответствующая
матрица приведена в статье
"Аффинные преобразования пространства". Можно использовать
и углы Эйлера (нужную матрицу можно найти там же).
Второй метод состоит в том, что программа запоминает текущее положение тела, а новое положение получается путём
поворота тела из текущего положения на небольшие углы вокруг трёх различных осей (обычно берутся оси
).
Здесь результат тоже зависит от порядка поворотов, но при малых углах поворота разница может быть незаметной "на
глаз". Если при этом методе сохранять углы поворота постоянными, то возникает эффект равномерного вращения тела
вокруг некоторой оси. Если углы поворота немного изменять, то эта ось будет медленно поворачиваться. Однако, может быть,
лучше использовать матрицу вращения вокруг заданной оси. Тогда Вы сможете
контролировать ось вращения непосредственно.
На этом позволим себе закончить, поскольку и так уже эта серия статей содержит, на наш взгляд, много лишнего.
Если у Вас возникнут какие-либо вопросы, Если вопросов будет много, мы, возможно, сделаем на сайте раздел вопросов и ответов.