Введение в моделирование для авиасимулятора FlightGear

Материал из База знаний
Перейти к: навигация, поиск

Автор: Никифоров Ю.В. aka Юрик_нск Дата: 18.05.2007 01:08
Рассматривается устройство моделей для FlightGear - авиасимулятора с открытым кодом. Визуалка, анимация, приборы, программирование. Приводятся примеры и пошаговые интрукции.

Содержание

Для чего и для кого написана эта статья?

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

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

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

Кроме непосредственно информации для разработчиков моделей FlightGear, я надеюсь, данная статья будет интересна и коллегам с других платформ, в первую очередь - MSFS. Быть может, кому-нибудь из них покажется интересным этот авиасимулятор, и те возможности, которые он предоставляет авторам моделей. Хотелось бы избежать "священной войны" - недостатки FlightGear в частности и открытого софта в целом безусловно существуют, но не об этом тут речь.

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

Поехали:)

Структура модели

Модель самолета в FlightGear состоит в общем из тех же компонентов, как и в MSFS. Можно выделить визуальную модель - то, что мы видим снаружи, панель приборов - двумерную панель и трехмерную ВК, а так же динамику - систему параметров, определяющих движение модели в мире FGFS. Кроме того, модель может использовать различные подсистемы (звук, субмодели) - реализованные автором модели либо входящие в комплект поставки симулятора в виде готовых блоков.

Все модели находятся в директории FlightGear/Aircraft. Для юниксов это будет где-то в /usr/local/share/FlightGear/Aircraft, для винды - Program FilesFlightGeardataAircraft. Все дальнейшие пути я буду указывать для юниксовой версии, пользователям винды следует сменить слэш на обратный. Никакого различия, с точки зрения моделлера, между версиями симулятора под разные операционные системы нет. Не существует моделей отдельно "под винду" или "под линукс" - они все абсолютно одинаковы.

Принята следующая структура каталогов:

  • Aircraft/модель/Model - тут находится визуальная модель, ее текстуры и конфигурационные файлы
  • Aircraft/модель/Panels - панели приборов. Обычно тут находятся только конфигурационные файлы.
  • Aircraft/модель/Panels/Instruments - тут лежат 2D приборы (их XML - файлы)
  • Aircraft/модель/Panels/Instruments/Textures - тут лежат текстуры для 2D приборов (файлы с расширением RGB).
  • Aircraft/модель/Panels/Instruments-3d/ - тут находятся 3d приборы. Обычно для каждого 3d-прибора выделяется собственный каталог, где лежат трехмерные объекты, текстуры и XML-файлы.
  • Aircraft/модель/Sounds - понятное дело, звуки. WAV-файлы.
  • Aircraft/модель/Systems - конфигурационные файлы подсистем

В корневом каталоге модели обычно файлы именуются следующим образом:

  • Aircraft/модель/модель.xml - файл динамики.

Aircraft/модель/модель-set.xml - главный конфигурационный файл модели. Объединяет все части модели в единое целое. Кроме того, в этом файле устанавливаются начальные значения для различных параметров модели. Тут же переопределяются клавиши, настраиваются режимы внешнего и внутреннего обзора, задается уровень топлива "по умолчанию". Таким образом, производится необходимая инициализация переменных симулятора. Все параметры из этого файла загружаются в дерево свойств (Property Tree) симулятора. Что это такое, будет рассмотрено позднее.

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

Данной структуры каталогов следует придерживаться - не все пути можно переопределить. Хотя я, например, выношу Instruments и Instruments-3d в корень модели - просто потому, что имхо так удобнее.

Визуальная модель

Вопросы трехмерного моделирования в данной статье не рассматриваются. Во-первых, потому, что я не могу похвастаться большим опытом в данной области, а во-вторых, потому, что визуальные модели для FGFS ничем не отличаются от моделей для любых других современных авиасимуляторов (с учетом возможности конвертации форматов, конечно). Вы можете использовать свой любимый 3D редактор, и руководствоваться подробными факами и хелпами, которых есть, например, на форумах авсим.ру. FlightGear понимает .3ds и .ac, причем второй формат (AC3D), на мой взгляд, предпочтительней, потому что текстовый - иногда это может пригодиться, и кроме того, он хорошо документирован. Вы можете пользоваться готовыми моделями, взятыми из сети, а если возникают "трудности перевода" - всегда можно воспользоваться blender-ом. Этот редактор читает и пишет почти все, что существует в трехмерной виртуальности, и вполне пригоден для создания моделей "с нуля", но его интерфейс, на мой взгляд, создавался для инопланетян, и я его ниасилил, сознаюсь честно.

FlightGear не читает mdl/bgl (несмотря на обещания авторов PLIB). Есть очень ограниченная поддержка mdl, но все это служит, скорее, иллюстративным целям. Не следует надеяться, что FGFS сможет использовать модели для MSFS, по крайней мере без серьезных трудозатрат по ручной разборке модели.

Это связано с тем, что симуляторы по-разному комбинируют объекты и код модели. Если для FG эти сущности разнесены по разным файлам, то MS собирает все это в один объектный модуль. В этом, имхо, и кроется основная трудность создания конвертора "из BGL во что-нибудь еще". BGL - это полноценный процедурный язык программирования, и модель для MSFS содержит в себе кроме объектов - полигонов и текстур, еще и код анимации со своими условиями, ветвлениями итд. Не так сложно вытащить модель, как правильно расставить анимированные объекты. Поэтому, на мой взгляд, полноценный конвертер форматов невозможен - всегда потребуется ручная обработка. Хотя, я был бы рад ошибиться в этих своих предположениях. Проекты таких конвертеров существуют...

Авторы FlightGear пошли другим путем. Модель и анимация разнесены по разным файлам. При загрузке модели загружаются только трехмерные объекты - вертексы, полигоны, текстуры. Все остальное игнорируется, поэтому для загрузки в симулятор пригодны модели, созданные в любых 3D редакторах, даже и тех, которые не поддерживают анимацию. Анимация в FlightGear делается отдельно, с помощью специального интерфейса и отдельных конфигурационных файлов.

Загрузить визуальную модель в FlightGear довольно просто. Давайте попробуем сделать это "с нуля".

Вначале, нам нужен какой-нибудь трехмерный объект. Вы можете наваять некое подобие самолета в своем любимом редакторе, но можно просто воспользоваться готовым файлом, например FlightGear/Models/Geometry/tuxcopter.ac

Создайте директорию test в своем домашнем каталоге, а в ней - директорию Model.

Сделайте символическую ссылку test-> FlightGear/Aircraft/test. Это единственное место, где нам понадобятся рутовые права. Как тут быть пользователям винды - я не знаю. Придется, наверно, создать Aircraft/test под администратором и открыть ее пользователю на запись. Впрочем, насколько я знаю, под виндой все сидят с правами администраторов, так что тут не должно быть проблем...

Создайте файл test/test-set.xml, и запишите в него следующее:

    <PropertyList>
    <sim>
      <description>Test FlightGear Model</description>
      <model>
    	  <path>Aircraft/test/Model/test-model.xml</path>
      </model>
      <flight-model>null</flight-model>
    </sim>
    </PropertyList>

Это главный файл модели. Тут мы пишем короткое описание модели и ставим ссылку на файл визуальной модели Model/test-model.xml. Кроме этого, мы указываем симулятору, что вычислять полетную динамику не нужно.

Скопируйте FlightGear/Models/Geometry/tuxcopter.ac ->; /test/Model/test.ac. Это у нас будет сама трехмерная модель.

Теперь опишем визуальную модель. Создайте файл test/Model/test-model.xml и запишите в него следующее:

 <PropertyList>
  <path<test.ac>/path>
  <offsets>
    <x-m>0.0</x-m>
    <y-m>0.0</y-m>
    <z-m>3.5</z-m>
    <heading-deg>90.0</heading-deg>
  </offsets>
 </PropertyList>

Тут мы указываем симулятору, что нужно использовать файл трехмерной модели test.ac и определяем начальные смещения: нулевые по оси "вперед-назад" и "влево-вправо", три c половиной метра вверх, и поворачиваем модель на 90 градусов против часовой стрелки (если смотреть сверху).

Готово. Теперь если дать команду в консоли fgfs --show-aircraft, то в длинном списке имеющихся самолетов можно увидеть: test Test FlightGear Model

Запустив симулятор командой fgfs --aircraft=test, и переключившись на внешний вид, мы получим картинку странно знакомого вертолетика в торце взлетной полосы KSFO.

Теперь следующий шаг. Закройте сим, замените в файле test-set.xml строку <flight-model>null</flight-model> строкой <flight-model>ufo</flight-model>.

Запустите сим. Теперь наш вертолетик управляется с помощью особой FDM - динамикой UFO, и как и положено приличному НЛО, способен на всякие энергичные эволюции. Можно порулить по сценарию Фриско и окрестностей, и погоняться за трафиком. Предполагается, что джойстик у вас настроен.

Как видим, все довольно просто.

Property Tree

Мне не нравится, как это принято переводить. "Дерево свойств"... по-русски как-то не звучит, хотя для программера привычно. Мне кажется, вместо "свойств" тут более точным был бы термин "параметры", ну да ладно. Свойства так свойства. В виде дерева.

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

Если открыть встроенный браузер свойств в меню File->Browse Internal Properties, то легко можно провести аналогию с фаловой системой. Переменные выполняют роль "файлов", а древовидная структура точно соответствует привычным "директориям". В дальнейшем, я буду иногда использовать эти термины, ставя их в кавычки.

С точки зрения автора модели, обмен с переменными property tree - единственная возможность чем-то управлять или получать какую-либо информацию в симе. Свойства можно читать, некоторые - можно изменять. Можно создавать свои собственные свойства, наподобие того, как программист может объявлять переменные в своей программе. Свойства могут быть разных типов - булевые, целые, строковые, с плавающей точкой. Свойства можно инициализировать, а можно и нет - тогда, до первого присваивания, свойство имеет особое значение "nil". Свойства можно устанавливать из различных конфигурационных файлов симулятора, и даже подгружать таким образом целые "деревья свойств", а можно любое свойство изменить из командной строки при старте сима, или из встроенного браузера в процессе полета, или даже с помощью встроенного HTTP или telnet - сервера, подключившись к ним средствами операционной системы.

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

Давайте научимся пользоваться свойствами property tree. Для начала, установим собственное свойство (параметр) и свяжем его с нажатием на клавишу.

Вообще, на данном этапе, предполагается что синтаксис xml не представляет сложностей. Важно следить за тем, чтобы каждый открывающий тэг имел свой закрывающий... да вобщем-то и все...

Итак. мы хотим сконфигурировать изменение свойства (параметра) при нажатии клавиши. Нажимать будем "d", ее код в симуляторе - 100. Коды клавиш можно посмотреть в FlightGear/Docs/keyboard/map.pdf, или в FlightGear/keyboard.xml. После просмотра крайнего файла, несложно понять, как это все конфигурируется.

Работаем с конфигурационным файлом test-set.xml. На первый раз я напишу подробный комментарий, но вообще все интуитивно понятно и так. После закрывающего тега </sim> добавляем:

 <input> < !-- тут в симе хранятся переменные для всех устройств ввода -->
   <keyboard> < !-- тут - для клавиатуры -->
     <key n="100"> < !-- это - конфигурация клавиши с кодом 100 -->
       <name>d</name> < !-- на клавиатуре она помечена как d -->
       <desc>my variable</desc> < !-- просто описание -->
       <binding> < !-- Связываем... -->
         <command>property-toggle</command> < !-- команду "инвертировать сойство"... -->
         <property>/tuxmodel/test</property> < !-- с свойством (переменной) /tuxmodel/test -->
       </binding>
       </key>
   </keyboard>
</input>

Запускаем сим, не нажимаем пока клавиши. Открываем File->Browse Internal Properties, и в открывшемся окошке убеждаемся, что никакого упоминания о нашей переменной нет. Все правильно - мы не нажимали сконфигурированную клавишу. Нажимаем "d", и видим внизу списка появившуюся в момент нажатия новую "директорию" /tuxmodel, а в ней - "файл" test. Нажимая "d", можно убедиться, что при каждом нажатии булевая переменная инвертируется.

Существует довольно ограниченный набор встроенных команд для работы со свойствами. Свойству можно присвоить фиксированное значение или значение, хранящееся в другом свойстве (команда property-assign), изменить значение на некоторую величину (property-adjust), при этом можно задать верхний и нижний пределы. Можно обменять местами значение двух свойств (property-swap), например, сменив частоты настроек "operate<->standby". Свойства можно умножить на фиксирванную величину (property-multiply), и можно связать переменную с осью джойстика (property-scale). Вот, в принципе, и все.

Следующий пример чуть сложнее. Он иллюстрирует, как сделать часто требуемую фичу - обработку отпускания клавиши. Переписываем связывание:

<input>
   <keyboard>
     <key n="100">
       <name>d</name>
       <desc>my variable</desc>
       <binding>
          <command>property-assign</command>
          <property>/tuxmodel/test</property>
          <value>"key d pressed"</value>
       </binding>
       <mod-up>
         <binding>
           <command>property-assign</command>
           <property>/tuxmodel/test</property>
           <value>"key d released"</value>
         </binding>            
       </mod-up>
      </key>
   </keyboard>
</input>

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

В практике работы с моделью, постоянно возникает необходимость инициализировать переменные при старте симулятора. Иногда (да почти всегда!) переменная должна иметь определенное значение, даже если код, который ее модифицирует, ни разу не выполнялся. Это типично для переменных, выполняющих функции разных флагов, признаков состояния итд. Давайте добавим такую инициализацию для нашего примера (продолжаем работать с test-set.xml). Добавляем описание переменной (свойства) test в "директории" /tuxmodel:

<tuxmodel>
  <test type="string" archive="y">"Key d has not pressed yet"</test>
</tuxmodel>

Модификатор type="string" указывает симу, что эта переменная - строковая. Это аналог объявления переменной в привычных языках программирования. Можно и не объявлять, сим достаточно умный, но в браузере свойств у необъявленных переменных стоит тип "unspecified", что не так информативно, как строгое описание типа "bool" или "string". Второй модификатор, archive="y", указывает симу, что данную переменную необходимо обрабатывать, когда выполняется сохранение полета. При последующей загрузке сохраненного полета, переменной будет присвоено нужное значение.

Ну вот. Теперь можно снова запустить сим, открыть браузер свойств, и, нажимая "d", убедиться, что все работает как ожидалось.

Анимация

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

Симулятор ( точнее, выбранный модуль полетной динамики ) рассчитывает движение модели в абсолютных координатах "широта-долгота-высота". Высота тут - это либо высота над уровнем моря, либо превышение над препятствием, оба параметра доступны одновременно. Получить эти цифры можно из переменных property tree, ветка /position. По большому счету, для симулятора нет никакой разницы - находитесь вы в воздухе или уже под поверхностью. Недавно в девел-листе, разработчики FlightGear обсуждали возможность создания FDM для моделирования движения надводных и подводных объектов - судов, подводных лодок, и соответствующих сценариев. Подводные экскурсии, дайвинг и все такое.

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

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

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

Если мы дизассемблируем модель для MSFS (файлы bgl, mdl) в формат SCASM, то среди различных элементов модели мы обязательно встретим что-то типа:

 Transform_Mat = 
  /-0.051 -0.273  -98.292 \
 |    1.0    0.0      0.0  |
 |    0.0    1.0      0.0  |
  \   0.0    0.0      1.0 /

Это и есть матрица преобразования. Для MSFS анимация собрана в единое целое с самой моделью, в единый двоичный файл. В FlightGear этот механизм реализован по-другому.

В FlightGear анимация задается с помощью специальных конфигурационных команд в xml-файле модели. Команды конфигурирования анимации - это текстовый интерфейс к матрицам преобразования OpenGL. Обычно, анимация связана с одним или несколькими переменными из property tree. Если рассмотренный нами в предыдущем разделе пример устанавливал переменную в зависимости от нажатия клавиши, (т.е. являлся источником информации) то анимация - это потребитель этой информации.

Для объектов FlightGear доступны следующие виды "настоящей" анимации:

  • translate - смещение объекта;
  • rotate - поворот объекта на заданный угол;
  • spin - вращение объекта с заданной скоростью;
  • scale - масштабирование, изменение размера;
  • billboard - поворот объекта к наблюдателю. эта анимация, имхо, используется только для наземных объектов, в основном деревьев.

Кроме этих видов, существуют еще "псевдо-анимации", не меняющие положение объекта, но изменяющие его атрибуты:

  • none - нет анимации. none - анимация "по умолчанию", если тип анимации не указан вообще. Этот тип используется для объединения объектов в группу, для последующей обработки группы как единого целого, либо для изменения порядка отрисовки объектов, что важно, если у нас есть прозрачные объекты.
  • blend - управление прозрачностью объекта;
  • select - удаление объекта из сцены или наоборот, его вставка в сцену;
  • timed - отрисовка объекта в течении заданного интервала времени;
  • texrotate - сам объект неподвижен, вращается текстура на объекте;
  • textranslate - сам объект неподвижен, текстура линейно смещается;
  • exmultiple - способ комбинирования двух предыдущих текстурных анимаций, применительно к одному объекту. Поскольку необходимость данной анимации вызвана ограничениями движка PLIB, эта анимация, возможно, будет неактуальна в OSG-ветке.
  • material - управление всеми возможными свойствами материала объекта, включая путь к файлу текстуры. Очень широко используемая анимация - она позволяет не только зажигать лампочки, но и динамически менять текстуры - что позволяет в полете менять ливреи, использовать подсвеченные ночные текстуры итд.
  • range - удаление объекта из сцены, если расстояние от него до наблюдателя вышло из заданного диапазона. С помощью этой анимации делается LOD.
  • alpha-test - способ оптимизации отрисовки группы объектов, имеющих прозрачность. Не могу ничего более подробно написать...
  • noshadow - не рисовать тень для объекта. Вообще, просчет и отрисовка тени - довольно дорогая фича, с точки зрения fps. поэтому для тех объектов, которые заведомо не могут давать видимую снаружи тень (интерьеры, ВК етс), следует использовать эту анимацию. Сильно способствует росту fps. Впрочем, код, отвечающий за отрисовку теней, сейчас переписывается, так что в osg-devel ветке теней пока нет вообще.
  • dist-scale - масштабирование объекта в зависимости от расстояния до точки наблюдения. Анимация специально разработана для компенсации видимости огней (полосы, VASI етс) в дымке. Огни слишком плохо было видно, вот и решили увеличить их размер с помощью этой анимации.
  • flash - масштабирование объекта в зависимости от угла его видимости. Казалось бы - абсолютно бессмысленная вещь, ничего похожего в реальности представить невозможно. отнюдь:) эта анимация придумана вот для чего. Представьте, что мы ночью смотрим на направленный источник света - например, фару. Если смотреть на такой источник сбоку, то размер светящейся области невелик, но если изменить положение точки наблюдения таким образом, что наблюдатель окажется в луче направленного света - размер светящейся области покажется значительно бОльшим. Особенно этот эффект хорошо заметен, если используется оптика - из-за засветки объектива. Анимация flash позволяет делать очень симпатичные проблесковые маячки, всякие мигалки, фары, которые при наблюдении в луче не выглядят мелкими точками, но превращаются в большие яркие светящиеся шары итд. Дефолтный beacon - мачта с вертящимся прожектором - хороший пример использования этой анимации.
  • pick - поддержка мышиных кликов. Наведя курсор на объект и нажав кнопку мыши, мы получим изменение заданного свойства. Имхо, это единственная анимация, которая изменяет значение переменной - все остальные только читают. Эта анимация появилась недавно, она еще не документрована и работает только в ветке OSG-devel симулятора. Я специально не использовал ее в модели Ан-2, чтобы дать возможность управлять моделью в текущем релизе.

Для получения полной информации о синтаксисе всех анимаций FlightGear, обязательно нужно прочитать файл FlightGear/Docs/model-howto.html. Да, на английском. Может быть, какой-нибудь доброволец сделает перевод? Только обратите внимание на дату последней модификации файла! В заголовке howto по-прежнему стоит 2002 год, но это дата создания - реально, изменения вносятся туда постоянно, последняя редакция этого файла (на момент написания статьи) - январь 2007 года. Последнюю версию документации можно взять из CVS, и если вы пользуетесь devel-версией сима (что я вам рекомендую, тем более есть готовые бинарники для винды) - обязательно обновляйте документацию!

Давайте попробуем анимировать нашу модель. У нас там сейчас летает простенький вертолетик, очень схематично сделанный. Для анимации, нам нужно знать названия объектов модели, которые мы хотим привести в движение, и в некоторых случаях - координаты. Нам теперь понадобится 3D редактор, способный понимать формат ac. Я буду пользовать AC3D, но с успехом можно применять blender.

Итак. Открываем test.ac в редакторе и смотрим, что там и как:

Mod 1fg.jpg

Видно, что модель неверно ориентирована - ось X смотрит вбок, а не вперед по ходу модели. Именно поэтому нам пришлось развернуть модель тегом <heading-deg>90.0</heading-deg> в файле test-model.xml. Убираем этот тег в исходном файле и разворачиваем модель в редакторе. Для этого "выделяем все" и поворачиваем на 90 градусов по оси Y. Здесь же, обнуляем вертикальное смещение - ставим <z-m>0.0</z-m>. В результате, при старте, в начальной точке модель просядет, но для FDM UFO это неважно - модель все равно не опирается на землю, а вот нулевое смещение модели будет важно, когда мы позже будем работать с ВК.

Допустим, мы хотим анимировать шасси. Их в модели есть - хотя и выглядят они своеобразно:

Mod 2fg.jpg

Кроме этого, мы анимируем оба ротора - несущий и хвостовой. Но начнем с шасси.

Мы запомнили названия объектов, теперь можно графический редактор закрыть и перейти к работе с анимациями. Вначале, подготовим переменную для управления анимацией шасси. Перепишем наш пример test-set.xml, чтобы файл содержал следующее:

<PropertyList>
  <sim>
    <description>Test FlightGear Model</description>
    <model>
      <path>Aircraft/test/Model/test-model.xml</path>
    </model>
    <flight-model>ufo</flight-model>
  </sim>
  <input>
    <keyboard>
      <key n="103">
        <name>g</name>
        <binding>
          <command>property-assign</command>
          <property>/tuxmodel/gear</property>
          <value>0.0</value>
        </binding>
      </key>
      <key n="71">
        <name>G</name>
        <binding>
          <command>property-assign</command>
          <property>/tuxmodel/gear</property>
          <value>1.0</value>
        </binding>
      </key>       
    </keyboard>
  </input>
  <tuxmodel>
    <gear type="double" archive="y">1.0</gear>
  </tuxmodel>
</PropertyList>

Мы связали две клавиши с одной переменной. Одной клавишей мы устанавливаем переменную в 1.0, второй - сбрасываем в 0.0. Переменную описываем как число с плавающей точкой и присваиваем ей начальное значение 1.0, что будет у нас соответствовать выпущенным шасси. На этом этапе можно снова запустить сим и убедиться, что переменная правильно управляется.

Открываем файл test-model.xml и пишем туда:

<animation>
  <type>translate</type>                   < !-- Тип анимации -->
  <object-name>landing_gear</object-name>  < !-- Имя объекта из файла модели -->
  <property>/tuxmodel/gear</property>      < !-- Имя управляющей переменной  -->
  <factor>0.3</factor>                     < !-- Коэффициент пропорциональности -->
  <axis>                    < !-- Ось, по которой будет производиться перемещение -->
    <x>0.0</x>
    <y>0.0</y>
    <z>-1.0</z>
  </axis>
</animation>

Запускаем сим, переключаемся на внешний вид, давим g/G и убеждаемся, что ноги дергаются, как и ожидалось.

Некоторые пояснения к анимации. В данном примере, мы смещаем объект landing_gear (это имя должно соответствовать имени объекта в файле test.ac). Расстояние в метрах, на которое смещается объект, получается из умножения переменной /tuxmodel/gear на множитель 0.3. Поскольку у нас переменная принимает значения 0.0 и 1.0, объект будет перемещен на 30 см. Направление перемещения задается вектором <axis> с координатами X:0.0, Y:0.0, Z:-1.0. Если мы сидим на пилотском кресле, то направление X будет для нас - назад, Y - вправо, Z - вверх. Абсолютное значение координат вектора направления особого смысла не имеет, важны их относительные величины. В данном примере, вектор смотрит вниз, и именно в этом направлении будет смещаться объект, от своего начального положения в файле test.ac.

Давайте поработаем с ротором. Для этого создадим еще одну переменную в дереве свойств (ветка /tuxmodel) и назовем ее rotor:

<tuxmodel>
  <gear type="double" archive="y">1.0</gear>
  <rotor type="double" archive="y">0.0</rotor>
</tuxmodel>

В ветке /input/keyboard сконфигурируем связывание клавиши d/D для этой переменной:

<key n="100">
  <name>d</name>
  <binding>
    <command>property-adjust</command>
    <property>/tuxmodel/rotor</property>
    <step>0.1</step>
    <max>1.0</max>
  </binding>
</key>
<key n="68">
  <name>D</name>
  <binding>
    <command>property-adjust</command>
    <property>/tuxmodel/rotor</property>
    <step>-0.1</step>
    <min>0.0</min>
  </binding>
</key>

Обратите внимание: команда тут другая, и мы на каждое нажатие изменяем переменную /tuxmodel/rotor на 0.1, при этом контролируем диапазон.

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

Mod 3fg.jpg

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

Заметим также, что модель у нас смещена влево от продольной оси симметрии, и это тоже нужно устранить. Чтобы избежать ошибок, я просто выделяю всю модель и даю команду "move to 0,0,0". Видно, что с симметрией у модели не все в порядке, ну да ладно.

Подвожу курсор к центру ротора: X:-1.871, Y:0.0, Z:-0.078. На скриншоте координаты курсора не соответствуют записанным - ибо пришлось мышой нажать на "сохранить экран".

Обратите внимание: оси модели не соответствуют осям FlightGear (к сожалению, особенность AC3D), и у получившихся координат нужно поменять местами Y и Z. Нулевое значение по Z смущать не должно - ось вращения совпадает с Z, так что координата по этой оси может быть любая.

Пишем новую анимацию в test-model.xml:

<animation>
  <type>spin</type>
  <object-name>rotors</object-name>
  <property>/tuxmodel/rotor</property>
  <factor>200.0</factor>
  <сenter>
    <x-m>-1.871</x-m>
    <y-m>-0.078</y-m>
    <z-m>0.0</z-m>
  </сenter>
  <axis>
    <x>0.0</x>
    <y>0.0</y>
    <z>1.0</z>
  </axis>
</animation>

Обратите внимание: задавая центр, мы поменяли местами Y и Z. Для анимации spin значение управляющей переменной - это RPM, обороты в минуту. Множитель 200 дает нам максимальный RPM 200 об/мин, т.к. сама переменная у нас меняется в диапазоне 0.0 - 1.0. Запустив сим, можно поиграться с плавным изменением скорости вращения, нажимая d/D. Видно, что ротор вращается кривовато, и не по центру симметрии модели - но это результат кривости самого ротора. Это хороший пример, показывающий, что лишней точности в установке вращающихся объектов модели просто не бывает.

Давайте освоим еще один способ задания оси вращения анимаций spin, rotate - указав координаты двух точек, через которые проходит ось. Такой способ рекомендуют применять в случае, когда ось вращения не совпадает с осью X, Y или Z. Это характерно, например, для осей элеронов, когда крыло стреловидное и V-образное. Опять откроем файл модели в графическом редакторе и запишем координаты двух точек, лежащих на воображаемой оси вращения хвостового ротора:

<animation>
  <type>spin</type>
  <object-name>tail_rotor</object-name>
  <property>/tuxmodel/rotor</property>
  <factor>400.0</factor>
  <axis>
    <x1-m>9.774</x1-m>
    <y1-m>-1.0</y1-m>
    <z1-m>1.469</z1-m>
 
    <x2-m>9.774</x2-m>
    <y2-m>1.0</y2-m>
    <z2-m>1.469</z2-m>    
  </axis>
</animation>

Все координаты тут - в метрах, о чем говорит <-m> в тегах. Скорость вращения хвостового ротора я увеличил вдвое. Вроде бы, все наглядно и понятно.

Ну вот, в общем, как конфигурируются основные типы анимации - смещение и вращение.

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

Виртуальный кокпит

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

Откроем наш редактор, и выберем координаты точки, где бы мы хотели поместить точку наблюдения в ВК - другими словами, откуда пилот будет смотреть на окружающий мир. Я взял точку с координатами X:-4.3, Y:-0.5, Z: 2.6. Точка наблюдения смещена влево на полметра от продольной оси модели - считаем, что там у нас "левая чашка":)

Конфигурируем обзор. В файл tes-set.xml, в секцию /sim добавляем:

<virtual-cockpit archive="y">true</virtual-cockpit>
   <view>
     <internal archive="y">true</internal>
     <config>
       <x-offset-m archive="y">-0.5</x-offset-m> 
       <y-offset-m archive="y">2.6</y-offset-m> 
       <z-offset-m archive="y">-4.3</z-offset-m> 
     </config>
</view>

Мы сконфигурировали нулевой режим обзора. Режимов обзора по умолчанию шесть: Cockpit View, Helicopter View, Chase View, Tower View, Tower View Look From, Chase View wo yaw. Переключаеются виды клавишей V, но очень желательно сдублировать ее на джойстике.

Вы можете добавлять свои собственные обзоры и менять дефолтные установки существующим. Кстати, все дефолтные настройки симулятора живут в файле preferences.xml.

Нулевой режим обзора - ВК (Cockpit View). Сим стартует именно в нем, но если он не сконфигурирован (как было у нас раньше) - в этом обзоре модель будет не видна - только окружающий мир.

Обратите внимание, что для координат точки наблюдения оси поменяны местами. Почему - лучше спросить в devel-листе у авторов... имхо, это один из тех случаев, когда баг объявляется фичей...

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

Приборы

Приборы - это то, что в MSFS называются "Gauges", а в FlightGear - Instruments. Не знаю, почему в FG используется другое слово. Возможно, чтобы избежать конфликтов с Сами Знаете Какой фирмой, любящей патентовать разные общеупотребительные слова в виде торговых марок своих изделий.

Дефолтных 3D приборов довольно много - они живут в директории FlightGear/Aircraft/Instruments-3d/. Начнем с asi300, который, как можно догадаться, измеряет воздушную скорость до 300 узлов.

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

Запускаем редактор, определяем положение прибора (его центра) на панели. Для удобства,можно скопировать модель в другой файл и в нем часть объектов модели прибить, оставив только панель - ни в коем случае не сдвигая ее!

Устанавливаем прибор - добавляем в test-model.xml:

<model>
   <name>asi</name>
   <path>Aircraft/Instruments-3d/asi300/asi300-3d.xml</path>
   <offsets>
     <x-m>-6.955</x-m>
     <y-m>-1.0</y-m>
     <z-m>1.5</z-m>
   </offsets>
</model>

Здесь мы указываем путь к xml-файлу прибора, и устанавливаем его смещение в координатах модели. При необходимости, прибор можно повернуть, наклонить - если у нас панель не вертикальна - см. синтаксис тега <offsets> в документации. Теперь можно запустить сим и убедиться, что прибор на месте. Для этой панели он явно мал (точнее, велико расстояние от точки наблюдения), это легко исправить. Измените координаты точки наблюдения ВК - X:-6.3 Y:-0.8 Z: 1.7, помня о перепутанных осях.

Видно, что прибор работает, и что скорость у НЛО значительно выше 300 knots.

Давайте откроем Aircraft/Instruments-3d/asi300/asi300.ac и посмотрим, как устроен этот прибор изнутри. Он состоит из трех объектов: циферблата ASIface, стрелки ASIneedle и наружного кольца с головками заклепок ASIbezel. Первые два объекта текстурированы - смотрите файл Aircraft/Instruments-3d/asi300/asi-300.rgb. Таким примерно способом устроены все приборы типа "будильник". Обратите внимание на следующие вещи:

Нормали объектов должны быть правильными - иначе объекты будут либо неправильно подсвечены, либо вообще исчезнут под определенным углом наблюдения.

Прибор ориентирован так, чтобы ось X "выходила" из него, и была направлена к наблюдателю. При этом, когда вы будете устанавливать его на панель, вам не придется применять дополнительные теги, разворачивающие прибор "лицом" к наблюдателю.

Геометрический центр прибора совпадает с нулем координат, одна из осей стрелок совпадает с осью X. В этом случае, предельно упрощается анимация стрелки - по умолчанию, ось вращения проходит через начало координат и совпадает с осью X.

Давайте добавим более сложный прибор, указатель скорости PA24. Добавляем следующие строки в test-model.xml:

<model>
 <name>asi-pa24</name>
 <path>Aircraft/Instruments-3d/asi-pa24/asi.xml</path>
 <offsets>
   <x-m>-6.94</x-m>
   <y-m>-0.8</y-m>
   <z-m>1.5</z-m>
 </offsets>
</model>

Я слегка изменил координату по X, т.к. панель кривовата и прибор "проваливается под панель". Как видим, при известных координатах, делать панели из готовых блоков несложно.

Теперь немного беллетристики. На мой взгляд, основным секретом изготовления интересных, выразительных приборов, являются качественные текстуры. Сами по себе, объекты приборов очень просты, и в большинстве случаев даже не трехмерны. Иллюзию объема придает качественно сделанные текстуры. При этом, к текстурам применимы такие же требования, как и текстурам MSFS - т.е. размеры в пикселах должны быть степенью двойки (128х128, 256х16 итд), с определенным предельным соотношением сторон. В документации встречается число 1/8, но я, помнится, успешно делал текстуры и с бОльшим отношением.

Формат SGI RGB, в котором FlightGear хранит текстуры, поддерживает альфа-канал, что позволяет создавать очень интересные объекты при минимуме полигонов. С успехом можно делать приборы на основе фотографий, для модели Ан-2 я сделал несколько таких приборов, взяв фото отсюда. Правда, чтобы это все выглядело достойно, нужен определенный навык при работе с двумерными графическими редакторами - в первую очередь, как ни странно, векторными. Специалисты-дизайнеры, думаю, со мной согласятся, но это уже за пределами данной статьи...

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

Допустим, наш прибор состоит из трех объектов: циферблат, стрелка и крышка - прозрачное стекло с ободком . Когда мы смотрим на прибор, сначала мы видим крышку, под ним, через стекло - стрелку, под ней - циферблат. Чтобы сим правильно отрисовал такой прибор, необходимо, чтобы порядок следования объектов в файле был: вначале - циферблат, потом - стрелка, и последней - крышка. Понятно, что это требование не так просто выполнить: хотя редакторы имеют возможность реорганизовывать объекты, это неудобно, и часто, в случае сложной модели, гораздо проще переставить объекты в ac файле вручную, с помощью обычного текстового редактора. Именно поэтому, текстовые форматы для трехмерных моделей для FG предпочтительнее.

Существует еще один способ принудительно указать порядок следования объектов: воспользоваться анимацией <none>. Эта анимация перегруппировывает объекты в тот порядок, который нужен для их правильного отображения. Кроме этого, анимация <none>, если указать ей имя, позволяет впоследствии по этому имени анимировать группу объектов как одно целое. С другой стороны, любая анимация, где объединены несколько объектов (т.е. где несколько тегов <object-name>), производит перегруппировку этих объектов. Но, поскольку правила группировки не допускают, чтобы один объект входил одновременно в несколько групп, существует определенная процедура, которая выполняется, когда мы пытаемся собрать в новую группу объект, уже состоящий в другой группе. Все это требует внимания, и на первом этапе освоения лучше вообще избегать много-объектной анимации, потому что ошибки группировки приводят к исчезновению объектов, неправильной работе других анимаций. Подобные ошибки "на ровном месте" могут сильно испортить впечатление от процесса моделирования, поэтому одно из правил начинающего моделлера должно быть - "вначале - никаких групп!". После отладки анимаций, можно пытаться сгруппировать однотипные анимации, но при этом важно внимательно проверять результат.

Давайте рассмотрим особенности приборной анимации. В первую очередь, это интерполяция. Вот пример анимации стрелки индикатора воздушной скорости из asi-pa24/asi.xml:

<animation>
 <type>rotate</type>
 <object-name>Needle</object-name>
 <property>/instrumentation/airspeed-indicator/indicated-speed-kt</property>
 <interpolation>
  <entry><ind>  10</ind><dep>    3</dep></entry>
  <entry><ind>  40</ind><dep>   35</dep></entry>
  <entry><ind>  60</ind><dep>   70</dep></entry>
  <entry><ind>  80</ind><dep>  105</dep></entry>
  <entry><ind> 100</ind><dep>  155</dep></entry>
  <entry><ind> 120</ind><dep>  190</dep></entry>
  <entry><ind> 140</ind><dep>  225</dep></entry>
  <entry><ind> 160</ind><dep>  260</dep></entry>
  <entry><ind> 180</ind><dep>  295</dep></entry>
 </interpolation>
 <center>
  <x-m>0.0</x-m>
  <y-m>0.001</y-m>
  <z-m>0.001</z-m>
 </center>
 <axis>
  <x>-1</x>
  <y>0</y>
  <z>0</z>
 </axis>
</animation>

Обратите внимание: <axis> задает вектор в направлении "минус X". Это типично для приборов - положительные углы в этом случае будут приводить к вращению объекта по часовой стрелке.

Кроме известных уже нам тегов <type> <object-name> <property> <axis> здесь используется тег <interpolation>. Он задает таблицу интерполяции, состоящую из строк (теги <entry>). В каждой строке есть два элемента: <ind> и <dep>. Первый из них, <ind>, задает входное значение интерполяции, второй <dep> - выходное. Входные значения берутся из <property>, таким образом, можно считать, что <interpolation> - это нелинейный коэффициент, на который умножается величина, взятая из <property>, и в результате получается угол, на который будет повернут объект. Из приведенной таблицы видно, что на скорости 10 узлов стрелка будет повернута на 3 градуса, а на скорости 100 узлов - на 155 градусов (<ind> в данном примере - узлы, <dep> - градусы).

Важное замечание по интерполяции. Первый и последний элементы таблицы определяют границы анимации, т.е. в данном примере при сколь угодно большой скорости стрелка никогда не повернется больше чем на 295 градусов, и даже на стоянке стрелка будет повернута на 3 градуса. Таким образом, интерполяция одновременно обрезает диапазон анимации, заменяя собой теги <min>, <max>.

Еще одно важное замечание. Интерполяция работает только для монотонно изменяющихся функций.

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

Откуда приборы получают данные? В симуляторе есть довольно много готовых приборов - они находятся в ветке /instrumentation. Например, скоростемеры, которые мы включали в свою тестовую модель, пользуются данными из /instrumentation/airspeed-indicator/. Запустите сим, откройте браузер свойств, зайдите в эту ветку и посмотрите, сколько инструментария создано для поддержки авторов моделей. Кстати, гироскопы моделируются с учетом дрейфа на данной широте, и даже моделируется выбег гироскопа после пропадания питания - поиграйтесь с параметром serviceable. Для некоторых приборов есть арретир - caged-flag. А если вам требуется несколько независимых экземпляров одного прибора - например, несколько радиокомпасов, каждый на свою частоту, или три гировертикали - можно задать их требуемое количество в файле instrumentation.xml в директории модели - взяв за основу FlightGear/Aircraft/Generic/generic-instrumentation.xml.

NASAL

Как быть, если нужного прибора нет в /instrumentation? как смоделировать сложную самолетную систему - электрическую, гидравлическую? топливную систему магистрального лайнера? каким образом создавать анимации, для которых требуются переменные, меняющиеся по сложным законам?

Ответ один. Запрограммировать все это с помощью встроенного языка программирования nasal.

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

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

Запустить программу (скрипт) nasal несложно. Создаем файл myprog.nas в директории test, где находится наша модель. Пишем туда:

  # my first program
 hello = func{
 print("script work!");
 }
 hello();

Подключаем нашу программу к модели. Добавляем в test-set.xml следующие строки:

<nasal>
 <test>
   <file>Aircraft/test/myprog.nas</file>
 </test>
</nasal>

Запускаем сим и в консоли, в окне, куда выводятся сообщения, наблюдаем ожидаемый текст.

Пояснения к программе. Мы описали функцию hello(), которая выводит сообщение в консоль. А потом, мы эту функцию вызвали один раз, при старте симулятора.

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

     # my 2-nd program
    hello = func{
    print("script work!");
    settimer( hello, 0.5 );
    }
    hello();

Теперь, после вызова в первый раз, функция hello() устанавливает таймер, куда передает свое имя и период времени. По истечении тайм-аута, таймер вызовет функцию вновь, и процесс повторится.

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

Другое применение nasal - обработка внешних событий (нажатий на клавиши, перемещение джойстика етс).

добавьте в myprog.nas

     key_handler = func{
    print("Key pressed!");
    }

а в test-set.xml измените связывание для клавиши g, чтобы тег <key> выглядел так:

     <key n="103">
       <name>g</name>
       <binding>
         <command>nasal</command>
         <script>test.key_handler()</script>
       </binding>
     </key>

Работает? давайте разберемся с параметрами. Вот так в функцию можно передавать параметры:

     key_handler = func{
    if( arg[0] == 1 )
      {
    print("Key pressed!");
      }
    if( arg[0] == -1 )
      {
    print("Shift+Key pressed!");
      }
    }

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

<key n="103">
       <name>g</name>
       <binding>
         <command>nasal</command>
         <script>test.key_handler(1)</script>
       </binding>
     </key>
     <key n="71">
       <name>G</name>
       <binding>
           <command>nasal</command>
           <script>test.key_handler(-1)</script>
       </binding>
</key>

Ввод-вывод в Nasal предназначен в первую очередь для работы с property tree. существуют довольно продвинутые средства работы с группами переменных (узлами, Node), но для начала давайте посмотрим как работать с одной переменной:

     key_handler = func{
      gear = getprop("/tuxmodel/gear");
      if( gear == nil ) { return; }
      print("gear up:", gear);
 
    if( arg[0] == 1 )
    {
    print("Key pressed!");
    }
    if( arg[0] == -1 )
    {
    print("Shift+Key pressed!");
    }
    }

Тут мы перед проверкой аргумента функции читаем переменную из property tree (ранее нами инициализированную), и присваиваем локальной переменной gear. Затем, выполняется проверка на nil - неопределенное свойство. Это необходимо, т.к. разные компоненты симулятора при старте инициализируются в разное время, и когда интерпретатор nasal уже готов к работе, property tree еще обрабатывается. Если в этот момент будет предпринята попытка использовать переменнную в числовом контексте (для арифметики, например) - будет зафиксирована ошибка, и nasal выгрузит целиком весь файл, дальнейшая работа функций из всего файла будет невозможна даже после полной инициализации property tree.

Давайте запишем свойство. Еще раз модифицируем программу:

     key_handler = func{
    if( arg[0] == 1 )
    {
    setprop("/tuxmodel/gear", 0.0);
    }
    if( arg[0] == -1 )
    {
    setprop("/tuxmodel/gear", 1.0);
    }
    }

Думаю, тут все понятно. А теперь - демонстрация работы еще одной очень полезной функции:

     key_handler = func{
    if( arg[0] == 1 )
    {
    interpolate("/tuxmodel/gear", 0.0, 2.0 );
    }
    if( arg[0] == -1 )
    {
    interpolate("/tuxmodel/gear", 1.0, 2.0 );
    }
    }

теперь "шасси" выпускаются плавно, а не конвульсивно дергаются.

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

Вот, мы освоили основные применения nasal в FlightGear. Теперь в вашем распоряжении полноценный процедурный язык программирования, средства ввода-вывода через property tree и отладочный вывод. Вы можете выполнять довольно сложную математическую обработку любого параметра FlightGear, а так же строить программные автоматы для моделирования систем. В директории FlightGear/Nasal находятся файлы с различными дополнениями, удобными и полезными функциями и всякими фичами - все они доступны из кода ваших моделей. При этом, скрипты работают довольно эффективно, и даже большое их количество сим не притормаживает. Можно читать файлы (писать нельзя - из соображений безопасности). Можно выводить красивые надписи и даже пользоваться готовыми виджетами для разных таблиц, менюшек итд.

Вообще, nasal, интегрированный в FlightGear, очень мощная вещь. Полет вашей творческой фантазии практически ничем не ограничен.

Заключение

Здесь я просто перечислю темы, которые остались за рамками статьи. Во-первых, и это, наверно,самая важная подсистема симулятора - полетная динамика. Обязательно загляните сюда. Вообще, создание реалистичной динамики - дело творческое и требующее определенных познаний в теории, и опусы типа "полетная динамика для чайников за четверть часа" вряд ли получатся. В помощь начинающим на сайте JSBSim есть раздел Aeromatic, который поможет создать упрощенную динамику для самолета и винтомоторной группы. Есть от чего оттолкнуться, и дальше уже можно двигаться самостоятельно.

Я старался, чтобы статья дала возможность самостоятельного изучения существующих моделей - разного качества, разных авторов, и учиться приемам использования различных анимаций и программирования nasal. Это отличный способ разобраться во всех тонкостях моделирования FlightGear и большое преимущество открытых систем. Используйте эту возможность как можно чаще!

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

Другими словами, для авторов моделей есть все возможности, чтобы приложить силы, проявить талант и достичь успеха. Будут модели - будет расти интерес к симулятору, ну а пока он почти неизвестен в нашей стране. Чтобы слегка сдвинуть дело с мертвой точки, под FlightGear портирована хорошо известная модель Ан-2 Антона Николаева. Виртуальный кокпит модели неплохо иллюстрирует возможности технологий FlightGear.

Mod 5fg.jpg

Добро пожаловать на www.flightgear.ru!

Ю.В,Никифоров aka Yurik_nsk

yurik{ухЪ}megasignal.com

май 2007

 
  Новости    Файлы    Статьи    Фото    Форумы    Блоги    Радио    Avsim Wiki  
Личные инструменты
Пространства имён
Варианты
Действия