Левое изображение показывает несколько
Рисунок 2.1. Левое изображение показывает несколько объектов, образующих трехмерную сцену и нацеленную на них камеру. Справа показано двухмерное изображение, созданное на основании того, что «видит» камера.
Цели |
Узнать, как в Direct3D представляются трехмерные объекты.
Изучить моделирование виртуальной камеры.
Познакомиться с конвейером визуализации — процессом генерации двухмерного изображения на основании математического описания трехмерного мира.
| |
Локальное пространство
2.3.1. Локальное пространство
Локальное пространство (local space) или пространство моделирования (modeling space)— это та система координат, в которой мы описываем объект в виде списка треугольных граней. Локальное пространство полезно потому что оно упрощает процесс моделирования. Создавать модель в ее собственной, локальной системе координат проще чем встраивать ее непосредственно в сцену. Локальное пространство позволяет нам создавать модели не заботясь об их расположении, размере или ориентации относительно других объектов сцены.
Мировое пространство
2.3.2. Мировое пространство
После того, как мы создали различные модели, каждая из которых описана в своей собственной локальной системе координат, нам надо собрать их воедино в сцену, описанную в единой, глобальной (мировой) системе координат (world space). Объекты преобразуются из локального пространства в мировое с помощью процесса, называемого мировым преобразованием (world transform), который обычно состоит из операций перемещения, вращения и масштабирования в результате которых модель приобретает то местоположние, ориентацию и размеры, которые должны быть у нее в сцене. Мировое преобразование задает взаимосвязь между всеми объектами мира в части их местоположения, размера и ориентации.
Несколько трехмерных объектов, описанных в единой мировой системе координат
Рисунок 2.9. Несколько трехмерных объектов, описанных в единой мировой системе координат
|
<
Мировое преобразование представляется с помощью матрицы и устанавливается в Direct3D с помощью метода IDirect3DDevice9::SetTransform, где в качестве вида преобразования указано D3DTS_WORLD. Предположим, мы хотим поместить куб в точку (–3,2, 6) мирового пространства, а сферу — в точку (5, 0, –2). Для этого следует написать:
// Создаем матрицу мирового преобразования для куба, // которая содержит только перемещение D3DXMATRIX cubeWorldMatrix; D3DXMatrixTranslation(&cubeWorldMatrix, -3.0f, 2.0f, 6.0f);
// Создаем матрицу мирового преобразования для сферы, // которая содержит только перемещение D3DXMATRIX sphereWorldMatrix; D3DXMatrixTranslation(&sphereWorldMatrix, 5.0f, 0.0f, -2.0f);
// Устанавливаем преобразование для куба Device->SetTransform(D3DTS_WORLD, &cubeWorldMatrix); drawCube(); // рисуем куб
// Теперь, поскольку сфера использует другую матрицу мирового // преобразования, мы должны изменить мировое преобразование для сферы. // Если не сделать этого, сфера будет рисоваться с использованием // предыдущей матрицы мирового преобразования, которая предназначалась // для куба. Device->SetTransform(D3DTS_WORLD, &sphereWorldMatrix); drawSphere(); // рисуем сферу
Это очень упрощенный пример, поскольку обычно объекты приходится не только перемещать, но и вращать и масштабировать, но он показывает как работает мировое преобразование.
Объект с фронтальными и обратными полигонами
Рисунок 2.11. Объект с фронтальными и обратными полигонами
|
Исследовав Рисунок 2.11 мы увидим, что фронтальные полигоны скрывают находящиеся за ними обратные полигоны. Direct3D может извлечь из этого пользу отбросив (исключив из дальнейшей обработки) обратные полигоны; этот процесс называется удалением невидимых граней (backface culling). На Рисунок 2.12 показан тот же самый объект, но уже после удаления невидимых граней. Камера будет все равно показывать ту же самую сцену, поскольку обратные грани скрыты и в любом случае их нельзя увидеть.
Освещение
2.3.5. Освещение
Источники света описываются в мировом пространстве, но потом преобразуются в пространство вида при соответствующем преобразовании сцены. В пространстве вида источники света применяются для освещения объектов сцены, что позволяет получить более реалистичный вид. Работа с освещением в фиксированном конвейере визуализации подробно рассматривается в главе 5. Позднее, в части IV, мы реализуем собственную схему освещения с использованием программируемого конвейера.
Отсечение
2.3.6. Отсечение
Теперь нам необходимо отбросить геометрию, которая находится вне видимого пространства; этот процесс называется отсечением (clipping). Есть три варианта размещения треугольной грани относительно усеченной пирамиды видимого пространства:
Полностью внутри— Если треугольник полностью находится внутри области видимого пространства, он переходит на следующий этап.
Полностью снаружи — если треугольник находится полностью вне пирамиды видимого пространства, он исключается из процесса дальнейшей обработки.
Частично внутри (частично снаружи) — если внутри пирамиды видимого пространства находится только часть треугольника, то он разбивается на две части. Часть, которая находится внутри пирамиды видимого пространства остается, а часть, которая находится снаружи — отбрасывается.
Все три рассмотренных варианта изображены на Рисунок 2.13.
Отсечение геометрии, находящейся вне видимого пространства
Рисунок 2.13. Отсечение геометрии, находящейся вне видимого пространства
|
Представление моделей
Сценой (scene) называется набор объектов или моделей. Объект представляется с помощью сетки с треугольными ячейками (triangle mesh), как показано на Рисунок 2.2. Отдельные треугольники сетки — это строительные блоки с помощью которых мы моделируем объекты. Чтобы сослаться на треугольник сетки мы будем использовать следующие взаимозаменяемые термины: полигон, примитив и ячейка сетки. (Треугольники являются примитивами, но Direct3D поддерживает еще два вида примитивов: линии и точки. Однако, поскольку линии и точки не слишком полезны для моделирования трехмерных твердых объектов, мы опустим обсуждение этих примитивов. О некоторых применениях точек мы поговорим в главе 14.)
Преобразование из мирового пространства
Рисунок 2.10. Преобразование из мирового пространства в пространство вида. В результате этого преобразования камера перемещается в начало координат и поворачивается так, чтобы быть направленной вдоль положительного направления оси Z. Обратите внимание, что все объекты сцены также подвергаются этому преобразованию, так что формируемый камерой вид сцены не изменяется
Чтобы вычислить матрицу преобразования вида можно воспользоваться следующей функцией библиотеки D3DX: D3DXMATRIX *D3DXMatrixLookAtLH( D3DXMATRIX* pOut, // указатель на возвращаемую матрицу преобразования CONST D3DXVECTOR3* pEye, // местоположение камеры в сцене CONST D3DXVECTOR3* pAt, // точка, на которую направлена камера CONST D3DXVECTOR3* pUp // вектор, задающий направление вверх – (0, 1, 0) );
Параметр pEye задает точку пространства, в которой располагается камера. Параметр pAt задает ту точку сцены, на которую направлена камера. Параметр pUp — это вектор, который задает направление «вверх» для нашей сцены. Почти всегда это вектор, совпадающий с осью Y — (0, 1, 0).
Предположим, мы разместили камеру в точке (5, 3, –10) и направили ее на начало системы координат нашей сцены (0, 0, 0). Чтобы создать матрицу преобразования пространства вида, надо написать: D3DXVECTOR3 position(5.0f, 3.0f, –10.0f); D3DXVECTOR3 targetPoint(0.0f, 0.0f, 0.0f); D3DXVECTOR3 worldUp(0.0f, 1.0f, 0.0f);
D3DXMATRIX V; D3DXMatrixLookAtLH(&V, &position, &targetPoint, &worldUp);
Преобразование пространства вида устанавливается с помощью метода IDirect3DDevice9::SetTransform, у которого в качестве типа преобразования указано D3DTS_VIEW: Device->SetTransform(D3DTS_VIEW, &V);
Преобразование порта просмотра
2.3.8. Преобразование порта просмотра
Преобразование порта просмотра отвечает за преобразование координат из окна проекции в прямоугольную область экрана, которая называется портом просмотра (viewport). Для игр портом просмотра обычно является весь экран. Однако, если приложение работает в окнонном режиме, портом просмотра является часть экрана или клиентская область. Прямоугольник порта просмотра описывается относительно содержащего его окна и задается в оконных координатах (Рисунок 2.16).
Прямоугольник, образованный из двух треугольников
Рисунок 2.4. Прямоугольник, образованный из двух треугольников
|
Vertex rect[6] = {v0, v1, v2, // треугольник 0 v0, v2, v3}; // треугольник 1
ПРИМЕЧАНИЕ
Порядок, в котором задаются вершины треугольника очень важен и называется порядком обхода (winding order). Подробнее об этом мы поговорим в разделе2.3.4. |
Прямоугольник порта просмотра
Рисунок 2.16. Прямоугольник порта просмотра
<
В Direct3D порт просмотра представляется структурой D3DVIEWPORT9. Ее объявление выглядит так:
typedef struct _D3DVIEWPORT9 { DWORD X; DWORD Y; DWORD Width; DWORD Height; DWORD MinZ; DWORD MaxZ; } D3DVIEWPORT9;
Первые четыре члена данных описывают прямоугольник порта просмотра относительно содержащего его окна. Переменная MinZ задает минимальное значение буфера глубины, а переменная MaxZ— максимальное значение буфера глубины. Direct3D использует значения буфера глубины в диапазоне от нуля до единицы, поэтому переменным MinZ и MaxZ следует присваивать эти значения, если только вы не хотите реализовать какие-нибудь спецэффекты.
После инициализации структуры D3DVIEWPORT9, мы устанавливаем порт просмотра Direct3D следующим образом:
D3DVIEWPORT9 vp = { 0, 0, 640, 480, 0, 1 }; Device->SetViewport(&vp);
Direct3D выполняет преобразование порта просмотра за нас автоматически, но для справки мы приведем матрицу, описывающую это преобразование. Переменные в ней соответствуют одноименным членам данных структуры D3DVIEWPORT9.
Проекция
2.3.7. Проекция
Для пространства вида остается задача получения двухмерного представления трехмерной сцены. Процесс перехода от n-мерного пространства к (n–1)-мерному называется проекцией (projection). Существует множество способов выполнить проекцию, но нас интересует один частный случай, называемый перспективной проекцией (perspective projection). Перспективная проекция выполняется таким образом, что объекты, расположенные дальше от камеры выглядят меньше, чем объекты того же размера, находящиеся ближе к камере. Этот тип проекции позволяет представить трехмерную сцену в виде двухмерного изображения. На Рисунок 2.14 показана точка в трехмерном пространстве, проецируемая в на плоскость проекции с использованием перспективной проекции.
Проекция точки в трехмерном пространстве в окно проекции
Рисунок 2.14. Проекция точки в трехмерном пространстве в окно проекции
|
Преобразование проекции описывает наше видимое пространство (усеченную пирамиду) и отвечает за проецирование геометрии из него в окно проекции. Матрица проекции сложная и мы не будем обсуждать формулы для ее получения. Вместо этого воспользуемся следующей функцией библиотеки D3DX, которая создает матрицу проекции на основании описания усеченной пирамиды видимого пространства. D3DXMATRIX *D3DXMatrixPerspectiveFovLH( D3DXMATRIX* pOut, // возвращает матрицу проекции FLOAT fovY, // вертикальный угол поля зрения в радианах FLOAT Aspect, // форматное соотношение = ширина / высота FLOAT zn, // расстояние до передней полскости FLOAT zf // расстояние до задней плоскости );
Пространство вида
2.3.3. Пространство вида
В мировом пространстве геометрия объектов и камера описаны относительно одной мировой системы координат, как показано на Рисунок 2.10. Однако, проекция и другие операции станут более трудными и менее эффективными, если камера не занимает определенное местоположение и не ориентирована требуемым образом. Чтобы упростить вычисления мы перемещаем камеру в начало координат и поворачиваем ее таким образом, чтобы она была направлена вдоль положительного направления оси Z. Вместе с камерой перемещаются и поворачиваются и все образующие сцену объекты, так что вид сцены остается неизменным. Данное преобразование называется преобразованием пространства вида (view space transformation), и после него говорят, что объекты расположены в пространстве вида (view space).
Растеризация
2.3.9. Растеризация
После преобразования вершин в экранные координаты, у нас образуется список двухмерных треугольников. Этап растеризации отвечает за вычисление цветов отдельных пикселей, образующих треугольник (Рисунок 2.17).
Растеризация треугольника на экране
Рисунок 2.17. Растеризация треугольника на экране
|
Процесс растеризации требует выполнения огромного объема вычислений в выполнение которых всегда вовлекается процессор видеокарты. Конечным результатом этапа растеризации является двухмерное изображение, выводимое на экран монитора.
Сцена после отбрасывания обратных граней
Рисунок 2.12. Сцена после отбрасывания обратных граней
|
<
Конечно, чтобы выполнить эту работу, Direct3D необходимо знать, какой полигон является фронтальным, а какой— обратным. По умолчанию Direct3D считает фронтальными гранями те треугольники, у которых порядок обхода вершин (в пространстве вида) задан по часовой стрелке. Треугольники, у которых порядок обхода вершин задан против часовой стрелки (опять же в пространстве вида) считаются обратными гранями.
ПРИМЕЧАНИЕ
| Обратите внимание, что мы говорим «в пространстве вида». Это вызвано тем, что при повороте треугольника на 180 градусов порядок обхода вершин у него меняется на противоположный. Следовательно, треугольник у которого порядок обхода вершин в локальном пространстве был по часовой стрелке, может сменить порядок обхода вершин в пространстве вида, поскольку в процессе преобразований выполнялось вращение объектов. |
Если по каким-то причинам вас не устраивает принятый по умолчанию вариант отбрасывания обратных граней, можно изменить его путем изменения режима визуализации D3DRS_CULLMODE.
Device->SetRenderState(D3DRS_CULLMODE, Value);
где Value может принимать одно из следующих значений:
D3DCULL_NONE — Удаление обратных граней выключено.
D3DCULL_CW — Отбрасываются треугольники с порядком обхода вершин по часовой стрелке.
D3DCULL_CCW — Отбрасываются треугольники с порядком обхода вершин против часовой стрелки. Это значение по умолчанию.
Составленный из треугольников куб
Рисунок 2.5. Составленный из треугольников куб
<
Для решения этой проблемы мы добавим концепцию индексов (indices). Она действует следующим образом: мы создаем список вершин и список индексов. В списке вершин перечисляются все уникальные вершины, а список индексов содержит последовательность номеров (индексов) вершин из списка вершин, показывающую как объединяются вершины для формирования треугольников. Для примера с прямоугольником список вершин мог бы выглядеть так:
Vertex vertexList[4] = {v0, v1, v2, v3};
Тогда список индексов, описывающий как из имеющихся вершин формируются два треугольника, будет выглядеть так:
WORD indexList[6] = {0, 1, 2, // треугольник 0 0, 2, 3}; // треугольник 1
Если облечь код в слова, определение массива indexList говорит, что треугольник 0 образован нулевым (vertexList[0]), первым (vertexList[1]) и вторым (vertexList[2]) элементами списка вершин, а треугольник 1 образован нулевым (vertexList[0]), вторым (vertexList[2]) и третьим (vertexList[3]) элементами списка вершин.
Треугольник, заданный тремя вершинами
Рисунок 2.3. Треугольник, заданный тремя вершинами
|
Треугольники
2.1.2. Треугольники
Треугольники являются основными строительными блоками трехмерных объектов. Чтобы сконструировать объект мы создаем список треугольников, описывающих его форму и контуры. Список треугольников содержит данные каждого треугольника, который мы будем отображать. Например, чтобы создать прямоугольник, мы разбиваем его на два треугольника, как показано на Рисунок 2.4, и задаем вершины каждого треугольника.
Удаление невидимых поверхностей
2.3.4. Удаление невидимых поверхностей
У полигона есть две стороны; одну из них мы будем называть лицевой (front), а другую— обратной (back). Обычно обратные стороны полигонов никогда не видны. Это происходит из-за того, что большинство объектов сцены являются сплошными объемными телами, такими как ящики, цилиндры, цистерны, персонажи и т.д. и камера никогда не попадает внутрь занимаемого объектом пространства. Поэтому камера никогда не может увидеть обратные стороны полигонов. Это очень важно знать, потому что если мы дадим возможность видеть обратные стороны полигонов, удаление невидимых поверхностей не будет работать.
На Рисунок 2.11 показан объект в пространстве вида, лицевая сторона каждой грани которого помечена стрелкой. Полигон, лицевая сторона которого обращена к камере, называется фронтальным полигоном (front facing polygon), а полигон, лицевая сторона которого обращена от камеры, называется обратным полигоном (back facing polygon).
Упрощенная схема конвейера визуализации
Рисунок 2.7. Упрощенная схема конвейера визуализации
Несколько этапов конвейера выполняют преобразование из одной системы координат в другую. Эти преобразования выполняются с помощью матриц. Direct3D выполняет вычисления преобразований за нас. Это полезно, потому что преобразования могут выполняться аппаратурой, если ваша видеокарта поддерживает аппаратную обработку преобразований. Если мы используем для преобразований Direct3D, нам надо только предоставить матрицу преобразования, которая описывает преобразования, необходимые для перехода от одной системы координат к другой. Мы задаем матрицу с помощью метода IDirect3DDevice->SetTransform. Он получает параметр, описывающий тип преобразования и указатель на матрицу преобразования. Например, на Рисунок 2.7, для преобразования, необходимого для перехода от локального пространства к мировому, мы должны написать: Device->SetTransform(D3DTS_WORLD, &worldMatrix);
В последующих разделах, где исследуется каждый этап конвейера визуализации, мы узнаем больше об этом методе.
Усеченная пирамида, определяющая область пространства, которую «видит» камера
Рисунок 2.6. Усеченная пирамида, определяющая область пространства, которую «видит» камера
Область видимого пространства преставляет собой усеченную пирамиду (frustum) и определяется углами поля зрения, передней и задней плоскостями. Причины использования усеченной пирамиды станут ясны, если принять во внимание, что экран на котором отображается сцена — прямоугольный. Объекты, которые не находятся внутри заданного пространства невидимы и должны быть исключены из процесса дальнейшей обработки. Процесс исключения таких данных называется отсечением (clipping).
Окно проекции (projection window) — это двухмерная область на которую проецируются находящиеся внутри области видимого пространства трехмерные объекты для создания двухмерного изображения, представляющего трехмерную сцену. Важно помнить, что мы определяем окно проекции таким образом, что координаты его правого верхнего угла будут (1, 1), а координаты левого нижнего угла — (–1, –1).
Для упрощения рисования в программах из этой книги плоскость проекции (плоскость в которой расположено окно проекции) и передняя плоскость совпадают. Также обратите внимание, что Direct3D определяет плоскость проекции как плоскость z = 1.
Виртуальная камера
Камера определяет какую часть мира может видеть зритель и, следовательно, для какой части мира нам надо создавать ее двухмерное изображение. Камера позиционируется и ориентируется в пространстве и определяет видимую облать пространства. Схема используемой нами модели камеры показана на Рисунок 2.6.
| | |