netlib.narod.ru< Назад | Оглавление | Далее >

Добавление трехмерных объектов к двухмерному миру

В таких играх, как Final Fantasy и Parasite Eve, созданных Square Co. Ltd, вы можете наслаждаться красотой предварительно визуализированных фоновых изображений и в то же время использовать трехмерные модели игровых объектов. Смешивание терхмерной и двухмерной графики является наиболее охраняемым секретом игровых компаний, и эту тайну стоит раскрыть.

Если вы никогда не видели трехмерную графику в двухмерном движке, о которой я говорю, взгляните на рис. 9.3, где показан результат работы движка, находящегося на прилагаемом к книге CD-ROM (в папке \BookCode\Chap09\3Din2D). На иллюстрации изображен статический двухмерный фон, поверх которого расположен трехмерный объект. Трехмерный объект может свободно перемещаться по фону так, будто тот тоже трехмерный.


Рис. 9.3. Движок, совмещающий трехмерную и двухмерную графику

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


Фон — это предварительно визуализированное растровое изображение, которое отображается в каждом кадре с использованием техники двухмерного копирования, обсуждавшейся в главе 7. Если более точно, объект ID3DXSprite выполняет рисование растрового изображения (загруженного в объект IDirect3DTexture9). Для трехмерных объектов движка замечательно подходит объект ID3DXMesh, не говоря уж о классах графического ядра cMesh и cObject, которые помогут вам и при загрузке и при отображении.

Итак, с одной стороны у вас есть предварительно визуализированный фон, помещаемый на экран в каждом кадре, а с другой стороны у вас есть трехмерные объекты, рисуемые в сцене. Кажется все просто? Нет, по крайней мере на первый взгляд.

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

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

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

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

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

Теперь вы готовы конструировать программу 3Din2D; а начнем мы с получения изображения фона и сетки, с которой будем работать.

Работа с двухмерным фоном

Как я упоминал в предыдущем разделе, вы разрабатываете двухмерный фон с помощью программы трехмерного моделирования, такой как gameSpace Light (а не в графическом редакторе, поскольку вам понадобятся данные о полигонах из программы моделирования). На рис. 9.4 представлены простая сетка и итоговый результат визуализации.


Рис. 9.4. Вы создаете сетку в программе трехмерного моделирования и визуализируете фон

Рис. 9.4. Вы создаете сетку в программе трехмерного моделирования и визуализируете фон


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

Когда смоделированная сцена визуализирована, вы сохраняете ее на диск в виде растрового изображения. Файл с растровым изображением необходимо разделить на текстуры меньшего размера. На рис. 9.5 снова показан пример фона, но на этот раз разделенного на шесть небольших прямоугольных кусков (текстур).


Рис. 9.5. Фон разделен на шесть небольших прямоугольных кусков

Рис. 9.5. Фон разделен на шесть небольших прямоугольных кусков


 

ПРИМЕЧАНИЕ
Если чувствуете себя храбрым, попытайтесь создать класс, который загружает растровое изображение произвольного размера и делит его на фрагменты. Благодаря этому вам не потребуется обращаться к графическому редактору для разрезания изображения, что упростит загрузку изображений с различным разрешением.

Вам необходимо разделить фоновое изображение на рис. 9.5 на несколько текстур, чтобы Direct3D смог обработать их. В данном случае размеры фонового изображения 640 × 480, так что размеры текстур 256 × 256 (для фрагментов 1, 2, 4 и 5) и 128 × 256 (для фрагментов 3 и 6). Обратите внимание, что если фрагмент недостаточно большой, вам необходимо увеличить его, чтобы он соответствовал допустимому размеру текстуры (например, фрагменты 4, 5 и 6 должны быть увеличены до высоты в 256 пикселов).

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

// Graphics = ранее инициализированный объект cGraphics
char     Filename[81]; // Имя файла загружаемой текстуры
cTexture Textures[6];  // Объекты для хранения текстур

for(short i = 0; i < 6; i++) {

    // Создаем имя файла с текстурой
    sprintf(Filename, "Scene%u.bmp", i+1);

    // Загружаем текстуру
    Textures[i].Load(&Graphics, Filename);
}

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

Работа с сеткой сцены

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

Когда я говорю «упрощенная», я действительно подразумеваю упрощение. Поскольку для создания Z-значений сетка должна будет визуализироваться в каждом кадре, то чем меньше полигонов вы используете, тем лучше. Однако, вам требуется достаточное количество полигонов, чтобы гарантировать корректное смешивание для трехмерных объектов. Чтобы увидеть, о чем я говорю, взгляните на рис. 9.6, где показано визуализированное изображение сцены, исходная сетка сцены и ее упрощенный вариант.


Рис. 9.6. Визуализированное изображение, используемое в качестве фона...

Рис. 9.6. Визуализированное изображение, используемое в качестве фона (слева). Исходная сетка, применявшаяся для визуализации фона в программе трехмерного моделирования (в центре). Упрощенная сетка, используемая для Z-буферизации и проверки пересечений (справа)


 

СОВЕТ
Для упрощенной сетки используйте только два материала (не текстуры). Первый материал представляет области с полигонами, которые нарисованы на фоне, а второй — скрытые полигоны, применяемые для обнаружения столкновений. Следовательно, во втором материале используется альфа-значение 0.0 (означающее, что он невидим и не будет визуализироваться).

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

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


Рис. 9.7. У сетки слева много полигонов и она используется при визуализации фона...

Рис. 9.7. У сетки слева много полигонов и она используется при визуализации фона. У упрощенной сетки справа недостаточно полигонов для точного соответствия оригинальной сетке, поэтому трехмерные объекты неправильно наложатся на исключенные пикселы


 

СОВЕТ
Чтобы сократить количество полигонов в упрощенной сетке, отбросьте те грани, которые никогда не будут видимы и не будут использоваться для проверки столкновений. Также рисуйте только те полигоны, которые действительно могут закрывать трехмерные объекты. Например, если на фоне у вас есть ящик, к которому персонаж игрока никогда не сможет подойти близко, не надо рисовать его в упрощенной сетке. Демонстрационная программа 3Din2D с прилагаемого к книге CD-ROM (находящаяся в папке \BookCode\Chap09\3Din2D) показывает, что использование упрощенных сеток и трехмерных объектов позволяет добиться хороших эффектов, поскольку надо визуализировать только один объект на переднем плане.

Ладно, вы завершили тяжелую работу и создали упрощенную сетку вашей сцены. Упрощенная сетка должна попасть в ваш движок, так что двинемся дальше и преобразуем ее в X-файл. Я сохраняю сетку в файл формата .3DS (совместимый со многими программами моделирования), а затем использую утилиту конвертирования от Microsoft (conv3ds.exe), поставляемую вместе с DirectX 9 SDK.

СОВЕТ
Чтобы использовать conv3ds.exe для конвертации из файла .3DS в X-файл достаточно ввести в окне интерфейса командной строки следующую команду:
conv3ds -mx filename.3ds
Показанная команда преобразует сетку из файла filename.3ds в filename.x. X-файл будет содержать одну сетку (все сетки будут объединены вместе) и записан в текстовом формате. Затем вы можете для экономии места удалить из файла все нормали сетки и данные о наложении текстур (эта информация не используется). Вам нужны только вершины сетки, грани, материалы и список шаблонов материалов сетки.

После преобразования файла .3DS (или любого другого файла сетки) в X-файл вы можете использовать классы cMesh и cObject для быстрой и простой загрузки упрощенной сетки:

// Graphics = ранее инициализированный объект cGraphics
cMesh   SceneMesh; // Содержит данные сетки
cObject SceneObj;  // Используется для визуализации сетки

SceneMesh.Load(&Graphics, "Scene.x");
SceneObj.Create(&Graphics, &SceneMesh);

Визуализация сцены

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

  1. Очистить Z-буфер, заполнив его значением 1.0 (и убедиться, что Z-буферизация включена).

  2. Визуализировать упрощенную сетку (это заполнит Z-буфер сцены), пропуская полигоны, у которых альфа-значение материала равно 0.0 (это значит, что они невидимы).

  3. Отключить Z-буфер.

  4. вывести на экран текстуру с фоном, используя ID3DXSprite.

  5. Включить Z-буфер.

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

// Graphics    = ранее инициализированный объект cGraphics
// Textures[6] = ранее загруженные текстуры сцены
// SceneObj    = Объект сетки сцены (cObject)

// Очищаем Z-буфер и начинаем сцену
Graphics.ClearZBuffer();
if(Graphics.BeginScene() == TRUE) {

    // Визуализируем упрощенную сетку для установки Z-значений
    Graphics.EnableZBuffer(TRUE);
    SceneObj.Render();

    // Рисуем фон (составленный из шести текстур)
    Graphics.EnableZBuffer(FALSE); // Отключаем Z-буфер
    Graphics.BeginSprite();
    for(long i = 0; i < 2; i++) {
        for(long j = 0; j < 3; j++)
            Textures[i*3+j].Blit(j*256, i*256);
    }

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

ПРИМЕЧАНИЕ
Большинство современных видеокарт могут работать с текстурами размером до 1024 × 1024 пикселей, а значит, вы можете загрузить в память все фоновое изображение целиком, не деля его на шесть текстур, как я делал в этой главе. Если чувствуете себя достаточно смелым, измените код из этой главы для работы с единой текстурой фона размером 1024 × 1024 пикселей.

    Graphics.EndSprite();

    // Завершаем сцену
    Graphics.EndScene();
}

// Отображаем сцену
Graphics.Display();

 

ВНИМАНИЕ!
Перед визуализацией сцены вам надо сделать еше несколько вещей, таких как создание и ориентирование камеры, чтобы она соответствовала камере, использовавшейся при визуализации изображения фона. Вам надо также, чтобы перспективная проекция соответствовала той, которая была задана в программе моделирования при визуализации изображения фона. Если вы используете 3D Studio Max, то угол зрения обычно составляет 34.516 градусов (или 0.6021124 радиан). Также убедитесь в соответствии форматного соотношения, которое обычно равно 1.333333.

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

Добавление трехмерных объектов

После рисования фона ничто не удерживает вас от рисования трехмерных объектов (сеток) в сцене, поскольку Z-буфер содержит требуемые значения глубины для каждого пикселя. Не стесняйтесь. Рисуйте персонажи, объекты и даже дополнения к фоновому изображению. Например, используйте трехмерные объекты для дверей; они могут открываться, закрываться и блокировать перемещение. Ничего не запрещено, наслаждайтесь!

Столкновения и пересечения

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

Если вы смотрите на исходный код упомянутого ранее в этой главе проекта 3Din2D, то поймете, что я позаимствовал код проверки пересечений из главы 8. В программе 3Din2D я блокирую перемещение персонажа сквозь стены и позволяю ему перемещаться вверх и вниз по лестнице. Сейчас я отсылаю вас к этим прекрасным процедурам движения.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz