Ëèöåíçèîííîå ñîãëàøåíèå

Лицензионное соглашение

Настоящее лицензионное соглашение между правообладателем и конечным пользователем данной программы.

Правообладатель - © Башков Алексадр, Tesak Studios, 2007.

Лицензионное соглашение (EULA) на использование и распространение программы

Программа "Справочная документация Ultimate 3D 2.0" (далее "программа", "программный продукт", "справка", "документация") распространяется по принципу "как есть", что не несет никаких гарантий, явных и/или подразумеваемых, со стороны правообладателя. Вина за весь возможный ущерб причиненный использованием и/или не использованием данного программного продукта полностью лежит на пользователе данного программного продукта. Пользователь программы принимает на себя всю ответственность за возможные последствия использования и/или не использования данного программного продукта. Все товарные знаки и/или иные зарегистрированные или нет названия принадлежат своим владельцам.

Условия лицензионного соглашения:

1. Всеми авторскими правами на данный программный продукт и его составляющие - текстовую информацию, графические изображения, и иную информацию; эксклюзивно владеет автор программы - Башков Александр. Автор программного продукта имеет право аннулировать любое лицензионное соглашение в одностороннем порядке. Все права защищены законами РФ об авторском и смежных правах, а также международными законами и соглашениями об авторских правах.

2. Пользователь не имеет права вносить изменения в программу, продавать, сдавать в аренду передавать другим лицам или организациям данный экземпляр программы и/или какую либо её часть во временное или постоянное пользование.

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

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

· www.tesak-studios.narod.ru
· www.ultimate3d.org
· www.gamecreating.ru

- Официальный сайт автора программы

- Официальный сайт Ultimate3D

- Сайт о создании игр без программирования
5. Установка, хранение и/или использование данной программы свидетельствует о вашем согласии с условиями данной лицензии. Если вы не согласны с условиями данной лицензии, то должны удалить файлы данного программного продукта со своих устройств хранения информации и отказаться от дальнейшего использования этого программного продукта

6. Пользователь несет полную юридическую ответственность за нарушение условий Лицензионного соглашения и авторских прав Башкова Александра. Любое нарушение условий Лицензионного соглашения влечет за собой немедленное прекращение действия Лицензии.

Вопрос - Ответ.

Вопрос: Как я могу пользоваться данной справкой?

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

Вопрос: Могу ли я процитировать часть статьи справки?

Ответ: Запрещено любое копирование или воспроизведение предоставленной программным продуктом информации, без письменного согласия автора. Но вы можете процитировать небольшую часть текста, при условии соблюдения авторских прав и указания источника цитирования.

Вопрос: Могу ли я выложить справку у себя на сайте?

Ответ: Запрещено распространение программного продукта с серверов/сайтов/веб узлов, кроме указанных в лицензионном соглашении. Т.е., например, если у вас есть сайт о Game Maker и вы бы хотели видеть данную справку у себя на сайте, то вы этого не можете сделать. Максимум что вы можете сделать так это поставить ссылку на официальный сайт автора данного справочного материала, откуда пользователи смогут загрузить дистрибутив программы. Более подробно смотрите на сайте автора справки. Если же вы все-таки разместите на своем сайте данную справку или прямую ссылку на её скачивание, то вы тем самым нарушите законы об авторском праве (в том числе и международные). Вам будет направлено письмо с требованием удалить всю нарушающую закон информацию. В случае отказа будет направлено аналогичное письмо обслуживающему сайт хостеру. Далее будет подано заявление в органы правопорядка по факту нарушения авторских прав, а в последствии возможно и исковое заявление в суд.

Обратите внимание что с 1 Января 2008 года вступает в силу новая редакция Гражданского Кодекса РФ, в котором ужесточается ответственность за нарушение авторских прав.

Вопрос: Я нашел опечатку / ошибку / неточность. Что мне делать?

Ответ: Убедитесь что у вас последняя версия справки, если так, то попробуйте собщить о найденом вами автору справки.

Вопрос: Как я могу связаться с автором справки?

Ответ: Вы можете написать электронное письмо на адрес Tesak-Studios@yandex.ru

© Башков Александр. Tesak Studios 2007. Все права защищены.


Äëÿ ðàñïðîñòðàíèòåëåé

Распространение справочной документации

Для возможности распространения перевода справочной документации Ultimate 3D на вашем сайте вы должны послать запрос на емаил автора, в котором вы указываете причину необходимости распространения справки именно с вашего ресурса + описание вашего ресурса (основная тематика, цели проекта, кол-во посетителей в день/месяц и т.д.).

Если вам было направлено предложение от автора о распространении справки, то вам отправлять запрос не нужно.

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

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

Пример запроса на распространение справки:

Кому: Tesak-Studios@yandex.ru

От кого: от меня, владельца портала www.bestengine.games (название естественно выдуманное)

Текст:

Здравствуйте Александр!

Я Семён Горбунков, владелец портала www.bestengine.games хочу распространять ваш перевод справочной документации Ultimate 3D со своего ресурса. Мой портал является крупнейшим в мире порталом о движках для создания игр и дополнениях к ним. Тут вы всегда сможете найти помощь по необходимым вам вопросам, поделиться своими произведениями и бла-бла-бла ...., все за бесплатно. Нас посещает до 100 человек в сутки!

Game Maker является самым популярным движком для создания игр, а дополнение Ultimate 3D открывает новые перспективы для этого движка. Ваша справка позволит посетителям нашего портала лучше познакомиться с ним.

Поэтому я прошу разрешить моему порталу распространять вашу справку, в соответствии с оговоренным в ней лицензионным сообщением.

Семён горбунков, www.bestengine.games. 2008

Пример окончательного договора:

Кому: Tesak-Studios@yandex.ru

От кого: от меня, владельца портала www.bestengine.games

Текст:

(это цитата положительного ответа автора на ваш запрос или цитата предложения автора)

Сообщение с предложением о распространении справки от автора:

Здравствуйте владец портала www.bestengine.games, я автор справки Ultimate 3D предлагаю вам возможность распростронять её с вашего ресурса. Ознакомиться с ней вы можете по этой ссылке tesak-studios.yandex.ru. Инструкция указана внутри справки.

(это текст лицензионного сообщения из полученной вами справки)

Лицензионное соглашение (EULA) на использование и распространение программы

Программа "Справочная документация Ultimate 3D 2.0" (далее "программа", "программный продукт", "справка", "документация") распространяется по принципу "как есть", что не несет никаких гарантий, явных и/или подразумеваемых, со стороны правообладателя. Вина за весь возможный ущерб причиненный использованием и/или не использованием данного программного продукта полностью лежит на пользователе данного программного продукта. Пользователь программы принимает на себя всю ответственность за возможные последствия использования и/или не использования данного программного продукта. Все товарные знаки и/или иные зарегистрированные или нет названия принадлежат своим владельцам.

Условия лицензионного соглашения:

1. Всеми авторскими правами на данный программный продукт и его составляющие - текстовую информацию, графические изображения, и иную информацию; эксклюзивно владеет автор программы - Башков Александр. Автор программного продукта имеет право аннулировать любое лицензионное соглашение в одностороннем порядке. Все права защищены законами РФ об авторском и смежных правах, а также международными законами и соглашениями об авторских правах.

2. Пользователь не имеет права вносить изменения в программу, продавать, сдавать в аренду передавать другим лицам или организациям данный экземпляр программы и/или какую либо её часть во временное или постоянное пользование.

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

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

· www.tesak-studios.narod.ru
· www.ultimate3d.org
· www.gamecreating.ru

- Официальный сайт автора программы

- Официальный сайт Ultimate3D

- Сайт о создании игр без программирования
5. Установка, хранение и/или использование данной программы свидетельствует о вашем согласии с условиями данной лицензии. Если вы не согласны с условиями данной лицензии, то должны удалить файлы данного программного продукта со своих устройств хранения информации и отказаться от дальнейшего использования этого программного продукта

6. Пользователь несет полную юридическую ответственность за нарушение условий Лицензионного соглашения и авторских прав Башкова Александра. Любое нарушение условий Лицензионного соглашения влечет за собой немедленное прекращение действия Лицензии.

(это ваше соглашение со всеми пунктами лицензионного соглашения)

Я Семён Горбунков, владелец портала www.bestengine.games согласен со всеми пунктами лицензионного соглашения и допускаю/разрешаю/приветствую/начну распространение справки с моего ресурса, согласно данному лицензионному соглашению.

(ваша подпись) Семён Горбунков, 2008 г.

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


Ïðèìå÷àíèÿ ïåðåâîä÷èêà

Примечания переводчика

О справке

Так как Ultimate 3D стремительно развивается, то также быстро меняется и справочная документация. Прежде чем читать справку убедитесь что она соответствует вашей версии Ultimate 3D. Если вы найдете ошибки, опечатки, неточности или же вам что-то совсем не понятно, но при этом у вас последняя версия справочной документации (узнать можно на сайте автора), то вам стоит сообщить о находке автору.

Текст справки основан на оригинальном тексте справки Ultimate 3D за авторством Christoph Peters. Текст перевел и дополнил Башков Александр. Все права защищены.

Версия справочной документации   : 1.00 RC

Дата последних изменений         : 1.01.2007

Версия библиотеки Ultimate 3D    : 2.0 RC 7.12.2007 8:27:06

*Все даты в формате H:mm:ss d:mm:yy

Что нужно знать об Ultimate 3D

Ultimate 3D - это 3Д библиотека, написанная на Delphi и использующая DirectX 8.1, созданная специально для Game Maker. Она позволяет использовать почти все современные технологии. Для того чтобы её использовать, вам нужно хорошо знать скриптовый язык Game Maker - GML и иметь опыт работы на нем, так как доступ к библиотеке осуществляется скриптовым языком.

Ultimate 3D имеет свои особенности: вы больше не сможете проверять существование той или иной переменной - U3D для облегчения вашей работы по вводу переменных, делает их равными нулю (это делает не сама библиотека, а GM: в настройках стоит галочка "установить переменные на 0" и её не нужно снимать). Примечание: как стало недавно известно, в финальной версии планируется отказаться от такого способа инициализации переменных и использовать стандартный.

Ultimate 3D для вывода на экран изображения использует Нулевой вид в комнате Game Maker. Вы больше не сможете его использовать для рисования, пока включен Ultimate 3D. (Хотя, на самом деле, Ultimate 3D создает новое окно, которое находится поверх нулевого вида Game Maker.) Так же не будут работать функции проверки нажатий кнопок мыши, когда курсор находится в окне Ultimate 3D, для проверки нажатий кнопок мыши в этот момент, используйте встроенные функции Ultimate 3D или же делайте проверку функцией keyboard_check_direct().

Многие продвинутые функции (terrain light mapping, parallax, ...) используют Шейдеры, и вам нужна видео карта с их поддержкой, для реализации этих возможностей. Рекомендуется видеокарта с поддержкой шейдеров версии не менее 1.2, а лучше 1.4 (Ultimate 3D позволяет использовать вершинные шейдеры версий 1.0 и 1.1, а так же пиксельные шейдеры версий 1.0, 1.1, 1.2, 1.3, 1.4)

Функция Step(), помещаемая почти во все объекты Ultimate 3D, обновляет информацию об объекте для которого она вызвана. Так если у вас есть объект, который никогда не изменит своих переменных, то вы можете удалить эту функцию из шага объекта - это незначительно повысит производительность. (обновляются только переменные о трансформации объекта: x, y, z, rotx, roty, rotz, scalx, scaly, scalz).

Все функции Ultimate 3D действуют на тот объект, из которого они вызваны. Но не стоит забывать о том, что в Game Maker есть функция With(), позволяющая выполнять код для указанного в скобках объекта.

Некоторые функции и возможности Ultimate 3D требуют от вас специальных знаний, например Матрицы (курс Высшая математика, изучается в ВУЗах) и вектора, различные формулы для шейдеров.

Если у переменной функции стоит пометка optional (опционально), то следует, что значение этой переменной можно не вводить или поставить 0.

Все ресурсы, которые вы загружаете в Ultimate 3D, будь то модели или текстуры загружаются только один раз, и вам не нужно беспокоится, о том, что вызвав несколько раз загрузку одного и того же ресурса, вам придется ждать пока он будет загружен, или что у вас будет существовать несколько абсолютно идентичных ресурсов, занимая память.


Ââåäåíèå â Ultimate 3D

Введение в Ultimate 3D

Введение в Ultimate 3D

Факт что вы читаете этот текст, позволяет мне думать, что вы решили попробовать Ultimate 3D. Это хороший выбор. Если вы раньше пытались создавать 3D игры с функциями Game Maker, то вы поняли, что создать красиво выглядящую 3D графику с их помощью очень сложно. И если вам удалось создать красивую графику на нем (работа наверняка заняла много времени), то вы заметили, что для комфортной игры требуется очень мощный компьютер класса High-End.

Game Maker – это отличная программа для создания игр, но его функции 3D рисования очень примитивны. Они не предназначены для создания сложной 3D графики. И если люди будут использовать их с целью обработки сложной 3D графики, то они столкнуться с проблемами. Так если вы хотите использовать по-настоящему сложную 3D графику в Game Maker, то вам нужно что-то большее. Возможно, вы уже пробовали другие 3D дополнения (движки) для Game Maker, но большинство из них очень сложно использовать, не так ли?

Именно поэтому есть Ultimate 3D. Это - попытка создать удобное дополнение для Game Maker, которое может использоваться, чтобы сделать чрезвычайно сложную трехмерную графику. Со старыми версиями Ultimate 3D (с версии 1.0 по 1.31) вы могли сделать весьма хорошую 3D графику, но в них не было возможностей создания спецэффектов и оптимизации производительности больших уровней. Именно поэтому я провел более года над созданием Ultimate 3D версии 2.0. В ней есть тонны новых функций, дающих вам возможность создавать замечательные спецэффекты и строить огромные уровни без заметного падения производительности. Фактически это ремейк старой версии. С выходом Ultimate 3D 2.0 моя разработка достигла пика своего развития. Ultimate 3D стал тем, чем и должен был быть изначально. Конечно, это не означает, что не будет новых версий в будущем, но Ultimate 3D 2.0 Final полностью завершенный продукт, в котором есть все, что необходимо для создания сложных 3D игр.

Позже на официальном форуме сообщества Ultimate 3D, автор Ultimate 3D выразил желание дополнить Ultimate 3D новыми возможностями: встроенной поддержкой физики ODE, дополнительными возможностями для частиц, возможно движком определения столкновений. Это и многое другое планируется добавить в Ultimate 3D 2.1.

Так как один из основных принципов Ultimate 3D это легкость в использовании, то все уроки очень детализированы. Они разделены на части: одна для новичков, другая для опытных пользователей. Это деление позволяет вам легче понять принцип работы Ultimate 3D. Функции, описанные в части для новичков очень легки и понятны в использовании. Вам не потребуется много времени, чтобы понять, как они работают, но даже с их помощью вы сможете создать красивую игру. А когда вы начнете изучать часть для опытных пользователей, вы сможете создавать действительно сногсшибательные игры с великолепнейшей графикой. Используя встроенный менеджер шейдеров, вы сможете создавать очень продвинутые спецэффекты. Встроенные функции Рельефного текстурирования (bump mapping), паралаксного смещения (parallax mapping) и обработчик ландшафта (terrain renderer) являются очень мощными средствами визуализации, очень легкими в использовании.

Ну ладно, вы всё увидите сами. Получайте удовольствие, изучая как создавать 3D игры :D


Ïðèñòóïàÿ ê ðàáîòå

Приступая к работе

Приступая к работе

Все начинается с файла

Перед тем, как вы начнете использовать Ultimate 3D, вам понадобится файл проекта Game Maker. Это означает то, что вы не можете использовать пустой проект в этих целях. Вам нужны скрипты и основные объекты созданные специально для Ultimate 3D. Если вы уже видели демонстрационный пример (demo), который поставляется вместе с Ultimate 3D, то вы, наверное, хотели бы его использовать как основу для вашей игры. Но я не рекомендую этого делать. Если вы действительно хотите создать свою собственную игру, то вы должны начать с нуля. Так демонстрационный пример окажется для вас всего-лишь не нужным мусором, мешающим работе. Если вы просто хотите изменить демонстрационный пример, то вы можете это сделать. Но народ может заметить это и обозвать вас бездарным плагиатчиком, невзлюбив ваше творение.

Именно по этой причине, вы должны делать ваш первый проект на Ultimate 3D, начиная с создания новой папки, и копирования в неё файла basic.gmd для Game Maker 5 или basicGM6.gm6 для Game Maker 6. Их можно найти в папке с Ultimate 3D SDK (пакет разработки), который можно скачать с официального сайта Ultimate3D.org. Этот файл проекта Game Maker содержит все, что вам нужно для работы с Ultimate 3D. Этот файл содержит по одному объекту каждого типа и объект контроля, который необходим для работы Ultimate 3D. Единственная комната содержит бессмысленную комбинацию этих объектов. Когда вы начнете делать игру, вам придется удалить все объекты, за исключением контролера и камеры, из комнаты.

Еще несколько моментов, которые вы должны знать о комнатах. Когда вы создаете новую комнату, которая будет использоваться с Ultimate 3D, необходимо выполнить следующие условия:

- Комната использует виды и первый (нулевой) вид включен.

- Отключен фоновый цвет. Это не так важно, просто повышает производительность.

- Комната должна содержать один объект управления (контроллер) и объект камеры.

Рекомендуется, чтобы вы создали две подпапки в директории вашего проекта. Одну из них назовите «gfx» - она будет использоваться для хранения текстур. А вторую назовите «models»- в ней будут храниться файлы 3D моделей. Это на ваше усмотрение. (прим. Переводчика: просто по умолчанию U3D использует эти папки как места хранения ресурсов и автоматически подставляет название директории к названию автоматически загружаемого файла, например текстур для модели)

Система видов

Еще один момент использования Ultimate 3D, который вам не понравится. Когда вы используете Ultimate 3D, то он рисует (рендерит) в первый вид Game Maker (индекс вида 0). Если это происходит, то вы больше не можете использовать этот вид для рисования в Game Maker. Просто не возможно рендерить двум совершенно разным программам в одну и ту же часть экрана одновременно. Именно поэтому Ultimate 3D имеет функции для рисования не только 3D сцен, но и для рисования 2D графики и текста. Еще вид не обязательно должен полностью покрывать окно Game Maker. Вы можете использовать множество видов, пока они не будут перекрывать вид для Ultimate 3D. Еще вы не сможете переключиться в полноэкранный режим, пока используете Ultimate 3D. Так что если вы хотите использовать полноэкранный режим, то вы должны включить его в настройках Game Maker или в опциях Ultimate 3D изменив скрипт Ultimate3DOptions().

Камера

Ну что ж, давайте перейдем к первой практической части: объекту камеры. По умолчанию объект камеры содержит кусок кода для управления при помощи мыши в событии шага и функции движения в событиях клавиатуры. Если вам это не нравиться, то вы можете спокойно удалить этот код. Я не стану подготавливать вас к теме движения. Так что взгляните на это:

Эта функция единовременно перемещает объект, для которого она вызвана.

Move( Longitude, Latitude, Speed)

Longitude, Latitude - Долгота, Широта

Эти два параметра определяют, в каком направлении должен двигаться объект. Работает это также как и глобус. Долгота (longitude) принимает значения от -90 до 90 и показывает, как сильно объект движется вверх или вниз. 0 означает, что объект не изменяет свою высоту, 90 означает, что объект движется вниз, -90 значит, что объект движется вверх. Широта (latitude) определяет горизонтальный угол направления движения объекта. Запомните, что есть отличие от системы, используемой в Game Maker. Для преобразования направления (direction) Game Maker в широту (latitude) Ultimate 3D вы должны использовать эту формулу: Latitude=direction+90.

Speed - Скорость

Этот параметр задает скорость, с которой движется объект. Запомните, что вы должны вызывать эту функцию каждый раз, когда хотите чтобы объект двигался (либо каждый шаг для постоянного движения).

С этого момента каждая функция, у которой есть параметры, будет рассмотрена на подобии этой. Если вам нужна простая информация, без разъяснений, то вы можете отрыть интересующий вас скрипт и посмотреть его комментарий – Каждый скрипт содержит краткое описание функции и её параметров.

Возможно, вы заметили что «Move» написано с заглавной буквы, как и все функции Ultimate 3D. На это есть несколько причин. Первая - то, что я использую названия для функций подобно как в C++. Вторая — это то, что так проще отличить, где функция Game Maker, а где Ultimate 3D. Если бы не было видимого различия, то пришлось бы использовать префикс «u3d_». Так что функция «Move» называлась бы «u3d_move». По-моему намного проще нажать клавишу [Shift] когда нужно, а не писать«u3d_» всё время. Между прочим, так лучше выглядит.

Но давайте вернемся к нашей теме... объекту камеры. В Ultimate 3D каждый объект сцены должен быть представлен образцом объекта Game Maker. Тогда вы сможете изменять свойства объектов сцены просто изменяя переменные объектов Game Maker. Функции, наподобие функции MoveCamera(), передадут индекс (ID) объекта в Ultimate 3D автоматически. У камеры есть следующие переменные:

x, y, z - координаты в пространстве

Эти переменные определяют позицию камеры. Как вы поняли, теперь мы в трехмерном пространстве и тут уже не только ось x и ось y. Теперь появилась новая ось z. Она определяет высоту объекта. Так если вы увеличите высоту объекта (z), то объект переместится вверх, а если уменьшите, то соответственно - вниз. Комбинация (набор) переменных x, y, z называется координатами. Вы должны запомнить это слово, оно может повторится снова.

height - высота

В шутерах от первого лица камера обычно находится на некотором расстоянии над землей. Это расстояние называется высотой. Действительная z-координата камеры (только в Ultimate 3D) рассчитывается по формуле z+height. Проще говоря, высота - это расстояние на котором находятся глаза (камера) от ног (координата z).

rotx, roty, rotz - вращение x, вращение y, вращение z

Эти переменные задают вращение камеры. Сокращение rotx означает угол наклона(pitch) вверх/вниз, roty - угол поворота(yaw) влево/вправо, rotz - угол крена(roll). Более подробное описание этих переменных дано во второй части статьи "Использование примитивов".

view - вид

Эта переменная определяет вертикальный угол вида камеры. Как и любой другой угол в Ultimate 3D, он должен быть в градусах и может быть дробным числом.

min_range, max_range - минимальная дистанция, максимальная дистанция

Камера будет показывать только те объекты, которые дальше min_range и ближе max_range. Все остальные будут невидимы. Вы должны использовать разумные значения для этих переменных. Если min_range очень мало или max_range очень велико, то может возникнуть ошибка - объекты будут рисоваться поверх тех, которые стоят перед ними.

falling, falling_speed (optional) - режим падения, скорость падения(опционально)

Если падение включено (falling=true), то z координата камеры будет увеличиваться (а с отрицательным значением скорости уменьшатся) на falling_speed каждый шаг. Если включена гравитация (global.gravitation<>0), то falling_speed будет уменьшатся каждый шаг(отрицательная скорость - движение вниз, а положительная вверх).

follow, perspective, distance (optional) - следовать за, перспектива, дистанция(опционально)

follow можно установить на ID объекта Game Maker, за которым будет следовать камера. perspective определяет как камера будет следовать за объектом. Её можно установить на 0 для инерциальной камеры около земли, на 1 для неподвижной камеры или на 2 для полностью подвижной камеры. Если perspective равна 1 или 2, то вы можете изменять rotatex и rotatey.

Пока, это - всё, что вам нужно знать о камере, хотя есть еще несколько переменных и функций для камеры, но они описаны в секции для опытных пользователей.

Теперь вы знаете как создать камеру. Но сейчас вы ничего не увидите (ну если вы уже очистили комнату). Но не волнуйтесь, скоро всё изменится.

Загрузка текстур

Перед тем как мы создадим первый видимый объект, есть еще кое-что, о чем вы должны знать: загрузка текстур. Для тех кто не знает, вот небольшое пояснение что такое текстура: Текстура (обычно) это - двухмерное изображение, которое используется при рисовании 3Д объектов в качестве их внешнего вида. Это изображение можно применить к объекту. Без текстур все объекты Ultimate 3D будут нарисованы только в одном цвете. Вам очень важно иметь подборку качественных текстур. Они позволят вашей игре выглядеть более реалистичней.

Для загрузки текстуры вы должны использовать эту очень простую функцию:

LoadTexture(TextureFile, TextureIndex, Width, Height)

TextureFile - Файл текстуры

Так как Ultimate 3D не имеет доступа к ресурсам Game Maker, то текстуры должны быть сохранены в отдельный файл. Он может быть любого из этих форматов: bmp, jpg, tga, png, dds, ppm или dib (но не gif). Я рекоммендую сохранять текстуры в подпапке (папке в той же директории что и файл проекта) "gfx". Но если вы хотите скрыть текстуры от пользователя, то просто присоедините их к игре, встроенным в Game Maker, механизмом, и загружайте их из временной папки.

TextureIndex - Индекс текстуры

Индекс текстуры - это номер с которым она будет ассоциирована. Он может быть от 0 до 998 включительно. Индекс - это что-то вроде id. Когда вы захотите использовать текстуру позже, то вы должны знать её индекс.

Width, Height - Ширина текстуры(опционально), Высота текстуры(опционально)

Обычно вы просто можете проигнорировать эти два параметра. Если вы введете 0 или ничего(что тоже будет равно 0) для обеих этих переменных, то Ultimate 3D будет использовать оригинальные размеры текстуры, взятые из файла. Но если вы введете значения, которые отличаются от стандартных, то текстура будет растянута(сжата) до этих размеров.

Кое-что важное, что вы должны знать о текстурах. Большинство графических адаптеров (видеокарт) могут работать только с текстурами, чьи размеры кратны двум. Еще есть видеоадаптеры, которые могут работать только с квадратными текстурами, но они очень устаревшие и практически не встречаются. В любом случае, ваша текстура будет растянута(не уменьшена), если её размеры не кратны двум, до ближайшего подходящего значения. Вот пример правильных размеров текстуры: 256*256; 128*512; 1024*64;

Я рекомендую загружать все текстуры в событии создания(create) объекта управления(control). Так, вы получите список всех текстур, вместе с их индексами. Но это на ваше усмотрение. Еще вы должны знать как сделать текстуру прозрачной. Есть два способа. Лучший - это использовать формат текстуры со встроенной поддержкой прозрачности, как tga, png или dds. Gimp (GNU Image Manipulation Program - бесплатный редактор изображений, вроде Photoshop) поддерживает такие форматы. Gimp - это лучший бесплатный редактор изображений с открытым исходным кодом. Если же вы пожелаете использовать другие форматы текстур, то вы всё равно можете получить прозрачную текстуру. Просто используйте в качестве прозрачного(невидимого) цвета, цвет с параметрами: красный=0, зелёный=128, синий=64 (RGB : r=0; g=128; b=64). Все пиксели, которые окрашены в этот цвет будут считаться прозрачными в Ultimate 3D.

Небольшой пример, демонстрирующий как правильно использовать эту функцию:

LoadTexture("gfx/WallTexture.png",1);


Ïðèìèòèâû

Использование примитивов

Использование примитивов

Особенности примитивов(простейшие 3D фигуры - шар, куб, конус, поверхность...) позволяют вам очень быстро создавать простейшие сцены. Кроме того огромное количиство примитивов очень быстро прорисовывается(рендерится). Но вам сейчас не нужно волноваться об этом. Определение объектов в Ultimate 3D работает следующим образом. Как я уже говорил, каждый объект в Ultimate 3D должен быть представлен образцом объекта в Game Maker. Так что, сначала, вы должны создать новый объект, затем вы должны назначить ему переменные. Потом вы должны вызвать функцию, которая передаст переменные в Ultimate 3D и создаст объект. Так что давайте создадим наш первый видимый объект.

Стена

Стена (wall) абсолютно плоская и сориентирована только вертикально. Перед тем как её создать, вы должны установить следующие переменные:

height - высота

Переменная обозначает высоту стены.

x2, y2 - относительные координаты конца стены

Эти две переменные определяют куда направлена стена из своей позиции x и y. На графике показано как это выглядит:

texture - индекс текстуры

Вы должны установить эту переменную равной одному из индексов, с которым вы связали текстуру функцией LoadTexture(). Эта текстура будет использована для стены. Если вы не хотите использовать текстуру, то поставьте значение равным -1.

texx1, texy1, texx2, texy2 (optional) - координаты углов текстуры (опционально)

Эти переменные не обязательны. Если вы не установите эти переменные, то будет использована вся текстура. Координаты текстуры определяют как текстура будет натянута на объект. texx1 и texy1 - это одна координата, а texx2 и texy2 - это другая. Координаты текстуры x=0 и y=0 (для сокращения (0|0)) представляют левый верхний угол текстуры. Координаты (0.5|0.5) - центр текстуры, (0|1) - нижний левый угол текстуры, (1|1) - нижний правый угол текстуры, ну и т.д. Для стены будет использоваться часть текстуры между этими двумя координатами. Координаты текстуры могут быть больше 1, тогда текстура будет уменьшена и вы увидите её плиткой (tiling), т.е. она несколько раз будет повторятся на стене. Взгляните на этот график:

Есть еще две дополнительные переменные, о которых вам сейчас не обязательно знать. Они еще есть у пола (floor) и куба (cube). Подробнее вы можете посмотреть в главе Освещение.

Теперь вы установили все требуемые переменные и можете вызвать функцию CreateWall(). У неё нет никаких параметров. Еще вы можете вставить функцию Step() в событие шага (step) объекта и Destroy() в событие его уничтожения. Все они не имеют никаких параметров. Destroy() должен быть вызван в событии уничтожения, так как Ultimate 3D не знает когда уничтожен объект. Что означает Step() вы узнаете в следующей главе. Так что продолжайте ;)

Трансформация примитивов

Что такое Трансформация? Если вы возьмете некий объект и начнете его перемещать вокруг - это и есть трансформация (изменение). Если вы его вращаете - это тоже транформация. Есть еще один вид трансформации, невозможный в реальной жизни - растяжение (scaling). Растяжение значит изменение размеров объекта. Объект можно растянуть в трех направления. Все эти процессы называются изменением (трансформацией). Так что вы должны запомнить что трансформация - это изменение размера, вращение и перемещение объекта.

А теперь начнем трансформировать примитивы. Вы уже знаете как это делать, потому что вы уже изменяли другой объект (если вы внимательно читали эту справку): камеру. Как вы помните, камера - это объект, каждый примитив имеет переменные x, y, z - координаты, rotx, roty, rotz - углы вращения. Еще у них есть scalx, scaly, scalz - масштаб. В главе о камере, значение переменных rotx, roty, rotz не было подробно описано. Тут более детальное их описание, еще вы узнаете что такое scalx, scaly, scalz.

rotx, roty, rotz - углы вращения

Как я уже говорил в главе о камере, переменная rotx задает наклон (pitch) объекта, roty - угол поворота (yaw) объекта, rotz - угол крена (roll) объекта. Что они означают? Взгляните на этот график.

Увеличение наклона (rotx) повернет перед объекта вниз, уменьшение - вверх. Вращение (roty) повернет объект на лево или на право, без изменения его z-координаты. Ну и наконец крен (rotz), но про него мне особо нечего сказать, крен как крен. Помните что сначала применяется крен объекта, затем наклон и только потом вращение.

Небольшой комментарий: Если вы читали внимательно, то вы могли заметить что roty вращает объект вокруг оси z, когда rotz - вокруг оси y. Вам не нужно об этом беспокоится, просто запомните этот момент.

scalx, scaly, scalz - масштабирование объекта

Принцип масштабирования(scaling) легко понять. Масштабирование равное 1 означает что объект будет иметь свои первоначальные размеры, 2 - что он будет увеличен в два раза, 0.5 - объект уменьшится в два раза. Обычно вы не должны использовать отрицательные значения, но если вы это сделаете, то объект будет растянут наоборот(то что было слева станет справа, сверху - снизу, сзади - спереди). Вы можете растянуть объект в любых из трех направлений. Запомните что масштабирование происходит перед тем как повернуть объект.

Еще вы не должны забывать о том, что каждый объект Ultimate 3D должен вызывать функцию Step() в своем событии шага. Иначе объект не будет обновлять о себе данные и трансформация не возымеет ни какого действия!

Плоскость

Плоскость (или "пол" - floor) абсолютно плоская и находится в горизонтальном положении. Переменные, которые вы должны установить перед созданием плоскости:

width, height - ширина, длина

Ширина(width) представляет собой протяженность плоскости вдоль оси x, а длина(height) - по оси y.

texture - индекс текстуры

Индекс текстуры, используемой объектом или -1 для отключения текстур. Более подробно смотрите в описании про стену, выше.

texx1, texy1, texx2, texy2 (optional) - координаты углов текстуры (опционально)

Часть текстуры, которая будет использована для рисования плоскости. Более подробно смотрите в описании про стену, выше.

Как вы заметили, между полом и стеной не так уж и много отличий. Для пола также существуют две дополнительные переменные, которые мы рассмотрим в главе об источниках освещения. После установки этих переменных вы должны вызвать CreateFloor() для создания плоскости (ведь пол и потолок это же плоскости?). И как обычно используйте Step() и Destroy().

Куб

Куб (cube) состоит из 4-х стен и 2-х полов. В старом демонстрационном примере Ultimate 3D версии 1.31 все здания были обычными кубами. Как и для других примитивов, вы должны установить некоторые переменные, перед тем как создать куб. Вот их список:

width, height, depth2 - ширина, высота, длина

Это размеры куба: ширина (width) это протяженность куба по оси x, высота (depth2) - это протяженность куба по оси y и, наконец, длина (depth2) - это протяженность куба по оси z. Длина называется depth2, потому что переменная depth(глубина, а для куба это длина) уже используется Game Maker.

texx1, texy1, texz1, texx2, texy2, texz2 (optional) - координаты текстуры (опционально)

Это часть текстуры, которая будет использована. Более подробно смотрите в описании про стену, выше. Так как куб объемный(в отличии от стены и пола) то и параметров у него три пары.

texture - индекс текстуры

Индекс текстуры, используемой объектом или -1 для отключения текстур. Более подробно смотрите в описании про стену, выше.

subdivide_texture (optional) - способ наложения текстуры на куб (опционально)

Как всем известно, у куба шесть сторон. Если установить эту переменную на (ложь - false - 0 - выкл), то текстура будет использоваться для всех граней куба, но если переменную установить на 1 (правда - true - 1 - вкл), тогда текстура будет поделена на шесть частей, и каждая из этих частей будет использоваться как текстура для одной из граней куба. На этом рисунке хорошо показан пример:

Когда разделение текстуры выключено, то текстура рисуется на каждой грани куба. А когда включено, то на каждой грани куба рисуется лишь часть текстуры.

originx, originy, originz (optional) - координаты точки привязки(опционально)

Переменные, обычно, принимают значения в пределах от 0 до 1. Они определяют где находится точка привязки (что-то вроде центра куба или как у спрайтов в game Maker). Очень важно ввести правильные значения, особенно когда вы поворачиваете куб. На этом графике всё показано:

После установки всех этих значений, вы должны вызвать функцию CreateCube() для создания куба. Как обычно используйте Step() и Destroy().

Поверхность (Billboard objects)

Слово Billboard переводиться с английского языка как "доска объявлений". Я заменил это понятие на "поверхность", так как billboard представляет собой обычную плоскость наподобие стены. Не стоит путать поверхности Game Maker (surface) с поверхностями в Ultimate 3D (billboard). Поверхности отличаются от остальных 3D объектов. Причина очень проста. Они не трехмерные. Чаще всего поверхности используют для представления сложной геометрии. Например - деревьев. В старых играх вы видели что деревья двумерные, хотя весь мир вокруг объемен. Поверхности - это двумерные объекты в трехмерном мире. Они зафиксированы в одной точке 3D пространства и все время повернуты к экрану единственной стороной.

Создание поверхностей не отличается от создания других примитивов. Переменные, которые вы должны установить:

width, height - ширина, высота

Размеры поверхности.

originx, originy - координаты точки привязки поверхности

Эти переменные определяют координаты точки привязки поверхности. Точка привязки - это точка поверхности, которая не изменяет своего положения, когда вращается камера. Чаще всего её устанавливают где-то в центре поверхности. В принципе это работает также, как и переменные originx, originy, originz для объекта куба. Так что можете взглянуть на их описание.

texture - индекс текстуры

Индекс текстуры, используемой объектом или -1 для отключения текстур. Более подробно смотрите в описании про стену, выше.

texx1, texy1, texx2, texy2 (optional) - координаты текстуры(опционально)

Это часть текстуры, которая будет использована. Более подробно смотрите в описании про стену, выше.

После установки этих переменных, вы должны вызвать функцию Create2D() для создания поверхности. Как обычно используйте Step() и Destroy().

Полигоны

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

Для создания полигонов не нужно вводить никаких переменных. Вы только должны вызвать три функции. Как всегда вам потребуется объект Game Maker для полигона. Первая функция которую вы должны вызвать - это BeginPolygon(). Она скажет Ultimate 3D что вы хотите создать полигон и подготовит всё необходимое для этого. Описание функции:

BeginPolygon(VertexNumber)

VertexNumber - количество вершин

Количество вершин полигона, которое вы хотите создать.

После вызова функции BeginPolygon() вы можете вызывать функцию AddVertex() для создания вершин, столько раз сколько определили в переменной VertexNumber. Здесь описание функции AddVertex():

AddVertex(X, Y, Z, U, V)

X, Y, Z - координаты точки в пространстве

Позиция вершины в трехмерном пространстве. Запомните что реальное положение вершины зависит от этих переменных: координат точки (вершины) x, y, z, размеров масштабирования scalx, scaly, scalz и от углов вращения rotx, roty, rotz. Таким образом вычисляется положение вершины относительно точки привязки своего объекта.

U, V - координаты текстуры

Текстурные координаты точки. Чтобы подробнее узнать об этих переменных, взгляните на описание переменных texx1 и texy1 стены.

Когда вы вызвали все фунции AddVertex() вы можете вызвать функцию CreatePolygon() для создания полигона. Как и любой другой примитив, полигон имеет переменную, отвечающую за индекс текстуры, и переменные трансформации (смотрите описание стены в главе "Изменение примитивов"). Поэтому вам нужно установить функции Step() и Destroy().

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

BeginPolygon(5);

AddVertex(0,0,0,0,1);

AddVertex(0, 0,5, 0,0.33);

AddVertex(0,2.5,7.5,0.5,0.0);

AddVertex(0,5,5,1,0.33);

AddVertex(0,5,0,1,1);

CreatePolygon();

texture=1;

На картинке вы видите результат этой функции:

Изменение полигонов

Изменение полигонов или "Модификация" отличается от трансформации тем, что при трансформации мы всего-лишь перемещаем объект, вращаем, изменяем его в размерах, но он остается тем же самым объектом, с той же самой структурой, только других размеров, в другом месте и под другим углом. А модификация - это изменение структуры самого объекта.

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

Эта функция получает данные о вершине. Её можно вызвать после вызова функции CreatePolygon().

GetVertex(VertexIndex, VertexElement)

VertexIndex - индекс вершины

Этот параметр определяет вершину, о которой вы хотите получить информацию. Вершина, которую первой добавили в полигон, носит индекс 0. Самая последняя: Количество вершин - 1 (VertexCount - 1).

VertexElement - элемент вершины

Этот параметр определяет какого типа информацию вы хотите получить об вершине. Элементы вершины бывают следующими:

0 = X;

1 = Y;

2 = Z;

3 = U;

4 = V

Эта функция изменяет данные вершины в полигоне для которого она вызвана. Её можно вызвать после вызова фукции CreatePolygon().

SetVertex(VertexIndex, X, Y, Z, U, V)

VertexIndex - индекс вершины

Этот параметр определяет вершину, параметры которой вы хотите изменить. Вершина которую первой добавили в полигон носит индекс 0. Самая последняя: Количество вершин - 1 (VertexCount - 1).

X, Y, Z - координаты вершины в пространстве

Это позиция вершины. Более подробно смотрите в описании функции AddVertex().

U, V - координаты текстуры

Текстурные координаты точки. Чтобы подробнее узнать об этих переменных, взгляните на описание переменных texx1 и texy1 стены.

Это всё, что вам нужно, для модификации геометрии полигона. А вот - пример изменения полигона. Если этот код поместить в шаг объекта, то каждый раз третья вершина полигона будет сдвигаться немного вверх.

SetVertex(2, GetVertex(2,0), GetVertex(2,1)+0.1, GetVertex(2,2), GetVertex(2,3), GetVertex(2,4));

Изменение материала примитивов

Это проще простого, изменить материал объекта значит изменить его цвет. Чтобы сделать это, Ultimate 3D предлагает очень простую функцию:

Эта функция изменяет материал примитива для которого она вызвана.

SetMaterial(Red, Green, Blue, Alpha)

Red, Green, Blue - компоненты цвета: Красный, Зелёный, Синий

Эти параметры задают новый цвет. Их значение может меняться в пределах от 0 до 255 включительно с обоих концов. (0|0|0) означает черный цвет и (255|255|255) означает белый.

Alpha - уровень прозрачности

Этот параметр задает уровень прозрачности объекту. Его можно варьировать в пределах от 0 до 255, включительно с обоих концов. 0 означает полную прозрачность, а 255 - полностью не прозрачный объект.

Эта функция изменяет эмиссионную (emissive) часть материала. Эмисионная часть материала не подвержена воздействию освещения, т.е. не затеняется и не освещается. Пример материала на который не влияет освещение - это экран телевизора. Он излучает свет, поэтому независимо от окружающих источников света, он светится.

SetMaterialEmissive(Red, Green, Blue)

Red, Green, Blue - компоненты цвета: Красный, Зелёный, Синий

Цвет, который будет использован для эмиссионной части материала. И снова значения пролегают в пределах от 0 до 255.

Обновление примитивов

Как вы только что узнали, вы можете трансформировать примитивы, после их создания, используя переменные x, y, z, rotx, roty, rotz, scalx, scaly, scalz. То же можно сделать и с текстурой. Всё это можно изменить в любое время. Но как насчет других свойств примитива? Например вы хотите анимировать текстуру, изменяя texx1, texy1, texx2, texy2. Если вы измените эти переменные после создания объекта, то ничего не произойдет - объект не изменится. Для этого существует функция RecreatePrimitive(). Она уничтожает существующий примитив и создает на его месте новый.


Èçìåíåíèå ñðåäû

Изменение среды

Изменение среды

Теперь вы уже умеете создавать сцены с простыми объектами. Но сцена состоит не только из одних объектов. Есть еще много чего, что составляет сцену. Некоторые из них мы сейчас рассмотрим. Эта глава очень легка, ведь Ultimate 3D делает всё автоматически. Вы просто должны сказать чего хотите.

Атмосферное освещение

Атмосферное освещение (Ambient lighting) действует повсюду. Если вы оглядитесь в вашей комнате (там где сидите, а не в комнате Game Maker), то вы не увидите ни единого абсолютно темного места. Даже если что-то не освещено напрямую от источника света, то оно всё равно получает свет. Естественно что все получает свет не только от его источника. Объекты отражают свет, свет рассеивается атмосферой и это как раз и освещает те объекты, что не освещены напрямую источниками света. Но моделирование такой системы освещения потребовало бы огромных ресурсов производительности. По этой причине используется атмосферное освещение.

Атмосферное освещение - это самый простой вид освещения, который можно придумать. Всё освещено с той же интенсивностью и с одинаковым цветом. Поэтому у атмосферного освещения только одно значение цвета. Его можно изменить следующей функцией:

SetAmbient(R, G, B)

R, G, B - компоненты цвета: Красный, Зелёный, Синий

Новый цвет для атмосферного освещения. Значение для этих параметров пролегает в пределах от 0 до 255.

По умолчанию атмосферное освещение имеет серый цвет (128|128|128). Ну а если вы напишите SetAmbient(255,0,0), то всё будет освещено красным цветом. Если вы напишите SetAmbient(0,0,0), то все объекты, у которых не установлен эмиссионный материал, будут абсолютно черными. Изменяя атмосферное освещение вы можете влиять на атмосферу в вашей игре. Вы сможете переключатся между днем и ночью или вы можете создать апокалиптическую атмосферу, используя красный цвет.

Использование трехмерных фонов

Еще важной частью сцены является фоновое изображение. Ultimate 3D использует три разных вида фонов. По умолчанию используется первый вид - однотонный цвет. Цвет фона можно поменять, изменив значение переменных BG_r, BG_g и BG_b контрольного объекта(control). Вы можете изменять их в пределах от 0 до 255.

Второй вид фонов называется "Небесная Сфера" (sky sphere). Для неё вам потребуется одно двумерное изображение. Оно должно быть бесшовным. Это изображение будет использовано как текстура для сферы, которая окружает всю сцену. Минус сферы в том что есть небольшое искажение в вверху, в точке, где сходятся все мередианы. Это ужасно выглядит, но для многих игр игроку не нужно смотреть вверх. Поэтому небесные сферы очень часто используют в играх.

Но как насчет игр, где фон выглядел бы нормально во всех направлениях? Лучшим примеров для этого послужит космический шутер (space shooter). Где верх, где низ, в космосе не имеет значения. Для подобных случаев в Ultimate 3D есть поддержка третьего вида фонов - Небесного Куба (sky cube). Небесный куб состоит не из одного двумерного изображения, а из шести квадратных изображений, наложенных на каждую из граней по отдельности. Как и сфера, куб окружает всю сцену. Создание изображений для небесных кубов более сложное занятие чем создание сферических карт (sphere maps). Но результат и выглядит лучше.

Теперь, когда вы знаете какие типы фонов поддерживаются, давайте перейдем к практике. Есть только одна функция для загрузки фонов:

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

LoadBackground(File)

File - путь к файлу

Вы должны ввести текстовое значение для этого параметра. Если строка содержит только название файла, тогда этот файл будет загружен и использован как текстура для небесной сферы. Если строка будет содержать символ *, то он будет заменен на английские слова "Front", "Back", "Top", "Bottom", "Left" и "Right" ("Спереди", "Сзади", "Сверху", "Снизу", "Слева" и "Справа"). Так что в этом случае Ultimate 3D загрузит шесть разных файлов. Они будут использованы для небесного куба. Сразу же после загрузки текстур будет активирован подходящий тип фона.

Если вам вдруг не захочется использовать фон вы можете вызвать функцию UnloadBackground(). Тогда снова будет использован первый тип фона - однотонный цвет.

Использование тумана

Густой туман очень редок в большинстве частей нашего мира. В компьютерных играх он встречается гораздо чаще. В дождливые дни всё что находится далеко от нас становится серым и выцветшим, а жаркими вечерами приобретает темно-оранжевый оттенок. В большинстве ваших игр вы можете использовать туман (ну это по вашему усмотрению, разумеется). Туман становится все гуще, в зависимости от дальности. Но если вы будете использовать слишком густой туман, луди могут подумать что в вашей игре очень низкая зона видимости. И в большинстве случаев они будут правы - туман меньшее из двух зол. Уж лучше удаленные (от слова даль) объекты будут исчезать в тумане, чем канут в пустоту.

Установка тумана не более сложное занятие, чем установка фона. Есть только одна функция чтобы включить туман и одна чтобы выключить туман. Эта используется для его включения:

SetFog(R, G, B, StartDistance, EndDistance)

R, G, B - компонеты цвета: Красный, Зелёный, Синий

Это цвет тумана. Эти переменные принимают значения от 0 до 255.

StartDistance, EndDistance - начальная дистанция, конечная дистанция

Область для тумана. Всё что ближе к камере чем StartDistance не будет подвержено туману. А всё что дальше EndDistance будет окрашено в цвет тумана и вы это не увидите. Всё что находится между этими двумя переменными будет линейно (linearly interpolate) подвержено затуманиванию.

Если вы захотите отключить туман - просто используйте функцию DisableFog().


Èñïîëüçîâàíèå îñâåùåíèÿ

Использование освещения

Добавление источников света

Атмосферное освещение конечно хорошо, но этого не достаточно. Для действительно живой сцены вам потребуются более динамические источни света, которые не освещают все одним и тем же образом. Именно по этой причине Ultimate 3D поддерживает вершинное освещение (vertex lighting). Оно работает следующим образом. Вы добавляете несколько источников света в сцену. Ultimate 3D теперь будет использовать их для расчета цвета каждой вершины (vertex). Этот цвет будет интерполирован (interpolated) по треугольнику, который связан с этой вершиной. Ultimate 3D также поддерживает по пиксельное освещение (per pixel lighting). Но это уже для опытных пользователей.

Существует три различных вида источников света. Первый из них называется "направленный свет" (directional light). Классический пример направленного света - Солнце. Оно освещает все с одного и того же направления. Не важно где вы находитесь (игнорируя то, что Земля круглая) солнце всё время будет в одном и том же месте на небе. В противоположность направленному свету существует второй вид источников освещения - "точечный свет" (point light). Точечный источник освещения можно сравнить с лампочкой висящей по середине комнаты. Она освещает левую и правую стены, т.к. висит между ними. Но чем дальше от неё объект, тем меньше он освещен. Третий вид источников света называется "частичное освещение" (spot lighting.) (прим. пер. "spot" переводится на русский как "пятно" или как "место", я решил что "частичное освещение" будет лучше чем "пятнистое" или "местное".). Оно очень похоже на точечный свет. Но в отличии от точечного света, частиное освещение не освещает всё вокруг, оно освещает только определенную часть объектов, находящихся в заданном конусе света.

Как и с примитивами, вам потребуется объект для каждого источника света. И опять вам придется установить несколько переменных перед его созданием. После этого вы сможете вызвать функцию для создания источника света, но не забудьте о функциях Step() и Destroy(). А вот и список переменных, которые вы должны установить.

rotx, roty - долгота, широта

Названия этих двух переменных достались нам из старых версий Ultimate 3D так как я(Christoph Peters, а не переводчик) не хочу терять обратную совместимость. Теперь я буду называть их долгота и широта. Они определяют направление направленного света. Чтобы получше узнать о долготе и широте взгляните на их описание в функции Move() в главе "Приступая к работе".

r, g, b - компонеты цвета: Красный, Зелёный, Синий

Эти переменные определяют цвет света источника освещения. Обычно, они принимают значения от 0 до 255. Увеличивая значения этих переменных, вы увеличиваете интенсивность света. Еще вы можете попробовать отрицательные значения, тогда свет будет наоборот - затенять объекты.

Направленный свет не имеет позиции и дальности действия, т.к. они просто не имеют значения. После установки всех этих значений, вы сможете вызвать функцию LightDirectional() для создания источника напрвленного света. И если вы не забудете добавить функцию Step() в событие шага, то вы сможете изменять его параметры. А теперь давайте рассмотрим переменные точечного освещения:

x, y, z - координаты по осям x, y, z

Эти переменные определяют позицию источника света. Чем ближе объекты находятся к этой точке, тем сильнее они освещены.

range - дальность освещения

Дальность освещения точечного источника света. Все что дальше чем значение этой переменной не будет освещено. Чем больше радиус действия, тем интенсивней свет.

r, g, b - компоненты цвета: Красный, Зелёный, Синий

Эти переменные определяют цвет света источника освещения. Обычно, они принимают значения от 0 до 255. Увеличивая значения этих переменных, вы увеличиваете интенсивность света. Еще вы можете попробовать отрицательные значения, тогда свет будет наоборот - затенять объекты.

После установки всех этих переменных, вы можете вызвать функцию LightPoint() для создания точечного источника света. И снова: если вы не забудете добавить функцию Step() в событие шага, то вы сможете изменять его параметры.

Давайте перейдем к последнему типу освещения, к частичному освещению. Оно более сложно и требует больше времени компьютера для обработки. Вот эти переменные:

x, y, z - координаты по осям x, y, z

Эти переменные определяют позицию источника света. Чем ближе объекты находятся к этой точке, тем сильнее они освещены.

range - дальность освещения

Дальность освещения точечного источника света. Все что дальше чем значение этой переменной не будет освещено. Чем больше радиус действия, тем интенсивней свет.

rotx, roty - долгота, широта

Эти две переменные задают направление для частичного освещения. rotx - это долгота, а roty - это широта.

deg - угол зоны освещения

Она определяет угол освещения. Если вершина находится вне зоны действия частичного освещения, то она не освещена. Другими словами, она определяет насколько широкой будет область освещения. Хороший пример для этого - фонарик.

r, g, b - компонеты цвета: Красный, Зелёный, Синий

Эти переменные определяют цвет света источника освещения. Обычно, они принимают значения от 0 до 255. Увеличивая значения этих переменных, вы увеличиваете интенсивность света. Еще вы можете попробовать отрицательные значения, тогда свет будет наоборот - затенять объекты.

После установки всех этих переменных, вы можете вызвать функцию LightSpot() для создания точечного источника света. И снова: если вы не забудете добавить функцию Step() в событие шага, то вы сможете изменять его параметры.

Детализация примитивов

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

partsx, partsy, (partsz) - уровень детализации примитивов по осям x, y, z

Эти переменные могут быть использованы, чтобы детализировать ("подразделить") примитивы. partz взято в скобки, т.к. оно нужно только для кубов. Естественно, что у полигонов нет этих переменных. Подразделяя примитивы, вы, тем самым, увеличиваете количество вершин. Так что подразделенный примитив будет более детально выглядеть и соответственно лучше освещен (только вершинным освещением). Переменные можно установить в любое целое положительное значение (integer). Но не переусердствуйте! Вы можете очень резко сократить ваш FPS (кадры в секунду).


Èñïîëüçîâàíèå ìîäåëåé

Использование моделей

Использование 3D моделей

Если ранее вы пользовались только встроенными в Game Maker 3D функциями, то эта возможность поразит вас. В Game Maker очень трудно загрузить 3D модель. А в Ultimate 3D вы просто должны вызвать одну функцию. Вы можете загружать модели следующих форматов: анимированные *.an8 с поддержкой скелетной анимации и скинингом, анимированные *.3ds, анимированные *.md2, анимированные *.x с поддержкой скелетной анимации и вершинного скинига (vertex skinning), анимированные *.ms3d с поддержкой вершинного скининга.

Если у вас нет никакого опыта 3D моделлера, то я (Christoph Peters) бы порекомендовал начать с изучения программы Anim8or от Стивина Гланвилля (Steven Glanville), посетив оффициальный веб-сайт программы www.Anim8or.com. Это очень дружественная для пользователя программа, с помощью которой можно создавать замечательные 3D модели. Также при помощи Anim8or можно легко создавать качественную скелетную анимацию. Anim8or использует собственный формат моделей *.an8. Если вам нужна более профессиональная программа для моделирования, то я советую попробовать Blender с сайта www.blender.org. Начинать с него очень сложно, но на сайте есть очень хорошие статьи и руководства. Как только вы научитесь им пользоваться, Blender вам понравится. Он может экспортировать в большинство самых распространенных форматов моделей. На форуме сообщества Ultimate 3D (Ultimate 3D Community) есть топик, в подкатегории "Игровая графика" (Game graphics), где написан список программ для моделирования и всего что вам может потребоваться для создания 3D игры.

Различия форматов

У каждого поддерживаемого Ultimate 3D формата моделей есть свои плюсы и минусы. Тут вы сможете прочитать про индивидуальные спецификации каждого из форматов.

*.3ds - файловый формат моделей 3D Studio Max (3DS MAX)

Этот формат поддерживается множеством программ для моделирования. Хотя этот формат и появился в 3DS MAX, но по неизвестной причине он стал популярен и его поддерживает множество программ. *.3ds поддерживает скелетную анимацию. Но существует очень мало некоммерческих программ для экспорта моделей с поддержкой скелетной анимации в формат *.3ds. Несмотря на то что он довольно распространен, *.3ds немного устарел - он не поддерживает вершинный скининг (vertex skinning), который является очень важной частью современной анимации персонажей.

*.an8 - файловый формат моделей Anim8or

Большой минус этого формата - это то, что его поддерживает лишь одна программа Anim8or. Но зато он поддерживает скелетную анимацию. Поэтому Anim8or можно использовать для создания анимированных моделей для Ultimate 3D.

*.md2 - файловый формат моделей Quake II

Этот формат использовался движком игры Quake II (Quake II Engine) для хранения моделей игроков. Он использовал совершенно другой метод анимации. Он прикреплял отдельные мешы (mesh - замкнутый контур, часть модели, состоящая из одного объекта) к так называемым "костям" и сохранял трансформацию этих костей (эта техника называется скелетной анимацией). В Ultimate 3D версии 1.31 вы получали скачкообразную анимацию *.md2, т.к. в модели не хватало кадров. Ultimate 3D версии 2.0 использует технику, названной "vertex tweening" для интерполяции между одиночными кадрами *.md2. Так вы получите сглаженную анимацию. Минус этого формата - это то что он использует больше памяти чем другие форматы и его анимацией нельзя манипулировать. К плюсам *.md2 можно отнести то что в сети Internet можно найти тысячи моделей этого формата.

*.x - файловый формат моделей DirectX

Этот формат довольно старый, но он очень удобный и большинство профессиональных программ для моделирования, как Blender, 3D Studio Max, Maya, Milkshape 3D и множество других поддерживают его изначально или через плагины. Многие из этих плагинов можно найти на этом сайте. Он поддерживает скелетную анимацию с или без вершинного скинига (vertex skinning), материалы и все что только Гэймдевелопер может представить.

*.ms3d - файловый формат моделей Milkshape 3D

Он поддерживает несколько материалов одновременно и анимацию с или без вершинного скинига (vertex skinning). есть множество плагинов для экспорта в него из других программ. Если у вас есть проблемы с экспортом *.x моделей (например плагин для 3ds Max "Panda DirectX Exporter" немного не так как надо экспортирует в этот формат) вы можете использовать этот формат.

*.u3d - формат данных Ultimate 3D

Сейчас только Ultimate 3D может экспортировать и импортировать его. На это есть несколько причин. Первая это то что Ultimate 3D может сохранить объект модели как он есть. Все эффекты и изменения что вы применили к модели будут сохранены. Когда вы будете читать часть для опытных пользователей, то вы поймете насколько это удобно. Для примера посмотрите в демонстрации "Огонь и вода" (Fire and Water Demo). Для создания этих эффектов требуется очень много кода, но вы просто можете загрузить их из *.u3d файла. Вы также можете сохранять данные, которые требуют некоторое время на обработку при их создании, например уровни детализации. В этот формат вы можете экспортировать все текстуры и эффекты, используемые Ultimate 3D, так вы сможете скрыть свои ресурсы. Также этот формат поддерживает защиту паролем и криптоалгоритмами. Экспорт моделей в этот формат будет подробно рассмотрен в главе "Дополнительный менеджмент моделей".

Комментарий: Если вы хотите добавить поддержку формата Ultimate 3D в вашу программу для моделирования, то свяжитесь со мной (Christoph Peters). Я не стану описывать тут спецификацию этого формата, так как это займет много места и времени.

Загрузка моделей

Как я уже говорил вам нужна всего-лишь одна простая функция для загрузки моделей. Но каждая модель требует свой объект Game Maker и предустановку некоторых переменных:

file - файл модели

Это путь к файлу модели, можно относительный. Я рекомендую поместить все модели в подпапку "models", но это на ваше усмотрение.

password (optional) - пароль (опционально)

Если вы загружаете зашифрованный файл Ultimate 3D, то вы должны использовать эту переменную как пароль. В остальных же случаях она вам не нужна.

После установки этих переменных, вы можете вызвать LoadMesh() для загрузки и создания модели. Название этой функции уходит своими корнями к ранним версиям Ultimate 3D. Они поддерживали только *.x формат моделей, содержащий только один объект (single mesh). Вы можете трансформировать модели также как и примитивы (используя переменные x, y, z, scalx, scaly, scalz, rotx, roty, rotz), поместив Step() в шаг объекта и Destroy() в событие его уничтожения.

Вот еще несколько переменных для анимации:

frame - кадр

Если значение этой переменной положительно, то анимация будет установлена на этот кадр. Если значение отрицательное, то оно будет использоваться как скорость анимации. Так что если вы установите его на -1, то каждый шаг будет использоваться новый кадр. Стоит отметить что индексация кадров начинается с нуля, то есть первый кадр имеет индекс не 1, а 0.

first_frame, last_frame - первый кадр, последний кадр

Эти две переменные представляют область кадров для циклического воспроизведения. Если первый кадр больше чем последний кадр, то анимация будет проигрываться задом наперед.

Чтобы узнать какой кадр анимации сейчас используется, вы можете вызвать функцию GetCurrentFrame(). У неё нет параметров и она возвращает значение отображаемого сейчас кадра модели, для которой она вызвана. Для моделей *.md2 вам потребуется еще одна переменная, известная по главе "Примитивы". Так как *.md2 не содержит информации о текстуре, то вам придется установить её вручную, используя индекс текстуры, загруженной функцией LoadTexture().


2D Ãðàôèêà

2D Графика

Рисование 2D графики

Так как Game Maker не может рисовать в виде Ultimate 3D, вы должны будете использовать функции Ultimate 3D, если хотите нарисовать что-нибудь двухмерное. Ultimate 3D предлагает вам две функции для рисования текстур и четыре для текста. Давайте начнем с той, которая рисует текстуру на экране:

DrawTex(TextureIndex, X, Y, Scaling, Rotation, Transparency)

TextureIndex - индекс текстуры

Этот параметр определяет индекс текстуры, которую следует нарисовать. Индеск текстуры вы вводите при загрузки текстур функцией LoadTexture()

X, Y - координаты текстуры на экране

Позиция, где будет нарисована текстура(относительно левого верхнего угла первого вида).

Scaling - размер текстуры

Размер текстуры. 1 означает без изменений(100%), 0.5 означает что текстуру уменьшат в два раза(50%), а 2 означает что текстуру увеличат в два раза(200%).

Rotation - вращение

Этот параметр можно использовать для вращения текстуры против часовой стрелки. Если 0, то текстура не повернута.

Transparency - уровень прозрачности

Этот параметр определяет уровень прозрачности текстуры. Он принимает целые значения от 0 (полностью прозрачный) до 255 (непрозрачный).

Если эта функция не удовлетворяет вашим требованиям, то вам нужна вторая функция для рисования текстур. Она похожа на предыдущую, но позволяет настроить больше параметров.

DrawTexEx(TextureIndex, Left, Top, Width, Height, X, Y, ScalingX, ScalingY, Rotation, R, G, B, A)

Left, Top, Width, Height - область для рисования

Эти параметры определяют область текстуры для рисования. Значения должны пролегать в промежутки от 0 до 1. Это текстурные координаты. Верхняя левая координата задается параметрами Left и Top а нижняя Left+Width и Top+Height.

ScalingX, ScalingY - масштаб текстуры

Масштаб текстуры для рисования. 1 означает без изменений(100%), 0.5 означает что текстуру уменьшат в два раза(50%), а 2 означает что текстуру увеличат в два раза(200%).

R, G, B, A - компоненты цветового смешивания

Эти параметры задают цвет, который будет использован как "материал" для рисования текстуры и смешивания её с фоном. Значения должны быть в пределах от 0 до 255. За уровень прозрачности отвечает параметр "A" - Он принимает целые значения от 0 (полностью прозрачный) до 255 (непрозрачный).

Это всё что вам нужно знать для рисования текстур. Рисование текста также легко. Сначала вы устанавливаете шрифт, затем используете его для рисования. Для установки шрифта вы должны использовать эту функцию:

SetFont(FontName, FontIndex, TextSize, TextAttributes, R, G, B, A)

FontName - название шрифта

Название файла шрифта в папке шрифтов Windows (по умолчанию "c:\windows\fonts"). Например "Arial" или "Times New Roman".

FontIndex - индекс шрифта

Это индекс с которым вы ассоциируете шрифт. Работает это также как и индексы текстур. Наибольший индекс для шрифта это 99, т.е. у вас может быть не более ста шрифтов (от 0 до 99).

TextSize - размер шрифта

Размер текста, такой какой вы видите в офисных программах (Блокнот, MS Word, Open Office)

TextAttributes - атрибуты текста

Это атрибуты текста.

0 - обычный шрифт

1 - Жирный (Bold)

2 - Курсив (Italic)

3 - Жирный наклонный (Bold+Italic).

R, G, B, A - компоненты цветового смешивания

Эти параметры задают цвет, который будет использован как "материал" для рисования текстуры и смешивания её с фоном. Значения должны быть в пределах от 0 до 255. За уровень прозрачности отвечает параметр "A" - Он принимает целые значения от 0 (полностью прозрачный) до 255 (непрозрачный).

Вызов этой функции потребует некоторое время на обработку. Поэтому я рекомендую загружать шрифты в событии создания контрольного (control) объекта. Если вы просто хотите изменить цвет шрифта, то нет проблем. Вы просто должны использовать эту функцию:

SetFontColor(FontIndex, R, G, B, A)

FontIndex - индекс шрифта

Индекс шрифта, цвет которого в хотите изменить.

R, G, B, A - компоненты цвета

Новый цвет шрифта.

После того как вы создали шрифт, вы сможете использовать его для рисования. Есть два различных способа рисовать текст. Вы можете рисовать обычный 2D текст на экране или внутри 3D сцены. Начнем с простейшей, с рисования текста в 2D:

DrawText(FontIndex, X, Y, Text)

FontIndex - индекс шрифта

Индекс шрифта, с помощью которого будет нарисован текст.

X, Y - координаты

Позиция текста, относительно Верхнего Левого угла Первого (0) Вида Game Maker.

Text - текст

Строка, содержащая текст для рисования.

Рисование 3D текста немного сложнее. Вы вводите трансформацию текста и его координаты.

DrawText3D(Text,FontIndex, X, Y, Z, RotX, RotY, RotZ, ScalX, ScalY, ScalZ)

Text - текст

Строка, содержащая текст для рисования.

FontIndex - индекс шрифта

Индекс шрифта, с помощью которого будет нарисован текст.

X, Y, Z, RotX, RotY, RotZ, ScalX, ScalY, ScalZ - параметры трансформации текста

Трансформация 3D текста. Чтобы больше узнать о значении этих переменных взгляните на вторую часть главы "Примитивы"


Äîïîëíèòåëüíûå ôóíêöèè

Дополнительные функции

Дополнительные функции

Несколько функций Ultimate 3D не попало ни в одну главу. Поэтому Christoph Peters занес их в эту.

Эта функция делает тоже что и функция Game Maker "mouse_check_button", так как эта функция Game Maker не может работать с Ultimate 3D.

MouseCheckButton(MouseButton)

MouseButton - Кнопка мыши

Этот параметр может принимать значения констант Game Maker mb_left, mb_right, mb_middle и mb_none.

Так как Ultimate 3D можно использовать и с Game Maker 5.0, который не имеет функции mouse_set_screen_position() для установки координат курсора мыши на экране, то Ultimate 3D предлагает свою аналогичную функцию.

Эта функция устанавливает переменные global.mouse_x и global.mouse_y на значение координат курсора мыши на экране:

GetMousePos()

Эту функцию можно использовать для установки координат курсора мыши на экране.

SetMousePos(X, Y)

X, Y - координаты курсора

Новая позиция курсора на экране.

Кроме функций для работы с мышью, есть еще две для снятия скриншотов. Они очень легки в использовании.

TakeScreenshot(BMPFile)

BMPFile - название файла для сохранения скриншота в формате bmp

Строка оканчивающаяся на "*.bmp". Определяет куда будет сохранен снимок экрана.

Вторая функция позволяет вам определить часть экрана для сохранения.

TakeScreenshotEx(BMPFile, Unused, Left, Top, Right, Bottom)

Unused - параметр не используется, установите на любое значение, лучше на 0

Просто проигнорируйте его. Этот параметр использовался в старых версиях Ultimate 3D, но теперь не используется и остался для совместимости.

Left, Top, Right, Bottom - область для сохранения

Эти параметры определяют область экрана для сохранения скриншота. Значения относительны к Левому Верхнему углу Первого Вида Game Maker.


Äëÿ îïûòíûõ ïîëüçîâàòåëåé

Для опытных пользователей

Новые функции

Возможности о которых вы узнаете в этой части поразят ваше воображение. С уже изученными функциями вы могли создать хорошую игру, но графика не была бы чемто выдающимся. У вас могли возникнуть проблемы с низким FPS (количество кадров в секунду), если вы не знаете о способах оптимизации. С новыми технологиями, описанными в этой части, вы сможете создавать потрясающую графику и гигантские уровни. Но вы не должны сразу переходить к этой части, если еще не прочитали часть "Для новичка". Она содержит основные понятия об объектах Ultimate 3D, принципах работы, нужных для использования дополнительных возможностей Ultimate 3D.

Некоторые из вещей, о которые вы узнаете в следующих главах проще чем вы себе их представляете (например Parallax и Bump Mapping), когда другие являются очень сложными для понимания (например: использование Шейдеров). Но вы легко сможете использовать функции для работы с ними. Большинство работы за вас сделает Ultimate 3D, вы просто должны сказать что вы хотите. Желаю успехов в изучении ;)


Ìåíåäæìåíò ìîäåëåé

Менеджмент моделей

Управление моделями

Когда вы поработаете с Ultimate 3D, вы поймете всю значимость моделей. В отличии от примитивов, модели могут быть любых форм. Но прорисовка моделей занимает больше времени а модели с большим количеством полигонов могут заметно снизить производительность ваших игр. Эта статья познакомит вас с приёмами, которые позволят более эффективно использовать модели.

Управление файлами моделей

Иногда нужно чтобы объект в вашей игре, который не существует в начале игры, был создан во время игры. Если этот объект загрузить в тот момент когда он потребуется, то это может вызвать небольшую задержку. Модели форматов *.md2 и *.an8 требуют особенно много времени на загрузку. Именно поэтому вы можете подгрузить (preload) модель использую эту функцию:

PreloadMesh(File, Password)

File - путь к файлу

Файл который вы хотите подгрузить.

Password - пароль (опционально)

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

Как только вы вызвали эту функцию для модели, создание объекта модели из неё не займет много времени. Так вы сможете избежать задержек (лагов - lag). Когда вы загружаете модель при помощи LoadMesh() и уничтожаете его после этого, то вы получаете такой же эффект. Ultimate 3D никогда не загрузит одну и туже модель дважды, потому что Ultimate 3D сохраняет информацию о модели в памяти, даже если основной объект для этой модели уничтожен. Это позволяет избежать продолжительных загрузок ресурсов. Естественно это не всегда удобно. Когда вы перейдете на следующий уровень у вас останутся загруженными в память модели из первого, даже если некоторые из них вам уже не нужны. Поэтому Ultimate 3D позволяет вам освобождать память занимаемую моделями.

Эта функция освобождает память занятую выбранной моделью, так что она больше не будет находится в памяти. Функция возвращает true (1 - правда) в случае успеха и false (0 - ложь) в случае неудачи. Если остается хотя бы один объект с этой моделью, то модель не будет удалена из памяти для избежания ошибок. Тогда то функция и вернет false.

ReleaseModel(File)

File - путь к файлу

Файл модели, который вы хотите удалить из памяти.

Экспорт данных в файлы формата *.u3d

Это проще простого. Есть только одна функция для экспорта объектов моделей в файловый формат Ultimate 3D и у неё всего три параметра.

Эта функция экспортирует модель объекта для которого она вызвана. В результате в файле Ultimate 3D будет содержаться модель в том состоянии, в котором она была при экспорте (вызове функции экспорта).

ExportToU3DFile(OutputFile, Password, ExportResources)

OutputFile - получаемый файл

Эта переменная определяет файл в который будет сохранена модель в случае успеха.

Password - пароль

Пароль, который будет использован для шифрования моделей в формате Ultimate 3D. Если ввести пустую строку или ноль, то файл не будет зашифрован. Чем длиннее пароль, тем более защищены ваши файлы и тем больше времени нужно для их расшифровки.

ExportResources - экспортировать ресурсы

Этот параметр принимает два значения: true (1 - да) и false (0 - нет). Если вы введете 0, то будет сохранена только модель. Потом её можно будет загружать из файлов, как обычно. Всегда будет экспортирован файл *.ufx - файл настроек спецэффектов модели. Если вы поставите true, то будут экспортированы все необходимые текстуры и шейдеры. Помните что модели, которые используют текстуру, получаемую от камеры (render target texture) в качестве одного из материалов, то вам не удастся экспортировать её ресурсы.

Естественно нет никаких гарантий что система шифрования Ultimate 3D сохранит ваши модели в безопастности от взломщиков - взломать можно всё! Возможно, когда-нибудь, найдется специалист, который сможет её вскрыть и расшифровать. Но всё равно защита шифрованием позволит вам скрыть ресурсы от других недобросовестных геймдевелоперов или хакеров. Только у меня (Christoph Peters) есть код для расшифровки, и даже я (Christoph Peters) не смогу расшифровать зашифрованный файл без верного пароля.

Создание уровней детализации (LOD - Levels Of Detail)

Модели могут состоять из множества полигонов. Их качество напрямую зависит от количества треугольников (треугольник - это полигон, многоугольник, только с которыми умеют работать видеокарты). Но если в модели содержится очень много полигонов, то производительность вашей игры заметно упадет и вы получите очень низкое количество кадров прорисовки экрана в секунду (FPS). Поэтому очень важно использовать столько полигонов сколько нужно для комфортной работы игры. Обычно полностью детализированные модели вам не нужны на далеких расстояниях от камеры - ведь там ничего особенного то и не разглядеть. Если объект находится далеко от камеры его детализация может быть уменьшена. Эта техника известна как LoD/LOD (Уровень Детализации). Ultimate 3D может автоматически создавать уровни детализации объектов и использовать их на заданном расстоянии от камеры. Следующее изображение показывает пример модели, которая использует LOD, с уровнями детализации автоматически сгенерированными в Ultimate 3D.

Различия между первой и второй моделью незаметны, но количество треугольников сократилось на 40%. А третья версия модели (LOD 2) сократила количество треугольников на 70%. Обычно очертания модели остаются неизменными. Для очень больших расстояний LOD очень подходит, особенно для игр с высококачественной графикой. Использовать уровни детализации очень легко. Вы просто вызываете одну функцию в которой вы говорите Ultimate 3D сколько уровней детализации вам нужно и на какой дистанции они будут использоваться.

Эта функция создает Уровни Детализации с заданным процентом полигонов от количества полигонов основной модели и назначает их для использования на определенном расстоянии от камеры:

CreateLODChain

(

CameraDistance1, LoD1,

CameraDistance2, LoD2,

CameraDistance3, LoD3,

CameraDistance4, LoD4,

CameraDistance5, LoD5

)

LoD1, LoD2, LoD3, LoD4, LoD5 - уровни детализации

Уровни детализации который будут созданы. Это процентное значение, так 100 означает что уровень детализации равен 100% а 0 что будет создано минимально возможное количество полигонов(три полигона). Параметры должны подчинятся этому условию LOD1>LOD2>=LOD3>=LOD4>=LOD5, если один из этих параметров равен нулю, то Ultimate 3D прекратит дальнейшее создание Уровней Детализации для этой модели.

CameraDistance1, CameraDistance2, ..., CameraDistance5 - дистанция от объекта до камеры

Дистанция от объекта до камеры на которой будет рисоваться LOD. Нормальный уровень детализации (100%) используется для рисования модели на дистанции от 0 до CameraDistance1, LOD 1 для дистанции от CameraDistance1 до CameraDistance2 и т.д.

Использование LOD может очень сильно увеличить кол-во кадров прорисовки сцены в секунду (FPS - Frame Per Second). Но они требую дополнительной памяти и некоторого времени на обработку при создании. Запомните что вы не должны создавать LOD для моделей формата *.md2. Их создание для каждого из кадров может занять несколько минут. А вот вам и пример как создавать уровни детализации. Этот код должен использоваться в конце события создания объекта, после загрузки модели:

CreateLODChain(100,70,500,40,1000,20);

Создание анимации из множества файлов модели

Если вы захотите, то вы сможете создавать анимацию из нескольких файлов с одиночными кадрами модели, даже если форматы этих моделей поддерживают скелетную анимацию (*.3ds, *.x, *.an8) или нет (*.md2). Чтобы создать её вам нужно добавить каждый кадр просто вызвав эту функцию после создания модели функцией LoadMesh():

AddFrame(File, Password)

File - файл

Файл содержащий добавляемый кадр.

Password - пароль

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

По-видимому вам потребуется большое количество кадров для создания плавной анимации, но вы можете использовать технику "Вершинное Смещение" (Vertex Tweening) для автоматического смещения вершин между кадрами анимации. Она будет работать только в том случае, если количество мешей (замкнутых контуров в модели), вершин и треугольников будет во всех моделях одинаковым. Функция, которая включает вершинное смещение(vertex tweening) называется EnableVertexTweening() и она не имеет параметров.

Создание примитивов из моделей

Как я уже говорил в главе о примитивах, примитивы очень быстро прорисовываются. Все примитивы, которые используют один и тот же материал и одну и ту же текстуру прорисовываются однообразно. Поэтому видеокарты могут обрабатывать их более эффективно. В играх очень часто встречаются модели, состоящие из примитивов, но таковыми не являющиеся (например, стол, состоит из 5 кубов - 4 опоры и 1 поверхность самого стола). Так что использование её как модель будет менее эффективным чем как примитив. Для преобразования модели в примитив в Ultimate 3D существует функция. Но перед её использованием вы должны установить эти переменные:

file - файл

Файл, содержащий модель, которую вы хотите преобразовать в примитив.

material - материал

Индекс материала модели, который будет использован для примитива.

После установки этих переменных вы можете вызвать функцию для создания из модели примитива CreatePrimitiveFromModel(). Как и для всех примитивов не забудьте установить в событиях шага и уничтожения вызов функций Step() и Destroy(). Примитивам, созданным из моделей нужно еще назначить текстуру. Запомните что только первый mesh (замкнутый контур) модели будет использован для создания примитива. В таком случае очень удобно использовать формат *.an8, т.к. когда Ultimate 3D загружает модели этого формата, то создает только один mesh на объект.


Ìàòåðèàëû è ñïåöýôôåêòû

Материалы и спецэффекты

Материалы и специальные эффекты

Материалы моделей могут заметно отличатся друг от друга в Ultimate 3D. Каждый материал может использовать свою комбинацию как текстур, так и шейдерных эффектов. Вся система шейдеров Ultimate 3D привязана к системе материалов. Использовать шейдерные эффекты значит установить свойства материала. Но создание шейдеров не тема для этой главы. В этой главе вы узнаете об основных спец. эффектах. Еще вы узнаете о двух замечательных спец. эффектах: Карте окружения(Environment mapping) и параллаксном смещении (Parallax mapping).

Загрузка и создание специальных текстур

Существуют не только 2D текстуры, о которых вы узнали из предыдущих частей. Сейчас мы рассмотрим еще два типа текстур. Первый тип - это карта высот (height map). Карта высот - это изображение окрашенное в серые цвета (от белого до черного), несущее информацию о высоте. Чем белее цвет тем больше высота точки а чем цвет темней, тем ниже. Вам очень важно понять что это такое, так как карта высот может понадобиться вам при использовании многих эффектов. Для того чтобы вы лучше поняли, я покажу вам пример.

Взгляните на эти текстуры. На них изображена обычная кирпичная кладка. Изображение слева цветное и будет использоваться для диффузного освещения (обычное освещение), оно еще называется диффузной картой (diffuse map). Справа вы видите карту высот.

Посмотрите что полости между камнями окрашены в темные цвета на карте высот - они ниже чем камни. Кирпичи же наоборот окрашены в светлые цвета, потому что они выше. Но некоторые кирпичи вдавлены в кладку, их цвет темнее чем у остальных.

Так зачем же нужны карты высот? Они очень полезны, так как их можно использовать для хранения информации о поверхности объекта. Так вы сможете симулировать объемность плоской поверхности, что позволит вашим играм выглядеть более реалистично без увеличения количества полигонов. Они используются для по пиксельного освещения и виртуального смещения (parallax mapping - Virtual Displacement Mapping). Но одна по себе карта высот для этих эффектов бесполезна. Вам нужна будет еще и карта нормалей (normal map). Но не стоит о ней беспокоится. Ultimate 3D сделает её для вас. Вы просто должны будете воспользоваться другой функцией для загрузки карты высот:

Эта функция загружает карту высот из заданного файла и создает для неё карту нормалей. Копия карты высот сохранится в альфа-канал(канал прозрачности) результирующей текстуры(цветовые каналы RGB будут заняты картой нормалей).

LoadHeightMap(TextureIndex, HeightMapFile, HeightFactor)

TextureIndex - индекс текстуры

Индекс, с которым будет ассоциирована текстура. Вы должны помнить этот параметр из описания функции LoadTexture().

HeightMapFile - файл карты высот

Название файла карты высот (включая путь и расширение)

HeightFactor - фактор высоты

Это новый для вас параметр. Когда Ultimate 3D рассчитывает карту нормалей, то нужно знать как высота относится к ширине и высоте текстуры. Одно могу сказать, это определяет значение белого цвета на карте высот. 16 - отличное значение для этого параметра.

А вот и второй тип текстуры, о котором, вы, пока не знаете. Он немного не обычный. Поначалу, вы не будете знать что с ним делать, но потом это изменится. Этот тип текстур называется "Кубическая карта" (cube map). Текстура состоит не просто из 2D изображения, а из шести квадратных изображений. В принципе, это работает также как и небесные кубы (sky cube). У вас есть шесть изображений собранных вместе для формирования куба. Поэтому вам придется использовать не двумерные текстурные координаты, а трехмерные. Вы увидите это позже, а так же узнаете для чего они нужны. Загрузка кубических карт (cube map) похожа на загрузку небесных кубов (sky cube). Есть только одна функция чтобы сделать это и ей нужна только одна строка для загрузки всех шести файлов:

Эта функция создает кубическую текстуру из шести файлов и ассоциирует её с заданным индексом.

LoadCubeTexture(FileScheme, TextureIndex, CubeWidth)

FileScheme - шаблон имени файла

Эта строка должна содержать символ звездочки *. Он будет заменен на слова "Left", "Right", "Top", "Bottom", "Front" и "Back" ("Слева", "Справа", "Сверху", "Снизу", "Спереди" и "Сзади"). Так что если вы напишите "gfx\CubeMap*.png", то Ultimate 3D загрузит файлы с именами "CubeMapLeft.png", "CubeMapRight.png", "CubeMapTop.png" и т.д.

TextureIndex - индекс текстуры

Индекс, с которым будет ассоциирована текстура. Вы должны помнить этот параметр из описания функции LoadTexture().

CubeWidth - ширина куба

Размер до которого будет растянута текстура, если она уже не имеет этот размер. Этот параметр должен быть степенью двойки (2^X => 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, ...).

Текстуры занимают много памяти, так что это не очень хорошо держать много текстур загруженными в память. Для того чтобы освободить память, вы можете удалить некоторые текстуры функцией ReleaseTexture(). Она удаляет текстуры из памяти и устанавливает индекс, с которым была ассоциирована текстура, в начальное состояние. Вот её описание:

ReleaseTexture(TextureIndex)

TextureIndex - индекс текстуры

Индекс текстуры, который вы хотите освободить, удалив связанную с ним текстуру.

Запомните что кубические текстуры (cube texture) не поддерживаются некоторыми очень старыми видеокартами. Для того чтобы узнать поддерживает ли видиокарта кубические текстуры нужно вызвать функцию GetCubeMapSupport(), которая вернет true (1 - да) если кубические карты поддерживаются или false (0 - нет) если нет.

Индексы материалов

Множество функций требует аргумент названный MaterialIndex (Индекс материала). Я объясню что это значит сейчас дабы избежать бесконечных повторений. Как вы уже знаете из вашего опыта моделирования, модели могут использовать различные материалы для различных поверхностей модели. Большинство программ для моделирования позволяют вам задавать имена для материалов. Это очень полезно, потому что если вы не используете программы для моделирования, то вам придется угадывать индекс материала. Я рекомендую вам давать имена для материалов. Называйте их не просто material01, material02 и т. д., а уникально - grass, ground, sky и т.п. Это поможет вам проще их использовать.

Файлы моделей в формате *.an8 и *.3ds содержат информацию о названиях материалов. Файлы моделей формата *.md2 содержит только один материал, который всегда называется "material_md2". Файлы моделей формата *.x не содержат названия материалов. Их материалы называются "materialXX", где "XX" это номер материала, например метериалы в этом формате могут называться от "material01" до "materialXX". Плюс в использовании названий материалов такой, что вам не нужно заботится об индексе материала, когда вы знаете его название, вы просто можете вызвать функцию для его получения:

Эта функция возвращает индекс материала с заданным именем или же индекс первого материала (0) если материал с таким именем не существует. Функция не чувствительна к регистру.

GetMaterialIndex(MaterialName)

MaterialName - название материала

Название материала, чей индекс вы хотите получить.

Иногда вам может понадобится сделать что-нибудь со всеми материалами модели. Для этого, вы можете выполнить нужные действия в цикле. Чтобы получить количество материалов модели вы можете использовать функцию GetMaterialCount().

Изменение цвета материала

Как и для примитивов, вы можете изменить цвет материала моделей когда захотите. Для этого есть две функции: одна чтобы установить диффузный цвет а другая эмиссионный. Вот она:

Эта функция изменяет цвет диффузии заданного материала модели.

SetModelMaterial(MaterialIndex, R, G, B, A)

MaterialIndex - индекс материала

Индекс материала, для которого вы хотите изменить цвет диффузии.

R, G, B, A - компоненты цвета

Новый цвет диффузии материала. Значения для этих параметров должны быть в пределах от 0 до 255.

Эта функция изменяет цвет эмиссии заданного материала модели.

SetModelMaterialEmissive(MaterialIndex, R, G, B, A)

MaterialIndex - индекс материала

Индекс материала у которого вы хотите изменить цвет эмиссии.

R, G, B, A - цвет эмиссии

Новый цвет эмиссии материала. Значения для этих параметров должны быть в пределах от 0 до 255.

Карта окружения (Environment mapping)

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

Есть два разных типа карт окружения. Первая называется "Сферическая карта окружения" (spherical environment mapping). Для этой техники вам понадобится сферическая карта. Это текстура, содержащая изображение окружения как будто отраженного в хромированной сфере (блестящей сфере; можете взять ложку и посмотреть с выпуклой стороны :). Вторая техника называется "Кубическая карта окружения" (cubical environment mapping). Для неё вам понадобится кубическая карта, о ней я рассказывал раньше.

Включить карты окружения очень легко. Вам просто нужно вызвать одну функцию, в которой скажете Ultimate 3D какой материал вы хотите использовать для карты окружения и какую текстуру вы будете использовать как карту:

Эта функция включает карту окружения для заданного материала объекта, для которго она вызвана.

SetMaterialEnvironmentMap(MaterialIndex, TextureIndex)

MaterialIndex - индекс материала

Индекс материала, для которого вы хотите применить карты окружения.

TextureIndex - индекс текстуры

Индекс текстуры, которая содержит карту окружения. Если это индекс нормальной текстуры, то будет использована сферическая карта окружения, если это индекс кубической карты, то будет использоваться кубическая карта окружения. Если вы захотите отключить карты окружения для этого материала, то просто поставьте значение этой переменной равным -1.

Когда вы активировали карты окружения, то вы должны использовать как можно более темные изображения в качестве карт, или же установить очень темный цвет материала модели. Это нужно потому что цвет текселя (пикселя текстуры) карты окружения добавляется к предыдущему цвету пикселя модели. Если вам не нравится, то вы можете изменить это.

Нужно лишь вызвать функцию SetMaterialStageTextureOperation(). О ней смотрите ниже

Рельефное текстурирование и параллакс

Теперь будет очень интересно. Эта техника невероятно популярна, потому что её результаты очень красиво выглядят. Термином "рельефное текстурировние" (bump mapping) называют очень много схожих техник. То о чем я говорю также известно как по-пиксельное освещение (per pixel lighting), карта нормалей (normal mapping) или рельефное текстурирование DOT3 (dot3 bump mapping). Всё это техники для по-пиксельного освещения материалов модели, основанные на симуляции поверхностей при помощи карт высот. Из школьного курса, вы должны знать что такое параллакс (изучают в 5-ом классе на географии и/или в 9-11 на астрономии). Если же нет, то напомню что Паралла́кс (греч. παραλλάξ, от παραλλαγή, «смена, чередование») — изменение видимого положения объекта относительно удалённого фона в зависимости от положения наблюдателя (по данным онлайн энциклопедии Википедия). Смещение параллакса (parallax mapping, так как нет единого русского названия этой техники, все называют это как хотят, то параллакс мэппинг, то просто параллакс, я назову это параллаксное смещение) - это техника, где карта высот используется для деформации текстуры, в зависимости от положения камеры. Это позволяет объектам выглядеть по настоящему объемными. Она создает ощущение глубины. Чтобы вы могли понять что это, я покажу вам несколько скриншотов:

Взгляните на последний. На нем изображена модель куба изнутри, которая освещена тремя источниками света(представлены в виде цветных сфер). Эта модель куба состоит из 12-и полигонов. Эффект глубины и детального освещения создается специальным эффектом. Это можно лучше разглядеть в нижней части куба. Зелёный свет освещает только левую сторону кирпичей справа и только правую - у кирпичей слева. Еще вы не видите заднюю сторону кирпичей, а передняя немного больше. Всё это благодаря параллаксному смещению (parallax mapping).

Параллаксное смещение и Рельефное текстурирование (parallax and bump mapping) очень сложные шейдерные эффекты. Они требуют очень много математических и низкоуровневых операций (особенно если используется Direct 3D 8.1). К счастью, вы используете Ultimate 3D ;) . Вам придется вызвать только одну функцию. Остальную работу берет на себя Ultimate 3D. Вот и она:

Эта функция включает параллаксное смещение и/или использование Рельефного текстурирования для заданного материала объекта.

ApplyParallaxAndBumpMapping

(

MaterialIndex,

HeightMapIndex,

ParallaxFactor,

LightSourceID1,LightSourceID2,LightSourceID3

)

MaterialIndex - индекс материала

Индекс материала, для которого применяется эффект.

HeightMapIndex - индекс карты высот

Индекс карты высот, которая была загружена при помощи функции LoadHeightMap() (еще вы можете использовать функцию LoadTexture() для загрузки уже просчитанной карты нормалей с картой высот в качестве альфа-канала карты нормалей). Вы можете поставить этот параметр на -1, если не хотите симулировать структуру поверхности, но тогда это займет много времени на расчет и карта параллакса потеряет свой смысл, т.к. не будет происходить параллаксное смещение.

ParallaxFactor - фактор параллакса

Этот параметр определяет как далеко будет происходить смещение. Он зависит от того, как текстура наложена на модель. Обычно, устанавливается очень маленькое значение (для скриншота в верху, я использовал 0.02). Если вы введете слишком большое значение, то вы можете исковеркать текстуру, и всё будет выглядеть неестественным. Так что будьте внимательны с этим. Если вы введете 0, то параллаксное смещение не будет использоваться, что увеличит производительность.

LightSourceID1, LightSourceID2, LightSourceID3 - индекс источников освещения

Индекс источников освещения, которые будут использованы для по пиксельного освещения. Для совместимости с видеокартами, которые поддерживают только шейдеры версии 1.4, было ограничено количество используемых источников освещения для расчета по пиксельного освещения до трех, т.к. эта модель (версия) шейдеров не поддерживает более трех источников света при расчете по пиксельного освещения. Хотя даже трех хватит для отличного эффекта. Для этого вы должны будете указать ID объектов Game Maker, которые являются источником освещения, для их использования при расчете по пиксельного освещения. Переменная LightSourceID1 может быть либо источником направленного света (directional light), либо точечным источником света (point light), тогда как оставшиеся два должны быть только источниками точечного света (point light). Чем меньше источников света вы используете, тем меньше времени потребуется на обработку этого эффекта. Если вы не используете ни один источник света, то тогда Рельефное текстурирование (bump mapping) будет отключено.

Как я уже говорил, эти два эффекта очень сложные и ресурсоёмкие. Ultimate 3D скрывает много нюансов от вас, чтобы вам было проще. Когда вы прочитаете главу о шейдерах, вы будете больше понимать о том что же на самом деле происходит в недрах процессора, пока Ultimate 3D выполняет эти эффекты. По этому вы должны кое-что знать, что нельзя использовать, когда включены эти эффекты. Вы не должны использовать карты окружения (environment mapping) или другие мульти-текстурные эффекты одновременно с Рельефным текстурированием и параллаксным смещением (parallax and bump mapping), и при этом вы не можете использовать другие шейдерные эффекты для этого материала. Ultimate 3D рассчитывает кое-что, названное инверсией матрицы пространства касательных (inverse tangent space matrices) когда включается этот эффект. Ultimate 3D переписывает часть информации о вершинах и нормали вершины, которая используется для по пиксельного освещения. Поэтому все мешы (замкнутые контуры, из которых состоит модель), которые используют материал с этим эффектом не могут использовать обычное освещение для других материалов. Если вы захотите переключится с по-пиксельного освещения на обычное, по вершинное, вы должны будете вызвать функцию RecalculateNormals(). Еще вы не можете использовать этот эффект для объектов, которые используют вершинное смещение (vertex tweening, используется моделями формата *.md2 и при по кадровой анимации, созданной из отдельных фалов модели, каждый из которых представляет собой кадр). Также модели которые используют вершинный скининг (vertex skining) не должны состоять из более чем 28 костей, если вы применили к ним этот эффект. Все кости, индекс которых больше чем 28 будут не правильно обработаны.

И наконец вам должно быть известно что не все видеокарты поддерживают параллаксное смещение и Рельефное текстурирование (parallax mapping and bump mapping). Эти эффекты требуют поддержки пиксельных шейдеров версии 1.4. Для того, чтобы узнать поддерживаемую версию шейдеров, используемой сечас видеокарты, вы должны вызвать функцию GetSupportedPSVersion(). Она возвращает десятичное значение максимально поддерживаемой версии шейдеров. Они могут быть 1.0, 1.1, 1.2, 1.3, 1.4, 2.0 и т.д. Так чтобы вы могли знать на какой системе (компьютере) можно использовать эти эффекты, вы должны написать:

if(GetSupportedPSVersion()>=1.4){

// Parallax mapping and bump mapping are supported

// Параллаксное смещение и Рельефное текстурирование поддерживаются

}

else{

// Parallax mapping and bump mapping are not supported

// Параллаксное смещение и Рельефное текстурирование не поддерживаются

}

Функции мульти-текстуринга (Multi texturing)

Материал не должен состоять только из одной текстуры. Вы только что видели два примера с использованием много текстурности (multy texturing / много текстурность - использование нескольких текстур для материала одновременно). Когда вы используете карты окружения, материал может использовать карту диффузии (обычную текстуру) и карту окружения одновременно. Когда используете параллаксное смещение или рельефное текстурирование, то материал использует карту высот и карту диффузии одновременно. В зависимости от видекарты можно использовать до восьми текстур одновременно. Функция GetSimultaneousTextureCount() возвращает количество текстур, которые одновременно можно использовать на текущей видеокарте. В худшем случае - это только одну.

Много текстурность можно использовать для крутых эффектов и шейдерного программирования, которое невообразимо без использования нескольких текстур одновременно. Одной очень важной особенностью много текстурности является, то что её можно использовать для карт освещения (light mapping), техники, когда вы создаете текстуру, описывающую как освещен объект, используя например программу Deled. Так вы можете получить очень детальное статичное освещение модели, без использования источников освещения, что увеличивает производительность.

Но как же оно работает? Да, в принципе, тут всё просто. В зависимости от видеокарты у вас может быть восемь, так называемых, текстурных стадий (texture stage). Каждая текстурная стадия использует свою текстуру, набор текстурных координат меша (mesh) и текстурную операцию. Для установки этих трех параметров текстурной стадии есть три функции:

Эта функция устанавливает текстуру, используемую заданной текстурной стадией материала объекта, для которого она вызвана.

SetMaterialStageTexture(MaterialIndex, TextureStage, TextureIndex)

MaterialIndex - индекс материала

Индекс материала, который вы хотите изменить.

TextureStage - индекс текстурной стадии

Индекс стадии, которую вы хотите изменить. Этот параметр может принимать значения от 0 до 7.

TextureIndex - индекс текстуры

Индекс новой текстуры, которую вы хотите использовать для этой текстурной стадии.

Эта функция изменяет текстурные координаты заданной стадии, выбранного материала объекта для которого она вызвана.

SetMaterialStageTexCoord

(

MaterialIndex,

TextureStage,

TextureCoordinateSetIndex

)

MaterialIndex - индекс материала

Индекс материала, который вы хотите изменить.

TextureStage - индекс текстурной стадии

Индекс стадии, которую вы хотите изменить. Этот параметр может принимать значения от 0 до 7.

TextureCoordinateSetIndex - индекс набора текстурных координат

В главе "Манипуляция моделями" вы узнаете о том, что меши (mesh) могут иметь более одного набора текстурных координат, но не более восьми много размерных наборов текстурных координат. Этот параметр задает индекс набора текстурных координат, который будет использоваться для этой текстурной стадии. По умолчанию этот параметр равен нулю (номер первого набора текстурных координат). В зависимости от того сколько наборов текстурных координат вы создали для меша, значение этого параметра может быть от 0 до 7. Еще вы можете использовать -1 чтобы получить текстурные координаты карты окружения, -2 для получения текстурных координат карты окружения, но рассчитаные по другой методике или же -3 для использования экранных координат вершин как текстурных координат.

Эта функция изменяет текстурную операцию для выбранной стадии материала объекта.

SetMaterialStageTextureOperation

(

MaterialIndex,

TextureStage,

TextureOperation

)

MaterialIndex - Индекс материала

Индекс материала, который вы хотите изменить.

TextureStage - Индекс текстурной стадии

Индекс стадии, которую вы хотите изменить. Этот параметр может принимать значения от 0 до 7.

TextureOperation - Текстурная операция

Текстурная операция определяет как текстура рисуется с предыдущим текстурным уровнем (стадией). Первая текстурная стадия всегда умножает цвет диффузии, вычисленный используя информацию материала, источники освещения, цвет текстуры с результатом, умноженным на два. Вторая текстурная стадия берет цвет (в формулах Current), который получился в результате первой текстурной стадии, и комбинирует его с цветом новой текстуры(в формулах Texture), используя выбранную вами текстурную операцию. То же и для последующих текстурных стадий. Каждое целое значение, что вы введете представляет собой номер текстурной операции, которая будет использована. Это список возможных значений переменной с их описанием:

1: Эта текстурная операция умножает текущий цвет с цветом текстуры: Texture*Current

2: Операция умножает текущий цвет на цвет текстуры и увеличивает в два раза: Texture*Current*2

3: Операция умножает текущий цвет на цвет текстуры и увеличивает в четыре раза: Texture*Current*4

4: Эта операция добавляет текущий цвет к цвету текстуры: Texture+Current

5: Эта текстурная операция вычитает из каналов R,G,B текущего цвета 128, а затем добавляет цвет текстуры: Texture+Current-128

6: Эта текстурная операция вычитает из каналов R,G,B текущего цвета 128, затем добавлет цвет текстуры и увеличивает получившийся результат в два раза: (Texture+Current-128)*2

7: Эта текстурная операция вычитает из цвета текстуры текущий цвет: Texture-Current

8: Эта текстурная операция берет значение текущего цвета и вычисляет значение цвета точки с информацией в пределах от -1 до 1: RGB=( (Texture.R-128)/128*(Current.R-128)/128 + (Texture.G-128)/128*(Current.G-128)/128 + (Texture.B-128)/128*(Current.B-128)/128 )*255

Когда вы используете мультитекстуринг, то альфа-компонента всегда будет вычислятся путем перемножения значений альфа-канала (Final.a=Texture.a*Current.a). Это означает что вы можете использовать до восьми текстур для альфа-смешивания.

Мультитекстуринг можно использовать для красивых эффектов. И самое главное, он дает вам возможность использовать сложные шейдерные эффекты. Приготовьтесь, следующая глава будет очень сложной и интересной. Вы научитесь использовать собственные шейдерные эффекты в Ultimate 3D. Написание собственных шейдеров очень сложно, но вы должны попытаться. В интернете есть много отличных справочников по написанию шейдеров (в основном на английском языке), как только вы научитесь, вас будет не остановить. Шейдеры могут быть использованы для создания невероятных эффектов. Пиксельные шейдеры заменяют текстурную операцию. А это означает что вы можете использовать любые арифметические операции для получения цвета. Вы сможете реализовать любой эффект, какой захотите. Это мощнейшее решение для всех ваших специальных эффектов!


Èñïîëüçîâàíèå øåéäåðîâ

Использование шейдеров

Использование шейдерных эффектов

Если вы играли в современные игры, то вы уже должны были слышать термин шейдеры. Самое простое объяснение, шейдеры - это то что позволяет вам создавать завораживающие эффекты. Но оно не совсем точно, давайте разберемся поподробнее. Существует два различных вида шейдеров: Вершинные шейдеры и Пиксельные шейдеры (vertex shaders и pixel shaders). Вершинные шейдеры можно использовать отдельно от пиксельных, а вот пиксельные шейдеры обязательно должны использоваться вместе с вершинными шейдерами.

В обычном режиме Ultimate 3D использует фиксированный метод обработки моделей (fixed function pipeline). Этот метод является стандартной частью Direct3D. Он рассчитывает позицию вершин на экране, их освещение, ну и тому подобное. Затем рассчитанная информация используется для рисования треугольников (полигонов, только которые могут обрабатываться видеокартами) пиксель за пикселем. Когда вы используете шейдеры, то больше не используется стандартный фиксированный алгоритм обработки моделей, вместо него, к моделям с шейдерными эффектами будут применены программируемые функции. Это означает что способы расчета Ultimate 3D данных вершин и цвета пикселей можно изменить в любое время как захотите.

Вершинные шейдеры - это очень короткие программы, которые выполняются для каждой вершины каждый кадр для расчета её данных. Так вы сможете изменять геометрию моделей без встроенных в Ultimate 3D функций манипуляции моделями, изменять финальные текстурные координаты. Пиксельные шейдеры еще более короткие программы, которые выполняются для каждого пикселя каждый кадр и рассчитывают его данные. Они могут получать информацию о текстурных координатах, рассчитанных вершинными шейдерами, еще они имеют доступ к текстуре. Результатом расчетов пиксельных шейдеров всегда будет значение цвета, которое будет использовано для пикселя. Знайте что шейдеры можно создать в любом текстовом редакторе, хотя бы в Блокноте (Notepad). На этом изображении в упрощенном виде проиллюстрировано как работают шейдеры:

Сначала T&L (Трансформация и освещение - Transformation & Lighting) или Вершинный шейдер обрабатывают вершины. Затем эти вершины передаются в растеризатор (блок растеризации). Он определяет какие пиксели нужно отрисовать для треугольника. И наконец фиксированная функция обработки (pipeline) или Пиксельный шейдер высчитывает цвет пикселя и выводит его на экран. Вообще в процессе обработки происходит намного больше чем я упомянул, например после пиксельных шейдеров происходит обработка тумана, но для нас это не так важно.

Я просто покажу вам как может выглядеть шейдер. Тут представлен очень простой шейдер. Он просто прорисовавыет объект с цветом его материала и его первой текстурой. Шейдерные эффекты всегда состоят из двух-трех файлов. Вершинные шейдеры (файл формата *.vsh) должны быть всегда, а вот пиксельные шейдеры (файл формата *.psh) по усмотрению. Еще должен быть файл эффекта Ultimate 3D (файл формата *.ufx), который содержит информацию о том как нужно использовать пиксельные и вершинные шейдеры.

Это вершинный шейдер:

// Эта строка должна быть первой в каждом вершинном шейдере

vs.1.1

// Эта строка кода трансформирует позицию вершины в меше (mesh) в

// экранную позицию. Команда которая выполняет это называется "m4x4".

// "oPos" это название выходного регистра, куда шейдер сохранит данные

// об экранной позиции. Позиция вершины в меше всегда сохраняется в

// регистр "v0". "c0" это переменная установленная перед обработкой

// модели, так называемая "Постоянный регистр" (Constant register).

// Константный регистр получает значение из *.ufx файла. Он содержит

// начало матрицы трансформации (преобразования, transformation matrix),

// которая нужна для вычисления экранной позиции.

m4x4 oPos, v0, c0

// Эта строка кода просто передает материал, копируя его из пятого

// константного регистра в регистр вывода цвета диффузии.

mov oD0, c4

// Эта строка кода передает координаты первой текстуры меша, копируя

// их из седьмого регистра данных вершины в регистр вывода данных текстуры

mov oT0, v7

Это пиксельный шейдер:

// Эта строка может быть "ps.1.0", "ps.1.1", "ps.1.2", "ps.1.3", "ps.1.4"

// и так далее. Чем больше версия шейдеров, тем меньше компьютеров её

// поддерживают, но вы можете применять более сложные эффекты.

// Сейчас большинство компьютеров поддерживают версию 2.0, а самые

// современные 3.0 и даже 4.0. Этот код использует версию ps.1.4

// потому что в этой версии этот код проще чем в предыдущих.

// Ultimate 3D поддерживает пиксельные шейдеры до версии 1.4.

ps.1.4

// Используем первые текстурные координаты (t0), для получения цвета

// первой текстуры (r0) и сохраняем результат во временный регистр "r0".

// Комментарий: Регистр r0 имеет у нас две цели: Он обозначает текстуру

// (для второй текстуры соответственно r1) и он используется как выходной

// регистр.

texld r0, t0

// Умнажаем цвет текстуры (r0) на цвет материала (v0) и сохраняем

// результат в регистр вывода (r0). Значение r0 на выходе из шейдера

// будет использоваться как цвет пикселя.

mul r0, r0, v0

Это файл эффекта Ultimate 3D:

// Эта строка должна быть первой во всех файла эффектов Ultimate 3D

Ultimate3DEffectFile 1.0

// Используем вершинный шейдер (полагается, что он сохранен в этом файле)

VertexShaderFile effects/VertexShader.vsh

// Используем пиксельный шейдер. Как я уже сказал вершинные шейдеры

// можно использовать и без пиксельных, хотя тут мы используем и их.

PixelShaderFile effects/PixelShader.psh

// Регистры с c0 до c3 будут содержать правильную матрицу преобразования

// в вершинном шейдере.

VSConstant 0 VS_CONST_WORLD_VIEW_PROJ_TRANS_1

VSConstant 1 VS_CONST_WORLD_VIEW_PROJ_TRANS_2

VSConstant 2 VS_CONST_WORLD_VIEW_PROJ_TRANS_3

VSConstant 3 VS_CONST_WORLD_VIEW_PROJ_TRANS_4

// c4 будет содержать цвет материала в вершинном шейдере

VSConstant 4 VS_CONST_MAT_DIFFUSE

Всего семь строк шейдерного кода и две из них всегда одни и те же. Как вы заметили, шейдерное программирование не такое уж и сложное. Обычно вам нужно хорошее знание математики. Его можно подкрепить в главе "Математические функции". Если вы захотите пропустить это главу (о шейдерах), то нет проблем. Но однажды, вы почувствуете, что стали лучше программировать и что вы готовы познать всю мощь шейдеров. И тогда вы вернетесь, дабы расширить горизонты своих знаний и утонуть в завораживающем потоке нескончаемых возможностей, открывшихся перед вашим взором.

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

- Отражение и преломление для реалистичной воды. (Reflection and refraction mapping)

- Шейдеры пост-обработки для таких эффектов, как Изображение с высокодинамическим диапазоном или Размытие движения. (HDR и Motion Blur)

- Искажение текстур для реалистичных погодных эффектов и огня. (Texture perturbation)

- Эффекты пост-обработки для искажения экрана. (Post screen warp effects)

- Многое, многое другое. На свете не существует человека, который бы знал все эти техники.

Еще в демонстрации Ultimate 3D содержатся несколько крутых шейдерных спец.эффектов. Я не стану описывать вступление в шейдерное программирование. Другие люди уже это сделали, в частности Вольфганг Энджел (Wolfgang Engel). Он написал отличную статью для знакомства с шейдерным программированием.

Вот отличная статья о программировании вершинных шейдеров от Wolfgang Engel. (англ. яз.)

А это его другая о программировании пиксельных шейдеров. (тоже на англ. яз.)

Вот и третья его статья с примером шейдерного программирования, показывающая как реализовать различные методы попиксельного освещения. (англ. яз.)

Вы не должны пропустить статью от Майкрософт "Вершинные шейдеры на Ассемблере" и еще одну "Пиксельные шейдеры на Ассемблере" (vertex shader reference и pixel shader reference). Это конечно не справка, скорее список функции и возможных регистров, но вы сможете получить полезную информацию о шейдерном программировании. (всё на англ. яз.)
На русском языке написано очень мало полезных статей, поэтому я написал статью о шейдерах, основанную на документации пакета разработки DirectX 8.1 SDK. Прочитать статью вы можете по этой ссылке: "Программирование шейдеров".

Как только вы прочитаете статьи Woflgang Engel, вы получите теоретическую базу для шейдерного программирования. Лучший способ что-то выучить - попробовать это сделать самому. Так что побалуйтесь с шейдерами. Не все шейдеры что вы напишите, пока изучаете их, будут вам полезны. Если у вас возникнут какие-либо вопросы о программировании шейдеров, то вы можете задать интересeющие вас вопросы на форуме Сообщества Ultimate 3D (англ. яз.). Для программирования шейдеров, совместимых с Ultimate 3D вы должны знать какой регистр ввода вершинных шейдеров для чего нужен. Вот небольшой списочек:

v0 - Позиция в координатах меша (Position in mesh space)

v1 - Данные скининга (Skinning weight data) для моделей со скинигом, вторая позиция для моделей с промежуточным смещением вершин (tweening)

v2 - Четыре индекса матриц для моделей со скинингом (skinning), вторая нормаль для моделей с промежуточным смещением вершин (tweening)

v3 - (первый) вектор нормали

v7 по v14 - До восьми одно-четырех размерных текстурных координат (texture coordinates)

Введение в формат *.ufx

Шейдерное программирование всё равно довольно сложно, вам было бы трудно каждый раз рассчитывать значения для шейдерных констант. Поэтому я создал формат *.ufx. Это формат файла в котором содержится вся информация, нужная для управления шейдером. Если вы используете *.ufx, то вам нужно будет только загрузить его. Вы не должны будете рассчитывать кучу шейдерных констант, вы просто выберите нужные из длинного списка используемых констант для шейдерных регистров. А еще вы можете предустановить константы в *.ufx файле, тогда они автоматически назначаться. Еще вы сможете установить альтернативные эффекты, которые будут использоваться если не поддерживается требуемая версия шейдеров. (это еще называют техникой отката)

Вы видите что файлы *.ufx могут сохранить вам кучу времени. Пока что создавать их сложно. Но не волнуйтесь, я напишу программу для создания эффектов как только у меня появится свободное время. В ней я реализую систему "Тащи и Бросай" (Drag and Drop) для облегчения создания *.ufx файлов, еще я реализую графический вывод того эффекта, что вы делаете, который вы сможете немедленно посмотреть.

Давайте разберемся в формате *.ufx. Каждый *.ufx файл должен состоять из нескольких строк. Каждая строка должна содержать только одну функцию/кусок кода. Линия всегда начинается с названия функции/куска кода. Затем идут параметры, которые могут быть строками или числами. Помните что вы можете поместить комментарий где захотите, написав "//". В примерах переменные будут начинаться с символа "%". Первая строка кода должна быть такой:

Ultimate3DEffectFile %version

version - версия *.ufx файла

Сейчас доступно две версии формата: 1.0 и 1.1. Вы должны писать здесь 1.1, так как форматы совместимы, но 1.1 лучше чем 1.0.

Далее вам придется определить файлы шейдеров для эффекта (они должны быть в файлах форматов *.vsh и *.psh). Для этого есть два параметра:

VertexShaderFile %FileNameWithPath

FileNameWithPath - имя файла, включая путь

Название файла и путь к нему, относительно папки с приложением игры (*.exe - файлом). Например вы можете использовать такой путь "effects\EffectVertexShader.vsh".

Если вы уже работали с форматом файлов эффектов Ultimate 3D версии 1.0, то вы удивитесь куда делся параметр "TextureCoordinateSize". Теперь Ultimate 3D определяет их автоматически, в зависимости от данных вершин модели. Это делает шейдерную систему более отказоустойчивой. Если бы вы применили шейдер к модели, которая не содержит необходимых данных вершин, то получили бы сообщение об ошибке. После того как вы определите вершинный шейдер вы можете задать пиксельный шейдер:

PixelShaderFile %FileNameWithPath

FileNameWithPath - имя файла, включая путь

Название файла и путь к нему, относительно папки с приложением игры (*.exe - файлом). Например вы можете использовать такой путь "effects\EffectPixelShader.vsh".

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

VSConstant %ConstantIndex %ConstantIdentifier %ManuallySettableValues

ConstantIndex - индекс константы

Индекс регистра констант, с которым ассоциировать значение. Это значение можно установить в пределах от 0 до 95.

ConstantIdentifier - идентификатор константы

То что вы тут видите это длинный список возможных регистров констант, которые Ultimate 3D может автоматически рассчитать. Все матрицы или векторы, указывающие направление или позицию других объектов уже будут преобразованы в координатной системе меша! Очень важно это знать. Трансформация направления или позиции в координатную систему меша перед передачей их в шейдер гораздо эффективней чем для каждой вершины вычислять в отдельности. Да и экранные координаты не так часто нужны для шейдеров. В таком случае вы сможете сконвертировать её назад используя функцию трасформации из коодинат меша в глобальные координаты. Исключение составляют лишь модели с вершинным скинингом, им требуется слишком много трансформаций из координат меша в глобальные. Для них информация передается в глобальных координатах, а матрицы "Мир в Мешь" и "Мешь в Мир" идентичны. Информация о цвете всегда принимает значение от 0 до 1 вместо значений от 0 до 255.

VS_CONST_MANUAL_SETTABLE: Этот параметр говорит Ultimate 3D, что нужно установить константу на значение следующего параметра (в %ManualSettebleValues)

VS_CONST_WORLD_VIEW_PROJ_TRANS_1: Первый столбец результата транформации мира, вида и проекции в матрице транфомации пространства меша в мировое пространство.

VS_CONST_WORLD_VIEW_PROJ_TRANS_2: Второй столбец этой же матрицы.

VS_CONST_WORLD_VIEW_PROJ_TRANS_3: Третий столбец этой же матрицы.

VS_CONST_WORLD_VIEW_PROJ_TRANS_4: Четвёртый столбец этой же матрицы.

VS_CONST_WORLD_VIEW_TRANS_1: Первый столбец результата транформации вида и мира в матрице транформации пространства меша в пространство вида.

VS_CONST_WORLD_VIEW_TRANS_2: Второй столбец этой же матрицы.

VS_CONST_WORLD_VIEW_TRANS_3: Третий столбец этой же матрицы.

VS_CONST_WORLD_VIEW_TRANS_4: Четвертый столбец этой же матрицы.

VS_CONST_WORLD_TRANS_1: Первый столбец матрицы пространства меша в мировое.VS_CONST_WORLD_TRANS_2: Второй столбец матрицы пространства меша в мировое.

VS_CONST_WORLD_TRANS_3: Третий столбец матрицы пространства меша в мировое.

VS_CONST_WORLD_TRANS_4: Четвертый столбец матрицы пространства меша в мировое.

VS_CONST_INV_WORLD_TRANS_1: Первый столбец матрицы пространства мира в меша.

VS_CONST_INV_WORLD_TRANS_2: Второй столбец матрицы пространства мира в меша.

VS_CONST_INV_WORLD_TRANS_3: Третий столбец матрицы пространства мира в меша.

VS_CONST_INV_WORLD_TRANS_4: Четвертый столбец матрицы пространства мира в меша.

VS_CONST_VIEW_TRANS_1: Первый столбец матрицы пространства мира в вида.

VS_CONST_VIEW_TRANS_2: Второй столбец матрицы пространства мира в вида.

VS_CONST_VIEW_TRANS_3: Третий столбец матрицы пространства мира в вида.

VS_CONST_VIEW_TRANS_4: Четвертый столбец матрицы пространства мира в вида.

VS_CONST_PROJ_TRANS_1: Первый столбец матрицы пространства вида в проекции.

VS_CONST_PROJ_TRANS_2: Второй столбец матрицы пространства вида в проекции.

VS_CONST_PROJ_TRANS_3: Третий столбец матрицы пространства вида в проекции.

VS_CONST_PROJ_TRANS_4: Четвертый столбец матрицы пространства вида в проекции.

VS_CONST_MATRIX_STACK: Эта константа нужна для моделей с вершинным скинингом (vertex skinning). Она отличается от остальных констант потому что она использует не один константный регистр, а все следующие за определённым регистром. Константные регистры, для которых это настроено, будут содержать значения x=количество переданных матриц, y=константный регистр первой матрицы, z=3, w=1. Для этих значений нужно преобразовать матрицу v2 к постоянному регистру смещения. Все константные регистры после VS_CONST_MATRIX_STACK будут заменены матрицами 4x3 пространства меша перемещенного в мировое пространство для каждой кости в отдельности. Вы можете использовать m4x3 для трансформации векторов с ними.

VS_CONST_CAMERA_POS: Позиция камеры (в пространстве меша).

VS_CONST_MAT_AMBIENT: Цвет окружающей среды материала (ambient color).

VS_CONST_MAT_DIFFUSE: Цвет диффузии материала (diffuse color).

VS_CONST_MAT_EMISSIVE: Цвет эмиссии(свечения) материала (emissive color).

VS_CONST_LIGHT_AMBIENT_COLOR: Цвет атмосферного освещения (ambient light color).

VS_CONST_LIGHT0_COLOR: Цвет первого источника освещения установленного для этого шейдера.

VS_CONST_LIGHT1_COLOR: Цвет второго источника освещения установленного для этого шейдера.

VS_CONST_LIGHT2_COLOR: Цвет третьего источника освещения установленного для этого шейдера.

VS_CONST_LIGHT_DIRECTIONAL_DIRECTION: Направление света от направленного источника освещения, установленного как первый источник освещения для данного шейдера (смотреть выше).

VS_CONST_LIGHT_POINT0_POSITION_INV_RANGE: Этот параметр заставит Ultimate 3D перейти от позиций в пространстве меша первого источника освещения к x, y и z компонентам шейдерной константы и обратного значения дальности освещения к w-компоненте.

VS_CONST_LIGHT_POINT1_POSITION_INV_RANGE: Тоже что, но только для второго источника света.

VS_CONST_LIGHT_POINT2_POSITION_INV_RANGE: Тоже что, но только для третьего источника света.

VS_CONST_FOG_DISTANCE: Этот параметр заставит Ultimate 3D перейти от начальной дистанции тумана к x-компоненте, конечной дистанции тумана к y-компоненте, обратного значения стартовой дистанции к z-компоненте и обратного значения конечной дистанции к w-компоненте.

VS_CONST_CURRENT_TIME: Этот параметр передаст время прошедшее с запуска системы в секундах к x-компоненте, время, прошедшее с запуска Ultimate 3D к y-компоненте, 0 к z-компоненте и 1 к w-компоненте.

VS_CONST_CURRENT_FRAME: Этот параметр передает дробную часть значения текущего кадра в x-компоненту и единица минус значение x-компоненты в y-компоненту. В z-компоненту передаст 0 и в w-компоненту передаст 1. Эта константа должна использоваться для вершинного смещения(vertex tweening).

Значения устанавливаемые вручную

Этот параметр нужен только тогда, когда вы поставили параметр VS_CONST_MANUAL_SETTABLE. Вы должны будете ввести четыре числовых значения для x, y, z и w -компонент шейдерной константы.

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

PSConstant %ConstantIndex %ConstantIdentifier %ManuallySettableValues

ConstantIndex - индекс

Индекс регистра константы, которую вы хотите установить. Это значение может быть от 0 до 7.

ConstantIdentifier

Как я и говорил для констант вершинных шейдеров не так много идентификаторов. Вот их список:

PS_CONST_MANUAL_SETTABLE: Этот параметр говорит Ultimate 3D чтобы она установила константу на значение следующего параметра (%ManuallySettableValues)

PS_CONST_LIGHT_AMBIENT_COLOR: Цвет атмосферного освещения (ambient lighting).

PS_CONST_LIGHT_AMBIENT_COLOR_MATERIAL: произведение цвета атмосферного освещения (ambient lighting) и цвета окружающего материала (ambient color).

PS_CONST_LIGHT0_COLOR: Цвет первого источника освещения установленного для этого эффекта. (см. ниже)

PS_CONST_LIGHT1_COLOR: Цвет второго источника освещения установленного для этого эффекта. (см. ниже)

PS_CONST_LIGHT2_COLOR: Цвет третьего источника освещения установленного для этого эффекта. (см. ниже)

PS_CONST_LIGHT0_COLOR_MATERIAL: Цвет первого источника освещения установленного для этого шейдера умноженный на цвет диффузии материала.

PS_CONST_LIGHT1_COLOR_MATERIAL: Цвет второго источника освещения установленного для этого шейдера умноженный на цвет диффузии материала.

PS_CONST_LIGHT2_COLOR_MATERIAL: Цвет третьего источника освещения установленного для этого шейдера умноженный на цвет диффузии материала.

PS_CONST_MAT_AMBIENT: Цвет окружающий материал (ambient color).

PS_CONST_MAT_DIFFUSE: Цвет диффузии материала (diffuse color).

PS_CONST_MAT_EMISSIVE: Цвет эмиссии материала (emissive color).

Значения устанавливаемые вручную

Этот параметр нужен только тогда, когда вы поставили параметр VS_CONST_MANUAL_SETTABLE. Вы должны будете ввести четыре числовых значения для x, y, z и w -компонент шейдерной константы.

Всё это потребуется вам для создания шейдерных эффектов. Но как насчет запасного варианта если нужная версия шейдеров не поддерживается? На самом деле всё просто. Вы должны будете написать:

FallBackTechnique

{

}

Между двумя скобками вы можете написать одну строку VertexShaderFile, одну строку PixelShaderFile и сколько хотите строк VSConstant и PSConstant.

Вот пример верного *.ufx файла (подразумевается что файлы шейдеров, на которые ссылается пример, существуют).

// Это пример *.ufx файла

Ultimate3DEffectFile 1.0

// Пиксельный шейдер ниже должен использовать версию 1.4

VertexShaderFile shaders/ShaderEffect1_4.vsh

PixelShaderFile shaders/ShaderEffect1_4.psh

VSConstant 0 VS_CONST_WORLD_VIEW_PROJ_1

VSConstant 1 VS_CONST_WORLD_VIEW_PROJ_2

VSConstant 2 VS_CONST_WORLD_VIEW_PROJ_3

VSConstant 3 VS_CONST_WORLD_VIEW_PROJ_4

VSConstant 4 VS_CONST_MAT_DIFFUSE

// Шейдеру нужны эти значения чтобы что-то посчитать. Они так же могут быть установлены инструкцией "def" в вершинном шейдере.

VSConstant 5 VS_CONST_MANUAL_SETTABLE 3.14 6.28 -1 5

// Этот код будет использован если пиксельные шейдеры версии 1.4 не поддерживаются

FallBackTechnique

{

// Пиксельный шейдер ниже использует версию 1.2

VertexShaderFile shaders/ShaderEffect1_2.vsh

PixelShaderFile shaders/ShaderEffect1_2.psh

VSConstant 0 VS_CONST_WORLD_VIEW_PROJ_1

VSConstant 1 VS_CONST_WORLD_VIEW_PROJ_2

VSConstant 2 VS_CONST_WORLD_VIEW_PROJ_3

VSConstant 3 VS_CONST_WORLD_VIEW_PROJ_4

VSConstant 4 VS_CONST_MAT_DIFFUSE

VSConstant 5 VS_CONST_MANUAL_SETTABLE 3.14 6.28 -1 5

}

Применение шейдеров

Всё это была теория. Теперь же мы вернемся к практическому использованию шейдеров. Установить шейдерный эффект очень легко. Каждый материал модели использует свой шейдер. Для его установки вы должны вызвать всего одну функцию:

Эта функция загружает заданный *.ufx файл и использует его для заданного материала объекта в котором эта функция вызвана.

LoadMaterialEffect(MaterialIndex, UFXFile) - LoadMaterialEffect(Материал, Файл)

MaterialIndex - Индекс материала

Индекс материала для которого вы хотите применить шейдер.

UFXFile - файл спец. эффекта

Файл *.ufx который будет использован для этого материала.

Если вы использовали вершинные шейдеры в Ultimate 3D версии 1.31 вы помните что там не было *.ufx формата. Когда вы только загружали шейдер, то получали набор установленных констант. Я бы не хотел ломать обратную совместимость этих функций в Ultimate 3D 2.0. Для этого вам не требуется *.ufx файл, но только *.vsh файл.

Эта функция устанавливает заданный вершинный шейдер для заданного материала используя список возможных констант:

0: VS_CONST_VIEW_TRANS_1

1: VS_CONST_VIEW_TRANS_2

2: VS_CONST_VIEW_TRANS_3

3: VS_CONST_VIEW_TRANS_4

4: VS_CONST_WORLD_VIEW_PROJ_TRANS_1

5: VS_CONST_WORLD_VIEW_PROJ_TRANS_2

6: VS_CONST_WORLD_VIEW_PROJ_TRANS_3

7: VS_CONST_WORLD_VIEW_PROJ_TRANS_4

8: VS_CONST_WORLD_TRANS_1

9: VS_CONST_WORLD_TRANS_2

10: VS_CONST_WORLD_TRANS_3

11: VS_CONST_WORLD_TRANS_4

12: VS_CONST_MAT_DIFFUSE

CreateMaterialVSEffect(MaterialIndex, VertexShaderFile)

MaterialIndex - Индекс материала

Индекс материала к которому будет применен вершинный шейдер.

VertexShaderFile - Файл вершинного шейдера

Путь к файлу вершинного шейдера (например "effects\VSEffect.vsh")

Я не рекомендую использовать эту функцию пока вы хотите использовать шейдеры, созданные для Ultimate 3D версии 1.31. Если вы не согласны, то должны создать *.ufx файл. Прелесть *.ufx в том что он делает всю работу за вас.Если вы хотите поддержать сообщество пользователей Ultimate 3D (Ultimate 3D Community) и знаете как создавать шейдеры, вы могли бы создать набор шейдерных эффектов, включая *.ufx, и опубликовать это на форуме сообщества. Иметь коллекцию уже созданных шейдеров - это будет здорово.

Установка констант

Большинство нужных констант можно установить используя *.ufx файл. Но как насчет тех которые не могут быть подсчитаны Ultimate 3D автоматически? Для этого есть две простых функции для изменения значений вершинных и пиксельных констант, которые Ultimate 3D не может установить автоматически. Вот их описание:

Эта функция устанавливает новое значение для константного регистра вершинного шейдера с заданным индексом в случае если его нельзя установить Ultimate 3D автоматически.

SetMaterialEffectVSConstant(MaterialIndex,VSConstantIndex, XValue, YValue, ZValue, WValue)

MaterialIndex - Индекс материала

Индекс материала который использует эффект.

VSConstantIndex - Индекс константы вершинного шейдера

Индекс константного регистра который вы хотите изменить. Это значение должно быть от 0 до 95.

XValue, YValue, ZValue, WValue - Значения для X, Y, Z, W

Новые значения для константного регистра. они должны быть числами.

Функция SetMaterialEffectPSConstant() выполняет тоже самое для констант пиксельного шейдера. Но индекс констант должен быть в пределах от 0 до 7.

Чуть ранее в этой главе, когда я говорил о константных регистрах, которые передают информацию о источнике освещения, я сказал: "см. ниже". Так что смотрите тут. Вы можете установить три источника освещения, которые будут использоваться для шейдерного эффекта. Для этого используйте следующую функцию:

Эта функция устанавливает три источника освещения, которые будут использоваться заданным материалом.

SetMaterialEffectLightSource(MaterialIndex, LightSourceID1, LightSourceID2, LightSourceID3)

MaterialIndex - Индекс Материала

Индекс материала для которого устанавливаются источники освещения.

LightSourceID1, LightSourceID2, LightSourceID3 - Индексы источников освещения

ID объектов Game Maker которые являются источниками освещения и будут использованы для шейдерного эффекта. Если вы не хотите использовать все три источника освещения, то просто поставьте 0 для того, который не хотите использовать.

Если вы прочитали всю справку и справку по программированию шейдеров, то вы должно быть счастливы. Вы знаете как использовать наиболее гибкую и широкую из возможностей Ultimate 3D. не недооценивайте это. По началу вы может быть не будете понимать как использовать шейдеры, но вскоре вас посетят идеи. В интернете выложены тонны замечательных спец. эффектов которые можно реализовать шейдерами. Я рекомендую поиграть шейдерами чтобы лучше их понять. Это лучший способ набрать опыта. Просто изменяя одну строку шейдеров можно получить забавные спец. эффекты, недоступные обычными средствами. Например, вы можете ввести значение номали вершины в качестве цвета диффузии вершины (в вершинном шейдере).

Так что наслаждайтесь :D


Øåéäåðû ïîñò îáðàáîòêè

Шейдеры пост обработки

Шейдеры пост обработки

Это очень интересная тема, потому что тут рассматривается очень мощный инструмент. Как только вы узнаете что такое шейдеры пост обработки (post screen shaders), вы сразу же согласитесь со мной. Перед тем, как изучить эту главу, вы уже должны знать что такое шейдеры и уметь их использовать. Если вы еще не прочитали главу "Использование шейдеров", то сделайте это немедленно. Если вы не будете знать как написать шейдер, то вы не сможете использовать шейдеры пост обработки. Обычный шейдерный эффект красив, потому что его можно использовать для реализации множества различных эффектов. Но всё равно их возможности ограничены, ведь их можно применять только к материалу модели. Этого недостатка у шейдеров пост обработки нет. Они не применяются к материалам моделей, а ко всей сцене. После того как Ultimate 3D обработает(отрендерит) сцену к ней применяются шейдеры пост обработки для рендеринга окончательного изображения.

Например вы хотите чтобы всё отображалось в черно-белом тоне (ну допустим проигрываются воспоминания героя). Вы можете создать черно-белые копии всех текстур изменяя цвета в сером масштабе. Вы так же можете применить пиксельные шейдеры ко всем видимым объектам. но обо этих способа очень неудобны. С шейдерами пост обработки это можно сделать намного проще. Вы просто напишите один (очень простой) шейдер пост обработки который преобразует в черно-белый цвет. Затем вы просто включаете его и всё, вам не нужно применять его к каждому объекту сцены. Шейдер пост обработки просто преобразует пиксели отрендеренного изображения и выводит результат этой обработки на экран.

Это был пример в котором шейдер сохраняет кучу времени, но не делает ничего что без него не возможно. А вот другой пример, который нельзя осуществить без шейдеров пост обработки : эффект размытия (blur). Представьте что герой был отравлен. Теперь вы должны показать игроку что с героем что-то не так. Эффект размытия примененный ко всему экрану будет очень подходящим для этой цели. С обычным шейдером это сделать невозможно, а с шейдером пост обработки это не проблема.

Спектр возможных эффектов очень широк. HDR, свечение (bloom) и различные эффекты размытия (blur, radial blur, motion blur...) доступны вам с помощью шейдеров пост обработки. Их можно использовать для различных эффектов искажения (warp) и для реализации некоторых необычных эффектов. Например вы можете обратить (инвертировать) цвета, изменить гамму(оттенок), продублировать изображения (для пьяного героя :), затемнить или осветлить некоторые участи экрана, выделить контуры для графики в стиле комиксов или можете создать шейдер пост обработки, который заставит всё выглядеть как в старом фильме. Шейдеры пост обработки можно использовать и для эффектов глубины (deep of field), но это займет довольно много времени.

Как работают шейдеры пост обработки

В этой короткой главе описаны процессы автоматически выполняемые Ultimate 3D . Но всё равно очень важно знать об этих вещах, иначе вы не поймете почему шейдеры пост обработки выглядят так как они выглядят. Когда вы будете использовать шейдеры пост обработки, то Ultimate 3D больше не будет рендерить изображение прямо на экран. Вместо этого Ultimate 3D будет рендерить всю сцену в текстуру. То что вы обычно видите на экране теперь будет нарисовано на текстуре. После этого Ultimate 3D будет рендерить прямоугольник, покрывающий весь экран, с текстурой сцены на экран.

Это даёт вам возможность многократно одновременно использовать шейдеры пост обработки. они будут применятся один за другим. Когда вы используете два шейдера пост обработки, то Ultimate 3D рендерит всю сцену в текстуру. Затем Ultimate 3D рендерит прямоугольник с этой текстурой, применяя к нему первый шейдер пост обработки, во вторую текстуру. После этого Ultimate 3D рендерит прямоугольник, использую вторую текстуру и применяя к нему второй шейдер пост обработки, на экран. Если же шейдеров пост обработки не два, а три, то Ultimate 3D рендерит второй квадрат не на экран а в первую текстуру и уже её использует для рендеринга прямоугольника, применяя к нему третий шейдер пост обработки, на экран. Это означает что для любого количества шейдеров пост обработки будет использовано не более двух текстур, так что использование шейдеров пост обработки очень экономично по отношению к памяти.

Еще вы должны знать о цепи последовательности шейдеров пост обработки - то в каком порядке шейдеры применяются к сцене, ведь это имеет важное значение. Давайте рассмотрим простейший пример: Скажем у вас есть сцена, где всё синее, по какой-либо причине (звучит не реалистично, но зато показательно). Красный и зелёный каналы цвета всегда равны нулю. И допустим у вас есть два шейдера пост обработки. Пусть первый делает всё в сером цвете, беря среднее арифметическое значение всех трёх каналов, а второй пусть копирует значение красного канала, игнорируя значения синего и зелёного каналов, во все три. Если вы примените второй шейдер (копирование красного) перед первым, то в результате получите черный экран., потому что красный канал не используется сценой а первый шейдер не может изменить черное изображение, ведь среднее арифметическое трёх нулей это ноль. Если же вы сначала используете первый шейдер, а за ним второй, то первый шейдер получит затемнённое серое изображение сцены и второму шейдеру будет что обработать и вывести на экран. Так что вы можете заметить что порядок использования шейдеров пост обработки очень важен.В зависимости от порядка применения эффектов можно получить разные результаты. Именно по-этому Ultimate 3D позволяет вам задать приоритет для каждого шейдера пост обработки.

Использование шейдеров пост обработки

Это может показаться немного странным, но шейдеры пост обработки должны быть представлены объектами Game Maker, как модели, примитивы и др. Это сделано для удобства их использования. У вас просто должен быть один объект для каждого вида шейдеров пост обработки и когда вы захотите включить какой-либо эффект, вы просто создадите новую копию (инстанцию) нужного объекта. Всё остальное Ultimate 3D сделает автоматически. Еще так вы сможете использовать одновременно несколько эффектов одного и того же типа для усиления эффекта. Для этого просто создайте несколько копий (инстанций) объекта. и если эффекты должны использоваться с начала игры, вы просто можете поместить объекты в комнату. И не нужно ни какого кодинга.

Теперь, для создания объекта шейдера пост обработки, вы должны знать только одно. Сначала вы должны установить переменные (в событии создания объекта). За тем вы должны вызвать функцию создания шейдера пост обработки. После этого вы можете вызвать еще несколько функций для установки переменных шейдера. И наконец вы должны поместить функцию Destroy() в событие уничтожения. Функция Step() не требуется. Вот список переменных, доступных для шейдеров пост обработки. Их только четыре:

vertex_shader - вершинный шейдер

Вершинный шейдер который используется этим шейдером пост обработки. Эту переменную нужно установить на путь к файлу с вершинным шейдером, например "effects\BlurPSS.vsh"

pixel_shader - пиксельный шейдер

Пиксельный шейдер который используется этим шейдером пост обработки. Эту переменную нужно установить на путь к файлу с вершинным шейдером, например "effects\BlurPSS.psh". Запомните что если версия пиксельных шейдеров не поддерживается, то вы не увидите сообщение об ошибке. Перед тем как создавать шейдер пост обработки убедитесь что поддерживается нужная версия пиксельных шейдеров, вы можете получить максимальную поддерживаемую версию пиксельных шейдеров функцией GetSupportedPSVersion().

camera_index (optional) - индекс камеры (опционально)

Каждый шейдер пост обработки применяется к отрендеренному изображению каждого объекта камеры в отдельности.Поэтому если эффект используется не для камеры по умолчанию, вы можете установить это значение на индекс нужной вам камеры, который может быть от 0 до 32. (не id объекта)

priority (optional) - приоритет (опционально)

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

После того как вы закончите с переменными вы должны вызвать функцию для создания шейдера пост обработки. Вот она CreatePostScreenShader(). Вы должно быть удивились почему шейдеры пост обработки не используют файл эффектов Ultimate 3D (*.ufx). Это потому что шейдеры пост обработки применяются не для одиночных 3D объектов, а для всей сцены сразу. Для них не так много заранее рассчитанных переменных. В них нет информации о материалах объектов, о их трансформации, нет связанных с шейдером источников освещения. Обычно вам потребуется лишь информация о цвете и некоторый фактор (величина) для изменения силы эффекта. Их можно установить инструкцией "def" в нужных шейдерах или можно использовать следующие две функции:

Эта функция устанавливает константу вершинного шейдера для объекта шейдера пост обработки, для которого она вызвана. С её помощью можно переписать значение константного регистра установленное инструкцией "def" в вершинном шейдере.

SetPSSVSConstant(VSConstantIndex, Value1, Value2, Value3, Value4)

VSConstantIndex - индекс константы вершинного шейдера

Индекс константного регистра вершинного шейдера который вы хотите изменить. Он должен быть в пределах от 0 до 95.

Value1, Value2, Value3, Value4 - значения

Значения которые вы хотите установить для этого константного регистра. Value1 будет скопировано в x-компоненту. Value2 будет скопировано в y-компоненту. Value3 будет скопировано в z-компоненту. Value4 будет скопировано в w-компоненту.

Эта функция устанавливает определенный константный регистр регистр пиксельного шейдера для шейдера пост обработки, для которого вызвана эта функция. Вы не можете переписать значение константного регистра, установленное инструкцией "def" пиксельного шейдера.

SetPSSPSConstant(PSConstantIndex, Value1, Value2, Value3, Value4)

PSConstantIndex - индекс константного регистра

Индекс константного регистра пиксельного шейдера, который вы хотите модифицировать. Может принимать значение от 0 до 7.

Value1, Value2, Value3, Value4 - значения для параметров

Это новые значения параметров, которые вы хотите установить.

Но шейдерные константы - это не всё, что вы можете установить для шейдера пост обработки. Еще можно установить по одной текстуре для каждой стадии (слоя) текстуры. Только первую текстурную стадию (стадия 0) нельзя изменить, так как она всегда использует текстуру сцены. Текстуры всех остальных стадий можно установить этой функцией:

Эта функция устанавливает выбранную текстуру для заданной текстурной стадии (слоя текстуры) шейдера пост обработки, для которого она вызвана:

SetPSSTexture(TextureStage, TextureIndex)

TextureStage - стадия текстуры

Индекс стадии (слоя), для которой вы хотите установить текстуру. Так как первая текстурная стадия (стадия 0) всегда используется под текстуру сцены, то возможные значения для TextureStage колеблются в пределах от 1 до 7.

TextureIndex - индекс текстуры

Индекс текстуры, которую вы хотите установить для выбранной стадии.

Когда пишешь шейдер пост обработки, часто случается что вам нужно изменить способ фильтрации какой-либо текстуры, чтобы эффект стал выглядеть лучше. Допустим, вы используете линейную фильтрацию(linear filtering) для текстуры сцены, из-за этого она будет выглядеть чуть размытой. Это может подойти вам, а может и нет. Поэтому вы можете установить для каждой текстурной стадии шейдера пост обработки свой фильтр. По умолчанию первая стадия текстуры (стадия 0) использует фильтр по ближайшей точки(nearest point filtering). А все остальные стадии текстуры будут использовать фильтрацию установленную функцией SetFilter(), по умолчанию которая установлена на линейную фильтрацию. Если вы захотите установить другой тип фильтрации, то просто воспользуйтесь этой функцией:

Эта функция устанавливает тип используемой фильтрации текстуры для указанной текстурной стадии шейдера пост обработки, для которого она вызвана:

SetPSSFilter(TextureStage, FilterType)

TextureStage - стадия текстуры

Стадия текстуры (слой), для которой вы хотите использовать новый тип фильтрации. Это значение должно быть в пределах от 0 до 7.

FilterType - тип фильтрации

Фильтр, который вы хотите использовать для этой текстурной стадии. Возможные значения полностью совпадают со значениями для функции SetFilter():

1: Фильтрация по ближайшей точки (Nearest point filtering) - Будет использован цвет ближайшего текселя.

2: Линейная фильтрация (Linear filtering) - Берется усредненное (интерполированое) значение ближайших четырех текселей.

3: Анизитропная фильтрация (Anisotropic filtering) - Наиболее лучший метод фильтрации. Он не поддерживается некоторыми старыми видеокартами.

Написание шейдеров пост обработки

Шейдеры пост обработки пишутся на ассемблере, как и обычные шейдеры. Но они немного отличаются. Особенно вершинные шейдеры. Во-первых больше не нужно производить матричных калькуляций, потому что позиция вершин уже преобразована для пространства проекции. Во-вторых, прямоугольник, который используется для рендера текстуры сцены, состоит не более чем из четырех вершин. Так что каждый вершинный шейдер пост обработки будет выполнятся не более четырех раз, что является ничем по сравнению с тысячами вершин для каждой из которых нужно выполнить обычный вершинный шейдер. По этому вам не нужно заботится об оптимизации вершинных шейдеров пост обработки. Если десять дополнительных строк кода вершинного шейдера пост обработки помогут сократить код пиксельного шейдера пост обработки, то вы должны это сделать. Такой ход сократит затраты на расчет цета пикселей. Ведь пиксельный шейдер (обычный и пост обработки) выполняется для каждого пикселя на экране (обычный только для пикселей модели), а это если посчитать то будут миллионы операций за шаг, а в секунду может достигать десятков миллионов операций. Например возьмем стандартное разрешение монитора по сегодняшним меркам 1024*768 пикселей = 786 432 раз будет выполнен пиксельный шейдер пост обработки за шаг! А в секунду, допустим у нас 30 шагов, тогда 1024*768*30 = 23 592 960 раз в секунду будет выполнен код писельного шейдера! Но ведь код состоит из отдельных инструкций (строк), а их может быть много. Возьмем например код пиксельного шейдера пост обработки эффекта "старого фильма" из демонстрационного примера "Демонстрация Огня и Воды" ("Water and Dire Demo"), файл называется "PostOldFilm.psh". Он состоит из 13-и выполняемых строк, не считая комментарии. И того получается 1024*768*30*13 = 306 708 480 инструкций в секунду!

Но самое главное что вы должны знать при написании правильных шейдеров пост обработки, это какие регистры вершин доступны. А доступны регистры v0, v7 и v8. Вот их описание:

v0 содержит позицию вершины в пространстве проекции. Так как все уже переведено в пространство проекции, то вы просто можете использовать инструкцию "mov" чтобы передать её в регистр вывода "oPos". Матрицы тут не нужны.

v7 содержит текстурные координаты, которые будут использоваться текстурой сцены.

v8 содержит текстурные координаты в пределах от 0 до 1, которые можно использовать для всех текстур.

Причина по которой v7 и v8 различаются, это то что текстуры всегда должны иметь размеры степени двойки, когда зона рендера может иметь любой размер. Так что если зона рендера (вид) имеет размеры 800*600, то текстура сцены будет иметь размеры 1024*1024, так что текстурные координаты v7 будут в пределах от 0 до 0,78125 (800/1024) для x-координаты и от 0 до 0,5859375 (600/1024) для y-координаты.

После всей этой теории, вот вам пример шейдера пост обработки. Он использует карту преломления (distortion map) текстурных координат, которая установлена для стадии 1 для искажения изображения на экране. Это довольно мощный эффект, его можно использовать например для телепорта или воронки на экране.

Это код вершинного шейдера:

vs.1.1

mov oPos, v0

mov oT0, v7

mov oT1, v8

Что может быть проще? Вот код пиксельного шейдера:

ps.1.4

texcrd r0.rgb, t0

texld r1, t1

mad r1.rgb, r1, c0, r0

phase

texld r0, r1

Пиксельный шейдер делает следующее. Сначала он берет первую текстурную координату для текущего пикселя и данные из карты искажения (distortion map). Затем перемножает данные из карты искажения на некоторое число (фактор) и добавляет первую координату текущего пикселя. И наконец новая текстурная координата используется для отображения текселя(тексель - это пиксель текстуры, пиксель - это цветная точка :) текстуры сцены. Это и будет результат работы данного шейдера. Для использования этого шейдера вам нужно установить карту искажения (обычная текстура, каналы которой используются для смещения координат: Красный-x, Зелёный-y, Синий-z. Можете попробовать любую текстуру) для стадии 1 и фактор силы искажения (число) для первой константы пиксельного шейдера. Считайте это домашним заднием. Вот собственно и всё.


Òåíè â ðåàëüíîì âðåìåíè

Тени в реальном времени

Тени в реальном времени

Ох да, тени в реальном времени. Я ждал этого так долго, и теперь, я могу использовать их абсолютно для всего в моей игре! Каждый листочек на дереве будет отбрасывать тень на землю. Это смотрится великолепно. Абсолютно у всего есть собственная тень, прямо как в реальности! (реальность это что видно за окном, иногда туда стоит выглядывать, однако:)

Если это всё о чем вы мечтали, то я хочу вас разочаровать. Это не возможно! Нет такого Персонального Компьютера, который может нормально просчитывать мягкие тени (soft shadows). Но вам все равно доступны каркасные (стенсильные, stencil - каркас) тени (stencil shadows) в реальном времени, при помощи Ultimate 3D. Сцены без теней выглядят недостоверно. Объекты должны быть затенены чтобы выглядеть реалистичными. Тень помогает человеческому глазу определить объемные объекты на плоском изображении, выводимом на экран. В шокирующих играх, тени могут придать драматичную обстановку. Тени дают игроку подсказку о существовании того, что он на прямую не видит. Поэтому тени могут быть частью геймплея.

Тени в реальном времени должны использоваться осторожно, ведь они требуют очень больших ресурсов производительности компьютера. Вы должны использовать тени в реальном времени только для не статических объектов и источников освещения. Для статических объектов вы можете использовать карты освещения (light mapping), которые реализуются через многотекстурность (multi texturing) и гораздо более производительны.

Ultimate 3D использует аппаратное ускорение каркасных теней (hardware accelerated stencil shadows). Вам не нужно знать как эти тени работают, но вы должны знать о минусах и плюсах этой техники. Плюсы данной техники - это очень высокое качество теней, которое полностью верно для каждого пикселя, малые системные требовани (не требуется поддержки пиксельных шейдеров), хотя в комбинации с шейдерными эффектами, такими как попиксельное освещение, да и то что они полностью используют аппаратное ускорение позволяет не нагружать центральный процессор расчетами. А минус данной техники это то, что ваши модели должны соответствовать некоторым условиям чтобы быть правильным источником тени (valid shadow caster), тени в реальном времени очень сильно нагружают графический процессор (GPU), да и использование мягких теней не возможно.

Использование теней в реальном времени

Использовать тени в реальном времени очень легко. Сначала вы должны убедится что они поддерживаются. Если да, то вы сможете включить отбрасывание тени для отдельных источников освещения, установить отдельные модели для создания тени (shadow casters) и отдельные модели, примитивы или ландшафты как затеняемые (shadow receivers). Первое что должно быть сделано для использования теней - это использование тридцати двух битного z-буфера. Это можно сделать в скрипте Ultimate3DOptions(), установив переменную global.u3d_z_buffer_format равной 32. Для того чтобы получше узнать о значении этой переменной посмотрите главу "Настройки Ultimate 3D". Причина по которой нельзя использовать каркасные тени без 32-х битного z-буфера, это то что 8 бит z-буфера используются как каркасный буфер (stencil buffer), который нужен для расчета теней. Если Персональный Компьютер (ПК, а по-английски PC), который вы используете поддерживает этот формат z-буфера и он установлен в верное значение, то тогда функция GetShadowSupport() вернет значение true (1), что значит то, что вы можете использовать каркасные тени. Если же вы их не можете использовать, то будет возвращено значение false (0).

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

Эта функция включает или выключает отбрасывание теней (shadow casting) для источника освещения, для которого вызвана эта функция. Её нужно выполнять после создания источника освещения одной из этих функций LightDirectional(), LightPoint() or LightSpot().

SwitchShadows(Enable)

Enable - состояние

Если вы поставите true (1) для этого параметра, то Ultimate 3D включит отбрасывание теней для этого источника освещения, иначе отключит (при enable=false / 0).

Теперь вы можете определить какие модели будут отбрасывать тени от каких источников освещения.

Эта функция включает или отключает отбрасывание теней для объекта модели, для которой она вызвана. Если эта модель использует вершинный скининг (vertex skinning), то она должна использовать не более 28-и костей, все остальные кости будут неверно трансформированы. Причина этому это нехватка констант вершинного шейдера в используемой версии Direct3D.

SwitchShadowCasting(LightSourceID, Enable)

LightSourceID - индекс источника освещения

Индекс (id) объекта источника освещения, от которого эта модель должна отбрасывать тень.

Enable - состояние

Отбрасывание тени будет включено при значении true (1) или отключено при значении false (0)

И наконец вы должны установить какие объекты будут принимать тени (затеняться). Это легко.

Эта функция включает/отключает прем тени от отдельных источников освещения. Её можно вызвать для ландшафта, модели или примитива (terrain, model or primitive).

SwitchShadowReceiving(LightSourceID, Enable)

LightSourceID - индекс источника освещения

Источник освещения от которого (не) будут приниматься тени.

Enable - состояние

Если вы используете true, то объект будет принимать тени от источника освещения, а если false, то нет.

Теперь вы можете включать тени от источников освещения, можете включать отбрасывание тени от моделей и включать затенение для нескольких типов объектов. Это всё что вам нужно для использования теней в реальном времени в Ultimate 3D. Но может случится так что результат выводимый на экран вам не понравится. Это потому что каркасные тени требуют специальной структуры геометрии для правильной работы. Геометрия не должна иметь дыр (holes) и углы должны состоять из треугольников, если конечно это не высоко полигональная модель. Только такая структура геометрии позволит отбрасывать правильную тень и будет хорошо выглядеть. Как всегда вам ничего особо то и не нужно делать - Ultimate 3D выполнит работу за вас, автоматически. вы только должны попросить.

Эта функция создает геометрию, которая оптимизирована для отбрасывания теней для объекта модели, для которого она вызвана. Её нужно вызывать после функций загрузки модели LoadMesh() и если используются уровни детализации, то и после CreateLODChain().

CreateShadowOptimizedGeometry(LODIndex, CreateConnectionPatches)

LODIndex - индекс уровня детализации

Этот параметр определяет для какого уровня детализации вы хотите создать оптимизированную геометрию. Это позволяет использовать вам тень низкой детализации, когда вы используете модель с высокой детализацией. Наиболее детализированный уровень оптимизированной геометрии будет использован для отбрасывания тени. Значение 0 для этого параметра ссылается на самый высокий уровень детализации (саму модель, не измененную), 1 на следующий уровень детализации, и т.д.

CreateConnectionPatches - улучшить геометрию для отбрасывания более точной тени

Если вы поставите этот параметр на true, то эта функция создаст геометрию, тени которой будут абсолютно точны, но цена за это высока. Будет создано по два треугольника для каждого угла модели. Если вы поставите false, то тогда участки связи (треугольники) не будут созданы, что означает более высокую производительность при менее детализированных тенях.

Но даже эта функция не может правильно оптимизировать геометрию в некоторых случаях. В таких случаях вы получите ужасный результат. Тень не остановится на модели, а продлится в бесконечность. Вы тогда увидите бесконечно длинные черные полосы. Так как же должна выглядеть модель что не получилось такого эффекта? Сказать то это легко, а вот понять - трудно. Все углы модели не должны быть разделены более чем двумя треугольниками. Вот иллюстрация, показывающая пример.

Геометрию справа можно было бы отлично оптимизировать, потому что она состоит из одногранных углов (синий цвет) и двухгранных углов (зелёный цвет). Но также есть и угол, граничащий с тремя треугольниками (красный цвет). Поэтому механизм Ultimate 3D, используемый для заполнения отверстий (дыр, holes) в геометрии модели, не может найти верное решение для такой ситуации, результатом чего становится не правильная тень. Вот почему в вашей сцене не должно быть моделей, отбрасывающих тени, с похожими углами. В этом вы должны сами убедится, Ultimate 3D не может сделать этого за вас, потому что математический механизм, используемый для этого не может найти уникальное решение для данной ситуации. Но это ведь малая плата за использование абсолютно реалистичных теней в реальном времени, не так ли?


Èçìåíåíèå ìîäåëåé íà ëåòó

Изменение моделей

Изменение моделей

В некоторых случаях вам может потребоваться изменить геометрию модели когда игра уже запущена. Например, вы хотите чтобы модель была деформирована после удара по ней оружием (например как в игре Мафия: Город Потерянных Ангелов, при ударе по машине, она деформируется). Эту деформацию можно реализовать через вершинные шейдеры. Но это очень не удобно. Именно по этому Ultimate 3D даёт вам возможность изменять геометрию моделей прямо во время игры. Вы можете редактировать каждую из вершин модели. Вы также можете изменить как именно вершины образуют треугольники. Вы так же можете изменить материал для треугольника. Вы даже можете сделать редактор моделей на основе Ultimate 3D.

Есть так же возможность изменять анимацию моделей. Например, в шутере от третьего лица торс или голова персонажа поворачиваются за его взглядом. Это можно сделать при помощи Ultimate 3D двумя разными способами.

Изменение геометрии моделей

Перед тем как я объясню как изменять геометрию моделей, я расскажу что такое меш (mesh - замкнутый контур геометрии). Меш - это часть геометрии, представляющая собой замкнутый контур, единое целое. Меш может состоять из множества вершин и треугольников. Если вы используете модели в формате *.md2, то каждый кадр - это один меш. Когда вы используете модели в формате *.3ds, то они могут состоять из нескольких мешей. Если вы используете анимированные модели в формате *.an8, То каждый созданный вами в редакторе объект - меш. Когда вы создаете уровни детализации модели (LOD), то тем самым создается по одной копии каждого меша.

Очень важно помнить что Ultimate 3D никогда не создает один и тот же меш дважды! Когда вы загружаете модель из файла, то все объекты, которые используют эту модель, будут использовать одни и те же меши. Иначе бы требовалось огромное количество памяти на использование стольких копий модели. Так что если вы модифицируете модель одного из объектов, то все остальные объекты, использующие эту же модель, тоже будут использовать модифицированную модель. Это не относится к другой информации, такой как кости, или материалы, ведь она занимает гораздо меньше памяти.

А вот и другой новый термин, который вам нужно знать. Как мы уже знаем, все 3D объекты состоят из вершин, которые формируют треугольники. А каждый треугольник состоит из трех вершин (во открытие то какое). Теперь взгляните на эту иллюстрацию.

Как вы видите, прямоугольник состоит из девяти вершин (помечены маленькими квадратиками) и восьми треугольников. Так как каждый треугольник состоит из трех вершин, то вы, наверное, подумали что требуется 24 вершины. Но тут всего девять, только две из которых используются только одним треугольником (помечены зелёным цветом). Вершина в центре (помечена красным цветом) используется шестью треугольниками. И такое происходит довольно часто. К счастью, давным давно (аж в эпоху больших компьютеров, с трехэтажные дома. щютка :) придумали простой способ избежать растраты памяти. Как же он действует? Всё очень просто. Вы сохраняете каждую вершину отдельно. Порядок не имеет значения. Затем вы добавляете так называемый буфер индексов (index buffer; это понятие вам нужно запомнить), который содержит три индекса (целые числа, типа integer, которые ссылаются на вершины) для каждого треугольника. Так что, в действительности, треугольник не состоит из трех вершин, а из трех ссылок на вершины (как ярлыки на рабочем столе).

После всей этой теории, пришло время практики. В Ultimate 3D вы можете заблокировать (lock) любой меш, любой модели в любое время. Блокирование меша означает его подготовку к передачи информации о нём и его модификации. Это необходимо, потому что память, где сохранены данные меша, может управляться графическим устройством. Очень важно чтобы вы разблокировали (unlock) каждый заблокированный меш. Если вы этого не сделаете, то при рендере меша произойдет ошибка доступа и вы получите сообщение об ошибке рендера или одно из сообщение Game Maker "unexpected errors" (неизвестная ошибка). Для того чтобы заблокировать меш, можно использовать эту функцию:

Эта функция блокирует заданный меш модели, для которой она вызвана.

LockMesh(LockedMeshIndex, MeshIndex, Frame, LoD)

LockedMeshIndex - индекс заблокированного меша

В Ultimate 3D вы не можете заблокировать более 32 мешей одновременно. Этот параметр принимает значения от 0 до 31. Это будет индексом, с которым ассоциируется блокируемый меш.

MeshIndex - индекс блокируемого меша

Индекс меша, который вы хотите заблокировать. Я рекомендую написать цикл для обхода всех мешей модели. Вы можете использовать функцию GetMeshCount() для получения количества мешей модели в выбранном кадре.

Frame - кадр

Кадр в котором вы хотите модифицировать меш. Если вы не используете эту функцию для блокирования мешей модели, загруженной из файлов формата *.md2 или объекта, созданного с помощью функции AddFrame(), то вы всегда должны ставить 0 для этого параметра.

LoD - уровень детализации

Уровень детализации, который вы хотите изменить. Наивысший уровень детализации имеет индекс 0. Если вы не используете уровни детализации для модели, то так же должны установить этот параметр равным 0.

Эта функция разблокирует меш и освобождает индекс заблокированного меша. Её нужно вызвать для каждого заблокированного меша функцией LockMesh().

UnlockMesh(LockedMeshIndex)

LockedMeshIndex - индекс заблокированного меша

Индекс меша который вы хотите разблокировать.

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

Эта функция изменяет одну вершину заблокированного меша модели:

SetLockedMeshVertex(LockedMeshIndex,VertexIndex,ValueIndex,NewValue)

LockedMeshIndex - индекс заблокированного меша

Индекс заблокированного меша, который вы хотите изменить. Это значение вы ввели первому параметру, когда вызывали функцию LockMesh() для блокирования меша.

VertexIndex - индекс вершины

Индекс вершины, которую вы хотите изменить. Я рекомендую написать цикл для обхода всех вершин. Вы можете использовать функцию GetLockedMeshVertexCount(LockedMeshIndex) для получения количества вершин заблокированного меша.

ValueIndex - индекс изменяемого параметра

Этот параметр определяет какую часть информации о вершине вы хотите изменить. Так как Ultimate 3D использует другую систему координат, нежели Game Maker, то информация отсортивана в таком порядке:

0 = VertexPositionX - 0 - Позиция вершины по оси X

1 = VertexPositionZ - 1 - Позиция вершины по оси Z

2 = VertexPositionY - 2 - Позиция вершины по оси Y

3 = VertexNormalX - 3 - X-компонента нормали вершины

4 = VertexNormalZ - 4 - Z-компонента нормали вершины

5 = VertexNormalY - 5 - Y-компонента нормали вершины

6 = VertexTextureCoordinate1U - 6 - Первая текстурная координата вершины U

7 = VertexTextureCoordinate1V - 7 - Первая текстурная координата вершины V

Затем следуют индексы текстурных координат, добавленных функцией AddTextureCoordinateSet(). Нормаль вершины - это вектор, необходимый для расчетов освещения объекта. Чаще всего его не требуется изменять вручную. Если вы изменили геометрию меша, то вы можете вызвать функцию RecalculateNormals() для автоматического перерасчета всех нормалей меша.

NewValue - новое значение

Новое значение, которое вы хотите установить для выбранного параметра.

Функция возвращает выбранную часть информации о вершине заданного меша:

GetLockedMeshVertex(LockedMeshIndex,VertexIndex,ValueIndex)

LockedMeshIndex - индекс заблокированного меша

Индекс заблокированного меша, чьи данные вы хотите получить. Это значение вы ввели первому параметру, когда вызывали функцию LockMesh() для блокирования меша.

VertexIndex - индекс вершины

Индекс вершины, о которой вы хотите узнать информацию. Я рекомендую написать цикл для обхода всех вершин. Вы можете использовать функцию GetLockedMeshVertexCount(LockedMeshIndex) для получения количества вершин заблокированного меша.

ValueIndex - индекс параметра

Этот параметр определяет какую часть информации о вершине вы хотите получить. Для подробного описания смотрите аналогичный параметр в функции SetLockedMeshVertex().

Эта функция изменяет вершины, которые используются треугольником.

SetLockedMeshTriangle(LockedMeshIndex, TriangleIndex, VertexIndexA, VertexIndexB, VertexIndexC)

LockedMeshIndex - индекс заблокированного меша

Индекс заблокированного меша, который вы хотите модифицировать. Это значение вы ввели для первого параметра, когда вызывали функцию LockMesh() для захвата меша.

TriangleIndex - индекс треугольника

Индекс треугольника, который вы хотите изменить. Я рекомендую использовать цикл для обхода всех треугольников меша.

Вы можете использовать функцию GetLockedMeshTriangleCount(LockedMeshIndex) для получения количества треугольников в заблокированном меше.

VertexIndexA, VertexIndexB, VertexIndexC - вершины 1, 2, 3

Индексы вершин, которые использует треугольник. Знайте что порядок в котором следуют вершины очень важен для техники отбора задней стороны полигона (задняя сторона полигона не рисуется, задней считается сторона, когда обход вершин идет против часовой стрелки). Вы не должны вводить значение большее чем количество вершин в меше. Это может вызвать серьезные проблемы с изображением.

Эта функция возвращает одну из вершин треугольника заблокированного меша:

GetLockedMeshTriangle(LockedMeshIndex,TriangleIndex,RequestedVertexIndex)

LockedMeshIndex - индекс заблокированного меша

Индекс заблокированного меша. Это значение вы ввели для первого параметра, когда вызывали функцию LockMesh() для захвата меша.

TriangleIndex - индекс треугольника

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

Вы можете использовать функцию GetLockedMeshTriangleCount(LockedMeshIndex) для получения количества треугольников в заблокированном меше.

RequestedVertexIndex - запрашиваемая вершина

Номер вершины в треугольнике чей индекс вы хотите получить. Вы можете использовать для этого параметра значения 0, 1 или 2 для получения первой, второй или третьей вершины треугольника.

Эта функция изменяет материал, который используется треугольником:

SetLockedMeshTriangleMaterial(LockedMeshIndex,TriangleIndex,NewMaterialIndex)

LockedMeshIndex - индекс заблокированного меша

Индекс заблокированного меша, который вы хотите модифицировать. Это значение вы ввели для первого параметра, когда вызывали функцию LockMesh() для захвата меша.

TriangleIndex - индекс треугольника

Индекс треугольника, который вы хотите изменить. Я рекомендую использовать цикл для обхода всех треугольников меша.

Вы можете использовать функцию GetLockedMeshTriangleCount(LockedMeshIndex) для получения количества треугольников в заблокированном меше.

NewMaterialIndex - индекс нового материала

Индекс нового материала, который вы хотите использовать треугольником. Вы можете использовать функцию GetMaterialIndex() для получения этого значения.

Эта функция возвращает индекс материала, который используется треугольником:

GetLockedMeshTriangleMaterial(LockedMeshIndex,TriangleIndex)

LockedMeshIndex - индекс заблокированного меша

Индекс заблокированного меша. Это значение вы ввели для первого параметра, когда вызывали функцию LockMesh() для захвата меша.

TriangleIndex - индекс треугольника

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

Вы можете использовать функцию GetLockedMeshTriangleCount(LockedMeshIndex) для получения количества треугольников в заблокированном меше.

Ниже представлена другая функции для изменения моделей. Её можно использовать для добавления нового набора текстурных координат для всех мешей модели (при этом мешы должны быть НЕ ЗАБЛОКИРОВАННЫМИ). Вы уже видели как можно изменить текстурную координату вершины в описании функции SetLockedMeshVertex(). Есть более простой способ добавить текстурные координаты. Вы просто создаете две версии модели с двумя различными текстурными координатами. Затем вы используете временный объект для модели со вторым набором текстурных координат, блокируете его меши и меши первой модели, затем копируете текстурные координаты второй модели к первой, во второй набор, в цикле. Когда вы закончите, вы можете удалить вторую модель и объект. Но давайте посмотрим на функцию.

Эта функция добавляет новый много-размерный набор текстурных координат для всех мешей объекта, для которого вызвана эта функция (и для всех объектов основанных на этой же модели!).

AddTextureCoordinateSet(DimensionCount)

DimensionCount - размерность набора текстурных координат

Размерность нового набора текстурных координат. Это значение должно быть целым числом (integer) в пределах от 1 до 4. Одноразмерный набор содержит только одно числовое значение в координате текстуры (U), двухмерный набор содержит два числовых значения в координате текстуры (U, V), трехмерный набор содержит соответственно три значения (U, V, W) и четырехмерный набор содержит четыре значения (U, V, W, Q).

Ну и наконец функция, которая позволяет использовать множество текстурных координат гораздо проще. Она позволяет вам просто добавить набор текстурных координат из другого файла такой же модели, но с разными наборами текстурных координат. Например использование карт освещения (light mapping) требует один набор текстурных координат для текстуры диффузии и еще один для карты освещения. Проблема состоит в том что не один из поддерживаемых форматов моделей (за исключением *.u3d) не поддерживает несколько наборов текстурных координат. Вам придется создать две одинаковые модели, но с разными текстурными координатами и использовать следующую функцию чтобы добавить набор текстурных координат из второй модели к загруженной первой.

Эта функция копирует все текстурные координаты из указанного файла модели и добавляет их к модели, для объекта которой вызвана эта функция. Все объекты что используют эту же модель будут так же использовать модифицированную её. Меши модели НЕ ДОЛЖНЫ БЫТЬ ЗАБЛОКИРОВАНЫ.

AddTextureCoordinateSetsFromModel(ModelFile, Password)

ModelFile - файл модели

Модель, чей набор текстурных координат будет добавлен. Эта модель должна иметь одинаковое число мешей и вершин как и модель для объекта которой вызвана функция.

Password - пароль

Пароль необходим только при загрузке зашифрованных *.u3d файлов, иначе вы можете его не указывать, или поставить 0, или использовать пустую строку.

Манипуляция анимацией

Для игр от третьего лица особенно часто требуется движения игрока происходили интерактивно. Ну например ваш персонаж целится в кого-то, то его торс должен наклонятся вверх или вниз, когда игрок целится вверх или вниз, чтобы выглядело реалистично. Ultimate 3D предлагает вам два различных способа сделать это. Первый - это просто изменить углы вращения отдельной кости модели. Это очень простой способ решить такую задачу, но это выглядит не очень красиво. Но есть еще возможность отдельным костям назначить произвольный кадр анимации. Так вы можете, например заставить верхнюю часть тела выполнять другую анимацию, нежели остальное. Для обоих этих способов вам потребуется функция для получения индекса кости, которую вы хотите модифицировать.

Эта функция возвращает индекс кости с заданным именем или 0 если она не существует:

GetBoneIndex(BoneName)

BoneName - название кости

Это название кости, чей индекс вы хотите получить. Оно зависит от того как вы назвали кость в редакторе (в некоторых называть кости нельзя).

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

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

SetBoneRotation(BoneIndex,RotationX, RotationY, RotationZ)

BoneIndex - индекс кости

Индекс кости которую вы хотите изменить.

RotationX, RotationY, RotationZ

Новое вращение. Переменные означают тоже что и переменные модели rotx, roty и rotz.

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

Эту функцию можно использовать для установки кадра анимации для отдельных костей модели,для объекта которой, вызвана эта функция.

SetBoneFrame(BoneIndex,Frame,EffectChildBones)

BoneIndex - индекс кости

Индекс кости для которой вы хотите изменить кадр.

Frame - кадр

Положительное значение указывающее на номер используемого кадра. Оно будет использоваться в независимости от значения переменной frame.

EffectChildBones - эффект сети

Если вы установите значение для этого параметра на true (1), то этот кадр будет установлен не только для выбранной кости, но и для всех костей, которые прикреплены к ней. Если одна из таких дочерних костей имеет свой кадр, установленный функцией SetBoneFrame(), то он будет использоваться в независимости от того, поставили ли вы true или же false Для этого параметра.

Creating custom meshes Создание новых мешей

Иногда вам может потребоваться создать новый мешь модели. Это легко сделать с помощью Ultimate 3D. Вы создаете этот объект так же как и другие. Сначала устанавливаете несколько переменных, затем вы вызываете функцию для создания, ну и наконец добавляете функции Step() и Destroy() в соответствующие события.

material_count - количество материалов

Количество материалов нового объекта. Это значение должно быть больше нуля.

vertex_count - количество вершин

Количество вершин меша нового объекта. Должно быть более трех.

triangle_count - количество треугольников

Количество треугольников меша нового объекта. Это значение не должно быть равным нулю.

После установки этих переменных вы можете вызвать функцию CreateEmptyMesh(). Тогда будет создан меш с заданным числом материалов, вершин и треугольников и ассоциирован с тем объектом, для которого вызвана эта функция. После добавления функций Step() и Destroy() объект можно будет использовать. Но перед тем как увидеть результат, вы должны воспользоваться функциями изменения моделей для создания нужной геометрии. По умолчанию все данные вершин и треугольников будут заполнены нулями и все материалы будут не затекстурированы и в белом цвете.

Дополнительные функции

Здесь собраны наиболее часто используемые функции для изменения моделей. Ultimate 3D предлагает несколько легко-используемых функций. Наиболее важная - это функция перерасчета вектора нормалей, которые нужны для правильного по вершинного освещения. Еще одна функция сглаживает нормали мешей. Это значит что она ищет вершины с одинаковой позицией, но с разными нормалями, и исправляет их. Третья функция вычисляет кое что, называемое инверсией матрицы пространства касательных (inverse tangent space matrices) для каждой из вершин. Это иногда может потребоваться для некоторых шейдерных эффектов, таких как смещение параллакса (parallax mapping). Их можно использовать для трансформации векторов в текстурное пространство в вершинном шейдере. Вы сами должны знать где именно они вам будут нужны в ваших шейдерах.

Эта функция рассчитывает нормали вершин всех мешей объекта, для которого она вызвана. Её нужно вызывать после того как вы изменили геометрию модели, потому что старые нормали больше не будут подходить. Она не содержит никаких аргументов.

RecalculateNormals()

Эта функция сглаживает нормали всех мешей модели. Так как нормали нужны не только для расчетов освещения, но и для таких эффектов как цел-шейдинг (cel-shading) и карта окружения (environment mapping), перед их использованием вы должны вызвать эту функцию. Иначе вы можете получить вот такой вот эффект:

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

Эта функция высчитывает инверсию матрицы пространства касательных (inverse tangent space matrices) для каждой вершины каждого меша модели. Это означает что будут переписаны нормали значениями из второго столбца матрицы. Это также добавляет два новых трехмерных набора текстурных координат. В первом хранится первый столбец инверсии матрицы пространства касательных, а во втором - третий столбец. У этой функции нет никаких параметров. (Вы не знаете что такое матрица? Вы учитесь еще в школе? Тогда загляните в статью Википедии о матрице. Проще говоря матрица - это таблица, чаще всего 3х3, содержащая значения. Для неё существуют свои правила математических операций.) Вот и сама функция:

AddInverseTangentSpaceMatrices()

Cel-shading

Cel-shading - это техника, используемая для создания графики, выглядящей как нарисованный комикс. Еще её можно использовать для добавления штриха вокруг объектов. Cel-shading создает выдавленную версию каждого меша и прорисовывает их, используя технику обратного отбора невидимой поверхности (reverse back face culling). В результате получается штрих вокруг модели. Когда применяется cel-shading вы можете определить толщину штриха в пространстве меша и его цвет. По умолчанию цвет штриха - абсолютно черный. Но вы можете использовать любой другой цвет, который пожелаете, для создания потрясающих эффектов. Например вы можете использовать прозрачный красный цвет для акцентирования внимания игрока на нужном вам объекте. Вот функция, которая это делает:

Эта функция включает Cel-Shading для модели объекта, для которого она вызвана.

ApplyCelShading(LineWidth,LineColorR, LineColorG, LineColorB,LineColorA)

LineWidth - толщина линии штриха

Толщина штриха в пространстве меша, которую вы хотите использовать.

LineColorR, LineColorG, LineColorB, LineColorA - компоненты цвета линии штриха

Цвет штриха. Значения для этого параметра должны быть в пределах от 0 до 255. Параметр LineColorA задает прозрачность штриха. 0 означает полную прозрачность и 255 полностью непрозрачный.

Помните что Cel-Shading использует вершинные шейдеры. Поэтому модели, использующие вершинный скининг (vertex skinning) и Cel-Shading должны состоять не более чем из 28-и костей, иначе некоторые кости будут неправильно преобразованы.


Ñîçäàíèå ÷àñòèö

Создание частиц

Создание эффектов при помощи частиц

Эффекты частиц. Какая это замечательная штука. Вы можете иметь тысячи маленьких поверхностей (billboards), которые интерактивно просчитываются, основываясь на заданной вами информации о поведении системы частиц. Система частиц Ultimate 3D 2.0 полностью переделана. Она стала очень удобной. Во-первых, вы можете изменить очень много свойств частиц, таких как скорость, ускорение, размеры, цвет, ... . Во-вторых, вы можете добавить эмиттеры гравитации. Ну и наконец вы можете установить модификаторы, которые изменяют частицы, когда они попадают в определенную зону. Каждая из частиц в Ultimate 3D может иметь неограниченные размеры. А использование частиц так легко, что вы не сможете пропустить эту главу.

Создание системы частиц и установка основных параметров

Создание системы частиц - это самое простое, что только можно представить. Вы не должны устанавливать никаких переменных. Всё что вы должны сделать, так это вызвать функцию CreateParticleSystem() в событие создания объекта. Но естественно это еще не всё. Вы должны сказать Ultimate 3D как должна выглядеть система частиц. Для этого вы должны вызвать несколько других функций, после CreateParticleSystem(). Еще есть переменная, определяющая текстуру частицы. Первые две функции определяют количество частиц, создаваемых каждый шаг и время жизни частиц. все следующие функции будут иметь несколько одних и тех же параметров - один для минимального значения, а другой для максимального значения. Ultimate 3D будет выбирать случайное значение в промежутке между минимальным и максимальным значением. Это позволяет каждой частице быть индивидуальной. Вот две эти функции:

Эта функция устанавливает количество частиц, которые будут созданы Ultimate 3D каждый шаг.

SetParticleCount

(

MinimumParticleCount,

MaximumParticleCount,

MaximumTotalParticleCount

)

MinimumParticleCount, MaximumParticleCount - минимальное и максимальное кол-во

Количество частиц, которое будет создаваться каждый шаг.

MaximumTotalParticleCount - всего частиц

Максимальное количество частиц, которые могут одновременно существовать. Если частиц больше чем этот параметр, то Ultimate 3D больше не будет создавать новые частицы, пока их количество снова не станет меньше этого параметра. Обычно подходящее для этого значение можно найти по формуле (МаксВремяЖизни + МинВремяЖизни)/2 * (МаксЧастицЗаШаг + МинЧастицЗаШаг)/2 . По-английски это будет выглядеть так: (MaximumLifetime+MinimumLifetime)/2*(MaximumParticleCount+MinimumParticleCount)/2 .

Эта функция устанавливает продолжительность жизни частиц для той системы частиц, для объекта которой вызвана эта функция. Время жизни - это количество шагов с момента создания частицы до её уничтожения.

SetParticleLifetime(MinimumParticleLifetime,MaximumParticleLifetime)

MinimumParticleLifetime, MaximumParticleLifetime - время жизни частицы

Промежуток для генерации времени жизни частиц этой системы частиц.

Теперь давайте поподробнее. Вы можете определить где будет создана частица. Если вы хотите то можете пропустить этот шаг. Но тогда все частицы будут созданы в одной и той же позиции, что выглядело бы довольно скучно. Для определения области создания частиц, вы должны установить трансформацию и числовое значение. Представьте что у вас есть модель сферы (первая сфера) с радиусом 1. Если к ней применить трансформацию, которую вы зададите следующей функцией, то вы увидите зону где могут быть созданы частицы. Числовое значение будет использовано как масштаб для второй сферы с такой же трансформацией. Это другой предел, ограничивающий зону для создания частиц. Изображение справа иллюстрирует это:

ParticleOriginRus

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

Эта функция устанавливает зону для создания частиц. Позиция системы частиц не устанавливается функцией - это сделано для большего удобства. Для установки координат системы частиц воспользуйтесь переменными x, y и z.

SetParticleOrigin

(

SecondSphereRadius,

RotationX, RotationY, RotationZ,

ScalingX, ScalingY, ScalingZ

)

SecondSphereRadius - радиус второй сферы

Радиус второй сферы, которая является второй границей для зоны создания частиц. Если вы поставите для этого параметра 0, то частицы будут появляться по всей первой сфере.

RotationX, RotationY, RotationZ - вращение X, Y, Z

Углы вращения, которые будут использоваться как трансформация сфер. Обычно вы не будете использовать этот параметр, если конечно не введете разные значения для масштабирования по координатным осям.

ScalingX, ScalingY, ScalingZ - масштаб X, Y, Z

Масштаб, который будет применен к обоим сферам.

Следующие две функции устанавливают скорость и ускорение частиц (ускорение - это насколько изменится скорость частицы каждый шаг). Это очень просто. Всё что вы должны помнить об этой функции, так это то что долгота (longitude) должна быть в пределах от -90 до +90, иначе методы, используемые Ultimate 3D для равномерного распределения частиц, могут неправильно работать.

Эта функция устанавливает первоначальную скорость и направление движения частиц системы частиц, для которой вызвана эта функция.

SetParticleVelocity

(

MinLongitude, MinLatitude,

MinVelocity,

MaxLongitude, MaxLatitude,

MaxVelocity

)

MinLongitude, MinLatitude, MaxLongitude, MaxLatitude - направление движения частиц

Начальное направление движения частиц в градусах. Значения для долготы должны быть в пределах от -90 до +90 градусов.

MinVelocity, MaxVelocity - скорость

Начальная скорость движения частиц каждый шаг.

Эта функция устанавливает начальное ускорение частиц в той системе частиц, для которой вызвана эта функция.

SetParticleAcceleration

(

MinLongitude, MinLatitude,

MinAcceleration,

MaxLongitude, MaxLatitude,

MaxAcceleration

)

MinLongitude, MinLatitude, MaxLongitude, MaxLatitude - направление ускорения

Направление изменения направления движения в градусах. Долгота (longitude) должна быть в пределах от -90 до +90.

MinAcceleration, MaxAcceleration - ускорение

Насколько будет изменятся скорость частицы каждый шаг зависит от этого параметра.

Далее вы можете установить центр силы толчка (initial center repulsion) . Это очень часто используется для создания эффектов взрыва. Когда создаются частицы, то сила толчка умножается на различие позиции частицы и центра зоны создания. Затем результат складывается с начальной скоростью движения частиц. Вот формула: Начальная скорость += ( Позиция частицы - Позиция системы частиц ) * Сила толчка ). Силу толчка нужно установить для каждой оси в отдельности. Вот сама функция:

Эта функция устанавливает силу толчка:

SetInitialCenterRepulsionFactor(RepulsionFactorX, RepulsionFactorY, RepulsionFactorZ)

RepulsionFactorX, RepulsionFactorY, RepulsionFactorZ - сила толчка

Сила толчка по каждой из осей.

Далее вы можете установить цвет и размер частиц. Для каждой из них вы можете установить промежуток возможных первоначальных и конечных значений. Финальные значения будут использоваться частицей в конце её жизни. Ниже приведены функции для установки этих значений:

Эта функция устанавливает промежуток возможных значений цвета для частиц.

SetInitialParticleColor(MinimumR, MinimumG, MinimumB, MinimumA,MaximumR, MaximumG, MaximumB, MaximumA)

MinimumR, MinimumG, MinimumB, MinimumA - минимальные значения цвета

Минимально возможные значения для первоначального цвета частицы. Эти значения должны быть в пределах от 0 до 255. Параметр MinimumA определяет первоначальный уровень прозрачности, где значение 0 - это полная прозрачность, а 255 - полностью не прозрачный цвет.

MaximumR, MaximumG, MaximumB, MaximumA - максимальные значения цвета

Максимально возможные значения для первоначального цвета частицы. Эти значения должны быть в пределах от 0 до 255.

Эта функция устанавливает промежуток возможных конечных значений цвета частиц.

SetFinalParticleColor(MinimumR, MinimumG, MinimumB, MinimumA, MaximumR, MaximumG, MaximumB, MaximumA)

MinimumR, MinimumG, MinimumB, MinimumA - минимальные значения цвета

MaximumR, MaximumG, MaximumB, MaximumA - максимальные значения цвета

Эти параметры полностью идентичны аналогичным параметрам функции SetInitialParticleColor(), но они уже применимы к финальному цвету частицы.

Эта функция устанавливает промежуток возможных начальных и финальных размеров частиц. Размеры даются в мировом пространстве, так что они интерпретируются так же как и размеры для поверхностей (billboards).

SetParticleSize(MinInitialSize, MaxInitialSize,MinFinalSize, MaxInitialSize)

MinInitialSize, MaxInitialSize - промежуток возможного начального размера

Промежуток возможного начального размера частицы.

MinFinalSize, MaxFinalSize - промежуток возможного конечного размера

Промежуток возможного конечного размера частиц, который они будут иметь, под конец своего существования.

Теперь вы знаете как установить свойства вашей системы частиц, пришло время привести её в действие. Чтобы сделать это вы должны поместить одну функцию в событие шага объекта, но на этот раз это не Step(). Эта функция содержит один параметр и её не нужно вызывать каждый шаг, потому что её выполнение требует некоторое время, в зависимости от количества частиц, гравитационных эмиттеров и модификаторов. Нет смысла выполнять расчеты для системы частиц, которую сейчас не видно на экране.

Эта функция выполняет шаг заданной длины для системы частиц, для объекта которой вызвана эта функция.

ParticleSystemStep(StepLength)

StepLength - длина шага

Длина шага на которую вы хотите рассчитать систему. Некоторые называют это фактором времени или количеством шагов, выполненных за раз. Если вы поставите тут единицу, то за каждый вызов функции будет выполняться один шаг.Если вы поставите 0.5, то все будет происходить в два раза медленнее, а если вы поставите 2, то в два раза быстрее. Помните что очень большие значения длины шага могут привести к некоторым неточностям при вычислениях, особенно когда имеется много гравитационных эмиттеров и модификаторов, но так вы можете повысить производительность, вызывая эту функцию, например раз в два шага Game Maker.

Ну и не забудьте написать функцию Destroy() в событии уничтожения объекта системы частиц, иначе система частиц будет все еще видима после уничтожения объекта.

Эмиттеры гравитации

Эмиттеры гравитации - это просто потрясающие штуки! (Gravity emitters are really cool). Они могут заставить частицы двигаться никогда не повторяющейся "цепочкой". Гравитационные эмиттеры ( от слова emit - испускать, излучать) могут иметь "отрицательную" гравитацию, что позволяет отталкивать частицы и является очень полезным для некоторых эффектов. Гравитационные эмиттеры используют реальную физику, так что если вы ничего не знаете о Ньютоновской теории гравитации (Пока вы спали на уроке физики, то ваш учитель рассказывал, что Ньютон - это тот чувак, которому по башке яблоком упало и тогда он понял что такое гравитация...), то вам будет казаться что частицы ведут себя вполне реалистично. Помните что с помощью гравитационных эмиттеров нельзя задать направление гравитации только в одну сторону (гравитация всегда направлена к центру эмиттера, а не только допустим вниз), это проще сделать с помощью правильной настройки постоянного ускорения.

Использовать гравитационные эмиттеры очень легко. Вы просто устанавливаете их позицию в мировом пространстве (world space) и интенсивность (силу) излучаемой гравитации. Остальное делается автоматически. Гравитационные эмиттеры следует использовать с осторожностью, так как они просчитываются для каждой частицы в отдельности, что занимает некоторое время для расчетов. В Ultimate 3D есть ограничение в 32 гравитационных эмиттера на систему частиц. Вот функция, которую вы можете использовать для создания гравитационных эмиттеров:

Эта функция добавляет новый гравитационный эмиттер в систему частиц и возвращает его ID, который можно использовать позже для модификации эмиттера.

AddGravityEmitter(PositionX, PositionY, PositionZ, GravityEmitterMass)

PositionX, PositionY, PositionZ - позиция гравитационного эмиттера

Позиция гравитационного эмиттера в мировом пространстве (world space).

GravityEmitterMass - масса гравитационного эмиттера

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

Эту функцию можно использовать для модификации или удаления гравитационного эмиттера, который был уже ранее создан функцией AddGravityEmitter().

SetGravityEmitter(GravityEmitterID, PositionX, PositionY, PositionZ, GravityEmitterMass)

GravityEmitterID - ID (индекс) гравитационного эмиттера

Индекс гравитационного эмиттера, который вы хотите изменить. Это значение вы получили при вызове функции AddGravityEmitter().

PositionX, PositionY, PositionZ - позиция гравитационного эмиттера

Новая позиция гравитационного эмиттера в мировом пространстве.

GravityEmitterMass - масса гравитационного эмиттера

Новая масса гравитационного эмиттера. Если вы поставите для этого параметра значение 0, то гравитационный эмиттер будет уничтожен.

Модификаторы частиц

Иногда нужно изменить частицы, когда они вошли в определенную зону. Например когда струя водопада касается водной поверхности, то должны появляться брызги. Это очень легко сделать с помощью модификаторов частиц. Модификаторы частиц (particle modifiers) изменяют частицы, когда они находятся в определенной зоне. Они могут изменить любой параметр частицы. Это делает системы частиц более удобными и гибкими в использовании.

Установка свойств модификатора частиц очень похожа на установку свойств системы частиц. Всё реализовано через функции, и многие из свойств подобны свойствам системы частиц. Но перед установкой свойств для модификатора частиц, нужно его создать. Для этого существует функция AddModifier(). она возвращает индекс (ID) созданного модификатора. Ниже представлены функции, необходимые для установки свойств модификатора частиц:

Эта функция устанавливает зону для модификатора частиц. Она работает также как и установка зоны создания частиц ( particle origin; смотрите SetParticleOrigin() ). Когда частица попадает в эту зону, то она изменяется:

SetModifierEffectedArea

(

ModifierID,

SecondSphereRadius,

PositionX, PositionY, PositionZ,

RotationX, RotationY, RotationZ,

ScalingX, ScalingY, ScalingZ

)

ModifierID - индекс модификатора частиц

Индекс модификатора частиц, который вы хотите изменить (естественно изменить модификатор).

SecondSphereRadius - радиус второй сферы

Радиус второй сферы, которая является второй границей для определяемой зоны.

PositionX/Y/Z, RotationX/Y/Z, ScalingX/Y/Z - трансформация зоны

Трансформация двух сфер, которые ограничивают определяемую зону.

Эта функция устанавливает модификатор времени жизни частицы, когда она находится в зоне модификатора частиц. Так что если вы установите его равным единице, то частице никогда не самоуничтожится, пока находится в зоне модификатора, так как её время жизни увеличивается (и уменьшается) на один за каждый шаг.

SetModifierLifetimeChange(ModifierID, LifetimeChange)

ModifierID - индекс модификатора частиц

Индекс модификатора частиц, параметр которого вы хотите изменить.

LifetimeChange - время жизни частицы

Насколько изменится время жизни частицы. (Что-то вроде таймера обратного отсчета, когда время жизни будет равно нулю то частица уничтожится)

Следующие две функции определяют как модификатор изменит скорость и ускорение частицы, когда она попадет в зону модификатора. Когда частица находится в зоне модификатора, то её скорость или ускорение изменяются по этой формуле: Значение = Значение * Фактор + Слагаемое. В этой формуле "Значение" - это скорость или ускорение. Так что установив фактор (фактором еще называется множитель) ускорения меньше единицы - вы получите эффект торможения (трения). А установив отрицательные значения вы можете обратить направление движения частиц. Вот функция для установки этих параметров:

Эта функция устанавливает модификатор скорости частиц для зоны модификатора частиц:

SetModifierVelocityChange

(

ModifierID,

VelocityFactorX, VelocityFactorY, VelocityFactorZ,

VelocitySummandX, VelocitySummandY, VelocitySummandZ

)

ModifierID - индекс модификатора частиц

Индекс модификатора частиц, параметры которого вы хотите изменить.

VelocityFactorX, VelocityFactorY, VelocityFactorZ - фактор скорости

Множитель, на который будет умножена скорость частицы в каждом шаге, пока частица находится в зоне модификатора частиц. Его можно установить индивидуально для каждой оси.

VelocitySummandX, VelocitySummandY, VelocitySummandZ - слагаемое

Слагаемое, которое будет добавлено к скорости частицы в каждом шаге, пока частица находится в зоне модификатора частиц. Его можно установить индивидуально для каждой оси.

Эта функция устанавливает модификатор ускорения частицы для модификатора частиц:

SetModifierAccelerationChange

(

ModifierID,

AccelerationFactorX, AccelerationFactorY, AccelerationFactorZ,

AccelerationSummandX, AccelerationSummandY, AccelerationSummandZ

)

ModifierID - индекс модификатора частиц

Индекс модификатора частиц, параметр которого вы хотите изменить.

AccelerationFactorX, AccelerationFactorY, AccelerationFactorZ - фактор ускорения

Множитель, на который будет умножено ускорение частицы в каждом шаге, пока частица находится в зоне модификатора частиц. Его можно установить индивидуально для каждой оси.

AccelerationSummandX, AccelerationSummandY, AccelerationSummandZ - слагаемое

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

Теперь вы можете установить новые конечные цвет и размер частицы, которая вошла в зону модификатора. Так как вы измените только финальные значения, то не произойдет никакого "скачка", и все изменения будут применены постепенно. Вот эти функции:

Эта функция устанавливает промежуток возможных значений конечного цвета частиц, попавших в зону модификатора частиц.

SetModifierNewFinalColor

(

ModifierID,

MinimumR, MinimumG, MinimumB, MinimumA,

MaximumR, MaximumG, MaximumB, MaximumA

)

ModifierID - индекс модификатора частиц

Индекс модификатора частиц, параметр которого вы хотите изменить.

MinimumR/G/B/A, MaximumR/G/B/A - цвет

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

Эта функция изменяет финальный размер частиц, попавших в зону модификатора частиц.

SetModifierNewFinalSize

(

ModifierID,

MinimumNewFinalSize, MaximumNewFinalSize

)

ModifierID - индекс модификатора частиц

Индекс модификатора частиц, параметр которого вы хотите изменить.

MinimumNewFinalSize, MaximumNewFinalSize - конечный размер

Промежуток возможного конечного размера частицы в мировом пространстве.


Èñïîëüçîâàíèå ëàíäøàôòîâ

Использование ландшафтов

Использование обработчика ландшафтов

С помощью обработчика ландшафтов можно создавать поистине гигантских размеров ландшафты из карт высот. Он использует одну из лучших методик прорисовки ландшафтов. Она называется Geo-mip-mapping (Гео-мип-мэппинг - Глобальное деление карты). довольно трудно использовать обработчик ландшафтов, не зная как он работает, так что я объясню вам это.

Geo-mip-mapping and texture splatting

Так что же такое Гео-мип-мэппинг? Это техника, которая используется для создания различных уровней детализации ландшафтов. Ландшафт делится на множество квадратных кусков - тайлов (tiles). Каждый из этих кусков имеет пять различных уровней детализации с количеством треугольников изменяющимся от 2 до 512, в зависимости от степени детализации. Все они используют один и тот же буфер вершин, что позволяет повысить производительность и сэкономить память. На этом рисунке показан пример различных уровней детализации тайлов ландшафта.

В зависимости от различия высоты тайлов и дистанции до камеры, Ultimate 3D определяет какой уровень детализации будет использоваться для прорисовки тайла. Это делает прорисовку ландшафта очень эффективной. Вы очень часто, при создании ландшафтов, столкнетесь с проблемой правильного текстурирования. Каждая часть ландшафта должна быть уникальна и детализирована, но текстура, которая покрывала бы весь ландшафт была бы очень огромной или же очень недетализированной. Ничего не поделаешь... Есть, конечно, одна техника для того чтобы избежать этого - использовать карты деталей (detail map), но будет это выглядеть так себе...

Но зато есть другая техника, более эффективная, и она называется Склеивание текстур (texture splatting - дословно "разбрызгивание текстур"). Когда используется склеивание текстур, то вы можете использовать столько текстур, сколько захотите, каждая будет многократно повторена (wrapping) на ландшафте. Затем вы можете использовать карты прозрачности для определения прозрачности текстур в некоторых точках. На рисунке показано как это происходит.

Texture splatting дает вам возможность создавать реалистично выглядящие ландшафты. Вы можете использовать текстуру камней для скал и текстуру травы или травы на поле для равнин. Еще вы можете добавить снег на вершины гор или добавить дороги по которым игрок сможет ходить.

Использование ландшафтов

Создать ландшафт очень легко. Сложности составляет только создание карт диффузии, карты высот и карт прозрачности (для этого нужно использовать сторонние программы). Но мы сейчас не об этом. В этой главе вы узнаете как создать ландшафт и установить различные текстуры для него. Как и любой другой объект Ultimate 3D, ландшафт требует объект Game Maker. И вам опять нужно будет установить переменные перед его созданием. Вот и они:

x, y, z - координаты ландшафта

Координаты начала (угла) ландшафта. Все точки ландшафта будут иметь координаты, большие чем эти значения.

height_map - карта высот

Файл карты высот, которую вы хотите использовать для создания ландшафта. (НЕ ИНДЕКС КАРТЫ ВЫСОТ). Например "gfx\TerrainHeightMap.png".

tile_count_x, tile_count_y - количество тайлов по осям

Количество тайлов по осям x и y. От этих значений зависит размер всего ландшафта. Они определяют насколько детально будет выглядеть ландшафт, сколько времени уйдет на его создание и прорисовку, а так же сколько памяти при этом будет потрачено. Вы не должны использовать большие значения, так например 100*100 - уже очень большое. Такой ландшафт займет в памяти около 57 мегабайт.

tile_size - размер тайла

Это значение определяет размер одного тайла по осям x и y в глобальном пространстве. Так что реальный размер ландшафта складывается из этих трех величин:

S=(tile_count_x * tile_size) * (tile_count_y * tile_size). Тайлы всегда квадратны.

height - высота ландшафта

Максимальная высота ландшафта. Черный пиксель на карте высот будет иметь z-координату равную координате ландшафта z, а белый пиксель карты высот будет иметь z-координату равную z-координате ландшафта плюс высота ландшафта: z+height.

base_texture - основная текстура

Файл, содержащий первую текстуру для ландшафта. Для этой текстуры не нужна никакая карта прозрачности, так как она не "лежит" поверх другой.

wrap_count_x, wrap_count_y - количество повторений текстуры

Количество повторений (wrap) первой текстуры по осям x и y. От этого зависит сколько раз текстура будет повторена на всем ландшафте. Обычно используются те же значения что и для tile_count_x и tile_count_y.

terrain_lod - уровень детализации ландшафта

Фактор детализации ландшафта, определяющий как Ultimate 3D будет выбирать какой Уровень Детализации использовать при прорисовке ландшафта. Эта переменная опциональна, так что вы не обязаны её устанавливать, в таком случае Ultimate 3D установит её на 1. Если вы введете значение меньшее чем 1, то будет использоваться менее детализированный ланшафт, если больше 1, то соответственно более детализированный ландшафт будет использован.

После установки этих переменных вы должны вызвать функцию CreateTerrain() для создания ландшафта и ассоциирования его с тем объектом, в котором вызвана эта функция. Теперь вы можете добавить текстуры ландшафту. Если же вы не хотите еще использовать текстуры, то посто вызовите функцию ApplyTerrainTextures(). Эта функция завершает наложение текстур на ландшафт. Так как ландшафт в основном статический объект, то вы не обязаны использовать функцию Step(). Но вам все же придется использовать Destroy(). Если вы хотите использовать больше текстур с помощью Текстурного Склеивания (texture splatting), то вы должны поместить еще несколько функций между CreateTerrain() и ApplyTerrainTextures(). Так как каждая текстура накладывается на предыдущую, то имеет порядок в котором вы будете применять текстуры. Вот эта функция:

Эта функция добавляет текстуру к ландшафту, используя технику texture splatting:

AddTerrainTexture(DiffuseMap, AlphaMap, WrapCountX, WrapCountY)

DiffuseMap - карта диффузии (текстура)

Файл с текстурой, которую вы хотите добавить к ландшафту.

AlphaMap - карта прозрачности

Файл с картой прозрачности для текстуры. Карта прозрачное это черно-белое изображение с градациями серого цвета. Белый цвет означает что в этом участке текстура не прозрачна.

WrapCountX, WrapCountY - наложение текстуры

Сколько раз текстура будет нарисована на ландшафте, по осям x и y. Это значит сколько раз текстура будет повторена на ландшафте. Будет лучше использовать разные значения для разных текстур.

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

Просчет карты освещения

Если вы уже создали несколько ландшафтов, то вы могли заметить что они не подвержены действию освещения. Это все потому что вершинное освещение (vertex lighting) было бы бесполезным, так как количество вершин в тайлах меняется в зависимости от расстояния, да и ежесекундно просчитывать миллионы вершин не такая уж легкая задача. Для затенения ландшафтов была придумана техника, называемая Карта Освещения (light map). Карта освещения - это текстура, накладывающаяся на ландшафт с текстурной операцией умножение (multiplicative texture operation), определяющая как освещен ландшафт.

Ultimate 3D может автоматически рассчитать карту освещения. Вы просто должны сказать какие источники освещения будут для этого использованы. Не советую использовать для этого движущиеся источники освещения, так как вы захотите обновлять карту освещения в каждом шаге, что просто невозможно из-за большого числа операций, которые нужно выполнить для создания карты освещения. Так что советую вам использовать для этого источники освещения, которые либо статичны, либо их движение незаметно, например солнце, так можно будет рассчитывать карту освещения не каждый шаг, а допустим раз в секунду, ну или раз в десять тысяч шагов. Ниже функция, которая рассчитывает карту освещения.

С помощью этой функции Ultimate 3D рассчитывает карту освещения ландшафта для того объекта Game Maker, Для которого вызвана эта функция.

CalculateTerrainLightMap(LightSourceID1, ..., LightSourceID10)

LightSourceID1, LightSourceID2, ..., LightSourceID10 - источники освещения

Индексы объектов Game Maker, которые являются источниками освещения и будут использованы для расчета карты освещения. Если вы хотите использовать менее десяти источников освещения, то просто не указывайте остальные или поставьте 0. Если вы установите 0 для всех источников освещения, то тогда будут использоваться все источники освещения сцены.

Если же встроенная функция расчета карты освещения вас не устраивает, то нет проблем. Ultimate 3D позволяет вам использовать внешнюю карту освещения. Вы можете создать её в любом графическом редакторе или специальной программе, такой как Earth Sculptor. Так вы можете создать карту освещения с уже рассчитанным затенением или чем то еще. Например у вас на ландшафте есть лес, то вы можете затемнить карту освещения в том месте, чтобы в игре ландшафт был затенен лесом. Такое невозможно сделать без использования внешних карт освещения. Так что, надеюсь, вы уже поняли насколько мощная эта функция.

Эта функция устанавливает текстуру в качестве карты освещения.

SetCustomTerrainLightMap(TextureIndex)

TextureIndex - индекс текстуры

Индекс текстуры, которую будут использовать как карту освещения для ландшафта. Если вы хотите снова переключится на автоматически рассчитываемую карту освещения, то просто введите неиспользуемый индекс.

Создание карты высот и карт прозрачности

Для создания карты высот и карт прозрачности я рекомендую вам использовать очень удобную программу Earth Sculptor. Её очень легко использовать, да и идет она вместе с подробным руководством. Так как программа имеет статус Бета-версии, то она бесплатна (пока что?). Так что если вы найдете ошибку (баг - bug) или у вас есть идеи для будущих версий программы, то вы должны сообщить их создателю программы Ernest Szoka.

Как только вы создадите ландшафт в , то вы сможете его сохранить. Тогда программа сохранит карту высот, и сжатые карты прозрачности и карту освещения. Карту высот и карту освещения можно будет использовать так как они есть. Но карты прозрачности нельзя использовать так как они были экспортированы. Они сжаты в одно RGBA изображение, по каналу на карту прозрачности. Так что вам нужно их извлечь. Я рекомендую использовать для этого программу The Gimp (бесплатны аналог фотошопа с открытым исходным кодом). Если вы кликните на меню |Фильтры| => |Цвет| => |Разобрать| и в опциях установите на RGBA, то тогда будут созданы четыре слоя - карт прозрачности. Затем вы должны сохранить каждый из них в разный файл.


Âñ¸ î êàìåðàõ

Всё о камерах

Использование нескольких камер

По умолчанию в вашей игре только одна камера. Но в некоторых ситуациях может потребоваться использовать несколько камер. Например вы хотите сделать много пользовательскую игру с разделенным экраном (). Еще вы можете захотеть добавить реальное отражение для водной поверхности. Или же добавить камеры охраны и мониторы на которые с них передается изображение в реальном времени. Для всего этого вам нужно более одной камеры.

В Ultimate 3D вы можете иметь до тридцати двух камер одновременно. Использовать их очень легко. В принципе все остальные камеры работают также как и первая. Они отличаются только тем что вы должны определить цель для рисования (рендеринга). Есть два различных вида цели. Вы можете указать либо часть экрана для рендера в него, либо специальную текстуру. Эту текстуру можно будет использовать как обычную. Её так же можно рисовать с помощью функций DrawTex() и DrawTexEx().

Добавление новой камеры в сцену

Каждый объект камеры имеет те же переменные, что и первая камера, а именно: x, y, z, height, rotx, roty, rotz, view, min_range, max_range, falling, falling_speed, follow, perspective и distance. Если вы уже забыли что они означают, то вам стоит взглянуть на главу Приступая к работе. Но еще у камер есть и другие переменные, о которых вы должны знать. Они так же есть и у первой камеры, но если вы их не установили, то они были установлены на значения по умолчанию. Вот эти новые переменные:

number - номер

Индекс камеры. Первая камера имеет индекс 0. наибольше значение для этого параметра 31. У вас не должно быть одновременно камер с одним и тем же индексом.

v_left, v_top, v_width, v_height - область экрана для рендера

Позиция и размеры вида в который будет рисовать камера. Эти значения относительны левого верхнего угла первого вида Game Maker (с индексом 0).

actual_aspect - отношение сторон (аспект)

Если вам не нужна эта переменная, то просто не используйте её. По умолчанию Ultimate 3D расчитает аспект автоматически, делением v_width/v_height. Но текстуры для рендера (render target textures) должны иметь разрешение, делящееся на два, и так может случится что это не тот аспект, который вам нужен. В таком случае вы можете ввести эту переменную.

render_target - текстура для рендера

Если вы не хотите рендерить в текстуру, то просто проигнорируйте эту переменную. Иначе вы должны установить эту переменную на индекс специальной текстуры - текстуры для рендера (render target texture). Текстуры для рендера можно создать с помощью функции CreateTextureRenderTarget() (подробнее смотрите ниже).

Каждый объект камеры должен вызывать функцию MoveCamera() в событии шага и Destroy() в событии уничтожения. Функция MoveCamera() передает любое изменение переменных в Ultimate 3D. Если у камеры цель рендера - это текстура для рендера, то вы должны вызывать функцию RenderToTexture(), для того чтобы камера отрендерила изображение в текстуру, каждый раз, когда хотите этого. Естественно что не всегда нужно вызывать её каждый шаг, так например если эта текстура нигде не используется или её не видно, то будет впустую проделано много работы. Еще такие вещи как камеры охраны не требуют обновления каждый шаг, вы можете сделать это раз в секунду. Так вы сможете повысить производительность.

Плоскости обрезки и ортогональные камеры

Иногда некоторые камеры не должны рендерить всё. Есть две возможности сделать это. Самый простой - это использовать дополнительные фукции обрезки. С помощью этих функций, вы можете установить какими камерами будут рендерится определенные объекты. Но иногда этого недостаточно. Например, для эффекта отражения водной поверхности, дополнительная камера должна рендерить только надводный мир. Чтобы сделать это, вы должны использовать так называемые плоскости обрезки (clipping planes). Вы просто задаете нужную плоскость. Все что находится за плоскостью не будет отрендерено, только то перед ней. Вот функция для установки зон обрезки для той камеры, для которой вызвана эта функция:

SetClippingPlane

(

ClippingPlaneIndex,

PlaneOriginX, PlaneOriginY, PlaneOriginZ,

PlaneOrientationLongitude, PlaneOrientationLatitude

)

ClippingPlaneIndex - индекс плоскости обрезки

Всего может быть установлено до шести плоскостей обрезки на камеру, в зависимости от видеокарты. Функция GetClippingPlaneSupport() возвращает максимальное количество плоскостей обрезки, которые можно установить на данном компьютере. Так что этот параметр определяет какую плоскость обрезки вы хотите установить. Этот параметр должен принимать значения от 0 до 5.

PlaneOriginX/Y/Z - позиция плоскости

Эти параметры задают точку, лежащую на плоскости, которую вы хотите использовать как плоскость обрезки.

PlaneOrientationLongitude, PlaneOrientationLatitude - вращение плоскости

Эти два параметра определяют ориентацию плоскости (направление, куда повернута плоскость).

Другая небольшая, но полезная особенность Ultimate 3D позволяет вам использовать камеры с ортогональной проекцией (orthogonal projection). В основном они используются в программа, например 3D редакторах или редакторах уровней. В ортогональной проекции удаленные объекты не кажутся меньшими. В ней больше нет угла поля зрения, потому что границы области вида всегда параллельны. Но вы должны будете задать прямоугольную зону - поле зрения. Ортогональные камеры не могут существовать в реальности, но они очень полезны для редакторов, потому что они уменьшают количество видимых осей проекции до двух.

Эта функция включает ортогональную проекцию для камеры.

SetOrtho(UseOrthogonalProjection, SeenAreaWidth, SeenAreaHeight)

UseOrthogonalProjection - использовать ортогональную проекцию

Если вы установите этот параметр на true, то Ultimate 3D будет использовать ортогональную проекцию для камеры, иначе нет.

SeenAreaWidth, SeenAreaHeight - размеры экрана

Длина и ширина видимой зоны. Эти переменные не зависят от значений размеров вида.

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

Создание специальных текстур для рендера

Creating render target textures and rendering to cube maps

Рендер в текстуру очень полезная возможность. Вы можете рендерить сцену в специальные текстуры и использовать их как и обычные текстуры. Функции рендера в текстуру особенно необходимы для шейдерных спецэффектов пост обработки, таких как HDR, motion-blur. Когда используются шейдеры пост обработки, то сцена рендерится не напрямую на экран, а в текстуру. Затем вы рендерите текстуру сцены на экран, применяя шейдеры пост обработки. Будующие версии Ultimate 3D будут использовать шейдеры пост обработки немного легче.

Так как вы уже знаете как установить текстуру, как цель рендера камеры, то вам осталось только узнать как создать специальную текстуру для рендера. Чтобы сделать это вам нужна всего то одна простая функция:

Эта функция создает текстуру для рендера (render target texture) с заданными размерами.

CreateTextureRenderTarget(TextureIndex, RequestedWidth, RequestedHeight)

TextureIndex - индекс текстуры

Индекс с которым будет ассоциирована текстура. Это значение должно быть в пределах от 0 до 500.

RequestedWidth, RequestedHeight - размеры текстуры

Требуемые размеры для текстуры для рендера (render target texture). Как и с большинством текстур других видов, не все видеокарты поддерживают размеры текстур, не кратные двум. А некоторые очень старые видеокарты поддерживают только квадратные текстуры.

Так же есть возможность отрендерить сцену в кубическую текстуру (cube textures). Так вы сможете создать абсолютно реалистичные отражения. Вы можете отрендерить сцену в кубическую текстуру и использовать ее как карту окружения (environment mapping). Это отличная техника для создания отражений, и в то же время она очень легка в использовании. Первый шаг - это создание кубической текстуры для рендера. Чтобы сделать это, вы должны вызвать только одну функцию:

Эта функция создает кубическую текстуру для рендера, с заданными размерами.

CreateCubeTextureRenderTarget(TextureIndex, RequestedEdgeIndex)

TextureIndex - индекс текстуры

Индекс с которым будет ассоциирована текстура. Этот параметр должен быть целым числом в пределах от 0 до 500.

RequestedEdgeLength - размер текстуры

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

Для рендера в кубическую текстуру не нужно использовать объект камеры. Это можно сделать намного проще. Так как в кубическую текстуру рендерится все окружающее пространство, то отпадает надобность направлении и угле вида. Важна только позиция и цвет (с прозрачностью). Когда вся сцена будет отрендерена в кубическую текстуру, то на ней будут нарисованы квадраты вершин в заданном цвете и прозрачности. Вы должны вводить значение прозрачности меньшее чем 255, иначе весь рендеринг пойдет насмарку - результат не будет виден. Вы должны использовать нечто вроде этого r=g=b=0 и a=128. Вот эта функция:

Эта функция рендерит сцену из заданной позиции в кубическую текстуру для рендера.

RenderToCubeTexture

(

CubeTextureIndex,

PositionX, PositionY, PositionZ,

ColorR, ColorG, ColorB, ColorA

RoomIndex1, RoomIndex2, ..., RoomIndex8

)

CubeTextureIndex - индекс кубической текстуры для рендера

Индекс кубической текстуры для рендера, в которую вы хотите отрендерить сцену. Это должен быть индекс кубической текстуры для рендера, которая создана функцией CreateCubeTextureRenderTarget(), иначе эта функция не будет работать.

PositionX, PositionY, PositionZ - координаты

Позиция, откуда сцена должна быть отрендерена.

ColorR, ColorG, ColorB, ColorA - цвет

Цвет вершин квадратов, которые будут отрендерены в кубическую текстуру для рендера после рендера в нее сцены. Значения для этих параметров должны быть в пределах от 0 до 255. Если вы не хотите чтобы они были нарисованы, просто поставьте 0 для параметра ColorA.

RoomIndex1, RoomIndex2, ..., RoomIndex8 - индексы комнат

Индексы комнат, которые будут отрендерены. Для более полной информации об индексах комнат прочтите главу Расширенные функции обрезки. Комната 0 всегда будет отрендерена, независимо от того что вы ввели.

Рисование двухмерной графики на текстурах

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

DrawTexEx(TextureIndex, Left, Top, Width, Height, X, Y, ScalingX, ScalingY, Rotation, R, G, B, A,CameraIndex)

CameraIndex - индекс камеры

Индекс камеры, в чью цель для рендера вы хотите нарисовать текстуру.

DrawText(FontIndex, X, Y, Text, CameraIndex)

CameraIndex - индекс камеры

Индекс камеры, в чью цель для рендера вы хотите нарисовать текст.

Помните что текстуры не будут нарисованы на текстуре для рендера, до того как для соответствующего объекта камера не будет вызвана функция RenderToTexture().


Îáðàáîòêà ñòîëêíîâåíèé

Обработка столкновений

Осуществление детекции столкновений и управление столкновениями

Вы видели кого-нибудь, проходящего сквозь стены или проваливающегося сквозь землю? Думаю нет. В реальности это не возможно, а так как в играх всегда пытаются скопировать реальность, то очень важно иметь хорошую систему детекции столкновений (коллизий - от английского "collision"). Вообще то это не так уж и легко. Именно поэтому я вам все детально объясню.

Чтобы объекты правильно могли реагировать на столкновения вы должны будете написать детектор столкновений и их обработчик. Детектор коллизий делает только одно: он определяет что-нибудь сталкивается с чем-нибудь еще и запоминает где произошло столкновение. Обработчик столкновений реагирует на произошедшие столкновения. Простейший способ это переместить объект, который столкнулся с другим объектом назад на его позицию до столкновения. Но в хорошем обработчике коллизий есть еще и различие по типам объектов. Если объект эластичный, то вы можете захотеть чтобы он отскочил назад. Поэтому данная глава сфокусируется целиком на определении столкновений.

Трассировка лучей

Существует всего одна маленькая функция, которую можно использовать для определения столкновений любого типа. Очень важно чтобы вы поняли что эта функция делает. Вообще то это не совсем одна функция. Это несколько функций, которые делают одно и тоже, но для разных типов объектов. То, что они делают, по разному называется: трассировка лучей (ray tracing) или тест пересечения треугольников (triangle intersection test). В Ultimate 3D эти функции всегда имеют название "получить дистанцию до чего-либо" (get distance to something). Но что же они на самом деле делают?

Представьте что у вас есть луч. Если вы не помните из школьного курса математики что такое луч, то луч это прямая линия, которая начинается в одной точке и длится в бесконечность. Например лазерная указка. Позиция где находится лазерная указка это точка происхождения (origin) луча. Если вы укажете указкой на какой-нибудь объект (естественно включа лазер), то вы увидите маленькую точку - там луч встречается с объектом. На рисунке это изображено.

Тест пересечения треугольников использует математический метод для определения где именно луч пересек объект. Он определяет первую точку пересечения с объектом.

Даже не думайте дальше читать пока не поймете, то что написано выше. Прочтите это несколько раз если потребуется. Если вы думает что это не детальное объяснение, то сообщите об этом Christoph Peters на форуме сообщества Ultimate 3D Community. Очень важно чтобы вы поняли это. Вы не сможете написать написать детектор столкновений без понимания того что означает трассировка лучей. В нижеследующем тексте я уверен что вы понимаете что это такое.

Функции трассировки лучей

В основном есть три типа объектов, которые имеют разную по типу геометрию: примитивы, модели и ландшафты. Для примитивов и моделей есть есть функции трассировки лучей, когда для ландшафтов функция трассировки лучей и функция, которая возвращает высоту ландшафта в указанной точке. Так как вы уже знаете что такое трассировка лучей (ray tracing), то у вас не будет проблем с пониманием следующих функций.

Эта функция выполняет тест пересечения треугольников между треугольниками заданной модели и заданного луча. Если луч пересекает модель, то функция возвращает дистанцию от точки происхождения луча (origin) до точки пересечения с моделью. Иначе эта функция возвращает 100000.

GetDistanceToModel

(

ModelID,

RayOriginX, RayOriginY, RayOriginZ,

RayDirectionLongitude, RayDirectionLatitude

)

ModelID - индекс объекта

Индекс объекта Game Maker, который является моделью, которую вы хотите проверить.

RayOriginX, RayOriginY, RayOriginZ - координаты

Точка происхождения луча в мировом пространстве.

RayDirectionLongitude, RayDirectionLatitude - направление луча

Направление луча. Чтобы получить больше информации об этих двух параметрах взгляните на описание функции Move().

Эта функция выполняет тест пересечения треугольников между треугольниками заданного примитива и заданного луча. Если луч пересекает примитив, то функция возвращает расстояние от точки происхождения луча до точки пересечения с примитивом. иначе функция возвращает 100000.

GetDistanceToPrimitive

(

PrimitiveID,

RayOriginX, RayOriginY, RayOriginZ,

RayDirectionLongitude, RayDirectionLatitude

)

PrimitiveID - индекс объекта

Индекс объекта Game Maker, который является примитивом, который вы хотите проверить.

RayOriginX, RayOriginY, RayOriginZ - координаты

Точка происхождения луча в мировом пространстве.

RayDirectionLongitude, RayDirectionLatitude - направление луча

Направление луча. Чтобы получить больше информации об этих двух параметрах взгляните на описание функции Move().

Эта функция выполняет тест пересечения треугольников между треугольниками всех примитивов, которые не являются поверхностями (billboard) и заданным лучом. Если луч пересекает примитив, то функция возвращает дистанцию от точки происхождения луча до точки где произошло первое пересечение с примитивами. Иначе она возвращает 100000. Использовать эту функцию гораздо эффективнее, чем вызывать GetDistanceToPrimitive() для каждого примитива в сцене.

GetDistanceToAnyPrimitive

(

RayOriginX, RayOriginY, RayOriginZ,

RayDirectionLongitude, RayDirectionLatitude

)

RayOriginX, RayOriginY, RayOriginZ - координаты

Точка происхождения луча в мировом пространстве.

RayDirectionLongitude, RayDirectionLatitude - направление луча

Направление луча. Чтобы получить больше информации об этих двух параметрах взгляните на описание функции Move().

Эта функция выполняет тест пересечения треугольников между треугольниками заданного ландшафта и заданным лучом. Если луч пересекает ландшафт, то функция возвращает дистанцию от точки происхождения луча до точки пересечения с ландшафтом. Иначе она возвращает 100000.

GetDistanceToTerrain

(

TerrainID,

RayOriginX, RayOriginY, RayOriginZ,

RayDirectionLongitude, RayDirectionLatitude

)

TerrainID - индекс объекта

Индекс объекта game Maker, который является ландшафтом, который вы хотите проверить.

RayOriginX, RayOriginY, RayOriginZ - координаты

Точка происхождения луча в мировом пространстве.

RayDirectionLongitude, RayDirectionLatitude - направление луча

Направление луча. Чтобы получить больше информации об этих двух параметрах взгляните на описание функции Move().

Эта функция возвращает высоту заданного ландшафта в мировом пространстве в заданной позиции. Если заданная позиция находится вне ландшафта, то функция возвращает 0. Эта функция более эффективнее чем функция GetDistanceToTerrain().

GetTerrainHeightAtPos

(

TerrainID,

PositionX, PositionY

)

TerrainID - индекс объекта

Индекс объекта Game Maker, который является ландшафтом, высоту которого вы хотите получить.

PositionX, PositionY - координаты

Позиция в которой вы хотите получить высоту ландшафта в мировом пространстве.

Использование трассировки лучей для определения столкновений

Следующие две статьи основаны на примере обработчика столкновений, который можно найти в секции примеров для Ultimate 3D. Это более менее хорошая работа, где разъяснено как использованы скрипты и как они работают вместе. Если вы этого еще не сделали, то советую вам загрузить это пример. После того как вы это сделаете мы продолжим.

Вы знаете о контроллерах парковки? Это маленькие ультразвуковые сенсоры на задней части машина, а что-то находится рядом сними, то вы услышите звуковой сигнал в машине. Они используют трассировку лучей для определения столкновений. То же самое и вы будете делать в своих играх, только вместо ультразвука будете использовать функции трассировки лучей.

Чтобы получить надежный детектор коллизий для игр от первого или третьего лица вы должны использовать два луча. Первый проверяет чтобы игрок не проваливался под землю. Он идет вниз и проверят расстояние до поверхности земли. И если игрок оказывается слишком близко к земле, то он передвигается вверх, если нет, то можно например сделать гравитацию. Второй луч проверяет столкновения со стенами. Он проверяет столкновения в том направлении, куда идет игрок. В том случае если оно произошло, то используется специальная возможность Ultimate 3D чтобы оттолкнуть его от стены (или чего-нибудь еще, далее просто стены). Перед тем как мы начнем делать детектор коллизий для всего уровня нам понадобится скрипт с таким синтаксисом.

GetDistanceToLevel

(

RayOriginX, RayOriginY, RayOriginZ,

RayDirectionLongitude, RayDirectionLatitude

)

Желаемый результат чтобы скрипт возвращал дистанцию от точки происхождения луча до точки пересечения луча с ближайшим объектом. Естественно это займет много времени на выполнение теста пересечения треугольников абсолютно с каждым объектом сцены, так что вы должны ограничиттся только теми объектами, столкновения для которых необходимы. Это можно сделать например установив переменную, ну назовем её "check_collision", для моделей и ландшафтов которые должны проходить проверку. Вот пример реализации этого скрипта, подразумевается что "check_collision" была установлена.

// GetDistanceToLevel(RayOriginX, RayOriginY, RayOriginZ,

// RayDirectionLongitude, RayDirectionLatitude)

// Эта функция возвращает дистанцию до ближайшей точки, в которой

// заданный луч встречает какой-то объект.

global.min_distance=GetDistanceToAnyPrimitive(argument0,argument1,argument2,argument3,argument4);

with(all){

if(u3d_type==1 && check_collision==true){

global.distance=GetDistanceToModel(id,argument0,argument1,argument2,

argument3,argument4);

if(global.min_distance>global.distance){

global.min_distance=global.distance;

}

}

if(u3d_type==5 && check_collision==true){

global.distance=GetDistanceToTerrain(id,argument0,argument1,argument2,argument3,argument4);

if(global.min_distance>global.distance){

global.min_distance=global.distance;

}

}

}

return global.min_distance;

В том случае если у вас есть ландшафты, то вы должны будете создать второй скрипт, называющийся GetLevelHeightAtPos(), который работает также как и GetDistanceToLevel() но использует GetTerrainHeightAtPos() вместо GetDistanceToTerrain(). Реализацию этого скрипта можно найти в примере.

Имея скрипты как эти, вы можете осуществлять детекцию столкновений следующим образом:

// Подходящие значения для этих переменных зависят от

// размер вашей модели персонажа

hip_height=5;

minimal_level_distance=3;

// Используем клавиатурное управление и запоминаем направление движения

xprevious2=x;

yprevious2=y;

Move(0,roty+90,keyboard_check(vk_right)*speed2-keyboard_check(vk_left)*speed2);

Move(0,roty,keyboard_check(vk_up)*speed2-keyboard_check(vk_down)*speed2);

moving_direction=point_direction(xprevious2,yprevious2,x,y)+90;

// Проверка столкновений под персонажем

distance_down=z+hip_height-GetLevelHeightAtPos(x,y,z+hip_height);

if(distance_down<=hip_height){

// Делаем чтобы игрок стоял на земле

// ... Смотри обработчик столкновений ...

}

if(distance_down>hip_height && distance_down!=100000){

// Делаем чтобы игрок падал

// ... Смотри обработчик столкновений ...

}

// Если игрок передвинулся, то вы должны проверить столкновение со стеной

if(xprevious2!=x || yprevious2!=y){

// Расстояние проверяется из позиции предыдущего шага,

// потому что игрок уже может находится внутри стены

distance=GetDistanceToLevel(xprevious2,yprevious2,z+hip_height,0,

moving_direction)-point_distance(x,y,xprevious2,yprevious2);

// Реакция на результат теста трассировки лучей

// ... Смотри обработчик столкновений ...

}

Переменная moving_direction нужна для хранения направления движения персонажа в том случае если тут нет стен. По этой причине переменные и должны быть установлены до того как скрипт обработает события клавиш и изменит координаты x и y. В следующих строках кода идет проверка на столкновения под персонажем. Это сделано независимым от движения персонажа, что делает это более простым для осуществления таких вещей как подъемник (элеватор). После этого код осуществляет проверку столкновений со стенами. Это нужно только в некоторых случаях, когда например движется игрок (не считая того что вы можете двигать стены в игре). Это очень легко, не так ли? Тогда вперед к обработчику столкновений, который более сложный в создании.

Обработчик столкновений

Статья обещает быть очень длинной, ведь существует бесконечное множество способов реагирования на столкновения. Иногда вам нужно чтобы объект отскочил назад при столкновении, иногда вам нужно чтобы объект двигался вдоль другого, с которым столкнулся, иногда комбинация из этих двух способов или же что-то совсем другое. Но она будет не такой уж и большой, потому что она сфокусируется на основных методиках обработки столкновений. Если вы поймете эти виды обработчиков событий, то вы должны попробовать и другие, но уже сами. Эти обработчики коллизий покажут вам как сделать обработчик столкновений, который заставит объект плавно скользить вдоль стены, прямо как в большинстве шутеров от третьего лица.

Обработчик столкновений рассмотренный ниже потребует от вас основных знаний в векторной алгебре. Он будет использовать некоторые функции расчета векторов Ultimate 3D. Если вы хотите понять код, который тут используется, то вы можете перескочить вперед и прочитать главу про математические функции. Если вы просто хотите использовать этот код, то вы должны уметь найти на клавиатуре клавиши Ctrl, C и V. Это вам решать какой именно способ лучше.

Есть одна функция, о которой вы должны знать, чтобы сделать правильный обработчик столкновений и называется она GetRayTracingNormal(). Эта функция возвращает вектор, который говорит вам в каком направлении вам нужно отбросить персонаж в случае обнаружения столкновения. Чтобы получить о ней информацию нажмите на эту ссылку. Проблема с текущим состоянием наших функций детекции столкновений состоит в том, что они не могут правильно работать вместе с GetRayTracingNormal(). После того как вы вызвали GetDistanceToLevel(), вы уже не знаете для какого объекта вернет вектор нормали функция GetRayTracingNormal(). Это не обязательно ближайший объект, но это то, что нам нужно. По этой причине скрипт GetDistanceToLevel нужно немного дополнить. Вы должны будете передавать идентификатор вектора, который будет использован для получения вектора нормали столкновения с самым ближайшим объектом.

// GetDistanceToLevel(RayOriginX, RayOriginY, RayOriginZ,

// RayDirectionLongitude, RayDirectionLatitude)

// Эта функция возвращает дистанцию до ближайшей точки, в которой

// заданный луч встречает какой-то объект. Векстор с ID

// RayTracingNormalIDOut будут использованы для хранения нормали

// трассировки лучей объекта, с которым произошло первое пересечение луча.

global.min_distance=GetDistanceToAnyPrimitive(argument0,argument1,argument2,argument3,argument4);

GetRayTracingNormal(RayTracingNormalIDOut);

with(all){

if(u3d_type==1 && check_collision==true){

global.distance=GetDistanceToModel(id,argument0,argument1,argument2,

argument3,argument4);

if(global.min_distance>global.distance){

global.min_distance=global.distance;

GetRayTracingNormal(RayTracingNormalIDOut);

}

}

if(u3d_type==5 && check_collision==true){

global.distance=GetDistanceToTerrain(id,argument0,argument1,argument2,argument3,argument4);

if(global.min_distance>global.distance){

global.min_distance=global.distance;

GetRayTracingNormal(RayTracingNormalIDOut);

}

}

}

return global.min_distance;

Если вы знаете как работает функция GetRayTracingNormal(), то у вас не будет проблем с пониманием модификации. Когда скрипт ищет пересечение, которое ближе чем предыдущие, то скрипт обновляет нормаль трассировки лучей, потому что нам нужна нормаль трассировки луча к ближайшему пересечению. К сожалению это была не самая сложная часть. Теперь вы можете получить нормаль трассировки луча, так что вы можете получить направление в котором нужно будет отбросить игрока назад после определения столкновения со стеной для эффекта скольжения. Но вы не знаете на сколько надо отбросить персонаж назад. Чтобы найти это, потребуются математические расчеты.

Но сначала давай те рассмотрим ситуацию. Что мы знаем? Мы знаем позицию игрока, позицию пересечения между стеной и лучом, вектор нормали стены и минимальную дистанцию до стены. Это будет хорошо если мы напишем маленький скрипт, который берет всю эту информацию для расчета расстояния, на которое нужно отбросить назад персонаж. Через позицию стены и ее вектор нормали мы можем найти дистанцию до стены. Далее мы должны будем сделать небольшое вычитание чтобы получить ту дистанцию на которую нужно отбросить персонаж. Так что давайте приступим к работе. Эта часть требует от вас знаний математических функций Ultimate 3D.

// GetCharacterOffset(CharacterPositionVectorID, RayDirectionLongitude,

// RayDirectionLatitude, DistanceToObject, RayTracingNormalVectorID,

// MinimumWallDistance)

// Эта функция использует полученную информацию для расчетов как далеко

// нужно отбросить персонажа. Если персонажа не нужно отбрасывать назад,

// то функция возвращает 0.

var ray_direction_vector, intersection_position, return_value;

// Если не произошло пересечение, то персонаж не должен отталкиваться

if(argument3==100000){

return 0;

}

// Расчет позиции пересечения

ray_direction_vector=CreateDirectionVector(-1,argument1,argument2);

CalculateVectorScalarProduct(ray_direction_vector,ray_direction_vector,argument3);

intersection_position=CalculateVectorSum(-1,argument0,ray_direction_vector);

ReleaseVector(ray_direction_vector);

// Первый результат это дистанция до стены, второй это расстояние до

// персонажа по нормали стены. Разница между минимальной дистанцией и

// расстояния до точки пересечения, максимизированная до нуля и будет

// тем самым расстоянием, которое нам нужно было найти.

return_value=argument5-abs(CalculateDotProduct(argument4,argument0)

-CalculateDotProduct(argument4,intersection_position));

ReleaseVector(intersection_position);

return max(0,return_value);

Вам не обязательно понимать как работает этот скрипт пока вы хотите лишь использовать его. И это проще простого. Но вам всеровно потребуются функции расчета векторов. Но не волнуйтесь, они не кусаются.

Вот пример того как обработчик столкновений должен использовать скрипт GetCharacterOffset() и дополнительные параметры для GetDistanceToLevel(). Это завершает пример кода выше.

// Подходящие значения для этих переменных зависят от

// размер вашей модели персонажа

hip_height=5;

minimal_level_distance=3;

// Используем клавиатурное управление и запоминаем направление движения

xprevious2=x;

yprevious2=y;

Move(0,roty+90,keyboard_check(vk_right)*speed2-keyboard_check(vk_left)*speed2);

Move(0,roty,keyboard_check(vk_up)*speed2-keyboard_check(vk_down)*speed2);

moving_direction=point_direction(xprevious2,yprevious2,x,y)+90;

// Проверка столкновений под персонажем

distance_down=z+hip_height-GetLevelHeightAtPos(x,y,z+hip_height);

if(distance_down<=hip_height){

// Делаем чтобы игрок стоял на земле

z+=hip_height-distance_down;

falling=false;

falling_speed=0;

}

if(distance_down>hip_height && distance_down!=100000){

// Делаем чтобы игрок падал

falling=true;

}

// Если игрок передвинулся, то вы должны проверить столкновение со стеной

if(xprevious2!=x || yprevious2!=y){

// Расстояние проверяется из позиции предыдущего шага,

// потому что игрок уже может находится внутри стены

ray_tracing_normal=CreateVector(-1,0,0,0);

distance=GetDistanceToLevel(xprevious2,yprevious2,z+hip_height,0,moving_direction,ray_tracing_normal)-point_distance(x,y,xprevious2,yprevious2);

// Реакция на результат теста трассировки лучей

if(GetVector(ray_tracing_normal,1)!=0 || GetVector(ray_tracing_normal,2)!=0){

// Z-компонент нормали трассировки луча имеет нулевую высоту вначале

// Проверка столкновения использует другой луч. Если стена должна

// толкнуть персонаж, то это позволит избежать множества проблем.

CreateVector(ray_tracing_normal,GetVector(ray_tracing_normal,1),

GetVector(ray_tracing_normal,2),0);

// Убедимся что нормаль трассировки луча имеет длину 1

CalculateVectorScalarProduct(ray_tracing_normal,ray_tracing_normal,

1/CalculateVectorLength(ray_tracing_normal));

// Рассчитаем верный отступ (offset) для персонажа

character_position=CreateVector(-1,xprevious2,yprevious2,z+hip_height);

character_offset=GetCharacterOffset(character_position,0,moving_direction,distance,ray_tracing_normal,minimal_level_distance);

ReleaseVector(character_position);

// Применяем рассчитанный ранее отступ для персонажа

x+=GetVector(ray_tracing_normal,1)*character_offset;

y+=GetVector(ray_tracing_normal,2)*character_offset;

}

ReleaseVector(ray_tracing_normal);

}

Первые изменения это то, что было добавлено стояние на земле и падение. Это очень легко. Просто помните что можете скопировать кусочек кода из MoveCamera() для объектов не-камер, чтобы заставить падение работать. Самая важная часть кода это там где происходит реакция на столкновения со стенами. Сначала происходит проверка где именно камера встречает что-то вертикальное, для этого ищется какая из компонентов нормали х или у не равна нулю. Если так, то создается нормализованная нормаль трассировки луча с z-компонентом равным нулю. Это сделано чтобы избежать то, что стены могут поднять камеру вверх. Обработчик вертикальных столкновений полностью делает тоже самое, но для другого луча. После этого, GetCharacterOffset() используется для расчетов отступа и наконец этот самый отступ применяется.

Надеюсь это не оказалось слишком сложным.


Ìàòåìàòè÷åñêèå ôóíêöèè

Математические функции

Математические функции

Ultimate 3D предлагает набор полезных функций, которые можно использовать для операций с векторами и матрицами. Математические матрицы и вектора - это очень сложные объекты, но мы будем рассматривать их только в двух частных случаях. Матрицы будут использоваться для описания трансформации а вектора для хранения позиции или направления. но давайте рассмотрим это более детально.

Вектор состоит из x-координаты, y-координаты и z-координаты. Вы, наверное, уже знакомы с векторами описывающими позицию объектов переменными x, y и z. Но вектора также могут хранить и направление с длиной (direction with a length). Для этого они будут хранить данные относительно точки начала (origin). Если вы нарисуете линию из точки начала (точка/вектор с координатами (0|0|0)) к вектору направления (точке с такими координатами, относительно точки начала), то она будет указывать направление к вектору направления. Вы можете представить её в виде стрелки. И если вы захотите переместить объект из вектора позиции в направлении, заданном вектором направления, вы просто должны будете к вектору позиции добавить вектор направления. Если вектор направления имеет длину, равную единице, то он называется нормализованным вектором (normalized vector).

Матрицы используются для хранения трансформации. Если вы забыли что такое трансформация, то я вам напомню что трансформация в Ultimate 3D представляет из себя совокупность переменных x, y, z, rotx, roty, rotz, scalx, scaly и scalz. Переменные x, y, z задают координату (трансляцию - translation), rotx, roty, rotz определяют вращение а scalx, scaly, scalz - масштаб. Так что любая трансформация может быть задана как комбинация трансляции, вращения и масштаба.

Вы можете очень эффективно использовать матрицы для различных расчетов. С их помощью можно решить проблемы, которые без матриц представляются трудноразрешимыми. Это небольшое пояснение поможет вам разобраться в назначении функций для работы с матрицами. Допустим у вас есть модель, загруженная в Ultimate 3D, вся информация о геометрии модели задана в координатной системе модели. Модель имеет свою собственную координатную систему, которая устанавливается в редакторе (программе для моделирования, в которой создана модель). Эта координатная система называется пространством модели (model space). Преобразование координатной системы модели в глобальные координаты (или пространство мира - world space), называется трансформация пространства модели в пространство мира ( model to world space transformation). Запомните, что трансформация чего-либо из пространства A в пространство B (transforms something from space A into space B) называется "трансформация из пространства A в B " (A to B space transformation) или же "матрица из пространства A в B" (A to B space matrix). Термины "матрица" и "трансформация" в данном контексте используются как синонимы.

Если у вас есть матрица трансформации из пространства A в B и из пространства B в C, то вы можете трансформировать матрицу из A в B матрицей из B в C, и в результате вы получите матрицу трансформации из пространства A в C. Так что если вы произведете трансформацию вектора полученной матрицей, то вы проведете трансформацию напрямую из пространства A в C. Вот почему матрицу так необычайно полезны. Вы можете трансформировать все в любую координатную систему, какую захотите и даже реализовать собственную систему "костей", например для привязки оружия к персонажу в шутере.

Теория закончилась, теперь пришло время приступить к практике.

Функции для расчетов с матрицами и векторами

Так как Game Maker не может хранить такие структуры данных, как вектора и матрицы, то вместо него это делает Ultimate 3D. Game Maker просто получает индекс структуры данных. Этот индекс нужно будет использовать в некоторых функциях в качестве одно из параметров. Большинство функций операций с матрицами и векторами имеют параметры OutputMatrixID и OutputVectorID. Чтобы избежать бесконечного повторения, я объясню значения этих параметров только здесь.

OutputMatrixID / OutputVectorID - индекс результирующей матрицы / вектора

Индекс матрицы или вектора, куда будет записан результат функции. Если вы не хотите переписывать матрицу или вектор, то вы можете поставить -1 для этого параметра. Тогда Ultimate 3D создаст новую матрицу или вектор и вернет индекс новой матрицы или вектора. Вы должны будете сохранить этот индекс в переменную. Когда вам больше не нужна матрица или вектор, то вы можете их удалить используя функции ReleaseMatrix(MatrixID) и ReleaseVector(VectorID) соответственно. Иначе вы можете получить ошибку переполнения, когда матриц или векторов больше разрешенного количества (сейчас это по 100).

Матрицы и вектора можно создавать вводя -1 для одного из этих параметров. Но большинство матриц уже существует. А именно матрицы трансформации всех моделей, примитивов и камер. Все эти матрицы могут быть получены одной простой функцией:

Эта функция возвращает индекс матрицы трансформации объекта с заданным индексом.

GetObjectTransformation(ObjectID)

ObjectID - индекс объекта

Индекс объекта Game Maker модели, примитива или камеры.

Получив с помощью функции GetObjectTransformation() индекс матрицы, вы можете считывать или записывать матрицу объекта. Так вы можете изменить трансформацию объекта без изменения переменных трансформации. Но вы всегда должны это делать после вызова функции Step(), потому что Step() переписывает матрицу трансформации, основываясь на переменных трансформации. Кроме матриц транформации существует еще огромное количество матриц. Это матрицы трансформации костей. Их также можно получить, но не просто получить их индекс, а записать данные в другую матрицу.

Эта функция копирует матрицу трансформации пространства кости в мировое пространство (bone to world space transformation matrix) заданной кости объекта, для которого вызвана эта функция, и сохраняет её в заданную матрицу.

GetBoneTransformation(OutputMatrixID, BoneIndex)

OutputMatrixID - результирующая матрица

Индекс матрицы, в которую будет сохранен результат, или -1 для создания новой.

BoneIndex - индекс кости

Индекс кости, трансформацию которой вы хотите получить. Вы можете использовать GetBoneIndex() для получения индекса кости.

Матрица, возвращаемая этой функцией, всегда будет матрицей трансформацией кости в текущем кадре (который виден на экране), так что если вы будете использовать эту функцию для "приклеивания" объектов к костям, то может произойти "эффект следования". Чтобы избежать этого воспользуйтесь функцией UpdateSkeleton() для обновления матрицы трансформации кости модели, для которой вызвана эта функция. Но сильно ею не увлекайтесь, она требует времени для расчетов.

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

Эта функция создает матрицу трансляции (координаты).

CreateTranslationMatrix

(

OutputMatrixID,

TranslationX, TranslationY, TranslationZ

)

Эта функция создает матрицу масштаба (scaling).

CreateScalingMatrix(OutputMatrixID, ScalingX, ScalingY, ScalingZ)

Эта функция создает матрицу вращения (rotation).

CreateRotationMatrix(OutputMatrixID, RotationX, RotationY, RotationZ)

Эта функция создает полную матрицу трансформации с трансляцией, вращением и масштабом.

CreateTransformationMatrix

(

OutputMatrixID,

TranslationX, TranslationY, TranslationZ,

RotationX, RotationY, RotationZ,

ScalingX, ScalingY, ScalingZ

)

OutputMatrixID - результирующая матрица

Индекс матрицы, в которую будет сохранен результат, или -1 для создания новой.

TranslationX, TranslationY, TranslationZ - трансляция

Эти переменные задают трансляцию. Они эквивалентны переменным трансформации x, y и z.

RotationX, RotationY, RotationZ - вращение

Эти переменные задают вращение. Они эквивалентны переменным трансформации rotx, roty и rotz.

ScalingX, ScalingY, ScalingZ - масштаб

Эти переменные задают масштаб. Они эквивалентны переменным трансформации scalx, scaly, scalz.

Но создание матриц это еще не всё, вам нужны функции для выполнения операций с ними. Первая из этих функций на самом деле не выполняет никаких расчетов, она просто копирует данные. Но даже так она будет весьма полезна во многих случаях.

Эта функция копирует матрицу с заданным индексом в другую матрицу.

CopyMatrix(OutputMatrixID, InputMatrixID)

OutputMatrixID - результирующая матрица

Индекс матрицы, в которую будет сохранен результат, или -1 для создания новой.

InputMatrixID - копируемая матрица

Индекс матрицы, которую вы хотите скопировать в другую.

Эта функция преобразовывает (трансформирует) одну матрицу другой матрицей.

TransformMatrix(OutputMatrixID, InputMatrixID1, InputMatrixID2)

OutputMatrixID - результирующая матрица

Индекс матрицы, в которую будет сохранен результат, или -1 для создания новой.

InputMatrixID1, InputMatrixID2 - матрицы для преобразования

Индексы двух матриц для преобразования. Первая матрица будет трансформирована второй матрицей (первая матрица будет умножена на вторую). Это подразумевает, что первая матрица - это матрица из пространства A в B (A to B space matrix),а вторая матрица из пространства B в C (B to C space matrix), результирующая матрица будет из пространства A в C (A to C space matrix). Помните что порядок, в котором перемножаются матрицы имеет значение (по правилам операций с матрицами: AB*BC не тоже, что и BC*AB, так как умножение происходит несколько иным способом - по специальной формуле, поэлементно со сложением).

И наконец функция, которая инвертирует матрицу. Инверсия матрицы, это матрица, полностью противоположная трансформации оригинальной матрицы. Так что если оригинальная матрица - это матрица из пространства A в B (A to B space matrix), то её инверсия - это матрица из пространства B в A (B to A space matrix). Если вы трансформируете матрицу её инверсией, то результирующая матрица не будет содержать трансформацию. Это логично, ведь если сначала перейти из пространства A в B, а потом из B в A, то получится переход из A в A, а для этого трансформация не требуется.

InvertMatrix(OutputMatrixID, InputMatrixID)

OutputMatrixID - результирующая матрица

Индекс матрицы, в которую будет сохранен результат, или -1 для создания новой.

InputMatrixID - матрица для инвертирования

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

Теперь вы можете расслабится, потому что самая тяжелая часть позади. Сейчас вы уже можете использовать ваши знания о матрицах для трансформации сложных объектов. Но матрицы также можно использовать для транформации одиночных векторов. Перед тем как вы сможете делать это, вам нужно узнать как создавать вектора. Давайте приступим.

Эта функция создает вектор с заданными x, y и z координатами.

CreateVector(OutputVectorID, X, Y, Z)

OutputVectorID - результирующий вектор

Индекс вектора, в который будет сохранен результат, или -1 для создания нового вектора.

X, Y, Z - координаты

Координаты, с которыми вы хотите создать вектор.

Есть и другой способ создать вектор, используя долготу и широту (longitude and latitude). Для этого и существует следующая функция:

CreateDirectionVector(OutputVectorID, Longitude, Latitude)

OutputVectorID - результирующий вектор

Индекс вектора, в который будет сохранен результат, или -1 для создания нового вектора.

Longitude, Latitude - долгота, широта

Долгота и широта, из значений которых будет создан вектор. Более подробное описание долготы и широты можно прочитать в описании функции Move().

Для получения информации из векторов, вы можете использовать эту функцию:

GetVector(VectorID, VectorElementID)

VectorID - вектор

Индекс вектора, информацию о котором вы хотите получить.

VectorElementID - элемент вектора

Этот параметр определяет какую координату вы хотите получить. Этот параметр может принимать значение 1 - для получения x-координаты, 2 - для y-координаты, 3 - для z-координаты.

Когда у вас есть два вектора вы можете получить их сумму. Вектора суммируются вместе поэлементно. Так что (x | y | z)+(x' | y' | z') в результате даст (x+x' | y+y' | z+z'). Это делается следующей функцией:

CalculateVectorSum(OutputVectorID, InputVectorID1, InputVectorID2)

OutputVectorID - результирующий вектор

Индекс вектора, в который будет сохранен результат, или -1 для создания нового вектора.

InputVectorID1, InputVectorID2 - вектора для сложения

Индексы векторов, которые вы хотите проссумировать (сложить) вместе.

Другая основная математическая операция с векторами - это произведение вектора на скаляр. Если у вас есть вектор v=(x | y | z) и скаляр (число с плавающей запятой) k, то их произведение k*v будет равно (k*x | k*y | k*z). Скалярное произведение вектора рассчитывается следующей функцией:

CalculateVectorScalarProduct(OutputVectorID, InputVectorID, ScalarFactor)

OutputVectorID - результирующий вектор

Индекс вектора, в который будет сохранен результат, или -1 для создания нового вектора.

InputVectorID - вектор для умножения

Индекс вектора, который будет умножен на скаляр.

ScalarFactor - скаляр

Число (с плавающей запятой), на которое будет умножен каждый из компонентов вектора.

Часто может потребоваться длина вектора. Длина вектора v=(x | y | z), которая обозначается как |v|, рассчитывается по формуле |v|=sqrt(x*x+y*y+z*z) (где sqrt - это квадратный корень из...), так что это дистанция от точки начала вектора (origin) до вектора (координат вектора). Следующая функция возвращает длину определенного вектора.

CalculateVectorLength(VectorID)

VectorID - вектор

Индекс вектора, длину которого вы хотите получить.

Это очень полезная функция, и не удивительно что она существует. Она трансформирует вектор матрицей.

Эта функция транформирует заданный вектор заданной матрицей. Если вектор задан в пространстве A, а матрица задает трансформацию из пространства A в B, то в результате получиться тот же вектор, но уже в пространстве B.

TransformVector(OutputVectorID, InputVectorID, InputMatrixID)

OutputVectorID - результирующий вектор

Индекс вектора, в который будет сохранен результат, или -1 для создания нового вектора.

InputVectorID - вектор

Индекс вектора, который будет трансформирован матрицей.

InputMatrixID - матрица

Индекс матрицы, которой будет трансформирован вектор.

Не смотря на то, что Ultimate 3D предлагает несколько функция для выполнения основных математических операций с векторами, наиболее востребованной операцией с векторами является скалярное произведение векторов (dot product). Если у вас есть два вектора v=(x | y | z) и v'=(x' | y' | z'), то скалярным произведением векторов <v, v'> будет x*x' + y*y' + z*z'. Скалярное произведение векторов равно произведению косинуса угла меду векторами на длину первого вектора на длину второго вектора. А если добавить это в нашу маленькую формулу, то скалярное произведение векторов будет расчитываться по формуле cos(a) * |v| * |v'| (где a - это угол между векторами v и v'). Так что если вектора нормализованы (длина равна единице), то тогда скалярное произведение векторов будет равно косинусу угла. Что означет если скалярное произведение будет равно 1, то вектора параллельны, если же оно равно 0, то они перпендикулярны. И это только один из способов применения скалярного произведения векторов.

Эта функция возвращает скалярное произведение двух заданных векторов.

CalculateDotProduct(InputVectorID1, InputVectorID2)

InputVectorID1, InputVectorID2 - вектора

Индексы двух векторов, которые будут использованы для расчета скалярного произведения векторов. Порядок не имеет значения.

Другая очень часто выполняемая операция с двумя векторами - это векторное произведение. В результате векторного произведения образуется новый вектор, который будет ортогонален (перпендикулярный) к двум векторам ввода. Длина вектора будет зависеть от размеров треугольника из двух векторов ввода в комбинации с нулевым вектором (zero vector). Если вектора ввода параллельны, то в результате получится нулевой вектор.

Эта функция рассчитывает векторное произведение двух заданных векторов.

CalculateCrossProduct(OutputVectorID, InputVectorID1, InputVectorID2)

OutputVectorID - результирующий вектор

Индекс вектора, в который будет сохранен результат, или -1 для создания нового вектора.

InputVectorID1, InputVectorID2 - вектора ввода

Индексы векторов, для которых вы хотите вычислить векторное произведение. Порядок имеет значение. Если вы поменяете местами вектора, то результирующий вектор поменяет знак на противоположный.

Еще есть другая функция, которая использует матрицу и в результате получается вектор. Она преобразует произвольную матрицу назад к углам вращения.

ComputeMatrixRotationAngles(OutputVectorID, InputMatrixID)

OutputVectorID - результирующий вектор

Индекс вектора, в который будет сохранен результат, или -1 для создания нового вектора. После вызова этой функции, x-компонента вектора будет содержать значение rotx, y-компонента - значение roty а z-компонента - значение rotz.

InputMatrixID - матрица

Индекс матрицы, для которой вы хотите определить значения rotx, roty, rotz, которые её правильно описывают.

Не смотря на то что это специальные функции, они не являются математическими, но они используют вектора в качестве результата. С помощью первой можно определить куда сейчас указывает курсор мыши.

Эта функция вычисляет вектор направления (direction vector), представляющий из себя луч, который начинается в позиции камеры и идет в направлении того, что видно на заданном пикселе экрана.

ScreenCoordToVector(OutputVectorID,ScreenCoordX,ScreenCoordY,CameraIndex)

OutputVectorID - результирующий вектор

Индекс вектора, в который будет сохранен результат, или -1 для создания нового вектора.

ScreenCoordX, ScreenCoordY - координаты экрана

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

CameraIndex - камера

Индекс камеры, для которой будет выполнена эта операция. Если вы хотите чтобы опреация была проведена для камиры по умолчанию, то введите 0 или ничего, иначе введите индекс камеры (не объекта), которую вы хотите проверить.

Эта функция выполняет противоположную операцию функции ScreenCoordToVector(), она рассчитывает позицию на экране, исходя из заданных 3D координат. Она не использует расчеты с векторами, но используются три различных скрипта для получения координат. Возвращаемое значение будет x-координатой или y-координатой на экране или же z-координатой.в пространстве камеры (camera space), которая используется для определения где находится точка - перед камерой или же позади неё.

CoordToScreenX(X, Y, Z, CameraIndex)

CoordToScreenY(X, Y, Z, CameraIndex)

CoordToScreenZ(X, Y, Z, CameraIndex)

X, Y, Z - координаты

Координаты в мировом пространстве (world space), которые будут преобразованы в пространство экрана (screen space).

CameraIndex - камера

Индекс камеры, для которой будет выполнена операция. Введите 0 или ничего, если хотите выполнить операцию для камеры по умолчанию.

И в заключение, функция, которая была объявлена в главе об определении и управлении столкновениями. Её можно использовать для получения вектора нормали треугольника, который был последним задет (пересечен) функцией трассировки лучей ( GetDistanceTo...() ). Нормаль треугольника - это нормализованный вектор, перпендикулярный к плоскости треугольника и его точкам. Так что если вы хотите чтобы объект отскочил от другого объекта, с которым столкнулся, то вы можете просто добавить вектор нормали к его позиции.

GetRayTracingNormal(OutputVectorID)

OutputVectorID - результирующий вектор

Индекс вектора, в который будет сохранен результат, или -1 для создания нового вектора.


Íàñòðîéêè Ultimate 3D

Настройки Ultimate 3D

Настройки Ultimate 3D

Существует несколько настроек того, как Ultimate 3D будет загружать данные и рендерить сцены. Некоторые из этих опций должны быть установлены до инициализации Ultimate 3D, в то время как остальные можно изменить в любое время специальными функциями. Те настройки что должны быть установлены до инициализации Ultimate 3D устанавливаются в скрипте Ultimate3DOptions(). Это не означет что пользователь должен вызывать этот скрипт сам, он будет вызван автоматически при инициализации Ultimate 3D. Вы просто должны будете изменить код скрипта на нужный вам. Такой способ задания настроек является более гибким: вы можете установить настройки прямо в скрипте или же выполнить какой-либо код для их получения, например из файла с настройками. Вот переменные, которые вы можете установить в скрипте Ultimate3DOptions().

global.u3d_splash_screen_file - всплывающий экран при загрузке движка

Вы должны установить эту переменную равной строке. Если вы не хотите чтобы при загрузке ресурсов Ultimate 3D, показывался всплывающий экран, то вы должны установить эту переменную равной пустой строке (""). Если же вы хотите чтобы отображался всплывающий экран, то установите эту переменную на путь к файлу со всплывающим экраном.

global.u3d_z_buffer_format - формат z-буфера

Эта переменная может принимать значение 16 или 32. Если вы установите её равной 32, то Ultimate 3D попробует использовать 32-х битный z-буфер. Некоторые видеокарты (и даже довольно мощные) не поддерживают 32-х битный z-буфер, вместо него они используют аналогичный более быстрый, но менее точный (точности с лихвой хватает даже на современные игры) 24-х битный z-буфер. В том случае если Ultimate 3D не удастся использовать 32-х битный (либо 24-х битный) z-буфер, то тогда она использует 16-и битный z-буфер, он поддерживается всеми современными (и не очень) видеокартами. Z-буфер используется для хранения глубины пикселя - это нужно для того чтобы объекты находящиеся позади других объектов не рисовались поверх них.

global.u3d_multi_sample_type - уровень экранного сглаживания

Эта переменная может принимать целочисленные значения от 2 до 16 и 0. Они зависят от поддерживаемого видеокартой уровня сглаживания (antialiasing), самые распространенные значения это 2х, 4х, 8х, 16х и не поддерживаться вообще. Вы должны использовать фактор кратности сглаживания для этой переменной. Эсли вы хотите чтобы было использовано четырех кратное сглаживание (4x), то установите переменную равной 4, если не хотите использовать сглаживание, то установите переменную на 0. Чем выше кратность сглаживания, тем качественнее получается изображение (исчезает "пикселявость") и тем больше времени требуется для рендеринга.

global.u3d_device_type - используемый рендер-движок (device type)

Без хорошей причины менять эту переменную крайне не рекомендуется, лучше оставить её как есть - установить на 0. Тогда Ultimate 3D выберет лучший рендер-движок с наибольшими возможностями. Если вы установите переменную равной 1, то Ultimate 3D будет использовать рендер-движок с программной обработкой вершин. Это означет что центральный процессор (CPU) будет рассчитывать все данные вершин вместо графическо процессора (GPU). Это может привести к небольшой потере производительности, но будет полезно в тех случаях, когда возникает ошибка на уровне драйверов в аппаратной обработке вершин, например они возникают в некоторых версиях драйверов ATI, когда используется вершинное смещение (vertex tweening). Также вы можете установить эту переменную равной 2 для использования полностью программного рендер-движка с использованием Direct 3D. Это приведет к катострофической потере скорости обработки игры, снижению количества кадров в секунду (FPS) - еще бы ведь всю работу, выполняемую видеокартой, взял на себя процессор, что позволяет использовать все возможности движка, даже не поддерживаемые видеокартой (например такие как: кубические карты / cube mapping, отбрасывание теней / shadow casting, пиксельные шейдеры версии 1.4 / pixel shader model 1.4).

Как я уже говорил, остальные настройки могут быть изменены в любой момент соответствующими функциями. Когда вы используете Ultimate 3D вы должны знать откуда загружаются текстуры для моделей (ведь текстуры грузятся автоматически). По умолчанию они загружаются из папки "gfx". Если вы хотите изменить папку для поиска текстур к моделям, то вы должны воспользоваться следующей функцией, чтобы задать новый путь (включая косую черту СЛЭШ на конце - "textures\").

Эта функция изменяет папку, где Ultimate 3D ищет текстуры для моделей.

SetTexturePath(TextureDirectory)

TextureDirectory - путь

Папка содержащая текстуры моделей, включая СЛЭШ на конце, например "textures\".

Следующая функция не изменяет никаких параметров, но она отключает/включает окно рендера Ultimate 3D, чтобы Game Maker мог использовать свой первый вид (индекс 0). Она не имеет никаких параметров.

SwitchView()

Следующая функция изменяет метод фильтрации, который будет использован для заданной текстурной стадии (текстурного уровня - texture stage). Метод фильтрации определяет как Ultimate 3D будет получать цвета с текстур и рассчитывать текстурные координаты. Способ фильтрации по умолчанию - это линейная фильтрация (linear filtering).

Эта функция устанавливает новый метод фильтрации для заданной текстурной стадии.

SetFilter(TextureFilter, TextureStage)

TextureFilter - текстурный фильтр

Фильтр, который будет использован для фильтрации текстур. Вот список различных значений, которые вы можете ввести для этого параметра. 1 - Фильтрация по ближайшей точке (Nearest point filtering), будет использован цвет ближайшего текселя (пикселя текстуры). 2 - Линейная фильтрация (Linear filtering), цвет ближайших четырех пикселей будет интерполирован (вычислено среднее значение) для достижения более слаженного результата. 3 - Анизитропная фильтрация (Anisotropic filtering), это более сложный метод фильтрации, который приводит к более качественным результатам. Этот метод не поддерживается некоторыми очень древними видеокартами.

TextureStage - текстурная стадия

Текстурная стадия для которой вы хотите изменить способ фильтрации. Это должно быть целое число в пределах от 0 до 7.По умолчанию каждая текстурная стадия использует Линейную фильтрацию. Если вы введете для этого параметра -1, то способ фильтрации будет установлен для рисования текстур (используя функции DrawTex() и DrawTexEx() ), так вы можете избежать потери качества при рисовании текстур.

Следующая функция определяет сколько мип-уровней (mip maps) будет создано для загружаемых текстур. Создание мип-уровней подразумевает создание уменьшенных копий текстуры, которые будут использоваться вместо неё, в зависимости от расстояния до камеры. Каждый новый мип-уровень в два раза меньше предыдущего по каждому из размеров (например количество мип-уровней установлено на три а размеры текстуры равны 512*256, тогда будут использованы мип-уровни со следующим разрешением: 512*256 - оригинальная текстура = мип-уровень 1, 256*128 - мип-уровень 2, 128*64 - мип-уровень 3).

Эта функция устанавливает количество создаваемых мип-уровней (mip maps) для загружаемых текстур.

SetMipMapCount(NewMipMapCount)

NewMipMapCount - количество мип-уровней

Количество мип-уровней, которые будут созданы для текстуры.

И наконец функция, которая переключает Ultimate 3D в режим каркасного рендера (wireframe rendering). Каркасный рендеринг означет, что будут нарисованы только грани (стороны) треугольников. Эта особенность будет полезна для редакторов. Использование каркасного рендеринга в играх не приносит ощутимого эффекта.

Эта функция может быть использована для включения/отключения каркасного рендеринга (wireframe rendering) для всех 3D объектов в сцене.

SwitchWireFrameMode(EnableDisable)

EnableDisable - состояние

Если вы введете true (1) для этого параметра, то тогда будет использован каркасный рендеринг, иначе он будет отключен.


Îïòèìèçàöèÿ ïðîèçâîäèòåëüíîñòè

Оптимизация производительности

Оптимизация производительности

Когда вы работаете над большим проектом, то очень важно позаботится о хорошей производительности игры. Довольно распространенное мнение что графика напрямую зависит от используемого 3D движка. Ну конечно более лучшие движки могут дать лучшие результаты. Но чем больше у движка потенциала, тем сложнее использовать все его возможности со стабильным показателем кадров в секунду. Сложность создаваемых на движке игр напрямую зависит от его возможностей по оптимизации. Обычно самый простой способ сделать что-то не означает лучший. Нужно немного опыта и знаний чтобы найти верное решение. Вы так же должны понимать как именно работает Ultimate 3D. Эта глава поможет вам узнать все эти вещи.

Основные приемы

Для опытных программистов следующие приемы покажутся очевидными. Но все равно о них очень важно знать. Один из наиболее важных факторов, влияющих на производительность игры - это количество вершин и треугольников в сцене. Расчеты всех данных для вершин занимают очень много времени, так что при моделировании старайтесь использовать как можно меньше вершин в своих моделях. Если вы работаете в профессиональных программах для моделирования, таких как Blender или 3D Studio Max, то вы можете загрузить специальные плагины для оптимизации ваших моделей. Более простые программы лишь позволяют вам видеть используемое количество вершин и полигонов. Это очень полезно для самостоятельного контроля за количеством вершин при моделировании. И конечно самым простым способом получить низкополигональную модель - это делать ее такой с самого начала моделирования. Будьте внимательны с инструментами по "сглаживанию" моделей, которые делят грани на несколько. Так же не используйте слишком большие значения для детализации примитивов (переменные partsx, partsy и partsz).

Следующий прием менее очевиден. Производительность ваших игр так же зависит от того как много геометрии нужно рендерить отдельно от другой. Если у вас есть две части геометрии в вашей модели, то Ultimate 3D будет рендерить их вместе только тогда, когда они будут являться частью одного меша и будут использовать один и тот же материал. Но хуже всего будет модель, в которой есть сорок различных мешей, каждый состоит не более чем из двадцати треугольников, но тем не менее использует три различных материала. В таком случае Ultimate 3D не сможет рисовать более десяти треугольников одновременно. Так что будьте по экономнее с количеством используемых материалов и используйте меши с большим количеством геометрии. Чаще использование одной текстуры гораздо эффективнее чем использование трех или четырех разных материалов и обычно так даже лучше смотрится.

Вы не должны использовать слишком большие текстуры, так как они занимают слишком много памяти. Ваши текстуры съедают очень много памяти и может получиться так, что память на вашей видеокарте переполнится. Тогда будет использована системная память (оперативная), а в этом случае текстуры придется передавать из системной памяти в видео память каждый шаг, что занимает очень много времени. Так что если одновременно вы загрузили очень много текстур, то вы должны как можно больше из них удалить из памяти вызывая функцию ReleaseTexture(). Помните, что вы должны использовать разрешения, которые являются степенью двойки (2^2=4 2^3=8 2^4=16 2^8=256). Если вы загрузите текстуру с разрешением 512*512, то она будет загружена как есть, с такими же размерами, но если вы загрузите текстуру с размерами 513*513, то она будет растянута до следующего уровня 1024*1024. Это очень огромный размер, который занимает много памяти и времени на расчеты.

Так же вы должны быть экономными с количеством источников освещения в вашей сцене. Если у вас будет очень большое количество источников освещения, то это сильно увеличит время, необходимое для расчетов освещения для каждой вершины в отдельности. Поэтому будет гораздо эффективней научится использовать программу Deled или другие программы для моделирования, чтобы использовать карты освещения. Чтобы получить эффективную игру вы должны найти компромис между динамическими и статическими решениями. Динамические решения требуют больше времени на расчеты, но более проще используются и придают игре дополнительную динамичность. Статические решения требуют ьольше памяти, для хранения уже рассчитанных данных, но тратят гораздо меньше компьютерных ресурсов и могут выглядеть намного лучше чем в динамическом исполнении. Сравнение по-вершинного и по-пиксельного освещения - это хороший пример для этого. Надеюсь мне не нужно повторять о том насколько затратно использование теней.

Поиск наиболее эффективных решений для рисования части геометрии

Ultimate 3D предлагает несколько способов хранения части геометрии, загруженной из файла модели. Вы можете использовать уровни детализации для этого и хранить как примитив. Какой из способ лучший зависит от ситуации. Иногда более эффективно рисовать модель используя LOD; иногда лучше хранить геометрию как примитив; в некоторых случаях это не сработает. Тут мы рассмотрим различные способы оптимизации производительности, используя различные способы хранения геометрии.

Давайте посмотрим как правильно использовать уровни детализации. Эта очень полезная особенность Ultimate 3D делает все автоматически и может сильно увеличить производительность ваших игр. Вообще то это лучше использовать для всех объектов, которые вблизи камеры должны выглядеть детально, а вдали не настолько. Но как я уже говорил никогда не используйте этого для моделей с покадровой анимацией (все модели загруженные из *.md2 файлов или анимация созданная функцией AddFrame()). Так же не имеет смысла использовать уровни детализации на тех моделях, от которых вы не сможете далеко отойти. Например у вас есть некая игра от первого лица, в которой игрок все время находится в маленьких помещениях, то использовать уровни детализации будет бесполезно. В таких случаях есть наиболее простой способ оптимизировать игру. Он будет описан ниже.

Есть несколько ситуаций, когда это может очень сильно увеличить производительность, когда вы используете функцию CreatePrimitiveFromModel(), а в некоторых ситуациях это будет неэффективным. В основном примитивы отлично подходят для статических объектов, таких из которых состоит уровень. Например у вас есть простые модели стен, которым не нужны спецэффекты чтобы хорошо выглядеть, и которые состоят менее чем из ста вершин, то это отличный пример чтобы использовать их как примитивы. Примитивы отлично подходят для рендера растений. Так что если это действительно можно сделать, то сделайте это. Естественно сложно сделать детальную модель солько с одной текстурой, но результат того стоит. Я рекомендую использовать файлы моделей в формате *.an8 для этой функции, потому что Ultimate 3D автоматически собирает содержимое одного такого файла в один меш.

Отключение альфа смешивания

В отличии от предыдущих версий Ultimate 3D у Ultimate 3D 2.0 и новее нет проблем с частично прозрачными текстурами. В ранних версиях очень часто происходили сбои. Но цена за это оказалась высока. Весь объект теперь приходится рендерить дважды в том случае если он использует частично прозрачную текстуру. В первый раз рендерится объект только с польностью непрозрачными частями, во второй раз рендерятся полностью прозрачные части объекта. Так как это может сильно снизить производительность, то Ultimate 3D позволяет вам отключить этот метод для некоторых объектов. Тогда частично прозрачные части станут абсолютно прозрачными, но это даст заметноо ускорение производительности.

Эта функция включает или отключает альфа смешивание для заданного объекта примитива или модели. По умолчанию альфа смешивание включено.

SwitchAlphaBlending(EnableDisable)

EnableDisable - состояние

Если вы введете true для этого параметра, то частично прозрачные части будут отрендерены за второй проход (затратив производительность), иначе частично прозрачные части будут полностью невидимы (менее затратно).

Функции дополнительного отбора

Концепция отбора геометрии проста. Это сделано чтобы избежать рендеринга всего, что сейчас не видимо. По умолчанию Ultimate 3D использует две техники отбора: Отбор задней поверхности (Back face culling) и Усеченный отбор (frustum culling). Отбор задней поверхности означает что только передняя сторона треугольника будет нарисована. Так будет нарисована только половина ото всей геометрии. Усеченный отбор подразумевает что только те объекты, которые попадают в плоскость вида будут отрендерены. Следующий график показывает что это такое:

Если часть геометрии, которая должна быть не видимой, рендерится, то это означает, что она была перекрыта (covered) другим объектом. Чтобы избежать этого требуется третья техника отбора геометрии. А функции дополнительного отбора геометрии отлично подходят для этой цели. Они работают следующим образом. Сначала вы присваиваете всем примитивам, моделям, ландшафтам, системам частиц, источникам освещения индексы виртуальных комнат Ultimate 3D, в которых они якобы будут находиться. Комната - это просто цифра и объекты, которые с ней связаны. По умолчанию все объекты ассоциированы с индексом комнаты 0. Далее вы устанавливаете какие комнаты видимы какими камерами. По умолчанию только комната с индексом 0 изначально видима для всех камер. это можно сделать вручную или Ultimate 3D выполнит это автоматически. Это всё.

В уровнях внутри помещений это может быть особенно полезным. Когда игрок открывает дверь из одной комнаты в другую, то она становится видимой, а когда он проходит сквозь неё и закрывает за собой, то предыдущая комната становится не видимой. Так можно сократить количество одновременно прорисовываемых комнат до двух. Остальные комнаты не интересны. Источники освещения будут освещать только объекты, находящиеся в одной и той же комнате, что позволяет увеличить производительность.

Функции, требуемые для этих целей очень просты. Их только две, одна для присваивания объекту комнат и одна для установки состояния видимости комнат для камер.

Эта функция присваивает объекту комнату, для которого она вызвана.

SetObjectRoom(RoomIndex)

RoomIndex - индекс комнаты

Индекс комнаты с которой вы хотите связать объект. может принимать целочисленное значение в пределах от 0 до 999.

Эта функция устанавливает комнату видимой или не видимой для камеры для которой вызвана эта функция или для первой камеры если она вызвана не для объекта камеры. Помните что эту функцию стоит вызывать после того как вы хотябы один раз вызвали для камеры функцию MoveCamera(), то есть камера должна быть уже создана.

SetRoomVisibility(RoomIndex, NewVisibilityState)

RoomIndex - индекс комнаты

Индекс комнаты с которой вы хотите связать объект. может принимать целочисленное значение в пределах от 0 до 999.

NewVisibilityState - новое состояние видимости

Состояние видимости, которое вы хотите установить для комнаты. Вы можете установить это значение на true (1) для видимости комнаты и на false (0) для не видимости комнаты.

Выше я говорил что устанавливать комнаты видимыми или не видимыми можно сделать вручную или автоматически. Как вы видите вручную это сделать очень просто, но это довольно трудоемко. А вы уже поработали присваивая объекты комнатам. Так что автоматический способ будет более предпочтительным. Он основан на так называемой технологии порталов (portals).

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

Это очень простой случай. Здесь четыре различных комнаты с четырмя дверьми между ними, а в каждой двери установлен портал (синий). Изначально камера находится в комнате с индексом 1, но затем она движется через портал из комнаты 1 в комнату 2, так что после перемещения она окажется в комнате 2 и Ultimate 3D сможет это определить, основываясь на информации портала. А теперь рассмотрим случай с моделью. Изначально она находится в комнате 1, так что видима только комната с индексом 1. Затем она движется в комнату 4 и Ultimate 3D определяет это с помощью портала. Так что теперь будет видима только комната 4. Для моделей и других геометрических объектов это всё что требуется, но для камеры это выглядит слишком простым, ведь камера может видеть больше комнат, не только в которой находится. Когда камера находится в комнате 1, то она может через дверь видеть комнату 2. Более точно можно сказать, что камера видит комнату 2 тогда, когда видит портал из комнаты 1 в комнату 2. Из того следует вывод, что камера видит комнату 2 тогда, когда видит дверь в комнату 2. Следующая иллюстрация покажет это.

На левом рисунке камера не смотрит не на один портал, так что нет необходимости рисовать комнаты за исключением той, в которой находится камера. На рисунке справа камера смотрит сквозь портал из комнаты 1 в комнату 2, так что комната 2 также будет видимой. И последний, особый случай. Камера видит комнаты не только с видимым порталом из текущей комнаты в другую, но также комнаты с видимыми порталами из любой видимой комнаты в другую. И опять же это проиллюстрировано на рисунке.

Как вы видите комната 1, комната 2 и комната 3 - видимы. Комната 1 видима, так как в ней находится камера, комната 2 видима, так как видим портал из комнаты с камерой (комната 1) в комнату с индексом 2, а комната 3 видима, так как видим портал из видимой комнаты, ведущий в комнату 3. Но все равно, даже так случаются ошибки, вы ведь видите что комната 3 не совсем видна камере. Это - маленькая ошибка, которая может возникнуть в Ultimate 3D Portal Engine (обработчике порталов Ultimate 3D). Но есть способ избежать этих проблем во многих случаях. Обычно двери закрываются сразу же после того как их прошел персонаж. Если двери закрыты, то вы не можете ничего видеть из предыдущей комнаты, и это используется в Ultimate 3D. Если комната закрыта, то она не будет видима даже если портал находится в области вида камеры (видим).

На всех этих примерах вы воочию убедились в эффективности системы порталов Ultimate 3D. На обычных уровнях в крупных проектах (играх) может быть более двадцати комнат. Рендерить их все одновременно будет просто убийственно для Центрального процессора (CPU) и видеокарты. Используя систему порталов Ultimate 3D вы можете сократить количество одновременно обрабатываемых комнат вплоть до одной, что позволит резко сократить нагрузку на компьютер. Это намного лучше, ведь использование системы порталов не тратит больших мощностей процессора на расчеты. Минусом является только то, что вы должны потратить время на установку порталов и ассоциирование всех объектов (или большинства) с комнатами. Различные механизмы, позволяющие автоматически ассоциировать объекты с комнатами были испробованы в процессе разработки Ultimate 3D 2.0, но они были отвергнуты по тем или иным причинам. Так что пока такой возможности нет. Да и вообще, вам что лень поработать лишних пять минут (два часа:) ради значительного прироста производительности. С редактором уровней для Ultimate 3D систему порталов будет гораздо проще использовать. Но всё равно это только лишь запланированные проекты, так что вам лучше этого не ждать. (Чего и я советую, так как за три месяца написания справки никаких новостей на этот счет я не слышал)

Итак, вы прочитали кучу теоретического материала, но если вы его поняли, то назначение функций будет очевидным для вас. Первая функция, которую вы должны знать, включает/выключает использование системы порталов определенной камерой. После того как система порталов включена любой вызов функции SetRoomVisibility() будет проигнорирован. Комната 0 будет всегда видимой, а остальный в зависимости от системы порталов.

Эта функция включает систему порталов для камеры, для объекта которой она была вызвана.

SwitchPortalEngine(EnableDisable)

EnableDisable - состояние

Будет ли система порталов включена (true или 1) или же выключена (false или 0).

Следующие четыре функции можно использовать для создания, изменения, закрытия и уничтожения порталов. Как я уже говорил выше, порталы выглядят (они не видимы, это просто их форма) в виде круга. Круг задается ориентацией (направлением "лицевой стороны"), центром (x, y, z) и радиусом. Еще портал содержит два индекса комнат.

Эта функция создает портал, используя введенные данные, и возвращает его индекс.

CreatePortal

(

CenterX, CenterY, CenterZ,

FacingDirectionLongitude, FacingDirectionLatitude,

Radius,

RoomIndex1, RoomIndex2

)

CenterX/Y/Z - координаты центра

Центр круга, который представляет область действия портала. (это про круг)

FacingDirectionLongitude, FacingDirectionLatitude - ориентация лицевой стороны круга

Направление лицевой стороны круга, представляющего область действия портала. Направление это перпендикуляр к плоскости круга, с его лицевой стороны. (начертите круг на листке с одной стороны - это лицевая сторона, и в какую сторону она повернута это и есть ориентация/направление)

Radius - радиус круга

Радиус круга, который задает границы портала.

RoomIndex1, RoomIndex2 - индексы связанных с порталом комнат

Индексы комнат, которые находятся по разные стороны круга. Он не должен быть равен 0, так как комната с индексом 0 всегда видима, когда используется система порталов. Порядок значения не имеет. Если камера в комнате с индексом RoomIndex1 и прошла сквозь портал, то она окажется в комнате с индексом RoomIndex2 и наоборот.

Эту функцию можно использовать для изменения портала, после того как он был создан.

SetPortal

(

PortalID,

FacingDirectionLongitude, FacingDirectionLatitude,

Radius, RoomIndex1, RoomIndex2

)

PortalID - индекс портала

Индекс портала, который вы хотите изменить. Это значение возвратила функция CreatePortal(), которая создала портал.

FacingDirectionLongitude, FacingDirectionLatitude - ориентация лицевой стороны круга

Направление лицевой стороны круга, представляющего область действия портала. Направление это перпендикуляр к плоскости круга, с его лицевой стороны. (начертите круг на листке с одной стороны - это лицевая сторона, и в какую сторону она повернута это и есть ориентация/направление)

Radius - радиус круга

Радиус круга, который задает границы портала.

RoomIndex1, RoomIndex2 - индексы связанных с порталом комнат

Индексы комнат, которые находятся по разные стороны круга. Он не должен быть равен 0, так как комната с индексом 0 всегда видима, когда используется система порталов. Порядок значения не имеет. Если камера в комнате с индексом RoomIndex1 и прошла сквозь портал, то она окажется в комнате с индексом RoomIndex2 и наоборот.

Эта функция может быть использована для открытия порталов (по умолчанию они открыты) или для их закрытия.

OpenPortal(PortalID, OpenClose)

PortalID - индекс портала

Индекс портала, который вы хотите изменить. Это значение возвратила функция CreatePortal(), которая создала портал.

OpenClose - состояние

Введите true для открытия этого портала или же false для его закрытия. Когда портал закрыт, то камера всё еще может проходить сквозь него, но нельзя будет увидеть другие комнаты сквозь портал.

Эта функция уничтожает портал с заданным индексом.

DestroyPortal(PortalID)

PortalID - индекс портала

Индекс портала, который вы хотите изменить. Это значение возвратила функция CreatePortal(), которая создала портал.

Информация, которую невозможно узнать системе порталов - это изначальное положение камеры. Именно поэтому вы должны ввести её вручную. Это можно сделать уже знакомой вам функцией SetObjectRoom(), прямо как и для остальных объектов.

Система порталов не просто дает прирост в производительности, а может стать полезным элементом в реализации геймплея. Например вы можете проиграть некоторую видеосцену, когда персонаж пересек портал первый раз. Еще это будет полезным для программирования искусственного интеллекта (AI). Если камера находится в комнате с врагами, то они активизируются. Для такого вам нужна функция, которая бы возвращала в какой комнате находится объект. Это можно узнать следующей функцией.

Эта функция возвращает индекс комнаты, в которой находится объект, для которого она была вызвана.

GetObjectRoom()

Еще вы можете избежать излишних расчетов, выполняя их только для объектов в видимых комнатах. Так, например не нужно обновлять систему частиц, если её не видит камера и не должно проверятся столкновение между объектами из других комнат. Что узнать какие комнаты видимы определенными камерами вы должны использовать следующую функцию.

Эта функция возвращает состояние видимости комнаты с заданным индексом для объекта камеры, для которого вызвана эта функция.

GetRoomVisibility(RoomIndex)

RoomIndex - индекс комнаты

Индекс комнаты, о которой вы хотите получить состояние видимости.


Îáíîâëåíèå ñòàðûõ ïðîåêòîâ

Обновление старых проектов Ultimate 3D

Обновление проектов Ultimate 3D 2.0 beta 3 до версии Ultimate 3D 2.0 RC

Ultimate 3D 2.0 RC это практически финальная версия Ultimate 3D. Так как разработка Ultimate 3D 2.0 занимает много времени, то ранее выпущенные бета версии были доступны с урезанными возможностями. Теперь эти возможности были добавлены и текущая бета версия Ultimate 3D 2.0 RC содержит все возможности финальной версии Ultimate 3D 2.0. Чтобы вы смогли их использовать вы должны обновить свой проект Game Maker. Пять минут чтения этой статьи, одна минута на обновление и вы можете использовать Ultimate 3D 2.0 RC со всеми возможностями.

Первое что вы должны сделать, так это загрузить самую последнюю версию пакета разработки (SDK) с официального сайта Ultimate3D.org (что вы, наверное, уже сделали). После этого вы должны заменить файл библиотеки Ultimate 3D 2.0 beta 3 "Ultimate3D.dll" новым файлом библиотеки Ultimate 3D из пакета разработки. Теперь вы должны заменить скрипты более новыми версиями. Просто откройте ваш старый проект *.gmd (или *.gm6) и файл проекта Ultimate 3D из пакета разработки "basic.gmd" или "basicGM6.gm6", откройте необходимые скрипты и скопируйте их содержание (код) из файла проекта Ultimate 3D пакета разработки в скрипты своего файла проекта.Вот список скриптов, которые вы должны заменить:

- CreatePrimitiveFromModel(...)

- PreloadMesh(...)

- LoadMesh()

- AddFrame(...)

- Step()

- Destroy()

- Init()

- SetFilter()

- GetBoneTransformation()

- CreateTerrain()

- DrawText()

- CreateCube()

- DrawTex()

- DrawTexEx()

- RenderToCubeTexture()

- GetObjectTransformation()

- MoveCamera()

- SetObjectRoom()

- CreateTerrain()

Теперь вы должны добавить новые скрипты, чтобы можно было использовать новые возможности Ultimate 3D. Вот список этих скриптов:

- ExportToU3DFile(...)

- SwitchAlphaBlending(...)

- SetBoneFrame(...)

- GetDistanceToTerrain(...)

- SetCustomTerrainLightMap(...)

- GetClippingPlaneSupport()

- SwitchWireFrameMode(...)

- UpdateSkeleton()

- ReleaseModel(...)

- AddTextureCoordinateSetsFromModel(...)

- ComputeMatrixRotationAngles(...)

- GetRayTracingNormal(...)

- ScreenCoordToVector(...)

- Все скрипты в папке (группе) "Shadow and post screen shader functions":

+ GetShadowSupport()

+ SwitchShadows(...)

+ SwitchShadowCasting(...)

+ CreateShadowOptimizedGeometry(...)

+ SwitchShadowReceiving(...)

+ CreatePostScreenShader()

+ SetPSSTexture(...)

+ SetPSSVSConstant(...)

+ SetPSSPSConstant(...)

+ SetPSSFilter(...)

- и в папке (группе) portal engine functions:

+ SwitchPortalEngine(...)

+ GetObjectRoom()

+ GetRoomVisibility(...)

+ CreatePortal(...)

+ SetPortal(...)

+ OpenPortal(...)

+ DestroyPortal(...)

Все эти скрипты доступны и в виде файла экспорта скриптов Game Maker, который идет вместе с пакетом разработки. Импортировав его вы тем самым можете сэкономить себе время, не добавляя новые скрипты (но обновляя старые !!!). В зависимости от того какую версию Ultimate 3D beta 3 вы использовали, вам может понадобится добавить скрипт GetBoneTransformation(), потому что он отсутствовал в некоторых релизах беты 3. Еще вы должны удалить скрипт LoadAnimated3DS(), потому что он больше не используется, его функции теперь на себя взял скрипт LoadMesh(). После того как вы всё это сделаете, ваш проект будет полностью совместим с (и обновлен до) Ultimate 3D 2.0 RC и теперь вы можете его смело использовать.


Ñïèñîê ôóíêöèé

Список функций

AddFrame(File,Password)

AddGravityEmitter(PositionX, PositionY, PositionZ,GravityEmitterMass)

AddInverseTangentSpaceMatrices()

AddModifier()

AddTerrainTexture(DiffuseMap,AlphaMap,WrapCountX, WrapCountY)

AddTextureCoordinateSet(DimensionCount)

AddTextureCoordinateSetsFromModel(ModelFile, Password)

AddVertex(X,Y,Z,U,V)

ApplyCelShading(LineWidth,LineColorR, LineColorG, LineColorB, LineColorA)

ApplyParallaxAndBumpMapping(MaterialIndex,HeightMapIndex,ParallaxFactor,LightSourceID1,LightSourceID2,LightSourceID3)

ApplyTerrainTextures()

BeginPolygon(VertexNumber)

CalculateCrossProduct(OutputVectorID,InputVectorID1, InputVectorID2)

CalculateDotProduct(InputVectorID1, InputVectorID2)

CalculateTerrainLightMap(LightSourceID1, LightSourceID2, , LightSourceID10)

CalculateVectorLength(VectorID)

CalculateVectorScalarProduct(OutputVectorID,InputVectorID,ScalarFactor)

CalculateVectorSum(OutputVectorID,InputVectorID1, InputVectorID2)

ComputeMatrixRotationAngles(OutputVectorID,InputMatrixID)

CoordToScreenXYZ(X, Y, Z,CameraIndex)

CopyMatrix(OutputMatrixID,InputMatrixID)

Create2D()

CreateCube()

CreateCubeTextureRenderTarget(TextureIndex,RequestedEdgeIndex)

CreateDirectionVector(OutputVectorID,Longitude, Latitude)

CreateEmptyMesh()

CreateFloor()

CreateLODChain(CameraDistance1, LoD1,CameraDistance2, LoD2,CameraDistance3, LoD3,CameraDistance4, LoD4,CameraDistance5, LoD5)

CreateMaterialVSEffect(MaterialIndex,VertexShaderFile)

CreateParticleSystem()

CreatePolygon()

CreatePortal(CenterX, CenterY, CenterZ, FacingDirectionLongitude, FacingDirectionLatitude, Radius, RoomIndex1, RoomIndex2)

CreatePostScreenShader()

CreatePrimitiveFromModel()

CreateRotationMatrix(OutputMatrixID,RotationX, RotationY, RotationZ)

CreateScalingMatrix(OutputMatrixID,ScalingX, ScalingY, ScalingZ)

CreateShadowOptimizedGeometry(LODIndex,CreateConnectionPatches)

CreateTerrain()

CreateTextureRenderTarget(TextureIndex,RequestedWidth, RequestedHeight)

CreateTransformationMatrix(OutputMatrixID,TranslationX, TranslationY, TranslationZ,RotationX, RotationY, RotationZ,ScalingX, ScalingY, ScalingZ)

CreateTranslationMatrix(OutputMatrixID,TranslationX, TranslationY, TranslationZ)

CreateVector(OutputVectorID,X, Y, Z)

CreateWall()

Destroy()

DestroyPortal(PortalID)

DisableFog()

DrawTex(TextureIndex,X,Y,Scaling,Rotation,Transparency)

DrawTexEx(TextureIndex, Left,Top, Width,Height, X,Y, ScalingX,ScalingY, Rotation, R,G,B,A,CameraIndex)

DrawTexEx(TextureIndex,Left, Top,Width, Height,X, Y,ScalingX, ScalingY,Rotation,R, G, B, A)

DrawText(FontIndex,X, Y,Text)

DrawText(FontIndex, X, Y, Text,CameraIndex)

DrawText3D(Text,FontIndex,X, Y, Z, RotX, RotY, RotZ, ScalX, ScalY, ScalZ)

EnableVertexTweening()

ExportToU3DFile(OutputFile,Password,ExportResources)

GetBoneIndex(BoneName)

GetBoneTransformation(OutputMatrixID,BoneIndex)

GetClippingPlaneSupport()

GetCubeMapSupport()

GetCurrentFrame()

GetDistanceToAnyPrimitive(RayOriginX, RayOriginY, RayOriginZ,RayDirectionLongitude, RayDirectionLatitude)

GetDistanceToModel(ModelID,RayOriginX, RayOriginY, RayOriginZ,RayDirectionLongitude, RayDirectionLatitude)

GetDistanceToPrimitive(PrimitiveID,RayOriginX, RayOriginY, RayOriginZ,RayDirectionLongitude, RayDirectionLatitude)

GetDistanceToTerrain(TerrainID,RayOriginX, RayOriginY, RayOriginZ,RayDirectionLongitude, RayDirectionLatitude)

GetLockedMeshTriangle(LockedMeshIndex,TriangleIndex,RequestedVertexIndex)

GetLockedMeshTriangleCount(LockedMeshIndex)

GetLockedMeshTriangleMaterial(LockedMeshIndex,TriangleIndex)

GetLockedMeshVertex(LockedMeshIndex,VertexIndex,ValueIndex)

GetLockedMeshVertexCount(LockedMeshIndex)

GetMaterialCount()

GetMaterialIndex(MaterialName)

GetMeshCount()

GetMousePos()

GetObjectRoom()

GetObjectTransformation(ObjectID)

GetRayTracingNormal(OutputVectorID)

GetRoomVisibility(RoomIndex)

GetShadowSupport()

GetSimultaneousTextureCount()

GetSupportedPSVersion()

GetTerrainHeightAtPos(TerrainID,PositionX, PositionY)

GetVector(VectorID,VectorElementID)

GetVertex(VertexIndex,ElementIndex)

InvertMatrix(OutputMatrixID,InputMatrixID)

LightDirectional()

LightPoint()

LightSpot()

LoadBackground(File)

LoadCubeTexture(FileScheme,TextureIndex,CubeWidth)

LoadHeightMap(TextureIndex,HeightMapFile,HeightFactor)

LoadMaterialEffect(MaterialIndex,UFXFile)

LoadMesh()

LoadTexture(TextureFile,TextureIndex,Width, Height)

LockMesh(LockedMeshIndex,MeshIndex,Frame,LoD)

MouseCheckButton(MouseButton)

Move(Longitude,Latitude,Speed)

MoveCamera()

OpenPortal(PortalID,OpenClose)

ParticleSystemStep(StepLength)

PreloadMesh(File,Password)

RecalculateNormals()

RecreatePrimitive()

ReleaseMatrix(MatrixID)

ReleaseModel(File)

ReleaseTexture(TextureIndex)

ReleaseVector(VectorID)

RenderToCubeTexture(CubeTextureIndex,PositionX, PositionY, PositionZ,ColorR, ColorG, ColorB, ColorARoomIndex1, RoomIndex2, , RoomIndex8)

RenderToTexture()

ScreenCoordToVector(OutputVectorID,ScreenCoordX, ScreenCoordY,CameraIndex)

SetAmbient(R,G,B)

SetBoneFrame(BoneIndex,Frame,EffectChildBonesdeclcodepbBoneIndexThe index of the bone you want to change the frame value forppbFrameA positive value giving an absolute frame value, which is to be used for the bone It will be used instead of the value of the frame variable, resp the return value of GetCurrentFrame()

SetBoneRotation(BoneIndex,RotationX, RotationY, RotationZ)

SetClippingPlane(ClippingPlaneIndex,PlaneOriginX, PlaneOriginY, PlaneOriginZ,PlaneOrientationLongitude, PlaneOrientationLatitude)

SetCustomTerrainLightMap(TextureIndex)

SetFilter(TextureFilter,TextureStage)

SetFinalParticleColor(MinimumR, MinimumG, MinimumB, MinimumA,MaximumR, MaximumG, MaximumB, MaximumA)

SetFog(R,G,B,StartDistance,EndDistance)

SetFont(FontName,FontIndex,TextSize,TextAttributes,R,G,B,A)

SetFontColor(FontIndex,R,G,B,A)

SetGravityEmitter(GravityEmitterID,PositionX, PositionY, PositionZ,GravityEmitterMass)

SetInitialCenterRepulsionFactor(RepulsionFactorX, RepulsionFactorY, RepulsionFactorZ)

SetInitialParticleColor(MinimumR, MinimumG, MinimumB, MinimumA,MaximumR, MaximumG, MaximumB, MaximumA)

SetLockedMeshTriangle(LockedMeshIndex,TriangleIndex,VertexIndexA, VertexIndexB, VertexIndexC)

SetLockedMeshTriangleMaterial(LockedMeshIndex,TriangleIndex,NewMaterialIndex)

SetLockedMeshVertex(LockedMeshIndex,VertexIndex,ValueIndex,NewValue)

SetMaterial(Red,Green,Blue,Alpha)

SetMaterialEffectLightSource(MaterialIndex,LightSourceID1, LightSourceID2, LightSourceID3)

SetMaterialEffectPSConstant()

SetMaterialEffectVSConstant(MaterialIndex,VSConstantIndex,XValue, YValue, ZValue, WValue)

SetMaterialEmissive(Red,Green,Blue)

SetMaterialEnvironmentMap(MaterialIndex,TextureIndex)

SetMaterialStageTexCoord(MaterialIndex,TextureStage,TextureCoordinateSetIndex)

SetMaterialStageTexture(MaterialIndex,TextureStage,TextureIndex)

SetMaterialStageTextureOperation(MaterialIndex,TextureStage,TextureOperation)

SetMipMapCount(NewMipMapCount)

SetModelMaterial(MaterialIndex,R, G, B, A)

SetModelMaterialEmissive(MaterialIndex,R, G, B, A)

SetModifierAccelerationChange(ModifierID,AccelerationFactorX, AccelerationFactorY, AccelerationFactorZ,AccelerationSummandX, AccelerationSummandY, AccelerationSummandZ)

SetModifierEffectedArea(ModifierID,SecondSphereRadius,PositionX, PositionY, PositionZ,RotationX, RotationY, RotationZ,ScalingX, ScalingY, ScalingZ)

SetModifierLifetimeChange(ModifierID,LifetimeChange)

SetModifierNewFinalColor(ModifierID,MinimumR, MinimumG, MinimumB, MinimumA,MaximumR, MaximumG, MaximumB, MaximumA)

SetModifierNewFinalSize(ModifierID,MinimumNewFinalSize, MaximumNewFinalSize)

SetModifierVelocityChange(ModifierID,VelocityFactorX, VelocityFactorY, VelocityFactorZ,VelocitySummandX, VelocitySummandY, VelocitySummandZ)

SetMousePos(X, Y)

SetObjectRoom(RoomIndex)

SetOrtho(UseOrthogonalProjection,SeenAreaWidth, SeenAreaHeight)

SetParticleAcceleration(MinLongitude, MinLatitude,MinAcceleration,MaxLongitude, MaxLatitude,MaxAcceleration)

SetParticleCount(MinimumParticleCount,MaximumParticleCount,MaximumTotalParticleCount)

SetParticleLifetime(MinimumParticleLifetime,MaximumParticleLifetime)

SetParticleOrigin(SecondSphereRadius,RotationX, RotationY, RotationZ,ScalingX, ScalingY, ScalingZ)

SetParticleSize(MinInitialSize, MaxInitialSize,MinFinalSize, MaxInitialSize)

SetParticleVelocity(MinLongitude, MinLatitude,MinVelocity,MaxLongitude, MaxLatitude,MaxVelocity)

SetPortal(PortalID,FacingDirectionLongitude, FacingDirectionLatitude, Radius, RoomIndex1, RoomIndex2)

SetPSSFilter(TextureStage,FilterType)

SetPSSPSConstant(PSConstantIndex,Value1, Value2, Value3, Value4)

SetPSSTexture(TextureStage,TextureIndex)

SetPSSVSConstant(VSConstantIndex,Value1, Value2, Value3, Value4)

SetRoomVisibility(RoomIndex,NewVisibilityState)

SetTexturePath(TextureDirectory)

SetVertex(VertexIndex,X,Y,Z,U,V)

SmoothNormals()

Step()

SwitchAlphaBlending(EnableDisable)

SwitchPortalEngine(EnableDisable)

SwitchShadowCasting(LightSourceID,Enable)

SwitchShadowReceiving(LightSourceID,Enable)

SwitchShadows(Enable)

SwitchView()

SwitchWireFrameMode(EnableDisable)

TakeScreenshot(BMPFile)

TakeScreenshotEx(BMPFile,Unused,Left, Top, Right, Bottom)

TransformMatrix(OutputMatrixID,InputMatrixID1, InputMatrixID2)

TransformVector(OutputVectorID,InputVectorID,InputMatrixID)

Ultimate3DOptions()

UnloadBackground()

UnlockMesh(LockedMeshIndex)

UpdateSkeleton()


Øåéäåðíîå ïðîãðàììèðîâàíèå

Шейдерное программирование

Статья основана на материалах DirectX 8.1 SDK

Навигация

Шейдеры

Вершинный шейдер

Инструкции

Регистры

Регистры ввода

Регистры вывода

Модификаторы

Пиксельный шейдер

Инструкции

Регистры

Ограничение доступа к регистрам

Операции доступа

Пределы значений

Модификаторы

Модификаторы инструкций

Модификаторы ресурсов

Селекторы

Маска регистров назначения

Модификаторы текстурных регистров для texld и texcrd

Селекторы регистров ресурса для texld и texcrd

Маска регистра назначения для texld и texcrd

Подробное описание инструкций

Вершинный шейдер

Пиксельный шейдер

Шейдеры

Во всех более/менее современных видеокартах (даже, которые не поддерживают шейдеры) есть так называемый блок Трансформации и Освещения (hardware T&L). Это что-то вроде отдельного процессора (в большинстве видеокарт его функции выполняют шейдерные конвейеры). Он выполняет фиксированный алгоритм преобразования матриц трансформации и вычисляет цвет пикселей. Если вы запустите старую игру или игру на видеокарте без поддержки шейдеров, то вы увидите картинку, которую и расчитывает этот самый блок T&L. И никак этот алгоритм изменить нельзя. Но позднее были придуманы программируемые шейдерные блоки. Тогда они были двух видов: вершинные конвейеры и пиксельные конвейеры (названия могут отличаться). Одни использовались для расчетов данных о вершине, а другие для расчетов цвета пикселя. И главной их особенность было то, что вы сами можете установить алгоритм, который и будет рассчитывать эти данные. Если в игре не активированы шейдеры, то расчет производится по стандартному алгоритму T&L, но как только активированы шейдеры, то расчеты для тех объектов, к которым они применены происходят с заданным вами алгоритмом. Под шейдером же сейчас понимается этот самый задаваемый алгоритм.

Шейдер - это специальная программа/скрипт, который будет выполнен при обработке вершины (вершинный шейдер) или пикселя (пиксельный шейдер). Они нужны для динамического изменения параметров вершин и пикселей при рендере. Так вершинный шейдер может рассчитывать цвет диффузии вершины, цвет отражения вершины, позицию вершины, силу тумана для вершины и т.д. Пиксельный шейдер рассчитывает только одно - цвет пикселя для рисования его на экране. Некоторые значения из вершинного шейдера передаются пиксельному шейдеру. Шейдеры могут применятся как для отдельных объектов, так и для всей сцены сразу (в таком случае эти шейдеры называются шейдерами постобработки). Вершинный шейдер может применятся без пиксельного, в таком случае для расчета цвета пикселя будет использоваться стандартный алгоритм T&L, а вот пиксельный шейдер обязательно должен быть использован вместе с вершинным шейдером, так как он должен получить из вершинного шейдера некоторые значения.

Для хранения значений в пиксельных шейдерах используются регистры. Говоря языком Game Maker, Регистр - это объект с четырьмя переменными: x, y, z и w (или r, g, b, a). Существует несколько разных типов регистров. Самые главные это регистры ввода и регистры вывода (input registers и output registers). В регистры ввода перед запуском шейдера записывается исходная информация. Шейдер должен ввести информацию в регистры вывода (не всегда и не во все), в дальнейшем информация из регистров вывода используется для отрисовывания пикселя.

Вершинный шейдер

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

Инструкции

Ниже приведен список допустимых инструкций для вершинного шейдера.

Сокращения:

dest - регистр назначения (destination register), куда будет записан результат инструкции

src - регистр ресурса (source register), один из аргументов инструкции

fVal - 32-х битное число с плаващей запятой (тип float)

Инструкция | Параметры | Действие
vs | vs.mainVersion.subVersion | Определяет версию вершинного шейдера.
def | dest, fVal0, fVal1, fVal2, fVal3 | Задает константу вершинного шейдера
Инструкция | Параметры | Действие
add | dest, src0, src1 | Сумма
dp3 | dest, src0, src1 | Трех-компонентное скалярное произведение
dp4 | dest, src0, src1 | Четырех-компонентное скал. произведение
dst | dest, src0, src1 | Рассчитывает вектор расстояния
expp | dest, src | Возведение в степень (экспотенциал) 2src
lit | dest, src | Вычисляет световой коэффициент
logp | dest, src | Вычисляет логарифм по основанию 2
mad | dest, src0, src1, src2 | Произведение и сумма: src0 * src1 + src2
max | dest, src0, src1 | Вычисляет наибольшее из значений
min | dest, src0, src1 | Вычисляет наименьшее из значений
mov | dest, src | Присваивает (копирует) значение src в dest
mul | dest, src0, src1 | Произведение
rcp | dest, src | Вычисляет обратную величину скаляра
rsq | dest, src | Вычисляет обратный корень скаляра
sge | dest, src0, src1 | Сравнение: src0 больше ли чем src1
slt | dest, src0, src1 | Сравнение: src0 меньше ли чем src1
sub | dest, src0, src1 | Разность: src0 - src1
Макрос | Параметры | Действие
exp | dest, src | Возведение в степень (с точностью 20бит)
frc | dest, src | Возвращает дробную часть
log | dest, src | Вычисляет log2(x) (с точностью 20бит)
m3x2 | dest, src0, src1 | Произведение вектора и матрицы 2x3
m3x3 | dest, src0, src1 | Произведение вектора и матрицы 3x3
m3x4 | dest, src0, src1 | Произведение вектора и матрицы 3x4
m4x3 | dest, src0, src1 | Произведение вектора и матрицы 4x3
m4x4 | dest, src0, src1 | Произведение вектора и матрицы 4x4

1. Вершинный шейдер всегда должен начинаться с инструкции vs, определяющей версию вершинного шейдера.
2. Шейдер должен записывать позицию вершины в регистр вывода позиции вершины (output vertex position register). Если шейдер вычисляет цвет вершины, то он должен его записывать в регистр вывода цвета вершины (output vertex color register).
3. Макросы (макро инструкции) состоят из основных инструкций и призваны повысить функциональность.
4. Модификаторы можно применять к аргументам инструкций, например вы можете в инструкции сложения add ко второму аргументу применить модификатор отрицания -r. И тогда у вас получится вычитание: add dest, src0, -src1;. Подробнее о модификаторах смотрите в главе Модификаторы.

Регистры

Все регистры представляют из себя четырех-компонентный вектор, где каждый компонент является 32-битным числом с плавающей запятой (тип floating point). Элементы вектора представлены как x, y, z и w. Регистры бывают трех типов: регистры ввода (Input Registers), регистры вывода (Output Registers) и временные регистры (Temporary Registers). Проще говоря, регистр это переменная, которая имеет четыре подпеременных x, y, z и w.

Регистры ввода.

Регистр | Тип | Операции | Кол-во | Кол-во на инструкцию | Версия
a0 | Адресный регистр | запись / использ | 1 скаляр | 0 в версии 1.0 и 1 для 1.1 | 1.1
cn | Константный регистр | чтение | 96 векторов | 1 | 1.0 - 1.1
rn | Временный регистр | чтение / запись | 12 векторов | 3 | 1.0 - 1.1
vn | Вершинный регистр | чтение | 16 векторов | 1 | 1.0 - 1.1

Адресный регистр - a0

Регистр a0 - это адресный регистр. Он не доступен в вершинном шейдере версии 1.0 и только один регистр доступен в версии 1.0. Адресный регистр, определяемый как a0.x может быть использован для относительной адресации констант: c[a0.x + n]. Чтение данных из констант вне допустимых пределов вернет (0.0, 0.0, 0.0, 0.0). Адресный регистр можно использовать только с инструкцией mov. Адресный регистр не может быть прочитан из вершинного шейдера, только использован в относительной адресации константных регистров. Чтение данных из не поддерживаемых константных регистров может превести к непредсказуемым результатам. Любое использование адресного регистра в вершинном шейдере версии 1.0 вызовет сбой приложения. Использование адресного регистра вершинным шейдером версии 1.1 до того как он был установлен также вызовет сбой приложения. (я бы не рекомендовал вам использовать данный регистр до тех пор пока вы не станете настоящим гуру по программированию шейдеров)

Константные регистры - cn

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

c[n] - Абсолютная адресация.

c[a0.x + n] - Относительная адресация.

Помните что вы можете использовать константы с индексами от 0 до 95 - всего 96 констант. Например: c0; c15; c37; c56; c95; с абсолютной адресацией и с относительной: c[a0.x+5]; c[a0.x+22]. Константные регистры предназначены только для чтения - вы не можете записать в них результат, значение задается только при инициализации константы инструкцией def или ей аналогичными внешними функциями. Чтение из регистра за допустимыми пределами вернет (0.0, 0.0, 0.0, 0.0). Каждая из инструкций может получить доступ только к одному константному регистру

Временные регистры - rn

Регистры rn - это временные регистры. Временные регистры скомпонованы в группу из 12 четырехмерных векторов с 32-х битной точностью с плавающей запятой (floating point). К каждому временному регистру можно получить доступ один раз для записи и три раза для чтения. Именно по этому инструкция может иметь не более трех временных регистров в качестве аргументов. Никакие значения во временном регистре, оставшемся с предыдущего вершинного шейдера, не могут быть использованы вновь. Чтение вершинным шейдером из временного регистра, до того как туда было занесено значение, вызовет сбой приложения. Доступно двеннадцать временных регистров с индексами от 0 до 11, например: r0, r1, r2, r3, r9, r11.

Вершинные регистры - vn

Регистры vn - это вершинные регистры ввода. Данные каждой вершины загружаются в вершинный регистр ввода до запуска вершинного шейдера. Доступно 16 вершинных регистров ввода, которые представляют из себя четырех-компонентный вектор с точнотью 32 бита с плавающей запятой (float). Допустимые индексы находятся в пределах от 0 до 15, например: v0, v4, v13, v15. Вершинные регистры ввода предназначены только для чтения. Любая инструкция может получить доступ только к одному вершинному регистру ввода. Вы можете использовать модификаторы для вершинных регистров ввода, такие как отрицание и перемешивание (swizzle).

Регистры вывода

Региcтры вывода вершинного шейдера служат для передачи данных в блок растеризации (растеризатор). Результирующие данные из арифметического логического устройсва вершинного шейдера (ALU) записываются в регистры вывода, доступ к которым только для чтения. Название регистров начинается с буквы "o" ([oh] - [эу] - в русской раскладке клавиша "щ"), означающее что эти регистры предназначены только для вывода/записи (агл output - вывод).

Регистр | Тип | Операции | Количество | Версия
oD0, oD1 | Регистры цвета | Только запись | 2 четырехмерных вектора | 1.0, 1.1
oFog | Регистр тумана | Только запись | 1 скаляр с плавающей запятой | 1.0, 1.1
oPos | Регистр позиции | Только запись | 1 четырехмерный вектор | 1.0, 1.1
oPts | Регистр размера точки | Только запись | 1 скаляр с плавающей запятой | 1.0, 1.1
oT0 - oT7 | Текстурные координаты | Только запись | 8 четырехмерных векторов | 1.0, 1.1

Регистры цвета вершины - oD0 и oD1

Регистр oD0 - это регистр цвета диффузии вершины (diffuse color register), а регистр oD1 - это регистр цвета отражения вершины (specular color register). Значение вершинного регистра вывода oD0 интерполируется и записывается в регистр ввода цвета v0 пиксельного шейдера. Значение регистра вывода oD1 интерполируется и записывается в регистр ввода цвета v1 пиксельного шейдера. Более подробно о регистрах пиксельного шейдера смотрите в главе Регистры.

Регистр тумана - oFog

Регистр вывода значения тумана (output fog value registers). Значение фактора силы тумана интерполируется и заносится в таблицу тумана. Используется только скаляр x-компонента тумана. Значение фиксируется в пределах от 0 до 1 перед тем, как передать его в растеризатор.

Регистр позиции - oPos

Регистр вывода позиции вершины. Значение - это позиция в однородном пространстве обрезки (homogeneous clipping space). Это значение должно быть записано вершинным шейдером.

Регистр размера точки - oPts

Ригистр вывода размера точки (output point-size registers). Используется только скаляр x-компонента размера точки.

Регистры текстурных координат - oT0 - oT7

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

Модификаторы

Как видно из таблицы, модификаторы могут быть применены к любому из компонентов вектора (где r - это регистр ввода либо любой из регистров вывода). Модификаторы отрицание и перемешивание нельзя использовать в следующих макро инструкциях m3x2, m3x3, m4x3, m4x4.

Модификатор | Описание
r.{x}{y}{z}{w} | Маска цели (Destination mask)
r.[xyzw][xyzw][xyzw][xywz] | Перемешивание данных (Source swizzle)
-r | Отрицание (Source negation)

Пиксельный шейдер

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

Инструкции

Инструкция | Действие | Параметры | 1.0 | 1.1 | 1.2 | 1.3 | 1.4
ps | Указывает версию шейдера | ps.mainVer.subVer | + | + | + | + | +
def | Задает константу | dest, fVal0, fVal1, fVal2, fVal3 | + | + | + | + | +
phase | Устанавливает вторую фазу |  |  |  |  |  | +
add | Сумма | dest, src0, src1 | + | + | + | + | +
bem | Fake bump environment-map 1 | dest.rg, src0, src1 |  |  |  |  | +
cmp | Сравнительный выбор src>=0 | dest, src0, src1, src2 |  |  | + | + | +
cnd | Сравнительный выбор src>0.5 | dest, src0, src1, src2 | + | + | + | + | +
dp3 | 3-х компонентный dot product | dest, src0, src1 | + | + | + | + | +
dp4 | 4-х компонентный dot product | dest, src0, src1 |  |  | + | + | +
lrp | Линейная интерполяция | dest, src0, src1, src2 | + | + | + | + | +
mad | Произведение и сложение | dest, src0, src1, src2 | + | + | + | + | +
mov | Копировать | dest, src | + | + | + | + | +
mul | Произведение | dest, src0, src1 | + | + | + | + | +
nop | Нет операций |  | + | + | + | + | +
sub | Разность src0 - src1 | dest, src0, src1 | + | + | + | + | +
tex | Загрузить цвет текстуры | dest | + | + | + | + |
texbem | Fake bump environment-map 2 | dest, src | + | + | + | + |
texbeml | Fake bump environment-map 3 | dest, src | + | + | + | + |
texcoord | Координаты в цвет 1 | dest | + | + | + | + |
texcrd | Координаты в цвет 2 | dest |  |  |  |  | +
texdepth | Глубина пикселя | dest |  |  |  |  | +
texdp3 | 3-х компонетный dot product 2 | dest, src |  |  | + | + |
texdp3tex | 3-х компонетный dot product 3 | dest, src |  |  | + | + |
texkill | Отмена рендера пикселя | src | + | + | + | + | +
texld | Смотр. подробное описание | dest, src |  |  |  |  | +
texm3x2depth | Расчет глубины для пикселя | dest, src |  |  |  | + |
texm3x2pad | Произведение первых строк | dest, src | + | + | + | + |
texm3x2tex | Произведение вторых строк | dest, src | + | + | + | + |
texm3x3 | Произведение матрицы | dest, src |  |  | + | + |
texm3x3pad | Произведение 1 или 2 строки | dest, src | + | + | + | + |
texm3x3tex | Произведение матрицы | dest, src | + | + | + | + |
texm3x3spec | Произведение матрицы | dest, src0, src1, src2 | + | + | + | + |
texm3x3vspec | Произведение матрицы | dest, src | + | + | + | + |
texreg2ar | Интерпретация (a; r) как (u; v) | dest, src | + | + | + | + |
texreg2gb | Интерпретация (g; b) как (u; v) | dest, src | + | + | + | + |
texreg2rgb | Интерпретация rgb как адрес | dest, src |  |  | + | + |

Регистры

Для пиксельного шейдера существует четыре различных типа регистров. В таблице показаны типы регистров пиксельного шейдера и их допустимое количество.

Регистр | Тип | 1.0 | 1.1 | 1.2 | 1.3 | 1.4
cn | Константный регистр | 8 | 8 | 8 | 8 | 8
rn | Временный регистр | 2 | 2 | 2 | 2 | 6
tn | Текстурный регистр | 4 | 4 | 4 | 4 | 4
vn | Регистр цвета | 2 | 2 | 2 | 2 | 2 в фазе 2

Константные регистры - cn

Регистры cn - это константные регистры. Они служат для хранения постоянных значений, которые нельзя изменить (констант). Данные в них можно записать только при объявлении константы с помощью внешних функций (см документацию движка) или при помощи инструкции def. Константные регистры не используются инструкциями с текстурными адресами. Исключением является лишь инструкция texm3x3spec, которая использует константный регистр для получения вектора зрения.

Временные регистры - rn

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

Текстурные регистры - tn

· Для пиксельных шейдеров версий от 1.0 до 1.3

Для пиксельных шейдеров версии от 1.0 до 1.3, текстурные регистры хранят данные текстуры, организованные в виде четырех значений с фиксированной запятой. Данные текстуры загружаются в текстурные регистры когда происходит выборка текстуры. Текстурная выборка использует текстурные координаты для выбора цвета в спецефических (u, v, w, q) координатах. Текстурные координаты интерполируются из вершинных текстурных координат и ассоциируются с определенной текстурной стадией. По умолчанию происходит ассоциация один к одному номера текстурной стадии и порядка текстурных координат. По умолчанию первый набор текстурных координат, заданных в вершинном формате ассоциируется с первой текстурной стадией с индексом 0.

Для арифметических инструкций пиксельных шейдеров версий 1.1, 1.2 и 1.3 эти регистры действуют как и временные регистры, то есть можно не только считывать данные, но и записывать их. Для арифметических инструкций пиксельных шейдеров версии 1.0 текстурные регистры доступны только для чтения.

· Для пиксельных шейдеров версии 1.4

Для пиксельных шейдеров версии 1.4 текстурные регистры содержат данные текстурных координат и доступны только для чтения. Это означает что наборы текстурных координат и текстурные стадии независимы друг от друга. Номер текстурной стадии (из которой происходит выборка текстуры) определен значением регистра назначения (с r0 по r5). Для инструкции texld набор текстурных координат определяется по регистру ресурса (с t0 по t5). Так что текстурный набор координат может быть применен к любой текстурной стадии. В дополнение, регистр ресурса для инструкции texld может быть временным регистром (rn), если содержит текстурные координаты.

Для этой версии пиксельных шейдеров текстурные регистры содержат данные текстурных координат а также доступны для инструкций с текстурной адресацией, в качестве ригистра ресурса.

Регистры цвета - vn

Регистры цвета содержат попиксельное значение цвета. Эти значения получены попиксельной итерацией (повторением) цвета диффузии (diffuse color) и цвета отражения (specular color) в данных вершины. Регистры цвета содержат данные в виде четырех значений с фиксированной запятой. Для пиксельных шейдеров версии 1.4 регистры цвета доступны только во второй фазе. В регистр цвета v0 загружается цвет диффузии вершины из вершинного шейдера, а в регистр цвета v0 загружается цвет отражения (specular color) вершины из вершинного шейдера. Вот почему пиксельные шейдеры должны всегда использоваться с вершинными шейдерами. Регистры цвета доступны только для чтения. Значения для этих регистров переводятся в диапазон от 0 до 1, так как это верный формат цвета для пиксельных шейдеров.

Ограничение на доступ к регистрам для чтения

Существует ограничение на количество попыток чтения данных из разных регистров одного типа для каждой из инструкции.

Регистр | Тип | 1.0 | 1.1 | 1.2 | 1.3 | 1.4
cn | Константный регистр | 2 | 2 | 2 | 2 | 2
rn | Временный регистр | 2 | 2 | 2 | 2 | 3
tn | Текстурный регистр | 1 | 2 | 3 | 3 | 1
vn | Ригистр цвета | 1 | 2 | 2 | 2 | 2

Например регистры цвета для большинства версий имеют ограничение на количество попыток для чтения равное двум. Это означает что любая инструкция может использовать максимум два различных регистра (например v0 и v1) в качестве регистров ресурса. Этот пример показывает как могут быть использованы регистры цвета в некоторой инструкции. Как показано в таблице, два регистра цвета могут быть использованы в любой версии пиксельного шейдера, за исключением версии 1.0.

mad r0, v0, v1, v1 // Эта инструкция верна для версий 1.1, 1.2, 1.3 и 1.4

Любой верный регистр назначения может быть использован в инструкции, так как это ограничение не касается регистров назначения.

Операции доступа

Доступ к различным типам регистров бывает только для чтения (в таблице RO) или для чтения и записи (RW). Регистры с доступом только для чтения могут использоваться только как регистры ресурса, и никогда как регистры назначения.

Регистр | Тип | 1.0 | 1.1 | 1.2 | 1.3 | 1.4
cn | Константный регистр | RO | RO | RO | RO | RO
rn | Временный регистр | RW | RW | RW | RW | RW
tn | Текстурный регистр | ??? | RW | RW | RW | RO
vn | Регистр цвета | RO | RO | RO | RO | RO

Примечание:

· Текстурные регистры для пиксельных шейдеров версии 1.0 для инструкций с текстурной адресацией доступны для чтения и записи (RW), но только для арифметических инструкций они доступны только для чтения (RO).
· Для пиксельных шейдеров версии 1.4 текстурные регистры доступны только для чтения (RO) для инструкций с текстурной адресацией. Текстурные регистры не могут быть записаны арифметическими инструкциями. Так как текстурные регистры содержат текстурные координаты, то статус "только для чтения" не является уменьшением их функциональности.

Пределы значений

У регистров есть предел минимально и максимально допустимых значений. Пределы значений сильно зависят от типа регистра.

Регистр | Тип | Предел значений | Версия
cn | Константный регистр | от -1 до +1 | Все версии
rn | Временный регистр | Зависит от устройства. Но от<=-1 до >=+1 | Все версии
tn | Текстурный регистр | Зависит от устройства. Но от<=-1 до >=+1 От -G до +G, где G - это максимальное количество повторений текстуры, оно зависит от движка. | от 1.0 до 1.3 Версия 1.4
vn | Регистр цвета | от 0 до +1 | Все версии

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

Для пиксельных шейдеров версий с 1.0 по 1.3 максимальное количество повторений текстуры будет не менее одного, а для версии 1.4 оно будет не менее восьми.

Модификаторы

Модификаторы используются для изменения инструкций, регистров ресурсов и регистров назначения.

Модификаторы инструкций

Модификаторы инструкций используются для изменения результирующего значения инструкции. Например их можно использовать для умножения или деления результата инструкции на два, или же для приведения результата в диапазон от 0 до 1. Модификаторы применяются после выполнения инструкции, но перед занесением значения в регистр назначения.

Модификатор | Описание | Синтаксис | 1.0 | 1.1 | 1.2 | 1.3 | 1.4
_x2 | Умножение на 2 | инструкция_x2 | + | + | + | + | +
_x4 | Умножение на 4 | инструкция_x4 | + | + | + | + | +
_x8 | Умножение на 8 | инструкция_x8 |  |  |  |  | +
_d2 | Деление на 2 | инструкция_d2 | + | + | + | + | +
_d4 | Деление на 4 | инструкция_d4 |  |  |  |  | +
_d8 | Деление на 8 | инструкция_d8 |  |  |  |  | +
_sat | Насыщение (в пределах от 0 до 1) | инструкция_sat | + | + | + | + | +

Модификаторы инструкций могут быть использованы только с арифметическими инструкциями. Их нельзя использовать с инструкциями с текстурной адресацией.

Примеры

Модификаторы умножения

Пример загружает в регистр назначения удвоенное значение суммы двух регистров ресурса.

add_x2 dest, src0, src1

Этот пример комбинирует два модификатора инструкций. Сначала суммируется два цвета в регистрах ресурса. Затем результат умножается на два и фиксируется в пределах от 0 до 1 для каждого из компонентов. Результат сохраняется в регистр назначения.

add_x2_sat dest, scr0, src1

Модификатор деления

Этот пример вычисляет сумму двух регистров ресурса, а затем делит её на два, и заносит в регистр назначения.

add_d2 dest, scr0, src1

Модификатор насыщения

Модификатор насыщения для арифметических инструкций фиксирует значение результата в пределах от 0 до 1 для каждого компонента. Следующий пример показывает как можно использовать этот модификатор.

dp3_sat r0, t0_bx2, v0_bx2   ; t0 - это бамп, v0 - это направление света

Этот модификатор применяется после любого модификатора инструкции - умножения или деления. Этот модификатор наиболее часто используется для насыщения (приведения значения в диапазон от 0 до1) результата скалярного произведения (dot product).

Этот пример вычисляет сумму двух цветов в регистрах ресурсов, а затем приводит результат в диапазон от 0 до 1, и заносит его в регистр назначения.

add_sat dest, scr0, src1

Этот пример комбинирует два модификатора инструкций. Сначала суммируются два цвета в регистрах ресурсов. Затем результат умножается на два и насыщается в пределах от 0 до 1 для каждого компонента. Результат сохраняется в регистр назначения.

add_x2_sat dest, scr0, src1

Модификаторы ресурсов

Используйте модификаторы ресурсов для изменения данных, прочитанных из регистров перед выполнением инструкции. При этом содержимое регистров ресурсов остается неизменным. Группа модификаторов, называемых селекторами (selectors) из одного канала в другой канал.

Модификатор | Синтаксис | 1.0 | 1.1 | 1.2 | 1.3 | 1.4
Смещение | регистр_bias | + | + | + | + | +
Инверсия | 1-регистр | + | + | + | + | +
Отрицание | -регистр | + | + | + | + | +
Удвоение | регистр_x2 |  |  |  |  | +
Удвоенное смещение | регистр_bx2 | + | + | + | + | +

Модификаторы регистров ресурсов могут быть использованы только в арифметических операциях. Их нельзя использовать в инструкциях с текстурной адресацией. Исключением является лишь удвоенное смещение (_bx2). Для пиксельных шейдеров версий 1.0 и 1.1 удвоенное смещение можно использовать с аргументами инструкций texm*. Для версий 1.2 и 1.3 удвоенное смещение можно использовать только с аргументами инструкций с текстурной адресацией.

Примечание:

· Отрицание может быть использовано со смещением, удвоением и удвоенным смещением (bias, scale x2, signed scaling). В таком случае оно выполняется последним.
· Инверсию нельзя использовать с другими модификаторами.
· Все эти модификаторы ресурсов можно использовать вместе с селекторами.
· Модификаторы ресурсов нельзя использовать с константами - это может привести к не предсказуемым результатам. В пиксельном шейдере версии 1.4 использование модификаторов ресурсов с константами запрещено и может привести к сбою в работе приложения.

Селекторы

Селекторы служат для присваивания данных одного канала регистра ресурса для всех каналов регистра назначения.

Селектор | Синтаксис | 1.0 | 1.1 | 1.2 | 1.3 | 1.4
Копирование красного канала | регистр.r |  |  |  |  | +
Копирование зеленого канала | регистр.g |  |  |  |  | +
Копирование синего канала | регистр.b |  | + | + | + | +
Копирование альфа канала | регистр.a | + | + | + | + | +

Маска регистра назначения

Маска регистра назначения служит для того чтобы копировать данные только в определенные каналы регистра назначения.

Маска | Синтаксис | 1.0 | 1.1 | 1.2 | 1.3 | 1.4
Красный, зеленый, синий, альфа | регистр.rgba | + | + | + | + | +
Отсутствует | регистр | + | + | + | + | +
Цвет (красный, зеленый, синий) | регистр.rgb | + | + | + | + | +
Альфа | регистр.a | + | + | + | + | +
Красный | регистр.r |  |  |  |  | +
Зеленый | регистр.g |  |  |  |  | +
Синий | регистр.b |  |  |  |  | +
Произвольная | регистр.rgba (см.ниже) |  |  |  |  | +

Примечание:

· Для произвольной маски доступна любая комбинация каналов в правильной последовательности - r - красный, g - зеленый, b - синий, a - альфа-канал, например ".rba". Произвольная маска доступна только в версии 1.4.
· Если маска не указана, то по умолчанию используется маска .rgba, то есть используются все каналы.
· Альтернативный синтаксис каналам r, g, b, a - это x, y, z, w.
· Для шейдера версии 1.3 и 1.4, инструкция dp3 может использовать только маску .rgb и .rgba.
· Маска поддерживается только для регистров назначения арифметических функций. Маски нельзя использовать в инструкциях с текстурной адресацией, за исключением инструкций texcrd и texld.

Модификаторы текстурных регистров для texld и texcrd

Для инструкций шейдера версии 1.4 с текстурной адресацией: texcrd и texld существует свой набор модификаторов - модификаторы регистра ресурса, селекторы регистра ресурса, маска регистра назначения. Модификаторы регистра ресурса делят значение x и y каналов на значение z или w канала:

Модификатор _dz или _db делает следующее:

x' = x/z ( x' = 1.0 if z == 0)

y' = y/z ( y' = 1.0 if z == 0)

z' не изменяется

w' не изменяется

Модификатор _dw или _da делает следующее:

x' = x/w ( x' = 1.0 if w == 0)

y' = y/w ( y' = 1.0 if w == 0)

z' не изменяется

w' не изменяется

Модификатор | Описание | Синтаксис | Версия
_dz | Делит x, y компоненты на z | регистр_dz | 1.4
_db |  | регистр_db | 1.4
_dw | Делит x, y компоненты на w | регистр_dw | 1.4
_da |  | регистр_da | 1.4

Селекторы регистра ресурса для texld и texcrd

Селекторы копируют данные одного канала во все другие.

Селектор | Описание | Синтаксис | Версия
xyz | Копирует данные x, y, z в каналы x, y, z, z | регистр.xyz | 1.4
rgb |  | регистр.rgb | 1.4
xyw | Копирует данные x, y, w в каналы x, y, w, w | регистр.xyw | 1.4
rga |  | регистр.rga | 1.4

Примечание:

Инструкции texcrd и texld никогда не читают более трех первых компонентов. Так что эти селекторы позволяют вам по выбору взять третий или четвертый компонент регистра ресурса.

Маска регистра назначения для texld и texcrd

Маска определяет какой канал в регистре назначения будет обновлен.

Маска | Описание | Синтаксис | Инструкция | Версия
xyzw | Обновляет каналы x, y, z, w | регистр.xyzw | texld | 1.4
rgba |  | регистр.rgba | texld | 1.4
Отсутствует |  | регистр | texld | 1.4
xyz | Обновляет каналы x, y, z | регистр.xyz | texcrd | 1.4
rgb |  | регистр.rgb | texcrd | 1.4
xy | Обновляет каналы x, y | регистр.xy | texcrd | 1.4
rg |  | регистр.rg | texcrd | 1.4

Список инструкций

Описание инструкций вершинного шейдера

инструкция

синтаксис: инструкция регистр_назначения, регистр_ресурса0, ...

Описание действия инструкции и примечания к ней.

Код выполняемого действия. Код для понимания, по возможности, приближен с С++ к универсальному математическому коду и скриптовому языку GML.

add

add dest, src0, src1

Инструкция выполняет сложение компонентов регистров ресурса и сохраняет их сумму в соответствующие компоненты регистра назначения:

dest.x = src0.x + src1.x

dest.y = src0.y + src1.y

dest.z = src0.z + src1.z

dest.w = src0.w + src1.w

def

def dest, fval0, fval1, fval2, fval3

Инструкция задает константу вершинного шейдера.

dp3

dp3 dest, src0, src1

Инструкция выполняет трехкомпонентное скалярное произведение регистров ресурса:

dest.w = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z)

dest.x = dest.w

dest.y = dest.w

dest.z = dest.w

dp4

dp4 dest, src0, src1

Инструкция выполняет трехкомпонентное скалярное произведение регистров ресурса:

dest.w = (src0.x * src1.x) + (src0.y * src1.y)

+ (src0.z * src1.z) + (src0.w * src1.w)

dest.x = dest.w

dest.y = dest.w

dest.z = dest.w

dst

dst dest, src0, src1

Инструкция рассчитывает вектор направления:

dest.x = 1

dest.y = src0.y * src1.y

dest.z = src0.z

dest.w = src1.w

expp

expp dest, src

Инструкция выполняет возведение двойки в степень => 2x :

dest.x = 2floor(src.w)

dest.y = src.w-floor(src.w)

dest.z = 2src.w

dest.w = 1

lit

lit dest, src

Инструкция рассчитывает коэффициент освещения из двух скалярных произведений и экспоненты:

Регистр ресурса должен содержать следующие данные

src.x = N*L ; скалярное произведение между нормалью и направлением к свету

src.y = N*H ; скалярное произведение между нормалью и полуветором (half vector)

src.z = не имеет значения ; Это значение игнорируется

src.w = экспонента ; Это значение должно быть в пределах от -128.0 до 128.0

Устанавливаются значения для регистра вывода, а затем выполняется код(см. ниже)

dest.x = 1

dest.y = 0

dest.z = 0

dest.w = 1

if src.x > 0

{

dest.y = src.y

if src.y > 0

dest.z = (src.y)(src.w)

}

logp

logp dest, src

Инструкция вычисляет логарифм по основанию 2 => log2(x) :

float v = ABSF(src.w);

if (v != 0)

{

int p = (int)(*(DWORD*)&v >> 23) - 127;

dest.x = (float)p; // exponent

p = (*(DWORD*)&v & 0x7FFFFF) | 0x3f800000;

dest.y = *(float*)&p;// mantissa;

float tmp = (float)(log(v)/log(2));

DWORD tmpd = *(DWORD*)&tmp & 0xffffff00;

dest.z = *(float*)&tmpd;

dest.w = 1;

}

else

{

dest.x = MINUS_MAX();

dest.y = 1.0f;

dest.z = MINUS_MAX();

dest.w = 1.0f;

}

mad

mad dest, src0, src1, src2

Инструкция находит сумму произведения src0 * src1 и src2 => src0 * src1 + src2

dest.x = src0.x * src1.x + src2.x

dest.y = src0.y * src1.y + src2.y

dest.z = src0.z * src1.z + src2.z

dest.w = src0.w * src1.w + src2.w

max

max dest, src0, src1

Инструкция вычисляет наибольшее из значений:

dest.x = max(src0.x, src1.x)

dest.y = max(src0.y, src1.y)

dest.z = max(src0.z, src1.z)

dest.w = max(src0.w, src1.z)

min

min dest, src0, src1

Инструкция вычисляет наименьшее из значений:

dest.x = min(src0.x, src1.x)

dest.y = min(src0.y, src1.y)

dest.z = min(src0.z, src1.z)

dest.w = min(src0.w, src1.z)

mov

mov dest, src0

Инструкция копирует значения из регистра ресурса в регистр назначения:

if (dest = a0) // Если регистр назначения - это адресный регистр

{

dest.x = floor(src.x)

}

else

{

dest = src

}

mul

mul dest, src0, src1

Инструкция вычисляет произведение регистров ресурсов => src0 * src1 :

dest.x = src0.x * src1.x

dest.y = src0.y * src1.y

dest.z = src0.z * src1.z

dest.w = src0.w * src1.w

rcp

rcp dest, src

Инструкция вычисляет обратную величину скаляра => 1/x :

If (src.w = 1)

{

dest.x = 1

dest.y = 1

dest.z = 1

dest.w = 1

}

else if (src.w = 0)

{

dest.x = +бесконечность

dest.y = +бесконечность

dest.z = +бесконечность

dest.w = +бесконечность

}

else

{

dest.x = 1 / src.x

dest.y = 1 / src.y

dest.z = 1 / src.z

dest.w = 1 / src.w

}

rsq

rsq dest, src0

Инструкция вычисляет обратный корень скаляра => 1 / sqrt(x) :

var v;

v = abs(src.w)

if (v = 1)

{

dest.x = 1

dest.y = 1

dest.z = 1

dest.w = 1

}

else if(v = 0)

{

dest.x = +бесконечность

dest.y = +бесконечность

dest.z = +бесконечность

dest.w = +бесконечность

}

else

{

dest.x = 1 / sqrt(src.x)

dest.y = 1 / sqrt(src.y)

dest.z = 1 / sqrt(src.z)

dest.w = 1 / sqrt(src.w)

}

sge

sge dest, src0, src1

Инструкция сравнивает значения каналов регистров ресурса и если значение первого больше либо равно значению второго, то в соответствующий канал регистра назначения записывается 1, иначе 0.

if (src0.x >= src1.x) dest.x = 1 else dest.x = 0

if (src0.y >= src1.y) dest.y = 1 else dest.y = 0

if (src0.z >= src1.z) dest.z = 1 else dest.z = 0

if (src0.w >= src1.w) dest.w = 1 else dest.w = 0

slt

slt dest, src0, src1

Инструкция сравнивает значения каналов регистров ресурса и если значение первого меньше значения второго, то в соответствующий канал регистра назначения записывается 1, иначе 0.

if (src0.x < src1.x) dest.x = 1 else dest.x = 0

if (src0.y < src1.y) dest.y = 1 else dest.y = 0

if (src0.z < src1.z) dest.z = 1 else dest.z = 0

if (src0.w < src1.w) dest.w = 1 else dest.w = 0

sub

sub dest, src0, src1

Инструкция вычисляет разность регистров ресурса => src0 - src1 :

dest.x = src0.x - src1.x

dest.y = src0.y - src1.y

dest.z = src0.z - src1.z

dest.w = src0.w - src1.w

vs

vs.ОсновнаяВерсия.ПодВерсия

Инструкция определяет как будет обработан вершинный шейдер. Алгоритм обработки зависит от версии шейдера, указанного этой инструкцией. Эта инструкция должна быть самой первой из незакоментированных строк в вершинном шейдере.

exp

exp dest, src

Инструкция вычисляет экспоненту с точностью до 1/220. (Инструкция выполняет возведение двойки в степень.)

dest.x = 2float(src.w)

dest.y = dest.x

dest.z = dest.x

dest.w = dest.x

frc

frc dest, src

Инструкция возвращает дробную часть компонентов регистра ресурса:

dest.x = src.x - floor(src.x)

dest.y = src.y - floor(src.y)

dest.z = игнорируется

dest.w = игнорируется

// Все значения пролегают в пределах от 0 до 1

log

log dest, src

Инструкция вычисляет логарифм log2(x) с высокой точностью до до 1/220.

if (abs(src.w) != 0)

{

dest.x = log(abs(src.w)) / log (2)

dest.y = dest.x

dest.z = dest.x

dest.w = dest.x

}

else

{

dest = MINUS_MAX()

}

m3x2

m3x2 dest, src0, src1

Инструкция вычисляет произведения вектора и матрицы размером 3 х 2.

src0 - вектор

src1 - матрица

src2 - следующий регистр в наборе, после src1 => src1[+1]

dest.x = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z)

dest.y = (src0.x * src2.x) + (src0.y * src2.y) + (src0.z * src2.z)

dest.z = игнорируется

dest.w = игнорируется

m3x3

m3x3 dest, src0, src1

Инструкция вычисляет произведения вектора и матрицы размером 3 х 3.

src0 - вектор

src1 - матрица

src2 - следующий регистр в наборе, после src1 => src1[+1]

src3 - следующий регистр в наборе, после src1 => src1[+2]

dest.x = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z)

dest.y = (src0.x * src2.x) + (src0.y * src2.y) + (src0.z * src2.z)

dest.z = (src0.x * src3.x) + (src0.y * src3.y) + (src0.z * src3.z)

dest.w = игнорируется

m3x4

m3x4 dest, src0, src1

Инструкция вычисляет произведения вектора и матрицы размером 3 х 4.

src0 - вектор

src1 - матрица

src2 - следующий регистр в наборе, после src1 => src1[+1]

src3 - следующий регистр в наборе, после src1 => src1[+2]

src4 - следующий регистр в наборе, после src1 => src1[+3]

dest.x = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z)

dest.y = (src0.x * src2.x) + (src0.y * src2.y) + (src0.z * src2.z)

dest.z = (src0.x * src3.x) + (src0.y * src3.y) + (src0.z * src3.z)

dest.w = (src0.x * src4.x) + (src0.y * src4.y) + (src0.z * src4.z)

m4x3

m4x3 dest, src0, src1

Инструкция вычисляет произведения вектора и матрицы размером 4 х 3.

src0 - вектор

src1 - матрица

src2 - следующий регистр в наборе, после src1 => src1[+1]

src3 - следующий регистр в наборе, после src1 => src1[+2]

dest.x = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z)

dest.y = (src0.x * src2.x) + (src0.y * src2.y) + (src0.z * src2.z)

dest.z = (src0.x * src3.x) + (src0.y * src3.y) + (src0.z * src3.z)

dest.w = игнорируется

m4x4

m4x4 dest, src0, src1

Инструкция вычисляет произведения вектора и матрицы размером 4 х 3.

src0 - вектор

src1 - матрица

src2 - следующий регистр в наборе, после src1 => src1[+1]

src3 - следующий регистр в наборе, после src1 => src1[+2]

src4 - следующий регистр в наборе, после src1 => src1[+3]

dest.x = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z)

dest.y = (src0.x * src2.x) + (src0.y * src2.y) + (src0.z * src2.z)

dest.z = (src0.x * src3.x) + (src0.y * src3.y) + (src0.z * src3.z)

dest.w = (src0.x * src4.x) + (src0.y * src4.y) + (src0.z * src4.z)

Описание инструкций пиксельного шейдера

инструкция

синтаксис: инструкция регистр_назначения, регистр_ресурса0, ...

Описание действия инструкции и примечания к ней.

Код выполняемого действия. Код для понимания, по возможности, приближен с С++ к универсальному математическому коду и скриптовому языку GML.

add

add dest, src0, src1

Инструкция выполняет сложение src0 и src1.

dest.x = src0.x + src1.x

dest.y = src0.y + src1.y

dest.z = src0.z + src1.z

dest.w = src0.w + src1.w

bem

bem dest, src0, src1

Инструкция применяет искусственную трансформацию карты окружения с рельефностью (fake bump environment-map transform).

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.4 фаза 1
src0 | Регистры ресурса |  | + |  | + | 1.4 фаза 1
src1 |  |  |  |  | + | 1.4 фаза 1

Примечание:

1. Инструкция должна использоваться в первой фазе.
2. Инструкция выполняется как две арифметические иструкции.
3. Разрешено только одно использование инструкции за шейдер.
4. Маска регистра назначения должна быть .rg или .xy.

cmp

cmp dest, src0, src1, src2

Инструкция производит сравнительный покомпонентный выбор между src1 и src2, основываясь на условии src0 >= 0.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + | + | 1.2, 1.3
 |  |  |  |  | + | 1.4
src0, src1, src2 | Регистры ресурса | + | + | + | + | 1.2, 1.3
 |  |  | + |  | + | 1.4 фаза 1
 |  | + | + |  | + | 1.4 фаза 2

Примечание:

1. Для пиксельного шейдера версии 1.2 и 1.3, инструкция выполняется как две арифметические. Убедитесь что вы не превышаете лимит инструкций на шейдер.
2. Регистр назначения не может быть одним из регистров ресурса.

cnd

cnd dest, src0, src1, src2

Инструкция производит сравнительный выбор между src1 и src2, основываясь на условии src0 > 0.5.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.0
 |  |  |  | + | + | 1.1, 1.2, 1.3
 |  |  |  |  | + | 1.4
src0 | Регистры ресурса |  |  |  | r0.a | 1.0 - 1.4
src0, src1 |  | + | + | + | + | 1.4 фаза 1
src0, src1, src2 |  |  | + |  | + | 1.4 фаза 2
 |  | + | + |  | +

Примечание:

1. Для версий с 1.0 по 1.3 регистр ресурса src0 должен быть r0.a, так как в этих версиях пиксельного шейдера не производится покомпонентное сравнение.
2. Для версии 1.4 такого ограничения нет и проводится уже покомпонентное сравнение.

// Для версий с 1.0 по 1.3

if r0.a > 0.5

{

dest = src1

}

else

{

dest = src2

}

// Для версии 1.4

if (src0.x > 0.5) then dest.x = src1.x else dest.x = src2.x

if (src0.y > 0.5) then dest.y = src1.y else dest.y = src2.y

if (src0.z > 0.5) then dest.z = src1.z else dest.z = src2.z

if (src0.w > 0.5) then dest.w = src1.w else dest.w = src2.w

def

def dest, fVal0, fVal1, fVal2, fVal3

Инструкция задает константу пиксельного шейдера. Все значения аргументов должны быть в пределах от -1 до +1.

dp3

dp3 dest, src0, src1

Инструкция рассчитывает трехкомпонентное скалярное произведение src0 и src1.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.0
 |  |  |  | + | + | 1.1, 1.2, 1.3
 |  |  |  |  | + | 1.4
src0, src1 | Регистры ресурса | + | + | + | + | 1.0, 1.1, 1.2, 1.3
 |  |  | + |  | + | 1.4 фаза 1
 |  | + | + |  | + | 1.4 фаза 2

Примечание:

1. Инструкция не приводит значения в диапазон от -1 до +1, для этого воспользуйтесь модификатором насыщения _sat.
2. Инструкция может быть соединена с другой инструкцией (можно использовать в связке), пока она заносит значения в rgb канал:
dp3 r0.rgb, t0, v0 // Копируем результат скалярного произведения в rgb канал
+mov r2.a, t0 // Копируем альфа канал в параллель

dest.w = (src0.x * src1.x) + (src0.y * src1.y) + (src0.z * src1.z)

dest.x = dest.w

dest.y = dest.w

dest.z = dest.w

dp4

dp4 dest, src0, src1

Инструкция рассчитывает четырехкомпонентное скалярное произведение src0 и src1.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.2, 1.3
 |  |  |  |  | + | 1.4
src0, src1 | Регистры ресурса | + | + | + | + | 1.2, 1.3
 |  |  | + |  | + | 1.4 фаза 1
 |  | + | + |  | + | 1.4 фаза 2

Примечание:

1. Инструкцию нельзя использовать в связке.
2. Инструкция не приводит значения в диапазон от -1 до +1, для этого воспользуйтесь модификатором насыщения _sat.

dest.w = (src0.x * src1.x) + (src0.y * src1.y)

+ (src0.z * src1.z) + (src0.w * src1.w)

dest.x = dest.w

dest.y = dest.w

dest.z = dest.w

lrp

lrp dest, src0, src1, src2

Инструкция выполняет линейную интерполяцию между src1 и src2, основываясь на пропорции заданной src0.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.0
 |  |  |  | + | + | 1.1, 1.2, 1.3
 |  |  |  |  | + | 1.4
src0, src1, src2 | Регистры ресурса | + | + | + | + | 1.0, 1.1, 1.2, 1.3
 |  |  | + |  | + | 1.4 фаза 1
 |  | + | + |  | + | 1.4 фаза 2

dest = src2 + src0 * (src1 - src2)

mad

mad dest, src0, src1, src2

Инструкция находит сумму произведения src0 * src1 и src2 => (src0 * src1) + src2

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.0
 |  |  |  | + | + | 1.1, 1.2, 1.3
 |  |  |  |  | + | 1.4
src0, src1, src2 | Регистры ресурса | + | + | + | + | 1.0, 1.1, 1.2, 1.3
 |  |  | + |  | + | 1.4 фаза 1
 |  | + | + |  | + | 1.4 фаза 2

dest.x = src0.x * src1.x + src2.x

dest.y = src0.y * src1.y + src2.y

dest.z = src0.z * src1.z + src2.z

dest.w = src0.w * src1.w + src2.w

mov

mov dest, src

Инструкция копирует значения из регистра ресурса в регистр назначения:

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.0
 |  |  |  | + | + | 1.1, 1.2, 1.3
 |  |  |  |  | + | 1.4
src | Регистр ресурса | + | + | + | + | 1.0, 1.1, 1.2, 1.3
 |  |  | + |  | + | 1.4 фаза 1
 |  | + | + |  | + | 1.4 фаза 2

dest = src

mul

mul dest, src0, src1

Инструкция вычисляет произведение регистров ресурсов => src0 * src1 :

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.0
 |  |  |  | + | + | 1.1, 1.2, 1.3
 |  |  |  |  | + | 1.4
src0, src1 | Регистры ресурса | + | + | + | + | 1.0, 1.1, 1.2, 1.3
 |  |  | + |  | + | 1.4 фаза 1
 |  | + | + |  | + | 1.4 фаза 2

dest.x = src0.x * src1.x

dest.y = src0.y * src1.y

dest.z = src0.z * src1.z

dest.w = src0.w * src1.w

nop

nop

Инструкция не выполняет никаких операций.

phase

phase

Инструкция определяет переход между первой и второй фазой шейдера. Если инструкции в коде нет, то шейдер запускает в режиме второй фазы.

Примечание:

1. Эта инструкция доступна только для шейдеров версии 1.4.
2. Все что находится выше (до) инструкции выполняется в первой фазе, а все что ниже (после) выполняется во второй фазе. Использование фаз позволяет увеличить максимальное количество инструкций на шейдер.
3. Нежелательным эффектом использования фаз является то, что при переходе фаз альфа компонент временных регистров не сохраняется.

// Пример шейдера с двумя фазами

ps.1.4

// Инструкции для первой фазы

...

phase

// Инструкции для второй фазы

...

ps

ps.ОсновнаяВерсия.ПодВерсия

Инструкция определяет алгоритм интерпретации шейдера. Инструкция задает версию используемого шейдера, по которой и определяется алгоритм обработки шейдера.

Аргумент | Описание | Значения
ОсновнаяВерсия | Номер основной версии шейдера | 1
ПодВерсия | Номер подверсии шейдера | 0, 1, 2, 3, 4

sub

sub dest, src0, src1

Инструкция вычисляет разность регистров ресурса => src0 - src1 :

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.0
 |  |  |  | + | + | 1.1, 1.2, 1.3
 |  |  |  |  | + | 1.4
src0, src1 | Регистры ресурса | + | + | + | + | 1.0, 1.1, 1.2, 1.3
 |  |  | + |  | + | 1.4 фаза 1
 |  | + | + |  | + | 1.4 фаза 2

dest.x = src0.x - src1.x

dest.y = src0.y - src1.y

dest.z = src0.z - src1.z

dest.w = src0.w - src1.w

tex

tex dest

Инструкция загружает в гистр назначения данные (RGBA цвет) из текстуры, занесенной в одну из текстурных стадий.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3

Примечание:

1. Регистр назначения зависит от номера текстурной стадии.
2. Текстурная выборка определяет цвет, основываясь на текстурных координатах (U,V,W,Q)
3. По умолчанию текстурные координаты ассоциируются по номерам один-к-одному, тоесть первый набор текстурных координат ассоциируется с текстурной стадией 0.
4. Набор текстурных координат можно ассоциировать с разной текстурной стадией.

texbem

texbem dest, src

Инструкция применяет искусственную трансформацию карты окружения с рельефностью (fake bump environment-map transform). Это достигается путем изменения адреса текстуры в регистре назначения на адрес данных возмущения (du, dv), и использованием двухмерной матрицы рельефной карты окружения (bump environment-map).

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3

Примечание:

1. Эта инструкция трансформирует красный и зеленый каналы используя двухмерную матрицу рельефной карты окружения (bump environment-map). Результат добавляется к набору текстурных координат, который используется для текущей текстурной стадии.
2. Эта инструкция всегда воспринимает du и dv как знаконезависимые, поэтому использовать модификатор Удвоенное смещение (_bx2) не имеет смысла (только для шейдера версии 1.0 и 1.1).

texbeml

texbeml dest, src

Инструкция применяет искусственную трансформацию карты окружения с рельефностью (fake bump environment-map transform) и с коррекцией освещения (luminance correction). Это достигается путем изменения адреса текстуры в регистре назначения на адрес данных возмущения (du, dv), и использованием двухмерной матрицы рельефной карты окружения (bump environment-map), а также освещения.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3

Примечание:

1. Эта инструкция трансформирует красный и зеленый каналы используя двухмерную матрицу рельефной карты окружения (bump environment-map). Результат добавляется к набору текстурных координат, который используется для текущей текстурной стадии.
2. Эта инструкция всегда воспринимает du и dv как знаконезависимые, поэтому использовать модификатор Удвоенное смещение (_bx2) не имеет смысла (только для шейдера версии 1.0 и 1.1).

texcoord

texcoord dest

Инструкция интерпретирует текстурные координаты (UVW1) как цвет (RGBA)

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3

Примечание:

1. Если какой-то компонент отсутствует, то он будет заменен на 0, четвертый компонент - альфа канал всегда установлен на 1.
2. Все значения насыщаются в диапазон от 0 до 1.
3. Используется только текущая текстурная стадия.

texcrd

texcrd dest, src

Инструкция копирует текстурные координаты в цвет (RGBA).

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.4
src | Регистр ресурса |  |  | + |  | 1.4 фаза 1
 |  |  |  | + |  | 1.4 фаза 2

Примечание:

1. Эта инструкция интерпретирует данные как цвет RGBA.
2. В отличии от texcoord, Эта инструкция не преобразует данные в диапазон от 0 до 1.

texdepth

texdepth dest, src

Инструкция устанавливает глубину пикселя для её сравнения в буфере глубин.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | r5 | 1.4 фаза 2

Примечание:

1. Эта инструкция использует значение r5.r/r5.g для сравнения глубины текущего пикселя в буфере глубин. Данные в синем и альфа каналах игнорируются. Если r5.g=0, то результат r5.r/r5.g = 1.
2. С инструкцией можно использовать только временный регистр r5.
3. После запуска этой инструкции, регистр r5 больше не доступен для дальнейшего использования в шейдере.

texdp3

texdp3 dest, src

Инструкция вычисляет трехкомпонентное скалярное произведение данных регистра и соответствуещего номеру регистра, набора текстурных координат.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.2, 1.3

dest(m).rgba = ТекстурныеКоординаты(m)uvw * t(n)rgb

Примечание:

1. Перед выполнением этой инструкции вы должны установить t(n): tex t(n)
2. Должно выполняться условие m > n.

texdp3tex

texdp3tex dest, src

Инструкция рассчитывает трехкомпонентное произведение для 1-D отображения.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.2, 1.3

u' = ТекстурныеКоординаты(m)uvw * t(n)rgb

dest(m).rgba = ТескстурнаяВыборка(m)rgba используя (u', 0, 0) как набор координат

Примечание:

1. Перед выполнением этой инструкции вы должны установить t(n): tex t(n)
2. Должно выполняться условие m > n.

texkill

texkill src

Инструкция отменяет рендеринг пикселя если хотя бы один из трех компонентов (uvw) текстурных координат меньше нуля.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3
 |  |  |  | + | + | 1.4 фаза 2

Примечание:

1. Вы можете использовать эту инструкцию для создания зоны обрезки для рендера.
2. Если вы используете в вершинном шейдере какую-либо трансформацию проекции, то тогда вам также прийдется трансформировать и зону обрезки.

texld

texld dest, src

Инструкция загружает в регистр назначения цвет (RGBA) и сэмплирует его использя содержимое регистра ресурса как текстурные координаты. Сэмплированная текстура ассоциируется с номером регистра назначения.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  |  | + | 1.4
src | Регистр ресурса |  |  | + |  | 1.4 фаза 1
 |  |  |  | + | + | 1.4 фаза 2

Примечание:

1. Один и тот же модификатор .xyz или .xyw должен быть применен при каждом чтении любого регистра tn в инструкциях texcrd и texld. Если .xyw был использован при чтении регистра tn, то его можно смешать с другим чтением того же регистра tn используя .xyw_dw
2. Модификатор _dz можно использовать только с rn.
3. Модификатор _dz можно использовать не более двух раз за шейдер.

texm3x2depth

texm3x2depth dest, src

Инструкция рассчитывает значение глубины, которое будет использовано при тесте глубины для этого пикселя.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.3
src | Регистр ресурса |  |  | + |  | 1.3

Примечание:

1. Эту инструкции нужно использовать вместе с инструкцией texm3x2pad. И делать это следует в таком порядке:
tex tn
texm3x2pad tm, tn
texm3x2depth t(m+1), t(n)
2. Убедитесь что значения z и w находятся в пределах от 0 до 1, иначе результат будет непредсказуем.
3. После выполнения этой инструкции регистр t(m+1) больше не доступен.

texm3x2pad

texm3x2pad dest, src

Инструкция вычисляет произведение первой строки двухстроковой матрицы 3x2. Эта инструкция должна использоваться с инструкцией texm3x2tex или с texm3x2depth.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3

texm3x2tex

texm3x2tex dest, src

Инструкция вычисляет финальное произведение матрицы 3x2 и использует результат для отображения текстуры. Эта инструкция должна использоваться с инструкцией texm3x2pad и стоять после неё в коде.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3

texm3x3

texm3x3 dest, src

Инструкция выполняет умножение матрицы 3х3, когда используется вместе с двумя инструкциями texm3x3pad.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.2, 1.3

texm3x3pad

texm3x3pad dest, src

Инструкция выполняет умножение первой или второй строки в трехстроковой матрице 3x3. Эта инструкция должна использоваться с инструкциями texm3x3, texm3x3spec, texm3x3vspec, texm3x3tex.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3

texm3x3spec

texm3x3spec dest, src0, src1

Инструкция выполняет умножение матрицы 3x3 и использует результат для отображения текстуры (lookup). Это может быть использовано для зеркального отражения или карт окружения, где вектор зрения константа. Инструкция должна быть использована вместе с двумя инструкциями tex3x3pad.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src0 | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src1 |  |  | + |  |  | 1.0, 1.1, 1.2, 1.3

texm3x3tex

texm3x3tex dest, src0, src1

Инструкция выполняет умножение матрицы 3x3 и использует результат для отображения текстуры (lookup). Инструкция должна быть использована вместе с двумя инструкциями tex3x3pad.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3

texm3x3vspec

texm3x3vspec dest, src

Инструкция выполняет умножение матрицы 3x3 и использует результат для отображения текстуры (lookup). Это может быть использовано для зеркального отражения или карт окружения, где вектор зрения не константа. Инструкция должна быть использована вместе с двумя инструкциями tex3x3pad.

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3

Примечание:

1. Если вектор зрения - константа, то инструкция texm3x3spec выполните теже действия что и texm3x3vspec.

texreg2ar

texreg2ar dest, src

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

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3

texreg2gb

texreg2gb dest, src

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

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3

texreg2rgb

texreg2rgb dest, src

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

Аргумент | Описание | Регистры |  |  |  | Версия
 |  | vn | cn | tn | rn
dest | Регистр назначения |  |  | + |  | 1.0, 1.1, 1.2, 1.3
src | Регистр ресурса |  |  | + |  | 1.0, 1.1, 1.2, 1.3