Авторизация  
weiss

Gamedev

Рекомендуемые сообщения

О шейдерах на примере HTML5 WebGL

 

WebGL базируется на OpenGL ES 2.0, о котором вы могли слышать. Шейдеры немного необычная концепция и требует объяснения.

 

Шейдер (shader), по своей сути, это программа на языке GLSL (в случае WebGL, это разновидность ANSI C с некоторыми дополнениями в виде необходимых для трехмерной графики векторными и матричными типами данных).

 

Общая задача шейдеров в том, чтобы объяснить GPU (видеокарте) как что-то должно выглядеть.

 

WebGL предоставляет два типа шейдеров — vertex shaders (вершинные или вертексные) и fragment shaders (фрагментные или пиксельные). За оба типа отвечает GPU в целях разгрузки CPU, который принято оставлять под другие нужды (физические рассчеты, например), видеокарты же сильно оптимизированы как раз под шейдеры.

 

Так зачем нужны эти шейдеры? Вертексные шейдеры оперируют данными о вершинах многогранников, т. е. данными о положении вершин в пространстве. Вообще, это интересно, ведь не стоит забывать, что мы проецируем 3D объекты (т. е. три координаты — x, y и z) на 2D экран. По сути задача вертексного шейдера сводится к тому, чтобы в нужный момент времени присвоить переменной gl_Position (опять же в случае WebGL) вектор, представляющий собой финальную позицию вершины (вертекса) на экране.

 

Пока вы не уснули, я создал для вас небольшой пример с помощью библиотеки Three.js:

 

 

(см. вкладку Result)

 

У нас есть некий объект с вершинами, и мы даже спроецировали его на двумерный экран, но то, что вы увидели в примере, не было цифрами с координатами вершин или чем-то подобным. Вы увидели вращающийся куб, у него было 6 граней какого-то цвета, как и у всех кубов. А еще освещение, вы же видели тени, верно? Всё это благодаря пиксельным шейдерам. Они отвечают за текстурирование и освещение.

 

По моему впечатлению понимание шейдеров открывает дверь в мир трехмерной графики.

 

http://threejs.org/examples/webgl_animation_skinning_morph.html

Поделиться сообщением


Ссылка на сообщение

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

Поделиться сообщением


Ссылка на сообщение

Формально это тип vec4(x, y, z, w), где w лучше не объяснять что такое xD Не стоит смешивать привычные векторы и эти.

Поделиться сообщением


Ссылка на сообщение

О векторах

 

В процессе рассказа о шейдерах я упомянул про векторы. Вы все сталкивались с ними в математике как с направленными отрезками, думаю, помните такие обозначения как AB со стрелочкой ➝ над буквами. В математике есть много разных векторов, в том числе 4-векторы — векторы в четырехмерном пространстве Минковского, где первые три координаты x, y и z представляют понятно что (обычное трехмерное пространство), а четвертая координата w — это время (обычно это 0 или 1). Естественно, у векторов своя математика, есть правила сложения, умножения векторов и т. д.

 

В применении к играм логично предположить, что в 2D-играх используются 2-векторы, т. е. содержащие в себе данные о двух точках на системе координат — x и y, а в 3D играх — 3- и 4-векторы, где добавляется ось z и компонента w. Может быть не совсем понятно зачем нужна w, если кратко, то для естественности вычислений перемещения (это еще связано с матрицами, которые мы не трогали). В английском языке 4-векторы называют 4D vectors, 4D float-vectors, 4D floating points. Для краткости я буду обозначать векторы как vec2, vec3 и vec4, можно сказать, это общепринятые обозначения, в том числе в GLSL.

 

Итак, больше об играх. Рассмотрим для начала 2D игры на примере браузерных игр на HTML5-элементе canvas. У canvas своя особенная система координат (не декартова), точнее он как бы использует отраженный участок обычной системы. Координата (0, 0) находится в верхнем левом углу, y увеличивается вниз, x увеличивается вправо. Т. е., если canvas имеет размер 100х100, нижний правый угол будет (100, 100), верхний правый (100, 0) и т. д. Что же касается векторов, программисты используют vec2(x, y) для представления положения точки в 2D пространстве, однако могут использоваться и vec3(x, y, z), в этом случае z координата будет представлять слой, на котором находится объект. Что это значит? Двухмерной игре практически всегда требуется отображать объекты слоями, чтобы один мог перекрывать другой, соответственно, то, какой какого перекроет, определяется координатой z — чем она больше, тем «ближе» объект к игроку. О трехмерных играх добавить, в общем-то, нечего, ведь всё и так понятно — vec3, vec4.

 

Практическая часть:

 

Всё это хорошо, но как представляются векторы в коде? Для программирования вектор — это абстракция. Её реализуют либо специальными типами данных, как в GLSL, т. е. их можно использовать из коробки. Или же программист сам пишет реализацию векторов из подручных средств. Давайте напишем тип Vec2, используя JavaScript. JS — объектно-ориентированный язык программирования, а значит для представления такого вектора удобнее всего использовать объект. Создадим такой класс (конструктор новых объектов, калька, если хотите) с методом сложения впридачу:

function Vec2(x, y) { // пусть слово function вас здесь не смущает, это особенности JS
    this.x = x;
    this.y = y;
}

// Метод сложения, берет текущий вектор, прибавляет к нему переданный в функцию и возвращает новый вектор. В векторной математике, чтобы сложить векторы, надо сложить их координаты.
Vec2.prototype.add = function(vec2) {
    return new Vec2(this.x + vec2.x, this.y + vec2.y);
}

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

var point = new Vec2(10, 15); // создаем точку с координатами x = 10, y = 15, это ничто иное, как простой объект с двумя параметрами (x, y) и одним методом
var point2 = new Vec2(20, 30); // еще одну с другими координатами

// А теперь нам понадобилось создать еще одну точку, которая будет суммой первых двух
var point3 = point.add(point2);

// Разумеется, мы можем получать значения координат по отдельности
point3.x // -> 30
point3.y // -> 45

// Или изменять их
point3.y += 50 // -> 95, сдвинули объект по оси y на 50 (пикселей)

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

Поделиться сообщением


Ссылка на сообщение

P. S. Векторные типы данных также часто используются для хранения цвета. Я не знаю насколько корректно называть это вектором с точки зрения математики, но по-моему это уже не имеет отношения к векторам в математике. По моему мнению, это происходит потому, что в таких языках, как GLSL, векторные типы данных просто удобны для представления цвета в формате RGB(A). Например, vec4(r, g, b, a), где r — красный канал (red), g — зеленый (green), b — голубой (blue) и a — альфа (alpha) канал, т. е. прозрачность. r, g и b представляются числами от 0 до 255, а alpha-канал числом от 0.0 до 1.0 (0 — прозрачность, 1 — непрозрачность, всё, что между ними — полупрозрачность). Соответственно, здесь тоже есть «своя математика», связанная со смешиванием каналов и т. п. операциями, которая может реализовываться в виде методов, как в примере выше, или же какими-то отдельными функциями для работы с цветом. О представлении цвета в формате RGB или RGBA подробнее можно почитать в википедии — http://ru.wikipedia.org/wiki/RGB и http://ru.wikipedia.org/wiki/RGBA

Поделиться сообщением


Ссылка на сообщение

P. S. Векторные типы данных также часто используются для хранения цвета. Я не знаю насколько корректно называть это вектором с точки зрения математики, но по-моему это уже не имеет отношения к векторам в математике. 

А что, если с точки зрения физики? Хотя понятия вектора, и там, и там, практически, одинаковые. 

101 из 100, что я  написал какую-то бессмысленную фигню, но все же. 

Поделиться сообщением


Ссылка на сообщение

Win4ester, вектор в программировании это не вектор в математике или физике, это просто еще один тип данных (понятие типизации данных), думай о нем как о контейнере для данных определенного типа, такого типа, который удобно хранить именно в таком контейнере.

Поделиться сообщением


Ссылка на сообщение

О спрайтах, спрайтшитах и текстурных атласах

 

Довольно забавная вещь происходит с терминологией. На самом деле spritesheet и texture atlas это одно и то же, сложно сказать, какое название появилось первым, но некоторых раздражает, когда texture atlas называют spritesheet'ом (наоборот не видел). Так или иначе, текстурный атлас это большое изображение, включающее в себя много маленьких, каждое из которых является текстурой какой-то части 3D-объекта, 2D-объекта (в этом случае чаще всего объекта сразу) или, например, части интерфейса игры (меню, HUD).

 

2w2MBc3.png

 

Под sprite'ом же в 2D-играх может пониматься сам объект, подлежащий такому текстурированию, например, я уверен, что Марио в примере спрайта выше в процессе разработки не раз и не два назвали спрайтом. В 3D-играх спрайты применяются реже, так как там мы имеем дело с трехмерными объектами, однако многие до сих пор помнят спрайтовых персонажей в Doom.

 

VFC0YAb.png

 

Те из вас, кто ковырялся в распакованных S.T.A.L.K.E.R.'ах, наверняка видели много примеров спрайтов в формате *.dds. Зачем же объединять много изображений в одно? Это делается в целях оптимизации, потому что выгоднее подгрузить одно изображение и работать с ним, чем подгружать множество.

 

Так, если нам известны координаты центра нужного изображения в атласе, его ширина и высота, то мы можем легко вычислить все его углы (за (0, 0) на атласе принимается его верхний левый угол, как у canvas, про который я писал выше). Пусть w и h — ширина и высота, x и y — координаты центральной точки, тогда:

  • Половина ширины: cx (традиционное обозначение нужного сдвига по x) = w / 2
  • cy = h / 2
  • Коор. верх. лев. угла = (x - cx, y - cy)
  • Коор. верх. прав. угла = (x + cx, y - cy)
  • Коор. нижн. лев. угла = (x - cx, y + cy)
  • Коор. нижн. прав. угла = (x + cx, y + cy)

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

Поделиться сообщением


Ссылка на сообщение

Те из вас, кто ковырялся в распакованных S.T.A.L.K.E.R.'ах, наверняка видели много примеров спрайтов в формате *.dds. Зачем же объединять много изображений в одно? Это делается в целях оптимизации, потому что выгоднее подгрузить одно изображение и работать с ним, чем подгружать множество.

То есть,  лучше загрузить одно, но подольше, чем каждый раз тратиться на кучу мелочи? 

Поделиться сообщением


Ссылка на сообщение

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

Поделиться сообщением


Ссылка на сообщение
О симуляции физики движения. Основы

 

Для начала стоит отметить, что симулировать всю физику реального мира в игре (а) невозможно и (б) не нужно. Если говорить о физике, то игры создают картинку, которая демонстрирует принципы, напоминающие реальные. Это значит, что объекты в них двигаются, пытаясь симулировать свою естественность, чтобы не вызвать у вас разрыв шаблона. Однако за кадром нет теории струн,  квантовой гравитации и прочих веселых штук, о которых я ничего не знаю. Балом правит некое подмножество механики Ньютона (Фримен не даст соврать, наверное).

 

Для начала немного школьной теории. Сила равна массе, умноженной на ускорение:

 

f = ma

 

Отсюда ускорение:

 

a = f/m

 

Т. к. ускорение — это скорость изменения скорости во времени и равно оно силе, деленной на массу, можно сказать, что сила, деленная на массу, это скорость изменения скорости:

 

dv/dt = a = F/m, где:

 

d — delta (обозначает конечную разность при изменении какого-то параметра, если кто-то забыл, например, последний раз мы измерили время, когда было 10 секунд, а сейчас 15, значит дельта равна 5),

v — velocity (скорость),

t — time (время).

 

Аналогично скорость — это скорость изменения позиции во времени:

 

dx/dt = v

 

Если нам известна текущая позиция и скрость объекта, а также силы, примененные к нему, мы можем рассчитать его позицию и скорость в каком-то моменте будущего. А ведь это нам и нужно — если кто-то в игре толкнул какой-то объект, мы ведь должны знать, куда его переместить и за какое время.

 

Итак, двигаясь к чему-то более практичному:

ускорение (a) = сила (f), деленная на массу (m);

изменение скорости (dv) = ускорение (a), умноженное на дельту времени (dt)

изменение позиции (dx) = скорость (v), умноженная на дельту времени (dt)

 

Для нас это имеет смысл, потому что если машина ускоряется на 10 км/ч каждую секунду со стартовой позиции, значит через 10 секунд она должна ехать 100 км/ч. В коде это может выглядеть так:

 



var t = 0;
var dt = 1;


var velocity = 0;
var position = 0;
var force = 10;
var mass = 1;


while (t < 10) {
    position = position + velocity * dt;
    velocity = velocity + (force / mass) * dt;
    t = t + dt;
}


Когда цикл while закончит работу, на выходе получим t = 10, velocity = 100 и position = 450 (можете убедиться).

Поделиться сообщением


Ссылка на сообщение

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация