Внимание: в июле 2005 появился M3G v1.1, имеющий некоторые отличия. В существующих телефонах стоит 1.0, вероятнее всего.
Object3D. Понятие объекта.
Почти все объекты в M3G (меши, узлы, камеры, контроллеры анимации, Е) так или иначе являются наследниками от общего класса Object3D.
Object3D содержит три базовых свойства (есть соотв. методы set и get):
- ID объекта (используется для поиска подобъектов);
Поиск подобъектов возможен от текущего подобъекта вниз по дереву (метод find()). При этом допускаются одинаковые ID в разных поддеревьях. В случае нахождения объектов с одинаковым ID в одном поддереве find() вернёт один из них (зависит от реализации).
- ссылка на ассоциированные пользовательские данные (произвольного формата);
Может быть null.
Внимание: при десериализации через метод Loader.load() пользовательские данные должны быть представлены в виде hash-таблицы пар (int ключ, byte[] значение).
- дескрипторы анимации (AnimationTrack) , 0 или более.
Можно добавить, удалить (по ссылке) или обратиться (по индексу) к любому AnimationTrack. Обновление анимации (объекта и всех его подобъектов) производится через метод animate(int время). Время - в единицах, зависящих от приложения. Внимание: новый трек добавляется не обязательно в конец списка треков, место добавления зависит от реализации.
Objsect3D имеет так же метод duplicate() и метод getReferences() получения всех ссылающихся на него других объектов (возвращает число таких объектов и массив ссылок на них).
Пространственные операции.
Объекты, имеющие позицию в мире и допускающие трансформацию, наследуются от Transformable (абстрактный класс, наследник Object3D).
Transformable допускает следующие операции:
- scale(float sx,sy,sz);
- setScale(float sx,sy,sz);
- translate(float tx,ty,tz);
- setTranslate(float tx,ty,tz);
- setTransform(Transform tr); (непосредственное задание матрицы 4x4 объекта)
- preRotate(float angle,ax,ay,az); (вращение на угол angle вокруг вектора, матрица вращения умножается на матрицу объекта)
- postRotate(float angle,ax,ay,az); (то же, матрица объекта умножается на матрицу вращения).
- setOrientation(float angle,ax,ay,az); (задание ориентации Ц субматрицы 3x3 в 4x4)
Имеются соответствующие get методы.
M3G не имеет специальных классов для задания позиций (типа Vector2D, Vector3D, Point) и не имеет специальных классов для простейших геометрических объектов (типа Sphere, Box, OOBB, Е). Есть только класс, агрегирующий матрицу 4x4 (Transform). Нумерация элементов:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
(Примечание: позиция X,Y,Z задана в столбце 3,7,11)
Transform (по умолчанию создаётся как единичная матрица) допускает операции:
- postMultiply(Transform transform) (домножение на матрицу)
- postRotate(float angle,ax,ay,az) (домножение на матрицу вращения)
- postRotateQuat(float qx,qy,qz,qw) (домножение на матрицу вращения)
- postScale(float sx,sy,sz) (домножение на матрицу скалирования)
- postTranslate(float tx,ty,tz) (домножение на матрицу смещения)
- transform(float[] vectors) (домножение на матрицу, заданную 16-ю эл-тами по столбцам)
- transform(VertexArray in, float[] out, boolean W) (умножение VertexArray на текущую матрицу, результат возвращается в out)
Инверсия и транспонирование:
- invert()
- transpose()
Задание матрицы (кроме конструктора по умолчанию и копирующего конструктора):
- set(float[] matrix) (16 элементов задают матрицу 4х4 по строкам)
- set(Transform transform)
- setIdentity() (единичная матрица)
Только один get метод:
- get(float[] matrix)
Пересечения.
Для хранения результатов пересечений имеется единственный класс RayIntersection.
Задаёт отрезок от текущей точки до точки пересечения. Дополнительно хранит нормаль к мешу в точке пересечения, S и T текстурные координаты меша в точке пересечения, и индекс submesh.
Проверка пересечений выполняется методами (всего двумя) pick() класса Group.
Иерархия объектов.
Единицей иерархии служит Node (наследник от Transformable). Node бывают пяти видов: Camera, Light, Sprite3D, Mesh и Group (группа Nodes) Ц это всё наследники от Node.
Node Ц основные операции:
- setAlignment(Е) и align(Node n) (выравнивание ориентации Node по осям других(ой) Node(s). Применяется, например, для "billboards". Важно: это выравнивание выполняется и в дальнейшем, при любых последующих операциях над базовой нодой Ц т.е. это некое связывание);
- setAlphaFactor(float alphaFactor) (полупрозрачность объекта [0..1], вычисляется с учётом полупрозрачностей родительских узлов. Не имеет влияния на Lights и Cameras);
- setPickingEnable(boolean enable) (разрешение на участие в тестах на пересечение, при условии наличия разрешения у предка);
- setRenderingEnable(boolean enable) (разрешение на рендеринг, при условии наличия разрешения у предка) ;
- setScope(int scope) - задать принадлежность ноды к некоторым игровым наборам (scope). Смысловое значение наборов зависит от конкретной игры. Наборы задаются битовыми масками. Node может входить более, чем в один набор. Scope может использоваться в дальнейшем при проверке пересечений, при посылке на рендер или в иных целях по усмотрению разработчика.
Есть соответствующие get и is методы. Дополнительно:
- getParent() Ц получить родителя или null.
- getTransformTo(Node t, Transform tr) Ц получить матрицу трансформации, переводящую из текущей ноды в указанную.
Группы объектов задаются классом Group.
Group (наследник от Node) Ц в неё могут быть добавлены новые Node, либо удалены старые. Внимание: после добавления новой Node их порядок в группе не определён и зависит от реализации.
При добавлении потомка, проверяется, что он не World, и что не образуются циклические ссылки (это всё ведёт к exception).
Кроме того, у Group имеются методы pick() для проверки пересечения группы с заданным лучом и указанным набором (scope).
World (наследник от Group) Ц является корнем в иерархии объектом. Дополнительно к свойствам класса Group имеет:
- ссылку на текущую камеру
- ссылку на текстуру background.
Геометрические объекты.
Представлены классом Mesh и его наследниками SkinnedMesh и MorphingMesh.
Mesh содержит один VertexBuffer, несколько IndexBuffer для задания sub-мешей, и такое же число Appearance, свой для каждого sub-меша (Appearance - аналог render state, см. ниже).
SkinnedMesh дополнительно содержит ссылку на скелетон (представлен Group Ц поддеревом произвольных Node). Для задания связи между костями скелета и вершинами меша служит метод addTransform(Е). Либо эти связи уже должны быть заданы в файле модели при экспорте. Реализация должна допускать связь одной вершины не менее, чем с 2-мя костями скелета.
MorphingMesh дополнительно содержит ссылку на набор целевых (target) VertexBuffers (они имеют в точности ту же топологию, что и базовый VertexBuffer) и изменяемый массив соответствующих им весовых коэффициентов.
Геометрия нижнего уровня.
В основе лежит класс VertexArray.
VertexArray может иметь 2, 3 или 4 элемента на каждый вертекс. Внимание: размерность каждого элемента 1 или 2 байта!
Дополнительно VertexArray имеет bias и scale (float) Ц базовое значение и скалирование.
Т. е. реальное значение элемента вычисляется по формуле real_val = bias + val*scale.
Следующий уровень:
VertexBuffer Ц состоит из default_color и из следующих VertexArray одинакового рамера:
- позиция (3 эл) (должен быть всегда)
- нормаль (3 эл) (может осутствовать, тогда нормаль не определена)
- цвет (3/4 эл Ц RGB/ARGB) (может отсутствовать, тогда берётся default color)
- текстурные координаты 1 (2 эл) (может отсутствовать, тогда т.к. не определены)
Е
- текстурные координаты N (N зависит от реализации, минимально Ц 1)
Индексные буферы, используемые в объектах класса Mesh, наследуются от абстрактного класса IndexBuffer.
IndexBuffer имеет новые методы в версии 1.1.
В настоящее время существует только одна конкретная реализация IndexBuffer в M3G:
TriangleStripArray. Другие (например, линейный буфер) надо ручками писать, пронаследовав их от IndexBuffer.
Параметры рендеринга.
Параметры задаются классом Appearance (аналог render_state и environment в одном флаконе).
Appearance содержит объекты классов:
- Fog (линейны или экспоненциальный);
- PolygonMode (задаёт тип сглаживания (FLAT или SMOTH), cull-mode (односторонний или двухсторонний рендеринг фейсов), обход вершин (CW или CCW)).
- Material (определяет цвета (ARGB) для AMBIENT, DIFFUSE, EMISSIVE (типа selfillum) и SPECULAR. Определяет величину блика shinnes (0..128), так же разрешает/запрещает использовать vertex_color, заданный в VertexBuffer).
- ComposingMode:
- разрешает/запрещает тест глубины (и задаёт величину этой глубины);
- разрешает/запрещает альфа-тест (и задаёт пороговую величину альфы);
- задаёт метод блендинга Ц ALPHA (с учётом альфы), ALPHA_ADD (аддитивный), MODULATE (мультипликативный), MODULATE_X2 (мультипликативный усиленный), REPLACE (простое копирование).
- разрешает/запрещает отрисовку пикселей.
- Texture2D (1 или более, зависит от реализации).
Объекты-изображения.
Texture2D:
- содержит ссылку на Image2D;
- задаются режимы фильтрации мипмапов (linear, nearest, base_level; реально могут зависеть от реализации);
- задаются wrapping режимы по S и T координатам (CLAMP или REPEAT).
- задаётся функция блендинга (FUNC_ADD, FUNC_BLEND, FUNC_DECAL, FUNC_MODULATE, FUNC_REPLACE) и бленд-color.
Image2D:
Конструируется:
- из MIDP или AWT Image.
- как пустая текстура размером NxM;
- как текстура размером NxM, заполненная ARGB данными
(имеется аналогичный метод set());
- как текстура размером NxM, заполненная палитровыми данными;
Дополнительно задаётся режим создания текстуры:
- RGB
- Alpha+RGB
- Luminance
- Alpha+Luminance
- Alpha only
Чтобы рисовать в Image2D в дальнейшем, надо выполнить Graphics3D.bindTraget(Е).
Background (фон игры). Имеет:
- ссылку на Image2D, режим его отображения (REPEAT, BORDER), параметры crop-рамки внутри image;
- разрешает/запрещает очистку буфера глубины и цвета (с заданием соответствующих значений);
Sprite3D:
Комбинирует в себе Image2D и Appearance (кроме того, является наследником Node, а значит, и Transformable). Дополнительно можно задать crop-прямоугольник, с помощью которого изображение спрайта будет вырезано из Image2D. Могут использоваться для billboard и particle system.
Камеры.
Camera бывает:
- проективной (задаётся методом setPerspective() и параметрами FOV, аспект, и дальней/ближней дистанцией отсечения),
- параллельно-проективной (задаётся методом setParallel() и параметрами FOV (используется как масштаб изображения на экране), аспект, и дальней/ближней дистанцией отсечения).
- generic (просто задаётся любой матрицей трансформации).
Источники света.
Light имеет стандартные типы:
- AMBIENT (рассеянный свет)
- DIRECTIONAL (общий направленный)
- OMNI (точечный)
- SPOT (конусный)
Задаются следующие параметры (есть и соотв. методы get):
setAttenuation(float constant, float linear, float quadratic)
setColor(int RGB)
setIntensity(float intensity)
setSpotAngle(float angle)
setSpotExponent(float exponent)
Реализация гарантирует не менее 8-ми источников света.
РЕНДЕРИНГ.
Для рендеринга используется самый мощный класс в M3G Ц Graphics3D.
Перед применением его надо забиндить (bindTarget()) с объектом класса Graphics из MIDP или с Image2D. После применения Ц разбиндить (releaseTarget()).
В Graphics3D :
- задаются/модифицируются/удаляются источники света Light (по индексам);
- задаётся камера (для режимов, когда рендерится не World, а отдельные объекты);
- задаётся, куда рисуем (bindTarget()). Допустимы объекты типа Graphics или Image2D (мутабельные).
- очищаются экран и буфера (операцией clear())
- разрешить/запретить буфер глубины.
- можно получить описание устройства (getProperties(), как то Ц количество текстур за проход, количество источников света, максимальную размерность текстур и т.д.)
- задать viewport - прямоугольную область на экране или в image, куда будет вестись отрисовка.
- и, наконец, ОТРЕНДЕРИТЬ (одной из 4-х функций render()):
- отрендерить World
- отрендерить Node
- отрендерить VertexBuffer (с учётом принадлежности к игровому набору scope или без)
Внимание: часть операций get доступна с версии 1.1.
Создание и загрузка объектов.
Объекты создаются в 3D Max7 (там есть стандартный экспорт в *.m3g формат).
Загрузка осуществляется методами статического класса Loader.
Loader имеет два метода load (один грузит из файла, другой из байтового массива).
Возвращается Ц массив ссылок на Object3D (если грузится m3g файл), или массив Image2D из одного элемента, если грузится *.png файл. Формат файла распознаётся по сигнатуре в заголовке (не по расширению).
Анимация.
Задаётся классами:
AnimationTrack Ц задаётся для Object3D. Связывает с ним AnimationController и KeyframeSequence для одного из свойств:
ALPHA
AMBIENT_COLOR
COLOR
CROP
DENSITY
DIFFUSE_COLOR
EMISSIVE_COLOR
FAR_DISTANCE
FIELD_OF_VIEW
INTENSITY
MORPH_WEIGHTS
NEAR_DISTANCE
ORIENTATION
PICKABILITY
SCALE
SHININESS
SPECULAR_COLOR
SPOT_ANGLE
SPOT_EXPONENT
TRANSLATION
VISIBILITY
AnimationController
- устанавливает весовой коэффициент для блендинга анимаций.
- устанавливает скорость анимации (1.0 Ц нормальная, >1 ускоренная, 0-стоп, <0 Ц реверсивная)
- имеет активный интервал [T1,T2] в единицах времени приложения, в течении которого контроллер будет активен. Если T1==T2, контроллер активен всегда.
- через него задаётся текущая позиция анимации (для текущего мирового времени с учётом скорости анимации).
KeyframeSequence
- задаёт непосредственно значения ключей анимации
- задаёт способ интерполяции между ключами:
LINEAR
SLERP
SPLINE
SQUAD
STEP
- задаёт range ключей.
- задаёт способ получения значений ключей вне range:
CONSTANT
LOOP
Версия M3G 1.1.
Отличия 1.1 от 1.0 в основном косметические. Например, следующие классы имеют дополнительные get методы:
AnimationController
Graphics3D
IndexBuffer
KeyframeSequence
Node
PolygonMode
SkinnedMesh
Texture2D
VertexArray
Всё.
Все классы кратко рассмотрел, ничего не пропустил.
© Вячеслав Медноногов
Ketsujin Russian Studio
17sep2005 / copperfeet