Урок 4. Установка матриц трансформаций и камеры

31.07.2012

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

Типы данных для хранения параметров камеры в DirectX10

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

Существует два вида представления камеры: ненаправленная,

И целевая, направленная камера. Для того, чтобы установить камеру, вообще говоря, нужно знать её координаты, направление, и угол обзора. Таким образом, для любой вашей камеры вы можете определить объект, хранящий эти данные:

classCameraDirectional
{
        D3DXVECTOR3 pos;
        D3DXVECTOR3 direction;
        float FOV;
};

Такая камера будет называться ненаправленной, так как не существует определенной точки в которую она смотрит. В качестве направления вы можете определить любой нормализованный вектор. Умножив вектор direction на одну или несколько матриц поворота вы сможете поворачивать камеру. Преимущество ненаправленной камеры в том, что для неё не обязательно иметь точку, в которую она смотрит – а постоянно следить за тем, какую конкретно точку направить камеру и к чему эту точку привязать – весьма проблематично.

Если вы точно или приблизительно знаете точку, в которую направлена камера, то вы можете определить другой тип камеры, это направленная камера:

classCameraTarget
{
        D3DXVECTOR3 pos;
        D3DXVECTOR3 target;
        float FOV;
}

Типы данных Direct3D

В предыдущем уроке мы рассмотрели различные математические операции и представления чисел. Давайте немного отвлечемся от установки камеры и рассмотрим, какие типы данных понадобятся в DirectX10:

  • Для хранения скалярных значений — чисел с плавающей точкой используется тип данных float
  • Для хранения трехкомпонентных векторов используется тип данных D3DXVECTOR3
  • Для хранения информации о цвете используется D3DXVECTOR4
  • Матрицы в DirectXописываются типом данных D3DXMATRIX

Тажке существуют и другие типы данных DirectX, однако они гораздо менее популярны.

Типы данных для хранения параметров камеры

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

struct Vertex
{
        D3DXVECTOR3 coord;
} Vertices[];

Чтобы осуществить нужные преобразования для камеры, достаточно лишь задать две матрицы:

D3DXMATRIX g_View;
D3DXMATRIX g_Projection;

И затем умножить координату каждой из вершин на обе матрицы:

FromViewVertices[].coord=Vertices[].coord*g_View*g_Projection;

Вы видите, что нужное преобразование осуществилось крайне просто. Таким образом, вы можете хранить камеру в любом формате, например в таком, который приведен выше:

class CameraTarget
{
        D3DXVECTOR3 pos;
        D3DXVECTOR3 target;
        float FOV;
}

Установка матрицы камеры и проективной матрицы в Direct3D

Итак, продолжим. Перед тем как установить камеру типа CameraTargetвам потребуется преобразовать её координаты в матрицы DirectX, для этого в Direct3D10 существует следующая функция:

D3DXMATRIX * D3DXMatrixLookAtLH(
  __inout  D3DXMATRIX *pOut,
  __in     const D3DXVECTOR3 *pEye,
  __in     const D3DXVECTOR3 *pAt,
  __in     const D3DXVECTOR3 *pUp
);

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

Таким образом, для того, чтобы преобразовать объект из CameraTarget в нужные нам матрицы нужно сделать следующее. Сначала заполним CameraTargetкакими-либо данными:

CameraTarget MyCamera;
MyCamera.pos=D3DXVECTOR3(0,1.0f,-2.0f);
MyCamera.target=D3DXVECTOR3(0,1.0f,0);
MyCamera.FOV=(float)D3DX_PI*0.5f;
D3DXVECTOR3 MyUpVector=D3DXVETOR3(0,1.0f,0);

Обратите внимание, что вместе с заданием координат камеры мы также задали параметр FOV. Это fieldofview, то есть угол обзора. Просто камера может узкоуголной и широкоугольной – по вашему выбору. Оказывается, в DirectXтоже можно менять линзы! Зададим в виде глобальных переменных матрицы

D3DXMATRIX                  g_World;
D3DXMATRIX                  g_View;
D3DXMATRIX                  g_Projection;

Теперь зададим нужные матрицы камеры и прекций:

D3DXMatrixIdentity(&g_World);
D3DXMatrixLookAtLH(&g_View,&MyCamera.pos,&MyCamera.target,&MyUpVector);
D3DXMatrixPerspectiveFovLH(&g_Projection,&MyCamera.FOV,1.6f.0f,0.1f,100.0f);

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

Установка матриц камеры, трансформаций и проективной матрицы в качестве констант шейдера

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

Любые константы шейдера можно представить в нашей программе как глобальные переменные типа объектов. Таким образом, инициализировав глобальную переменную для шейдеров можно затем просто устанавливать константы для шейдера, записывая в эту переменную новые значения. Сначала объявим в приложении наши объекты – константы шейдера:

g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix();
g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix();
g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix();

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

g_pWorldVariable = g_pEffect->GetVariableByName( "World" )->AsMatrix();
g_pViewVariable = g_pEffect->GetVariableByName( "View" )->AsMatrix();
g_pProjectionVariable = g_pEffect->GetVariableByName( "Projection" )->AsMatrix();

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

Итак, в процедуре Renderустановим глобальные переменные шейдера для наших матриц (вы помните, что раньше мы получили нужные матрицы, преобразовав их из объекта CameraTarget.

g_pWorldVariable->SetMatrix( ( float* )&g_World );
g_pViewVariable->SetMatrix( ( float* )&g_View );
g_pProjectionVariable->SetMatrix( ( float* )&g_Projection );

Вы можете спросить, зачем два раза устанавливать матрицы? Сначала мы установили матрицы при помощи кода

D3DXMatrixIdentity(&g_World);
D3DXMatrixLookAtLH(&g_View,&MyCamera.pos,&MyCamera.target,&MyUpVector);
D3DXMatrixPerspectiveFovLH(&g_Projection,&MyCamera.FOV,1.6f.0f,0.1f,100.0f);

А потом установили еще раз, при помощи установки переменных для шейдера (см. выше).

Ответ заключается в том, что на самом деле, матрицы устанавливались один раз. Просто второй раз, в процедуре Renderмы передали значения, находящиеся в матрицах в шейдер. Если бы мы этого не сделали, то матрицы вместе с переменными для их хранения остались бы неиспользованными.

Полезные мелочи: матрица трансформаций

Итак, мы установили матрицы для камеры, однако невыясненным остался вопрос, зачем нужна переменная g_World, заполнявшееся единичной матрицей. Это матрица трансформаций. На самом деле этой переменной можно присваивать значение, отличное от единицы. И это полезная матрица, так как перед тем как отобразить объект мы его можем правильно расположить в пространстве.

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

При помощи матриц трансформаций g_World мы можем переместить объекты куда угодно перед тем как сделать их Render. При этом предварительно мы можем повернуть объект вокруг своей оси на нужный угол а также увеличить или уменьшить объект. Зачастую объекты «приходят» из 3dредактора в таком виде, что их надо подгонять по размеру. В редких случаях в редакторе можно точно угадать и подобрать нужную величину создаваемого объекта, так как системы измерений всегда могут отличаться.

Пример приложения

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

В качестве целевой точки для камеры будет выберем центр координат. Значение FOV для камеры установим по умолчанию.

Обзор приложения

Теперь остается скомпилировать и запустить приложение.

Исходный текст приложения к данному уроку вы можете найти тут. Данное приложение устанавливает камеру в соответствии с одной из точек эллиптической траектории и динамически изменяет положение камеры.

Заключение

В данном уроке вы изучили как устанавливать камеру, какие типы данных и объекты можно использовать для хранения информации о камере. Также вы узнали каким образом передавать в шейдер данные о положении камеры. Следующий урок мы посвятим несколько необычной теме – процедурной генерации 3d поверхности. То есть, столкнемся с конкретным примером практического применения Direct3D.

Заполнен: DirectX10
Присвоен тэг:

avatar

Об Авторе ()

Планета назначения, JO - 8703 - IV, обозначается светлой точкой на объемном экране корабля. К тому времени, как Робоид нанялся на юпитерианский круговой рейс, ему следовало бы стать главным инженером, но после Суховодного пионерского его вышибли, внеся в черный список, и высадили в Луна-Сити за то, что вместо слежения за приборами он провел время, программируя синтезатор пищи корабля строжайше запрещенной корабельными инструкциями последовательностью синтеза пива.

Комментирование закрыто.

Наверх