Нюансы при экспорте из 3DS MAX
Автор: hax
Вступление
Базовые понятия
Система координат
Матрицы объекта и узла (Node)
Non-uniform scale
Отрицательное масштабирование
Спрятанные объекты
Спрятанные треугольники
Экспорт материалов
Multi/sub-object material
Sub-region tiling
Экспорт привязки вершин
Иерархия из Dummy
Линки-сплайны
Типы вершин
Ручное задание весов
Удаленные кости
Иерархия
Link Constraint
Biped
Экспорт нормалей
Ссылки
Вступление
Поскольку эта статья родилась из комментария к статье "Заметки о разработке плагина для экспорта геометрии и ещё чуть-чуть" Glorg'a, пожалуйста начните чтение с оригинальной статьи [1], а я обойдусь без вступления :)
Вкратце, в статье пойдет речь о нюансах, с которыми вы (хотите или нет) обязательно столкнётесь при написании плагина экспорта из 3DS MAX.
Базовые понятия
Система координат
Обратите внимание, как ориентированы оси системы координат в 3DS MAX, и сравните системой, используемой в DirectX.
Рисунок 1. Системы координат 3DS MAX и DirectX.
Мало того, что вверх направлена ось Z, а не Y, так в 3DS MAX еще и используется правосторонняя (right-handed), а не левосторонняя (left-handed) система координат, как в DirectX.
Если этого не учитывать, отэкспортченный персонаж в игре будет лежать на полу.
Поскольку системы разносторонние, то не существует такого поворота, с помощью которого можно перейти от одной системы к другой. Тут требуется еще и отражение относительно одной из координатных плоскостей.
Для того чтобы не путаться, проще всего при экспорте поменять местами оси Y и Z. Таким образом, если в игре персонаж должен бежать вдоль оси Z, то аниматор в 3DS MAX должен анимировать его вдоль оси Y – очень простое правило.
Для того чтобы поменять оси местами, нужно просто поменять местами компоненты Y и Z в позициях вершин и нормалях. Но при этом при экспорте анимации, каждую матрицу 3DS MAX необходимо умножить спереди и сзади на матрицу перемены осей (), чтобы вернуть позицию обратно в систему координат 3DS MAX для анимации, а потом опять в нашу систему координат.
Матрица перемены осей выглядит следующим образом:
При инвертировании, матрица не изменяется.
Полностью все выглядит так:
Матрицы объекта и узла (Node)
В документации к 3DS MAX есть раздел "Must Read Sections by Plug-In Type". Так вот, его действительно нужно прочитать! В частности, там объясняется, что такое матрица узла (node) и объекта (object).
Вся сцена в 3DS MAX представлена иерархией узлов. Когда мы создаем кубик (box) - мы создаем узел (INode) и объект (IObject), на который этот узел ссылается.
Центр локальной системы координат объекта (pivot), который мы видим в интерфейсе 3DS MAX - это визуальное представление матрицы узла. Матрицу узла можно получить методом INode->GetNodeTM().
Кроме того, объект может быть смещен относительно узла с помощью матрицы объекта. По умолчанию матрица объекта - единичная, но ее можно изменить, двигая pivot.
Рисунок 2. Включение режима преобразования pivot'а.
Когда мы двигаем pivot, 3DS MAX изменяет одновременно и матрицу узла, и матрицу объекта так, чтобы визуально геометрия оставалась на том же месте.
Полная формула преобразования геометрии в мировое пространство выглядит так:
Напрямую получить матрицу объекта невозможно. Можно получить матрицу преобразования геометрии в мировое пространство (INode->GetObjectTM()), и помножить ее справа на инвертированную матрицу узла.
Non-uniform scale
Non-uniform scale(масштабирование с разными коэффициентами по осям, NUS) - это зло. Это настолько большое зло, что в ранних версиях 3DS MAX при включении этого режима выскакивало предупреждение. Но в последний версиях 3DS MAX его убрали (наверное потому, что художники его все равно не читали :).
NUS рождает две следующие проблемы:
1. Для преобразования нормалей необходимо использовать inverse transpose матрицу.
Обычно, в играх для преобразования нормалей используется та же матрица, что и для преобразования позиций, только с обнуленным смещением. В случае с NUS это не работает:
Рисунок 3. Если для преобразования нормалей использовать ту же матрицу, что и для позиций, нормали больше не перпендикулярны поверхности.
Если для преобразования позиций используется матрица M, то для преобразования нормалей необходимо использовать . Впрочем, можно просто считать нормали уже после преобразования позиций.
Обычно проблему NUS можно решить путем выделения из матриц масштабирования, и применения его к координатам вершин (таким образом удается избавиться от масштабирования вообще). К сожалению, это не избавляет от второй, фундаментальной проблемы.
2. Если к кости применен NUS, то при вращении она сжимается.
Вообще-то, до того, как модель дошла до стадии экспорта, проблемы уже должны были возникнуть у аниматоров, и они обязаны были вернуть модель назад моделеру :).
Поскольку в матрице узла содержится неравномерное масштабирование, то при вращении кости она описывает эллипс, а не круг. Поскольку в играх анимация кости сохраняется только в виде положения и вращения (кватернионы), то анимация в игре не будет соответствовать анимации в 3DS MAX.
Другими словами, NUS - это зло, и ваши художники должны следить, чтобы матрицы узлов не содержали его. Если нужно выполнить неравномерное сжатие, его нужно выполнять над вершинами геометрии (vertices sub-object), а не над узлом.
Матрицы также могут содержать искривление осей (переход к неортогональной системе координат). К счастью, добиться этого стандартными методами 3DS MAX очень сложно, поэтому такие случаи редки (используйте метод Matrix3->Orthogonalize()).
Отрицательное масштабирование
3DS MAX позволяет указывать отрицательное масштабирование.
Рисунок 4. Отрицательное масштабирование.
Эффективно это масштабирование+отражение по одной из осей. Если объект отражен или отмасштабирован с отрицательным коэффициентом, то нужно поменять порядок следования вершин в треугольнике (отразить нормаль). Проверить это можно, проанализировав матрицу:
bool RF2_Export_FaceNeedFlip(INode *Node, float time) { Matrix3 m = (Node->GetObjectTM (time)); return (DotProd(CrossProd(m.GetRow(0),m.GetRow(1)),m.GetRow(2))<0.0)?1:0; };
Спрятанные объекты
Иногда проблемы возникают из-за незнания интерфейса 3DS MAX. На самом деле, вы - программист, и знать 3DS Max не обязаны, но все же...
3DS MAX позволяет прятать (hide) объекты. Это очень полезная функция, и художники часто этим пользуются. Чтобы у вас не возникало проблемы, когда в отэкспорченной сцене появляются какие-то непонятные объекты, которых в 3DS MAX вроде бы нет, вам нужно знать, что 3DS MAX позволяет спрятать объекты тремя разными способами.
1. Спрятать выделенные объекты с помощью контекстного меню:
Рисунок 5. Контекстное меню (вызывается правой кнопкой мыши).
Для того, чтобы показать все объекты сцены, спрятанные этим способом, нужно выбрать в том же меню "Unhide all".
2. С помощью слоев:
Рисунок 6. Окно Layer Manager (вызывается Tools->Layer Manager).
3. С помощью панели Display:
Рисунок 7. Панель Display options.
Объект, спрятанный любым способом, не будет отображаться в окнах ViewPort и в списке объектов. Сам плагин не различает способа скрытия; в нем можно использовать единый метод INode->IsHidden().
Спрятанные треугольники
Рисунок 8. Панель face sub-object.
Кроме целых объектов, 3DS MAX позволяет скрывать отдельные треугольники. Плагин может запросить статус треугольника методом Face->Hidden().
22 апреля 2006 (Обновление: 17 июня 2006)