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

20.08.2012

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

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

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

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

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

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

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

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

const u=8;
const v=8;

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

struct VERTEX{
      glm::vec3 pos[u*v];
      glm::vec4 color[u*v];
      glm::vec3 normal[u*v];
} vertices;

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

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.pos[j*u+i]=    glm::vec3(x,hmap[i][j],y)*7.5f;
      vertices.color[j*u+i]=  glm::vec3(0,1,0);
      vertices.normal[j*u+i]= glm::vec2(x+0.5f,y+0.5f);
}

Сетка сгенерирована правильно. Однако обратите внимание, что хотя координаты 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;
}

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

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

Заключение

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

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

avatar

Об Авторе ()

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

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

Наверх