gamedev Tutorials Программирование игр

 

Внимание: в июле 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

PMG  17 января 2006 (c)  Вячеслав Медноногов