Урок 5. Процедурная генерация моделей для DirectX11

22.09.2012

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

Процедурная генерация

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

Однако есть немало примеров того, когда использование внешних моделей для каких-то конкретных целей может только замедлить процесс разработки игры. Когда использование внешнего 3d редактора оказывается неэффективным, используется процедурная генерация. В число таких задач входит генерация ландшафта. На самом деле, разрабатывать ландшафт в 3d редакторе – очень утомительно. Начать хотя бы с того, что ландшафт очень большой, так что подготовить правильный каркас 3d ландшафта сложно.

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

Определение формата исходных данных

Плоскость для нашего ландшафта мы определим как сетку из точек. Количество вершин в сетке будет определять разрешение нашего ландшафта. Чем больше вершин в ландшафте, тем детальнее он будет. Однако не стоит увлекаться излишней детализацией, так как при большом количестве обрабатываемых вершин вершинный шейдер окажется перегружен. Так, мы имеем для сетки ландшафта размером 512×512 вершин 524000 отображаемых полигонов в сцене, что чрезмерно много, нас интересует количество около 40000 полигонов, с учетом моделей сцены.

Для нашего текущего примера мы создадим совсем небольшой тестовый ландшафт. Исходными данными для ландшафта будет количество вершин по горизонтали u и по вертикали v а также размер ландшафта size. Зададим размер ландшафта:

const u=8;
const v=8;

Определим формат вершинного буфера для ландшафта. Обратите внимание, что в вершинный буфер добавлена новая переменная normal. Эта переменная потребуется для правильного освещения ландшафта. О том, как работать с освещением и устанавливать его мы поговорим уже в следующем уроке. Итак, определим формат вершинного буфера для сетки ландшафта:

struct VERTEX{
      XMFLOAT3 pos;
      XMFLOAT4 color;
      XMFLOAT3 normal;
} vertices[u*v];

Теперь определим формат индексного буфера:

DWORD indices[IndicesCount];

Теперь посмотрим какой код потребуется для генерации сетки и заполнения вершинного буфера:

for (int i=0; i<u; i++)
for (int j=0; j<v; j++)
{
      float x=(float)i/(float)u-0.5f;
      float y=(float)j/(float)v-0.5f;
      vertices[j*u+i].pos  = XMFLOAT3(x,hmap[i][j],y)*7.5f;
      vertices[j*u+i].color= XMFLOAT4(1,1,1,1);
      vertices[j*u+i].normal=XMFLOAT3(0,1,0);
}

Сетка сгенерирована правильно. Однако обратите внимание, что хотя координаты x иz просчитаны правильно, высота элемента ландшафта взята из пока еще неопределенного массива hmap[][]. В этом массиве будет храниться карта высот для нашего ландшафта. Для индексного буфера мы должны сгенерировать номера вершин в следующем виде:

indexes[] = {
      0,1,9,            0,9,8
      1,2,10,     1,10,9
      2,3,11,     2,11,10
      ....
}

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

for (int i=0; i<(u-1); i++)
for (int j=0; j<(v-1); j++)
{
      unsigned int indexa=j*(u-1)+i;
      unsigned int indexb=j*u+i;
      indices[indexa*6+0]=indexb;
      indices[indexa*6+1]=indexb+1+u;
      indices[indexa*6+2]=indexb+1;
 
      indices[indexa*6+3]=indexb;
      indices[indexa*6+4]=indexb+u;
      indices[indexa*6+5]=indexb+u+1;
}

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

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

Заключение

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

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

avatar

Об Авторе ()

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

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

Наверх