Создание игр для.народа.ру!

Как делать игры, создание игр - это реальность!

Сайт о том, как делать игры, уникальный сборник информации

Главная |  Софт, программы |  Информация по созданию игр |  Игры |  Гостевая книга |  Чат про создание игр
Форум по теме |  Размещение рекламы |  Ссылки |  Обратная связь


Вы находитесь на
Главной странице сайта





Киберсант-Матрица
Реальный заработок в сети


Букмекерская контора с бонусом
Разбираешься в спорте?Тебе сюда!


Биодобавки.com
Интересная партнерка большого спроса


Эффективная реклама
Ваша реклама на нашем сайте


  Яндекс.Новости

Как делать игры?

Сайт о том, как создаются игры. Программы, утилиты, статьи и многое другое

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

Поддержите наш сайт! Уделите хоть центов 30! Отправьте sms :

sms.копилка Как делать игры. Информация по теме создания игр.

Все средства идут на улучшение сайта.


Новые статьи на сайте

      Шейдеры в Delphi  Использование шейдеров в Delphi

Загружать шейдеры в видеокарту можно "вручную" или с помощью юнитов, упрощающих загрузку (например, shader.pas+dglOpengl.pas, движок eXgine, пример glsl_soulchild.pas из dglsdk и т.п.).

После загрузки шейдера у вас появляется ссылка на этот шейдер, и вы можете включать/выключать работу шейдера по своему усмотрению. Можно провести аналогию с glEnable(GL_TEXTURE_2D) / glDisable(GL_TEXTURE_2D). Вы включаете и выключаете шейдер: glUseProgramObjectARB( ССЫЛКА_НА_ШЕЙДЕР ). Если в качестве ссылки на шейдер передать число 0, то шейдер отключится.

Об использовании шейдеров и типах переменных в GLSL есть хорошая статья на gamedev.ru. Особое внимание хочу обратить на переменные типа uniform и attribute. Uniform-переменные вы можете передать в шейдер до начала блока glBegin/glEnd, а attribute-переменные можно задавать внутри блока glBegin/glEnd. В примере со скелетной анимацией я сначала передаю массив глобальных матриц как uniform, а индексы костей передаются внутри блока glBegin/glEnd для каждой вершины (attribute).

Для передачи массива из тридцати двух матриц 4x4 я воспользовался функцией glUniformMatrix4fv(shader_boneMat, 32, false,@skelState[i].shaderAbsoluteMat). Здесь:

shader_boneMat - ссылка на массив с матрицами в шейдере
32 - количество передаваемых матриц
false - при передаче матрицы не транспонируются
@skelState[i].shaderAbsoluteMat - указатель на массив с матрицами для i-того персонажа

С помощью функции glUniformMatrix4fv данные из Delphi - массива

shaderAbsoluteMat: packed array[0..31] of TMatrix4x4raw;

были переданы в GLSL - массив

uniform mat4 boneMat[32];

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

glVertexAttrib1fARB(shader_boneIndex, номер_вершины);
glVertex3f(coord[0], coord[1], coord[2]);

Здесь:

shader_boneIndex - ссылка на переменную типа attribute
номер_вершины - число, которое нужно передать в шейдер

Но откуда взять ссылку на переменную, находящуюся внутри шейдера? Эти ссылки получают при загрузке программы, после того как шейдер загрузится в видеокарту:

shader_boneMat := glGetUniformLocationARB(po, PGLcharARB(PChar('boneMat')));
shader_boneIndex := glGetAttribLocationARB(po, PGLcharARB(PChar('boneIndex')));

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

uniform mat4 boneMat[32];
attribute float boneIndex;

Вершинные шейдеры выполняются для каждой вершины. Поэтому, например, вы можете сделать пульсацию 3D поверхности по синусу: для этого достаточно прибавлять в вершинном шейдере к координате gl_Vertex нормаль, домноженную на синус от времени, а полученный результат отправлять в gl_Position. Помимо вершинных шейдеров существуют ещё и фрагментные, которые выполняются уже для пикселей. В примере Parallax Mapping перед выводом пикселя на экран его текстурные координаты модифицируются в зависимости от положения камеры, благодаря чему появляется эффект объёмной картинки.

      Делаем игры своими руками  Оптимизация скелетной анимации

Использование вершинных шейдеров для ускорения расчётов

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

Изменения в версии 1.2

1. Чтобы шейдер работал на видеокартнах ATI, строчка
float texNum2 = floor(texNum*255-1+0.001);
была заменена на
float texNum2 = floor(texNum*255.0-1.0+0.001);


2. По совету CyberZX чтобы уменьшить число умножений
теперь рассчитывается общая матрица трансформации вершины:
(http://www.gamedev.ru/code/forum/?id=56039)


3. Индексы костей и текстур по прежнему передаются в диапазоне
0..1, так как если передавать числа 0..255, то возникает 
странное падение скорости на 30 FPS.

Использование VBO для ускорения рендеринга модели

Всем хорошо известен способ по выводу моделей с помощью связки glBegin/glEnd, когда наша программа посылает данные в видеокарту многочисленными вызовами glTexCoord2f, glColor3f, glVertex3f и glNormal3f. В таком случае 3D модель из памяти CPU (Central Processing Unit) отправляются в память GPU (Graphics Processing Unit), что занимает определённое время.

Современные видеокарты могут хранить 3D модели прямо в своей памяти. Отрисовка модели из памяти видеокарты происходит существенно быстрее, так как не тратится время на вызовы glTexCoord2f, glVertex3f и подобных функций, требующих времени на копирование данных из одной памяти (CPU) в другую (GPU). Осуществить ускоренную работу видеокарты позволяют Vertex Buffer Objects (VBOs).

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

Совместное использование VBO и шейдеров

Максимальный прирост производительности дают VBO с полностью статическими моделями: модели один раз загружаются в память видеокарты сразу после запуска программы. Под воздействием шейдеров статическая модель "оживает" непосредственно внутри видеокарты. В таком случае у нас есть два источника прироста производительности: VBO в режиме вывода статических моделей и быстрое перемножение вершин на матрицы трансформации костей внутри шейдера.

Выбор формата для хранения 3D моделей в памяти видеокарты

В описании к функции glInterleavedArrays сказано, что "For some memory architectures this is more efficient than specifying the arrays separately". Поэтому в целях оптимизации, а заодно и упрощения исходного кода, рендеринг в VBO режиме будем производить через функции glInterleavedArrays и glDrawArrays.

Для начала нам необходимо выбрать формат для хранения данных 3D модели в памяти видеокарты, который поддерживается функцией glInterleavedArrays. В документации к OpenGL перечислены следующие форматы: GL_V2F, GL_V3F, GL_C4UB_V2F, GL_C4UB_V3F, GL_C3F_V3F, GL_N3F_V3F, GL_C4F_N3F_V3F, GL_T2F_V3F, GL_T4F_V4F, GL_T2F_C4UB_V3F, GL_T2F_C3F_V3F, GL_T2F_N3F_V3F, GL_T2F_C4F_N3F_V3F, or GL_T4F_C4F_N3F_V4F.

Наиболее подходящим является формат GL_T4F_C4F_N3F_V4F, так как он позволяет хранить для одной вершины наибольшее количество данных:

  • T4F - четыре значения типа float (координаты текстуры s,t,r,q)
  • C4F - четыре значения типа float (цвет r,g,b,a)
  • N3F - три значения типа float (нормаль x,y,z)
  • V4F - четыре значения типа float (координата вершины x,y,z,w)

У вас может возникнуть вопрос, зачем нам V4F (x,y,z,w) вместо V3F (x,y,z) и четыре координаты текстуры T4F вместо двух T2F, да ещё и цвет C4F. Ответ на этот вопрос состоит в следующем: "излишки" данных мы будем использовать для хранения весов (bone weight) и индексов костей, к которым прикреплена вершина. Посмотрим, где есть излишки, которые можно использовать для наших целей:

  • T4F - можно позаимствовать две координаты текстуры r и q (float, float)
  • C4F - отсюда можно взять все четыре значения (float, float, float, float)
  • N3F - лишних данных нет - нормали нам нужны
  • V4F - можно взять четвёртую координату w (float)

Всего получилоь 7 значений типа float, а это означает возможность прикрепить одну вершину как минимум к трём костям и задать текущую текстуру:

  • float N1 - индекс первой кости
  • float N2 - вес влияния первой кости
  • float N3 - индекс второй кости
  • float N4 - вес влияния второй кости
  • float N5 - индекс третьей кости
  • float N6 - вес влияния третьей кости
  • float N7 - номер текстуры

Все эти семь значений будет использовать в своей работе вершинный шейдер. В принципе можно ухитриться, и "упаковать" в эти 7 float-ов больше данных, а затем "распаковывать" эти данные в шейдере. Но для простоты рассмотрим случай, когда на вершину влияет не более трёх костей.

Загрузка данных VBO в память видеокарты

В загрузке данных VBO нет ничего сложного: достаточно объявить в Delphi правильный тип, соответствующий выбранному нами формату данных GL_T4F_C4F_N3F_V4F, и воспользоваться функциями OpenGL для работы с VBO.

Для начала необходимо создать VBO для хранения модели. Нам понадобится создать только один буфер:

glGenBuffersARB(1, @VBOlink);

Эта функция создаст один VBO и вернёт ссылку на этот объект в переменную VBOlink. Теперь созданный VBO необходимо сделать текущим:

glBindBufferARB(GL_ARRAY_BUFFER_ARB, VBOlink);

Нечто подобное мы уже наблюдали с функцией glBindTexture(GL_TEXTURE_2D, texID) для установки текущих текстур. Перед загрузкой модель нужно привести к тому виду, в котором она будетнаходиться в памяти видеокарты (GL_T4F_C4F_N3F_V4F). Тип данных для такой вершину на Delphi будет выглядеть так:

type TVertexForVBO=packed record
                           ts,tt,tr,tq : GLFloat;
                           r,g,b,a     : GLFloat;
                           nx,ny,nz    : GLFloat;
                           x,y,z,w     : GLFloat;
                          end;

После создания массива tempData из вершин TVertexForVBO и наполнения его описанными выше данными, можно приступать к загрузке данных в память видеокарты:

 glBufferDataARB( GL_ARRAY_BUFFER_ARB,
           3*length(myModel.poligons)*sizeof(TVertexForVbo),
           tempData,
                  GL_STATIC_DRAW_ARB );

На вход функции glBufferDataARB передаются следующие параметры:
GL_ARRAY_BUFFER_ARB - тип загружаемых данных
3*length(myModel.poligons)*sizeof(TVertexForVbo) - объём загружаемых данных
tempData - указатель на загружаемые данные (pointer)
GL_STATIC_DRAW_ARB - признак того, что загружаются данные статической модели (без анимации)

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

Рендеринг VBO-модели

Загрузив один раз в начале программы нашу модель в VBO, мы получаем ссылку VBOlink на этот объект. Теперь вместо того, чтобы передавать в видео карту десятки тысяч вершин, нормалей и текстурных координат достаточно одной только ссылки VBOlink, и видео карта сразу же имеет доступ к 3D модели, так как она уже находится в её памяти. Благодаря использованию функции glInterleavedArrays рендеринг осуществляется предельно просто:

glBindBufferARB(GL_ARRAY_BUFFER_ARB, myModel.VBOlink);
glInterleavedArrays(GL_T4F_C4F_N3F_V4F, 0,nil);
glDrawArrays(GL_TRIANGLES,0,3*length(myModel.poligons));

Шейдеры для скелетной анимации

Индексы и веса влияющих на вершину костей мы записывали в текстурные координаты R,Q и в цвет R,G,B,A. Вершинный шейдер выполняется для каждой вершины, поэтому мы можем сразу узнать данные о костях, к которым принадлежит данная вершина. Чтобы избежать ошибок при отсечении с помощью функции floor дробной части от значений индексов костей и текстур, к ним прибавляется 0.001 (надёжность данного метода для разных видеокарт и драйверов пока неизвестна). Исходный код вершинного шейдера:

uniform mat4 boneMat[32]; - матрицы всех костей
varying float texNum; - индекс текстуры для данной вершины
(тип varying сделан с целью передачи в фрагментный шейдер)

void main(void)
{

float boneIndex[3]; - индексы трёх костей
float boneWeight[3]; - веса трёх костей


texNum = gl_Vertex[3]; - получаем индекс текстуры

vec4 fixedTexCoord = gl_MultiTexCoord0;
vec4 fixedColor = gl_Color;
vec4 fixedVertex = gl_Vertex;

vec4 finalVertex = vec4(0,0,0,1);

Получаем данные (индекс, вес) для трёх костей:
boneIndex[0] = floor(fixedTexCoord[2]*255.0+0.001);
boneWeight[0] = fixedTexCoord[3];
boneIndex[1] = floor(fixedColor[0]*255.0+0.001);
boneWeight[1] = fixedColor[1];
boneIndex[2] = floor(fixedColor[2]*255.0+0.001);
boneWeight[2] = fixedColor[3];
Домножение на 255 служит для перевода из диапазона
0..1 в диапазон 0..255, где это требуется. Прибавление
числа 0.001 сделано с целью избежать ошибок при отсечении
дробной части.

Все необходимые данные получены, можно восстанавливать
нормальные OpenGL-евские значения:
fixedTexCoord[2] = 0.0;
fixedTexCoord[3] = 1.0;
fixedColor[0] = 1.0;
fixedColor[1] = 1.0;
fixedColor[2] = 1.0;
fixedColor[3] = 1.0;
fixedVertex[3] = 1.0;



mat4 finalMatrix = mat4(0);

for (int i = 0; i < 3; i++)
 finalMatrix += boneWeight[i]*boneMat[int(boneIndex[i])];

Трансормация вершины с учётом весов и матриц трёх костей:
finalVertex = finalMatrix*fixedVertex;




finalVertex[3] = 1.0;

Записываем итоговые значения (координата вершины, цвет,
текстурные координаты):
gl_Position = gl_ModelViewProjectionMatrix * finalVertex;
gl_FrontColor = fixedColor;
gl_TexCoord[0] = fixedTexCoord;
}                           

Номер текстуры из вершинного шейдера через переменную texNum передаётся в фрагментный шейдер:

uniform sampler2D myTexture0; - ссылки на текстуры
uniform sampler2D myTexture1;
uniform sampler2D myTexture2;
uniform sampler2D myTexture3;
uniform sampler2D myTexture4;
uniform sampler2D myTexture5;
uniform sampler2D myTexture6;
uniform sampler2D myTexture7;


varying float texNum; - номер нужной текстуры (эту переменную
передаст сюда вершинный шейдер, т.к. тип varying)
void main(void) { Перевод из диапазона 0..1 в диапазон 0..255: float texNum2 = floor(texNum*255.0-1.0+0.001); Отрисовываем пиксель, подставляя нужную текстуру: if (texNum2==0.0) gl_FragColor = texture2D( myTexture0, gl_TexCoord[0].st ); else if (texNum2==1.0) gl_FragColor = texture2D( myTexture1, gl_TexCoord[0].st ); else if (texNum2==2.0) gl_FragColor = texture2D( myTexture2, gl_TexCoord[0].st ); else if (texNum2==3.0) gl_FragColor = texture2D( myTexture3, gl_TexCoord[0].st ); else if (texNum2==4.0) gl_FragColor = texture2D( myTexture4, gl_TexCoord[0].st ); else if (texNum2==5.0) gl_FragColor = texture2D( myTexture5, gl_TexCoord[0].st ); else if (texNum2==6.0) gl_FragColor = texture2D( myTexture6, gl_TexCoord[0].st ); else if (texNum2==7.0) gl_FragColor = texture2D( myTexture7, gl_TexCoord[0].st ); }

Загрузка шейдеров.

Загрузка шейдеров осуществляется с помощью удобного юнита shader.pas (delphi3d.net). Сначала идёт загрузка вершинного и фрагментного шейдера, почле чего мы получим две ссылки типа GLHandleARB:

vertex := LoadShaderFromFile('.\shaders\vertex.txt', GL_VERTEX_SHADER_ARB);
fragment := LoadShaderFromFile('.\shaders\fragment.txt', GL_FRAGMENT_SHADER_ARB);

Затем мы объединяем шейдеры в одну шейдерную программу с помощью функции LinkPrograms из файла shader.pas:

FShaders[0]:=LinkPrograms([vertex,fragment]);

Далее необходимо получить ссылки для обращения к переменным шейдера:

shader_boneMat := glGetUniformLocationARB(po, PGLcharARB(PChar('boneMat')));
for i:= 0 to 7 do
shader_myTexture[i] := glGetUniformLocationARB(po,
PGLcharARB(PChar('myTexture'+intToStr(i))));

Трансформация VBO-модели с помощью шейдеров в процессе рендеринга

Сначала необходмо выбрать текущий шейдер. Так как мы загрузили шейдеры в нулевой элемент массива FShaders, то включение этого шейдера будет выглядеть так:

glUseProgramObjectARB(FShaders[0]);

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

    for i:= 0 to 7 do
      glUniform1iARB(shader_myTexture[i],i);


     for i:= 0 to 7 do
      begin
       glActiveTexture(GL_TEXTURE0+i);
     	 glBindTexture(GL_TEXTURE_2D, i+1);
      end;

Далее следует копирование матриц трансформации из нашей программы на Delphi в шейдер:

glUniformMatrix4fv( shader_boneMat, 32, false,@skelState[i].shaderAbsoluteMat);

Теперь можно приступать к обычному выводу VBO-модели с помощью функций glBindBufferARB, glInterleavedArrays и glDrawArrays (см. выше).

Если вы захотите изменить количество костей с 32 на другое число, то это необходимо сделать в трёх местах:

1) в файле .\shaders\vertex.txt "uniform mat4 boneMat[32];"
2) в файле .\_model.pas "shaderAbsoluteMat: packed array[0..31] of TMatrix4x4raw;"
3) в файле .\unit1.pas "glUniformMatrix4fv( shader_boneMat, 32, false,@skelState[i].shaderAbsoluteMat);"

При загрузке моделей Half-Life 2 SMD мне удавалось создавать 57 матриц костей (boneMat[57]), а при 64 программа выдавала шейдерную ошибку.

При том же количестве матриц количество передаваемых
полезных данных можно увеличить вдве: строки матрицы 4x4 можно 
использовать для хранения перемещений (x,y,z) и кватернионов
(x,y,z,w).

Полученные результаты

Совместное использование VBO и шейдеров позволило увеличить FPS в несколько раз. Возможные источники прироста производительности таковы:

  • Благодаря функции glInterleavedArrays и выбору текстуры внутри шейдера отрисовка модели осуществляется за один вызов glDrawArrays.
  • Данные о вершинах и креплении к скелету 3D модели загружаются в память видеокарты только один раз после старта программы.
  • Возможно, что при использование единого массива данных GL_T4F_C4F_N3F_V4F более эффективно происходит кеширование данных, так как считывание данных о вершине и скелетной анимации происходит практически из одного участка памяти.
  • Высокая скорость GPU при перемножении вершин модели на матрицы костей.
  • При использовании VBO все необходимые шейдеру данные уже находятся в памяти видеокарты и отсутствует потеря времени на ожидание передачи данных от CPU.

Странным является то, что передача индексов костей и текстур, отнормированных в диапазон 0..1 даёт прирост производительности на 30fps.

Результаты тестирования (модель Half-Life 1 smd, 2215 полигонов):

Количество моделей 1 2 3 4 5 30 100 300
FPS 814 634 530 460 405 99 39 15

2215 * 100 = 221500 полигонов при 39fps

Для модели Half-Life 2 smd с 3852 полигонами:

Количество моделей 1 2 3 4 5 30 100 300
FPS 775 600 493 419 361 82 26 9

3852 * 100 = 385200 полигонов при 26 fps

Интересно!!!

www.superanekdot.net
Подборка смешных фотографий - самые прикольные фото только для вас!

Новые идеи бизнеса
Здесь собраны лучшие идеи для открытия собственного бизнеса

Квест для веб-дизайнера
Интересный квест только для веб-дизайнеров

SMS@Sender
Java-приложение на мобилу для бесплатной отправки sms и еще куча полезных программ

Заработай на изготовлении баннеров

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


Дизайн, администрирование сайта - Anomaly inc.   Copyright ©2007-2009 «Anomaly inc.», все права защищены.
Опубликование и использование любых материалов сайта разрешено только с указанием обратной ссылки на сайт. Любое нарушение авторских прав преследуется по закону РФ.


Hosted by uCoz