Функция vDrawInterfaceObject()
Функция vDrawInterfaceObject() не является частью DirectX. Я создал ее специально для этой программы чтобы упростить трехмерную визуализацию двухмерных объектов. Функция выполняет ту же работу, что и стандартная функция копирования двухмерных изображений. Она берет изображение и помещает его на экран в указанное с помощью координат место. Вот как выглядит прототип функции:
void vDrawInterfaceObject( int iXPos, int iYPos, float fXSize, float fYSize, int iTexture );
Первые два параметра, iXPos и iYPos, задают местоположение текстуры на экране. В отличие от вызовов, относящихся к трехмерной графике, здесь следует указывать координаты в двухмерном пространстве экрана.
Следующие два параметра, fXSize и fYSize, задают размер отображаемой на экране текстуры. Они необходимы для того, чтобы система знала как выполнять масштабирование.
Последний параметр, iTexture, является индексом в глобальном массиве текстур. Он определяет какая исменно текстура будет отображена.
Теперь взгляните на код этого бриллианта из мира функций:
void vDrawInterfaceObject(int iXPos, int iYPos, float fXSize, float fYSize, int iTexture) { D3DXMATRIX matWorld, matRotation; D3DXMATRIX matTranslation, matScale; float fXPos, fYPos;
// Установка начальных значений местоположения, // масштабирования и вращения D3DXMatrixIdentity(&matTranslation); // Масштабирование спрайта D3DXMatrixScaling(&matScale, fXSize, fYSize, 1.0f); D3DXMatrixMultiply(&matTranslation, &matTranslation, &matScale); // Поворот спрайта D3DXMatrixRotationZ(&matRotation, 0.0f); D3DXMatrixMultiply(&matWorld, &matTranslation, &matRotation); // Вычисление местоположения на экране fXPos = (float)(-(g_iWindowWidth / 2) + iXPos); fYPos = (float)(-(g_iWindowHeight / 2) - iYPos + fYSize - g_iYOffset); // Перемещение спрайта matWorld._41 = fXPos; // X matWorld._42 = fYPos; // Y // Установка матрицы g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld); g_pd3dDevice->SetTexture(0, g_pTexture[iTexture]); g_pd3dDevice->SetStreamSource(0, g_pVBInterface, 0, sizeof(CUSTOMVERTEX)); g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX); g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); // Разыменовывание текстуры g_pd3dDevice->SetTexture(0, NULL); }
В начале кода создается матрица для трехмерного объекта, содержащая значения по умолчанию. Это достигается путем вызова функции D3DXMatrixIdentity(). Эта вспомогательная функция предоставляется DirectX SDK и удобна для создания матрицы по умолчанию. Она обнуляет за вас все значения в матрице, за исключением тех, которые расположены на главной диагонали (им она присваивает значение 1). Это эквивалент стирания старых записей со школьной доски.
В следующем блоке кода выполняется создание матрицы масштабирования. Она предназначена для масштабирования трехмерного квадрата таким образом, чтобы его размеры совпадали с размером текстуры. Поскольку глубина в нашем случае не используется, коэффициет масштабирования по оси Z задан равным 1.0. Готовая матрица масштабирования умножается на матрицу преобразования.
Далее расположен код для вращения графики. В рассматриваемом примере я не использую вращение, так что для задания угла поворота используется значение 0.0. Позднее, в других примерах программ, вы увидите как можно использовать отличные от нуля значения угла поворота. Затем матрица преобразования умножается на матрицу вращения.
По умолчанию матрица описывает геомертию трехмерного пространства. Поскольку мы выполняем операции с двухмерной поверхностью дисплея, необходимо вычислить координаты объекта в экранных пикселах. Делая это я учитываю высоту и ширину экрана. Как можно увидеть в коде примера, я делю размеры экрана на два и использую их в формуле вместе с желаемыми координатами объекта, чтобы вычислить его местположение на экране. Концепцию трехмерных координат в пространстве экрана поясняет рис. 6.20.
Рис. 6.20. Отображение текстуры в трехмерном пространстве на экране
На рис. 6.20, точка с координатами (0,0) соответствует центру экрана. Это коренным образом отличается от традиционной двухмерной визуализации. В традиционной двухмерной среде изображенной на рис 6.20 точке в центре экрана соответствуют координаты (400,300). Так как вы имеете дело с трехмерным миром, вам необходимо компенсировать это различие. Для этого и пригодился код о котором я только что говорил. Он преобразует трехмерную геометрию для отображения в двухмерном пространстве экрана.
Координаты вычислены, и теперь их надо поместить в матрицу. Для этого можно было бы снова воспользоваться умножением матриц, но я предпочитаю просто поместить значения перемещения непосредственно в элементы матрицы. Такой метод работает гораздо быстрее любого другого.
Теперь матрица содержит данные о масштабировании, вращении и перемещении, необходимые для визуализации. Матрицу следует активировать, для чего необходимо вызвать функцию IDirect3DDevice9::SetTransform(). Я вызываю эту функцию, которая меняет матрицу D3DTS_WORLD на матрицу, созданную ранее для отображения растра. В результате активируется новая матрица.
Затем я активирую требуемую текстуру. Для этой цели применяется вызов функции IDirect3DDevice9::SetTexture(), которой в качестве параметра передается указатель на ту текстуру, которую мы хотим отобразить.
Чтобы при визуализации использовался созданный ранее в программе буфер вершин, я должен активировать его вызвав функцию IDirect3DDevice9::SetStreamSource(). Эта функция активирует указанный буфер вершин, после чего он будет использован в качестве потокового источника для последующих вызовов функций визуализации.
Следующей вызывается функция с именем IDirect3DDevice9::SetFVF(), которая сообщает системе визуализации формат буфера вершин. В нем содержится важная информация, такая как нормаль, цвет и координаты текстуры. В параметре этой функции я передаю описание настраиваемого формата вершин D3DFVF_CUSTOMVERTEX определенное в заголовочном файле программы.
И последней — но от этого она не становится менее важной — я вызываю функцию IDirect3DDevice9::DrawPrimitive(). Она является самым сердцем визуализации и выполняет всю работу, необходимую для отображения трехмерных объектов. Поскольку для изображения квадрата использовалась полоса треугольников, в первом параметре функции я указываю тип данных D3DPT_TRIANGLESTRIP.
И, наконец, я разыменовываю текстуру, присваивая активной текстуре значение NULL.
Закончив разбирать функцию рисования элементов интерфейса, вернемся назад к функции vRender() и посмотрим, каким образом в ней реализовано рисование интерфейса. Ниже я еще раз привел отвечающий за это фрагмент кода:
vDrawInterfaceObject(0, 0, 256.0f, 256.0f, 0); vDrawInterfaceObject(256, 0, 256.0f, 256.0f, 1); vDrawInterfaceObject(512, 0, 256.0f, 256.0f, 2); vDrawInterfaceObject(0, 256, 256.0f, 256.0f, 3); vDrawInterfaceObject(256, 256, 256.0f, 256.0f, 4); vDrawInterfaceObject(512, 256, 256.0f, 256.0f, 5); vDrawInterfaceObject(192, 64, 256.0f, 256.0f, 6);
Чтобы лучше представить себе результат этих вызовов функций, взгляните на рис. 6.21.
Рис. 6.21. Расположение текстур на титульном экране
На рис. 6.21 изображен экран обрамленный тонкой линией. Кроме того там изображены шесть текстур, расположенных в виде сетки. Эти шесть текстур полностью заполняют экран. Поскольку ширина и высота каждой текстуры равна 256 точкам, их общий размер превышает размеры экрана ширина которого равна 640 точкам, а высота — 480 точкам. Такие размеры текстур необходимы для того, чтобы они соответствовали требованиям оборудования, которое поддерживает только текстуры с размером, равным степени двойки. Большинство современных видеокарт могут работать только с текстурами размером 2 x 2, 4 x 4, 8 x 8, 16 x 16, 32 x 32, 64 x 64, 128 x 128, 256 x 256 и т.д. точек, поэтому и требуется данное действие. Лучший способ учесть эти требования — создать экран в требуемом разрешении, а затем разбить его на блоки размером 256 x 256 точек. Конечно, в результате увеличится объем использукмой памяти, но это можно проигнорировать.
Единственная текстура, которая не рисуется при отображении сетки — это логотип игры. Поскольку он находится в центре экрана, для него следует задать слегка отличные координаты. Попробуйте изменить координаты текстур в коде и посмотрите что получится. Вы можете даже добавить к титульному экрану несколько своих тестур, чтобы обрести необходимые навыки.
netlib.narod.ru | < Назад | Оглавление | Далее > |