netlib.narod.ru | < Назад | Оглавление | Далее > |
Как только мы описали геометрию трехмерной сцены и установили виртуальную камеру, перед нами встает задача формирования двухмерного представления этой сцены на мониторе. Последовательность действий, которые должны быть выполнены для решения этой задачи называется конвейером визуализации (rendering pipeline). На рис. 2.7 представлена упрощенная схема этого конвейера и в последующих разделах мы подробнее обсудим каждый его этап.
Рис. 2.7. Упрощенная схема конвейера визуализации
Несколько этапов конвейера выполняют преобразование из одной системы координат в другую. Эти преобразования выполняются с помощью матриц. Direct3D выполняет вычисления преобразований за нас. Это полезно, потому что преобразования могут выполняться аппаратурой, если ваша видеокарта поддерживает аппаратную обработку преобразований. Если мы используем для преобразований Direct3D, нам надо только предоставить матрицу преобразования, которая описывает преобразования, необходимые для перехода от одной системы координат к другой. Мы задаем матрицу с помощью метода IDirect3DDevice->SetTransform. Он получает параметр, описывающий тип преобразования и указатель на матрицу преобразования. Например, на рис. 2.7, для преобразования, необходимого для перехода от локального пространства к мировому, мы должны написать:
Device->SetTransform(D3DTS_WORLD, &worldMatrix);
В последующих разделах, где исследуется каждый этап конвейера визуализации, мы узнаем больше об этом методе.
Локальное пространство (local space) или пространство моделирования (modeling space) — это та система координат, в которой мы описываем объект в виде списка треугольных граней. Локальное пространство полезно потому что оно упрощает процесс моделирования. Создавать модель в ее собственной, локальной системе координат проще чем встраивать ее непосредственно в сцену. Локальное пространство позволяет нам создавать модели не заботясь об их расположении, размере или ориентации относительно других объектов сцены.
Рис. 2.8. Чайник, описанный в его собственной, локальной системе координат |
После того, как мы создали различные модели, каждая из которых описана в своей собственной локальной системе координат, нам надо собрать их воедино в сцену, описанную в единой, глобальной (мировой) системе координат (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.10. Однако, проекция и другие операции станут более трудными и менее эффективными, если камера не занимает определенное местоположение и не ориентирована требуемым образом. Чтобы упростить вычисления мы перемещаем камеру в начало координат и поворачиваем ее таким образом, чтобы она была направлена вдоль положительного направления оси Z. Вместе с камерой перемещаются и поворачиваются и все образующие сцену объекты, так что вид сцены остается неизменным. Данное преобразование называется преобразованием пространства вида (view space transformation), и после него говорят, что объекты расположены в пространстве вида (view space).
Рис. 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);
У полигона есть две стороны; одну из них мы будем называть лицевой (front), а другую — обратной (back). Обычно обратные стороны полигонов никогда не видны. Это происходит из-за того, что большинство объектов сцены являются сплошными объемными телами, такими как ящики, цилиндры, цистерны, персонажи и т.д. и камера никогда не попадает внутрь занимаемого объектом пространства. Поэтому камера никогда не может увидеть обратные стороны полигонов. Это очень важно знать, потому что если мы дадим возможность видеть обратные стороны полигонов, удаление невидимых поверхностей не будет работать.
На рис. 2.11 показан объект в пространстве вида, лицевая сторона каждой грани которого помечена стрелкой. Полигон, лицевая сторона которого обращена к камере, называется фронтальным полигоном (front facing polygon), а полигон, лицевая сторона которого обращена от камеры, называется обратным полигоном (back facing polygon).
Рис. 2.11. Объект с фронтальными и обратными полигонами |
Исследовав рис. 2.11 мы увидим, что фронтальные полигоны скрывают находящиеся за ними обратные полигоны. Direct3D может извлечь из этого пользу отбросив (исключив из дальнейшей обработки) обратные полигоны; этот процесс называется удалением невидимых граней (backface culling). На рис. 2.12 показан тот же самый объект, но уже после удаления невидимых граней. Камера будет все равно показывать ту же самую сцену, поскольку обратные грани скрыты и в любом случае их нельзя увидеть.
Рис. 2.12. Сцена после отбрасывания обратных граней |
Конечно, чтобы выполнить эту работу, Direct3D необходимо знать, какой полигон является фронтальным, а какой — обратным. По умолчанию Direct3D считает фронтальными гранями те треугольники, у которых порядок обхода вершин (в пространстве вида) задан по часовой стрелке. Треугольники, у которых порядок обхода вершин задан против часовой стрелки (опять же в пространстве вида) считаются обратными гранями.
Если по каким-то причинам вас не устраивает принятый по умолчанию вариант отбрасывания обратных граней, можно изменить его путем изменения режима визуализации D3DRS_CULLMODE.
Device->SetRenderState(D3DRS_CULLMODE, Value);
где Value может принимать одно из следующих значений:
D3DCULL_NONE — Удаление обратных граней выключено.
D3DCULL_CW — Отбрасываются треугольники с порядком обхода вершин по часовой стрелке.
D3DCULL_CCW — Отбрасываются треугольники с порядком обхода вершин против часовой стрелки. Это значение по умолчанию.
Источники света описываются в мировом пространстве, но потом преобразуются в пространство вида при соответствующем преобразовании сцены. В пространстве вида источники света применяются для освещения объектов сцены, что позволяет получить более реалистичный вид. Работа с освещением в фиксированном конвейере визуализации подробно рассматривается в главе 5. Позднее, в части IV, мы реализуем собственную схему освещения с использованием программируемого конвейера.
Теперь нам необходимо отбросить геометрию, которая находится вне видимого пространства; этот процесс называется отсечением (clipping). Есть три варианта размещения треугольной грани относительно усеченной пирамиды видимого пространства:
Полностью внутри — Если треугольник полностью находится внутри области видимого пространства, он переходит на следующий этап.
Полностью снаружи — если треугольник находится полностью вне пирамиды видимого пространства, он исключается из процесса дальнейшей обработки.
Частично внутри (частично снаружи) — если внутри пирамиды видимого пространства находится только часть треугольника, то он разбивается на две части. Часть, которая находится внутри пирамиды видимого пространства остается, а часть, которая находится снаружи — отбрасывается.
Все три рассмотренных варианта изображены на рис. 2.13.
Рис. 2.13. Отсечение геометрии, находящейся вне видимого пространства |
Для пространства вида остается задача получения двухмерного представления трехмерной сцены. Процесс перехода от n-мерного пространства к (n–1)-мерному называется проекцией (projection). Существует множество способов выполнить проекцию, но нас интересует один частный случай, называемый перспективной проекцией (perspective projection). Перспективная проекция выполняется таким образом, что объекты, расположенные дальше от камеры выглядят меньше, чем объекты того же размера, находящиеся ближе к камере. Этот тип проекции позволяет представить трехмерную сцену в виде двухмерного изображения. На рис. 2.14 показана точка в трехмерном пространстве, проецируемая в на плоскость проекции с использованием перспективной проекции.
Рис. 2.14. Проекция точки в трехмерном пространстве в окно проекции |
Преобразование проекции описывает наше видимое пространство (усеченную пирамиду) и отвечает за проецирование геометрии из него в окно проекции. Матрица проекции сложная и мы не будем обсуждать формулы для ее получения. Вместо этого воспользуемся следующей функцией библиотеки D3DX, которая создает матрицу проекции на основании описания усеченной пирамиды видимого пространства.
D3DXMATRIX *D3DXMatrixPerspectiveFovLH( D3DXMATRIX* pOut, // возвращает матрицу проекции FLOAT fovY, // вертикальный угол поля зрения в радианах FLOAT Aspect, // форматное соотношение = ширина / высота FLOAT zn, // расстояние до передней полскости FLOAT zf // расстояние до задней плоскости );
Рис. 2.15. Компоненты пирамиды видимого пространства |
Параметр форматного соотношения заслуживает дополнительных пояснений. Геометрия в окне проекции в конечном итоге преобразуется в экранное пространство (см. раздел 2.3.8). Перенос изображения из квадратной области (окна проекции) на экран, который, как известно, прямоугольный, приводит к возникновению искажений. Форматное соотношение, являющееся просто соотношением между сторонами экрана, используется для корректировки искажений возникающих при отображении квадрата на прямоугольник.
форматноеСоотношение = ширинаЭкрана / высотаЭкрана
Матрица проекции устанавливается с помощью метода IDirect3DDevice9::SetTransform, в котором указан тип преобразования D3DTS_PROJECTION. В приведенном ниже примере создается матрица проекции на основании усеченной пирамиды видимого пространства с углом поля зрения в 90 градусов, передней плоскостью, расположенной на расстоянии 1 единицы и задней плоскостью, расположенной на расстоянии в 1000 единиц.
D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH( &proj, PI * 0.5f, (float)width / (float)height, 1.0, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj);
Преобразование порта просмотра отвечает за преобразование координат из окна проекции в прямоугольную область экрана, которая называется портом просмотра (viewport). Для игр портом просмотра обычно является весь экран. Однако, если приложение работает в окнонном режиме, портом просмотра является часть экрана или клиентская область. Прямоугольник порта просмотра описывается относительно содержащего его окна и задается в оконных координатах (рис. 2.16).
Рис. 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.17).
Рис. 2.17. Растеризация треугольника на экране |
Процесс растеризации требует выполнения огромного объема вычислений в выполнение которых всегда вовлекается процессор видеокарты. Конечным результатом этапа растеризации является двухмерное изображение, выводимое на экран монитора.
netlib.narod.ru | < Назад | Оглавление | Далее > |