LXF84:Ogre
Yaleks (обсуждение | вклад) (Новая: {{Цикл/Ogre}} == Ogre: Освещаем новый дом == ''ЧАСТЬ 3: Как превратить травянистый холм в крепость в стиле Тюдор...) |
Yaleks (обсуждение | вклад) м |
||
Строка 1: | Строка 1: | ||
{{Цикл/Ogre}} | {{Цикл/Ogre}} | ||
+ | |||
== Ogre: Освещаем новый дом == | == Ogre: Освещаем новый дом == | ||
− | ''ЧАСТЬ 3: Как превратить травянистый холм в крепость в стиле Тюдоров и создать солнце и луну всего на четырех страницах? У '''Пола Хадсона''' есть | + | ''ЧАСТЬ 3: Как превратить травянистый холм в крепость в стиле Тюдоров и создать солнце и луну всего на четырех страницах? У '''Пола Хадсона''' есть ответ…'' |
− | В этот урок мы включили много интересного: наша | + | В этот урок мы включили много интересного: наша задача — взять |
пустой ландшафт из прошлого номера, построить дом на плато, | пустой ландшафт из прошлого номера, построить дом на плато, | ||
добавить света и тени, и, самое интересное, позволить игроку | добавить света и тени, и, самое интересное, позволить игроку | ||
− | гулять по дому. Легко? Ой, нет. А моя | + | гулять по дому. Легко? Ой, нет. А моя задача — как раз облегчить работу, поэтому приготовьтесь разогнать игру до скорости света! |
Мы загружали ландшафт в игру Висельник Чед с помощью файла | Мы загружали ландшафт в игру Висельник Чед с помощью файла | ||
Строка 16: | Строка 17: | ||
Переместите файл terrain.cfg из каталога media в ваш главный | Переместите файл terrain.cfg из каталога media в ваш главный | ||
каталог, где размещен код. Затем переместите файлы terrain_detail.jpg, | каталог, где размещен код. Затем переместите файлы terrain_detail.jpg, | ||
− | terrain.png и terrain_texture.jpg из media/materials/textures в ваш главный каталог. Учтите, я сказал «переместите», а не | + | terrain.png и terrain_texture.jpg из media/materials/textures в ваш главный каталог. Учтите, я сказал «переместите», а не «скопируйте» — не |
оставляйте оригиналы там, где они находятся, не то они будут читаться вместо ваших собственных файлов. Эти четыре файла определяют, | оставляйте оригиналы там, где они находятся, не то они будут читаться вместо ваших собственных файлов. Эти четыре файла определяют, | ||
как выглядит и ведет себя ландшафт. | как выглядит и ведет себя ландшафт. | ||
Строка 22: | Строка 23: | ||
Используемый нами менеджер сцены, ответственный за обработку неба и земли, создает ландшафт по двумерной карте высот (это | Используемый нами менеджер сцены, ответственный за обработку неба и земли, создает ландшафт по двумерной карте высот (это | ||
полутоновой план ландшафта, на котором наивысшие точки показаны | полутоновой план ландшафта, на котором наивысшие точки показаны | ||
− | белым цветом, а самые | + | белым цветом, а самые низкие — черным). В файле terrain.cfg указана |
карта высот terrain.png. Действительный цвет определяется файлом | карта высот terrain.png. Действительный цвет определяется файлом | ||
terrain_texture.jpg, который «натягивается» на весь ландшафт. Наконец, | terrain_texture.jpg, который «натягивается» на весь ландшафт. Наконец, | ||
Строка 33: | Строка 34: | ||
Gimp»). Вы также заметите, что я сменил цвет terrain_texture. | Gimp»). Вы также заметите, что я сменил цвет terrain_texture. | ||
jpg на цвет травы, ну устал я от этой пустыни! Теперь откройте в текстовом редакторе файл terrain.cfg и найдите строчку #VertexNormal=Yes. | jpg на цвет травы, ну устал я от этой пустыни! Теперь откройте в текстовом редакторе файл terrain.cfg и найдите строчку #VertexNormal=Yes. | ||
− | Знак # | + | Знак # — это комментарий, означающий, что VertexNormal отключен. |
− | Удалите #, чтобы включить | + | Удалите #, чтобы включить опцию — это вынудит Ogre генерировать |
нормали для нашего ландшафта, которые понадобятся нам позже | нормали для нашего ландшафта, которые понадобятся нам позже | ||
(см. врезку «Зачем нужны нормали»). В файле resources.cfg | (см. врезку «Зачем нужны нормали»). В файле resources.cfg | ||
проверьте, что в секции General указано FileSystem=., это заставит Ogre | проверьте, что в секции General указано FileSystem=., это заставит Ogre | ||
считывать файлы ландшафта из вашего текущего каталога. Вперед! | считывать файлы ландшафта из вашего текущего каталога. Вперед! | ||
− | Запустите нашу | + | Запустите нашу игру — вы увидите обширную площадку, здесь-то мы |
− | и | + | и поставим… |
=== Дом, который построил Пол === | === Дом, который построил Пол === | ||
Строка 58: | Строка 59: | ||
HouseNode->scale(0.25,0.125,0.25); | HouseNode->scale(0.25,0.125,0.25); | ||
</source> | </source> | ||
− | Файл tudorhouse. | + | Файл tudorhouse.mesh — один из стандартных сеточных объектов, |
входящих в Ogre, и он выглядит великолепно. Заметим также, что дом | входящих в Ogre, и он выглядит великолепно. Заметим также, что дом | ||
огромный, поэтому я использовал scale() и приспособил его размер к | огромный, поэтому я использовал scale() и приспособил его размер к | ||
ландшафту. Вот и все, что требовалось для добавления дома в нашу | ландшафту. Вот и все, что требовалось для добавления дома в нашу | ||
игру, поэтому перезапустите make и полюбуйтесь результатом. Нет, | игру, поэтому перезапустите make и полюбуйтесь результатом. Нет, | ||
− | определения столкновений пока | + | определения столкновений пока нет — оставим его на потом! |
=== Небесное вторжение === | === Небесное вторжение === | ||
Строка 83: | Строка 84: | ||
три типа теней и три типа света. Разница между тенями заключается | три типа теней и три типа света. Разница между тенями заключается | ||
в скорости: тень низкого качества прорисовывается быстрее всего. | в скорости: тень низкого качества прорисовывается быстрее всего. | ||
− | Первый | + | Первый тип — SHADOWTYPE_TEXTURE_MODULATIVE, использующий |
простую текстуру для создания теней в нужных местах. На практике | простую текстуру для создания теней в нужных местах. На практике | ||
− | тени получаются | + | тени получаются грубоватые — сгодятся только для тех, у кого слабая видеокарта, все остальные в восторг не придут. Следующий по |
− | качеству | + | качеству тип — SHADOWTYPE_STENCIL_MODULATIVE. Тени выглядят |
более привлекательно, но создаются в один проход, поэтому результат не идеален. Наконец, SHADOWTYPE_STENCIL_ADDITIVE. Тут тени | более привлекательно, но создаются в один проход, поэтому результат не идеален. Наконец, SHADOWTYPE_STENCIL_ADDITIVE. Тут тени | ||
выглядят превосходно, для каждого источника света построение осуществляется за отдельный проход, поэтому пересечение теней от двух | выглядят превосходно, для каждого источника света построение осуществляется за отдельный проход, поэтому пересечение теней от двух | ||
Строка 93: | Строка 94: | ||
Каждый из трех типов источников характеризуется своим способом | Каждый из трех типов источников характеризуется своим способом | ||
− | освещения. Точечный источник излучает свет как | + | освещения. Точечный источник излучает свет как Солнце — одинаково |
во всех направлениях, из определенной точки. Источник направленного света излучает свет в одном направлении и не имеет начальной | во всех направлениях, из определенной точки. Источник направленного света излучает свет в одном направлении и не имеет начальной | ||
точки. С нашей позиции на Земле солнце выглядит направленным | точки. С нашей позиции на Земле солнце выглядит направленным | ||
Строка 102: | Строка 103: | ||
Оба наших источника, солнце и луна, находятся очень далеко, поэтому они могут считаться источниками направленного света. | Оба наших источника, солнце и луна, находятся очень далеко, поэтому они могут считаться источниками направленного света. | ||
− | Не будем пренебрегать | + | Не будем пренебрегать деталями — выберем опцию SHADOWTYPE_STENCIL_ADDITIVE, чтобы тени хорошо смотрелись. В последующем |
коде немного приглушим рассеянное освещение, чтобы заметнее стали дневной и ночной источники света. | коде немного приглушим рассеянное освещение, чтобы заметнее стали дневной и ночной источники света. | ||
− | Вот | + | Вот код — поместите его в метод createScene(): |
<source lang="cpp"> | <source lang="cpp"> | ||
m_SceneMgr->setAmbientLight( ColourValue(0.35, 0.35, 0.35) ); | m_SceneMgr->setAmbientLight( ColourValue(0.35, 0.35, 0.35) ); | ||
Строка 137: | Строка 138: | ||
крепость не похоже, правда? Сейчас мы это изменим, соорудив внутри заведомо неприветливую обстановку. На последних трех уроках мы | крепость не похоже, правда? Сейчас мы это изменим, соорудив внутри заведомо неприветливую обстановку. На последних трех уроках мы | ||
играли в песочнице менеджера сцен Ogre для открытого ландшафта, | играли в песочнице менеджера сцен Ogre для открытого ландшафта, | ||
− | но если наши персонажи намерены разгуливать по зданию, потребуется еще один менеджер | + | но если наши персонажи намерены разгуливать по зданию, потребуется еще один менеджер сцены — BSP. |
BSP означает binary space partition [двоичное разбиение пространства] и позволяет очень быстро загружать и обрабатывать закрытые | BSP означает binary space partition [двоичное разбиение пространства] и позволяет очень быстро загружать и обрабатывать закрытые | ||
Строка 179: | Строка 180: | ||
scenemanager = ST_EXTERIOR_CLOSE; | scenemanager = ST_EXTERIOR_CLOSE; | ||
</source> | </source> | ||
− | Метод frameStartedInside() новый, но ничего особенного не делает | + | Метод frameStartedInside() новый, но ничего особенного не делает - |
в данный момент он должен представлять урезанную версию метода | в данный момент он должен представлять урезанную версию метода | ||
frameStartedOutside() и обрабатывать простой ввод от клавиатуры. Вот | frameStartedOutside() и обрабатывать простой ввод от клавиатуры. Вот | ||
Строка 199: | Строка 200: | ||
} | } | ||
</source> | </source> | ||
− | Вы заметите, что переменная playerspeed умножена на | + | Вы заметите, что переменная playerspeed умножена на пять — дело |
в том, что карта Quake огромна, и прогулка с прежней скоростью превратилась бы в вечность. Если такое решение вы находите примитивным, попробуйте увеличить ландшафт, удалив вызов scale() для дома, | в том, что карта Quake огромна, и прогулка с прежней скоростью превратилась бы в вечность. Если такое решение вы находите примитивным, попробуйте увеличить ландшафт, удалив вызов scale() для дома, | ||
а затем выберите значение скорости, пригодное везде. | а затем выберите значение скорости, пригодное везде. | ||
Строка 238: | Строка 239: | ||
к камере. Метод getSuggestedViewport() считывает произвольную начальную позицию игрока на карте и устанавливает камеру в эту | к камере. Метод getSuggestedViewport() считывает произвольную начальную позицию игрока на карте и устанавливает камеру в эту | ||
точку. Нам необходимо установить оси камеры pitch и yaw потому, | точку. Нам необходимо установить оси камеры pitch и yaw потому, | ||
− | что Quake использует для плоскости пола координаты Х и Y, а | + | что Quake использует для плоскости пола координаты Х и Y, а Z — для |
− | высоты, а мы обычно используем для пола X и Z и | + | высоты, а мы обычно используем для пола X и Z и Y — для высоты. |
Мы еще не закончили: понадобится добавить две строки в начало | Мы еще не закончили: понадобится добавить две строки в начало | ||
Строка 252: | Строка 253: | ||
CChadGame() (который находится в начале chad.cpp) заменен на | CChadGame() (который находится в начале chad.cpp) заменен на | ||
createOutdoorScene(). Ну вот и все: запустите make, затем chad. | createOutdoorScene(). Ну вот и все: запустите make, затем chad. | ||
− | Посмотрим, заметите ли вы | + | Посмотрим, заметите ли вы разницу…. |
=== Сложный вопрос === | === Сложный вопрос === | ||
− | ОК, разницы | + | ОК, разницы нет — по крайней мере, с точки зрения игрока. Это |
потому, что мы написали код обработки для закрытой сцены, но не | потому, что мы написали код обработки для закрытой сцены, но не | ||
написали кода, загружающего эту сцену. Вы вольны написать код, | написали кода, загружающего эту сцену. Вы вольны написать код, | ||
Строка 267: | Строка 268: | ||
области просмотра, расположен в методах create*Scene(), поэтому | области просмотра, расположен в методах create*Scene(), поэтому | ||
о них беспокоиться не надо. Все, что нам надо сделать, это вызвать | о них беспокоиться не надо. Все, что нам надо сделать, это вызвать | ||
− | требуемый метод create*Scene(),например, так: | + | требуемый метод create*Scene(), например, так: |
<source lang="cpp"> | <source lang="cpp"> | ||
if (m_InputReader->isKeyDown(KC_F1)) createIndoorScene(); | if (m_InputReader->isKeyDown(KC_F1)) createIndoorScene(); | ||
Строка 280: | Строка 281: | ||
Мы рассмотрели в этом руководстве много нового. Труднее всего | Мы рассмотрели в этом руководстве много нового. Труднее всего | ||
уместить в голове переход от одного менеджера сцены к нескольким; | уместить в голове переход от одного менеджера сцены к нескольким; | ||
− | все остальное сравнительно просто! Я надеюсь, что вам понравилось, как легко Ogre создает освещение и тени и работает с уровнями BSP, хотя покамест некоторые недостатки игры могут и | + | все остальное сравнительно просто! Я надеюсь, что вам понравилось, как легко Ogre создает освещение и тени и работает с уровнями BSP, хотя покамест некоторые недостатки игры могут и раздражать — отсутствие обнаружения столкновений, плохой ввод, небо, на |
котором не сказывается освещение, и так далее. Часть недостатков | котором не сказывается освещение, и так далее. Часть недостатков | ||
вы можете исправить сами, ведь это руководство написано для того, | вы можете исправить сами, ведь это руководство написано для того, | ||
чтобы игру программировали вы, а не я. Но с остальными мы разберемся вместе. До следующего раза! | чтобы игру программировали вы, а не я. Но с остальными мы разберемся вместе. До следующего раза! |
Версия 21:22, 22 ноября 2008
|
|
|
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Содержание |
Ogre: Освещаем новый дом
ЧАСТЬ 3: Как превратить травянистый холм в крепость в стиле Тюдоров и создать солнце и луну всего на четырех страницах? У Пола Хадсона есть ответ…
В этот урок мы включили много интересного: наша задача — взять пустой ландшафт из прошлого номера, построить дом на плато, добавить света и тени, и, самое интересное, позволить игроку гулять по дому. Легко? Ой, нет. А моя задача — как раз облегчить работу, поэтому приготовьтесь разогнать игру до скорости света!
Мы загружали ландшафт в игру Висельник Чед с помощью файла terrain.cfg, поставляемого вместе с медиа-пакетом Ogre. Всего одной строкой кода создается живописная местность, где можно побродить, но остаются две проблемы: на границах ландшафт обрывается в пустоту и нет места, где можно поставить дом. Поэтому нам надо сначала отредактировать файл ландшафта, пусть запляшет под нашу дудку.
Переместите файл terrain.cfg из каталога media в ваш главный каталог, где размещен код. Затем переместите файлы terrain_detail.jpg, terrain.png и terrain_texture.jpg из media/materials/textures в ваш главный каталог. Учтите, я сказал «переместите», а не «скопируйте» — не оставляйте оригиналы там, где они находятся, не то они будут читаться вместо ваших собственных файлов. Эти четыре файла определяют, как выглядит и ведет себя ландшафт.
Используемый нами менеджер сцены, ответственный за обработку неба и земли, создает ландшафт по двумерной карте высот (это полутоновой план ландшафта, на котором наивысшие точки показаны белым цветом, а самые низкие — черным). В файле terrain.cfg указана карта высот terrain.png. Действительный цвет определяется файлом terrain_texture.jpg, который «натягивается» на весь ландшафт. Наконец, файл terrain_detail.jpg обеспечивает детали, которые будут расположены поверх terrain_texture.jpg, чтобы текстура выглядела сложнее, чем она есть на самом деле.
Чего нам не хватает, так это места для нашей постройки. В моей версии terrain.png (она находится на диске) я подредактировал карту, чтоб выделить пространство для здания (см. «Создание карты высот в Gimp»). Вы также заметите, что я сменил цвет terrain_texture. jpg на цвет травы, ну устал я от этой пустыни! Теперь откройте в текстовом редакторе файл terrain.cfg и найдите строчку #VertexNormal=Yes. Знак # — это комментарий, означающий, что VertexNormal отключен. Удалите #, чтобы включить опцию — это вынудит Ogre генерировать нормали для нашего ландшафта, которые понадобятся нам позже (см. врезку «Зачем нужны нормали»). В файле resources.cfg проверьте, что в секции General указано FileSystem=., это заставит Ogre считывать файлы ландшафта из вашего текущего каталога. Вперед! Запустите нашу игру — вы увидите обширную площадку, здесь-то мы и поставим…
Дом, который построил Пол
В LXF83 я писал, что в игре Висельник Чед предусмотрено наличие зданий и возможность игроков входить в них, а там, возможно, вступать в борьбу. Теперь, когда мы разровняли место, пора строить домик в тюдоровском стиле. Чтобы создать сетку дома, нам требуется объект Entity, представляющий наш дом, и SceneNode (оболочка объекта, которая позволит позиционировать дом в пространстве). Мы ставим дом раз навсегда, двигаться ему не надо, поэтому просто объявим Entity в chad.h. Добавьте строку в chad.h сразу за определением m_OceanFlowNum:
Entity* HouseEntity
Теперь добавьте этот код в конец метода createScene() файла chad.cpp:
HouseEntity = m_SceneMgr->createEntity("house", "tudorhouse.mesh"); SceneNode* HouseNode = m_SceneMgr->getRootSceneNode()-> createChildSceneNode("HouseNode"); HouseNode->attachObject(HouseEntity); HouseNode->translate(1100,137, 500); HouseNode->scale(0.25,0.125,0.25);
Файл tudorhouse.mesh — один из стандартных сеточных объектов, входящих в Ogre, и он выглядит великолепно. Заметим также, что дом огромный, поэтому я использовал scale() и приспособил его размер к ландшафту. Вот и все, что требовалось для добавления дома в нашу игру, поэтому перезапустите make и полюбуйтесь результатом. Нет, определения столкновений пока нет — оставим его на потом!
Небесное вторжение
Сейчас свет в нашей сцене рассеянный, и у сцены скучный и безжизненный вид. Добавлю-ка я немного простых источников, чтобы вы увидели, как работают свет и тени. Упор сделан на слове «простые», потому что Ogre плоховато работает с освещением неба и земли.
Потребуется четыре переменных для работы со светом в chad.h; добавим их в конец класса CChadGame:
Light* m_SunLight; Light* m_MoonLight; double m_SunY; double m_SunZ;
Да, мы собираемся создать два света: один для солнца, второй для луны. Для получения простого эффекта смены дня и ночи нам надо вращать два источника света по кругу, чтобы свет плавно перемещался по ландшафту. Также необходимо включить тени. У Ogre есть три типа теней и три типа света. Разница между тенями заключается в скорости: тень низкого качества прорисовывается быстрее всего. Первый тип — SHADOWTYPE_TEXTURE_MODULATIVE, использующий простую текстуру для создания теней в нужных местах. На практике тени получаются грубоватые — сгодятся только для тех, у кого слабая видеокарта, все остальные в восторг не придут. Следующий по качеству тип — SHADOWTYPE_STENCIL_MODULATIVE. Тени выглядят более привлекательно, но создаются в один проход, поэтому результат не идеален. Наконец, SHADOWTYPE_STENCIL_ADDITIVE. Тут тени выглядят превосходно, для каждого источника света построение осуществляется за отдельный проход, поэтому пересечение теней от двух источников будет выглядеть темнее, чем остальные части тени. Как вы понимаете, это довольно сложно, но заманчиво!
Каждый из трех типов источников характеризуется своим способом освещения. Точечный источник излучает свет как Солнце — одинаково во всех направлениях, из определенной точки. Источник направленного света излучает свет в одном направлении и не имеет начальной точки. С нашей позиции на Земле солнце выглядит направленным источником, потому что мы видим его свет, исходящий из одного направления, но не видим его в других направлениях. Наконец, существуют источники узконаправленного света, типа софитов: у них есть начальная точка, направление, их свет слабеет с расстоянием, ширину угла освещения вы назначаете сами.
Оба наших источника, солнце и луна, находятся очень далеко, поэтому они могут считаться источниками направленного света. Не будем пренебрегать деталями — выберем опцию SHADOWTYPE_STENCIL_ADDITIVE, чтобы тени хорошо смотрелись. В последующем коде немного приглушим рассеянное освещение, чтобы заметнее стали дневной и ночной источники света.
Вот код — поместите его в метод createScene():
m_SceneMgr->setAmbientLight( ColourValue(0.35, 0.35, 0.35) ); m_SceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_ADDITIVE); m_SunLight = m_SceneMgr->createLight("Sun"); m_SunLight->setType(Light::LT_DIRECTIONAL); m_SunLight->setDiffuseColour(1.0, 1.0, 1.0); m_SunLight->setSpecularColour(1.0, 1.0, 1.0); m_SunLight->setDirection(Vector3(0, sin(m_SunY), sin(m_SunZ))); m_MoonLight = m_SceneMgr->createLight("Moon"); m_MoonLight->setType(Light::LT_DIRECTIONAL); m_MoonLight->setDiffuseColour(0.3, 0.3, 0.5); m_MoonLight->setSpecularColour(0.0, 0.0, 0.0); m_MoonLight->setDirection(Vector3(0, -sin(m_SunY), sin(m_SunZ)));
Привести луну и солнце в движение можно, отредактировав метод frameStarted(), чтобы метод setDirection() вызывался для каждого источника. Необходимо также изменить переменные m_SunY и m_SunX, заставив их медленно увеличиваться. Вставьте этот код в начало метода frameStarted():
m_SunLight->setDirection(Vector3(0, sin(m_SunY), sin(m_SunZ))); m_MoonLight->setDirection(Vector3(0, -sin(m_SunY), -sin(m_SunZ))); m_SunY += 0.001; m_SunZ += 0.001;
Теперь вы должны увидеть, что здание отбрасывает тень.
Похождения бравого солдата Квейка
Вы помните, что я собирался строить «Тюдоровскую крепость», но пока что мы имеем только невинного вида домик на плоской траве. На крепость не похоже, правда? Сейчас мы это изменим, соорудив внутри заведомо неприветливую обстановку. На последних трех уроках мы играли в песочнице менеджера сцен Ogre для открытого ландшафта, но если наши персонажи намерены разгуливать по зданию, потребуется еще один менеджер сцены — BSP.
BSP означает binary space partition [двоичное разбиение пространства] и позволяет очень быстро загружать и обрабатывать закрытые пространства. Карты BSP используется во многих играх, главным образом в тех, что используют движок Quake, включая Jedi Knight, Soldier of Fortune, Half-life. Проблема с BSP состоит в том, что он не умеет хорошо обрабатывать открытые пространства (включая наш ландшафт), поэтому текущий менеджер сцены тоже придется оставить.
Добавление нового менеджера сцены вводит интересные осложнения в наш игровой движок. Во-первых, необходимо отредактировать файл resources.cfg, чтобы использовался файл карты Quake 3. Сотни карт доступны бесплатно через сеть, но на самом деле демо-версии Ogre уже поставляются с очень красивой картой Chiroptera (доступа для скачивания по адресу http://simland.planetquake.gamespy.com/pages/q3maps/chiroptera.htm), ею мы и воспользуемся.
Во-вторых, необходимо разделить методы createScene() и frameStarted() на CreateIndoorScene(), createOutdoorScene(), frameStartedInside(), frameStartedOutside(). Проще всего это сделать, переименовав createScene() и frameStarted(), например, как createOutdoorScene() и frameStartedOutside(), а затем создав заглушки для createIndoorScene() и frameStartedIndoor(). Также потребуется объявить новые методы в chad.h. Сделав это, добавьте строчку в chad.h в конце класса CChadGame:
int scenemanager;
Переменная будет показывать, снаружи мы или внутри. Теперь можно написать новый метод frameStarted() для автоматического вызова нужного «подметода», нечто вроде такого:
bool CChadGame::frameStarted(const FrameEvent& evt) { switch (scenemanager) { case ST_EXTERIOR_CLOSE: return frameStartedOutside(); break; case ST_INTERIOR: return frameStartedInside(); break; } return true; }
Переменную scenemanager необходимо переустанавливать, как только происходит смена типа сцены. Для открытого пространства необходимо добавить эту строку в начале метода createOutdoorScene():
scenemanager = ST_EXTERIOR_CLOSE;
Метод frameStartedInside() новый, но ничего особенного не делает - в данный момент он должен представлять урезанную версию метода frameStartedOutside() и обрабатывать простой ввод от клавиатуры. Вот пример подобного кода:
bool CChadGame::frameStartedInside() { m_InputReader->capture(); if(m_InputReader->isKeyDown(KC_ESCAPE)) return false; Vector3 translateVector = Vector3::ZERO; float playerspeed = m_Player->getSpeed(); if (m_InputReader->isKeyDown(KC_W)) translateVector.z =-playerspeed * 5; if (m_InputReader->isKeyDown(KC_S)) translateVector.z =+playerspeed * 5; if (m_InputReader->isKeyDown(KC_A)) translateVector.x =-playerspeed * 5; if (m_InputReader->isKeyDown(KC_D)) translateVector.x =+playerspeed * 5; if (m_InputReader->isKeyDown(KC_F1)) createIndoorScene(); if (m_InputReader->isKeyDown(KC_F2)) createOutdoorScene(); m_Camera->moveRelative(translateVector); return true; }
Вы заметите, что переменная playerspeed умножена на пять — дело в том, что карта Quake огромна, и прогулка с прежней скоростью превратилась бы в вечность. Если такое решение вы находите примитивным, попробуйте увеличить ландшафт, удалив вызов scale() для дома, а затем выберите значение скорости, пригодное везде.
Теперь перейдем к трудной задаче: загрузке карты Quake. Это делается в методе createIndoorScene(), который загрузит нашу карту и создаст новую камеру и область просмотра. Прежде чем перейти к другому менеджеру сцены, необходимо удалить камеры и области просмотра, ассоциированные с текущим менеджером. Вот этот код:
void CChadGame::createIndoorScene() { scenemanager = ST_INTERIOR; if (m_SceneMgr != NULL) { m_Ogre->getAutoCreatedWindow()->removeAllViewports(); m_SceneMgr->destroyAllCameras(); } m_SceneMgr = m_Ogre->createSceneManager("BspSceneManager"); ResourceGroupManager::getSingleton().linkWorldGeometryToResourceGroup( ResourceGroupManager::getSingleton().getWorldResourceGroupName(), "maps/chiropteradm.bsp", m_SceneMgr); ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); ResourceGroupManager::getSingleton().clearResourceGroup(ResourceGroupManager::getSingleton().getWorldResourceGroupName()); ResourceGroupManager::getSingleton().loadResourceGroup(ResourceGroupManager::getSingleton().getWorldResourceGroupName(), false, true); m_Camera = m_SceneMgr->createCamera("Player Cam"); m_Camera->setNearClipDistance(4); m_Camera->setFarClipDistance(4000); m_Viewport = m_Ogre->getAutoCreatedWindow()->addViewport(m_Camera); m_Viewport->setBackgroundColour(ColourValue(0, 0, 0)); ViewPoint vp = m_SceneMgr->getSuggestedViewpoint(true); m_Camera->setPosition(vp.position); m_Camera->pitch(Degree(90)); m_Camera->rotate(vp.orientation); m_Camera->setFixedYawAxis(true, Vector3::UNIT_Z); }
Установка значений «ближней» и «дальней» дистанций обрезания необходима, потому что наша камера работает внутри замкнутой области, и нужно фокусироваться на вещах, расположенных близко к камере. Метод getSuggestedViewport() считывает произвольную начальную позицию игрока на карте и устанавливает камеру в эту точку. Нам необходимо установить оси камеры pitch и yaw потому, что Quake использует для плоскости пола координаты Х и Y, а Z — для высоты, а мы обычно используем для пола X и Z и Y — для высоты.
Мы еще не закончили: понадобится добавить две строки в начало метода createOutdoorScene(), чтобы Ogre обновлял все свои ресурсы при загрузке сцены в открытом пространстве. Без них закрытая сцена обновит ресурсы и выгрузит все ресурсы открытой сцены. Итак, добавляем две строки:
ResourceGroupManager::getSingleton().clearResourceGroup(ResourceGroupManager::getSingleton().getWorldResourceGroupName()); ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
Наконец, проверим, что вызов createScene() в конструкторе CChadGame() (который находится в начале chad.cpp) заменен на createOutdoorScene(). Ну вот и все: запустите make, затем chad. Посмотрим, заметите ли вы разницу….
Сложный вопрос
ОК, разницы нет — по крайней мере, с точки зрения игрока. Это потому, что мы написали код обработки для закрытой сцены, но не написали кода, загружающего эту сцену. Вы вольны написать код, способный обнаруживать, что игрок входит в дверь дома, а мы напишем более простую (лишь бы работала) «клавишную реализацию переключения сцен», которую можно использовать в любом месте ландшафта.
У нас уже есть функции обработки клавиатуры frameStaretd*(), поэтому остается добавить в них поддержку двух дополнительных клавиш: F1 (для загрузки закрытой сцены) и F2 (для загрузки открытой сцены). Код, который загружает и выгружает ресурсы, камеры и области просмотра, расположен в методах create*Scene(), поэтому о них беспокоиться не надо. Все, что нам надо сделать, это вызвать требуемый метод create*Scene(), например, так:
if (m_InputReader->isKeyDown(KC_F1)) createIndoorScene(); if (m_InputReader->isKeyDown(KC_F2)) createOutdoorScene();
Поместите эти две строчки вместе с остальными вызовами isKeyDown(), перезапустите make, затем саму игру. На этот раз вы должны попасть на карту Quake и исследовать ваш новый интерьер, просто нажав клавишу F1 и пару секунд подождав, пока загрузятся необходимые ресурсы Ogre.
Мы рассмотрели в этом руководстве много нового. Труднее всего уместить в голове переход от одного менеджера сцены к нескольким; все остальное сравнительно просто! Я надеюсь, что вам понравилось, как легко Ogre создает освещение и тени и работает с уровнями BSP, хотя покамест некоторые недостатки игры могут и раздражать — отсутствие обнаружения столкновений, плохой ввод, небо, на котором не сказывается освещение, и так далее. Часть недостатков вы можете исправить сами, ведь это руководство написано для того, чтобы игру программировали вы, а не я. Но с остальными мы разберемся вместе. До следующего раза!