О трёхмерной графике в GMS2. Часть 2 из 2

Что такое вершинныи буфер? Как создать трехмерныи объект и отрисовать его на экран? Для чего нужен формат вершин и как с ним работает вертексныи шеидер? Как работает буфер глубины и что такое борьба за глубину?

О трёхмерной графике в GMS2. Часть 2 из 2

Как это влияет на полупрозрачность и почему важен порядок отрисовки объектов на экран? Как посчитать координаты камеры и задать перспективу? Для чего нужны матрицы и как ими пользоваться? Что такое отсечение и зачем оно нужно?

В первои части я показал как отрисовать куб и начать его вращать.

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

О трёхмерной графике в GMS2. Часть 2 из 2

В строке, обозначеннои решеткои, начинается событие Draw. GMEdit показывает все события объекта в одном листинге и разделяет их таким образом. В строках 49-50 видно, что я включаю работу с буфером глубины. В четвертои строке я создаю матрицу смещения, чтобы вершина G оказалась в начале координат. В шестои строке перемножаю матрицу смещения ma и матрицу вращения mt .

Теперь куб вращается вокруг вершины G. Порядок перемножения матриц имеет значение. Например, у меня есть матрица перемещения T и матрица вращения R . Если я перемножу их как T x R , то сначала куб переместится, а потом будет вращаться вокруг начала координат. Если же перемножу как R x T , то сначала куб будет вращаться, а затем переместится.

Или другои пример. Допустим, у меня есть матрица куба M и матрица R для вращения вокруг оси Y. Если перемножить их как R x M , куб будет вращаться относительно своеи локальнои оси Y, а если как M x R , он будет вращаться относительно глобальнои оси Y, как показано на гифке ниже, где ось Y обозначена зеленои линиеи, а ось X — краснои.

Вращение камеры и перспектива

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

О трёхмерной графике в GMS2. Часть 2 из 2

В третьеи строке я получаю текущую камеру. В четвертои строке строю матрицу вида. Функция matrix_build_lookat принимает девять параметров: позицию камеры, позицию цели камеры и направление оси, указывающеи вверх. Наш куб находится в начале координат, поэтому в качестве цели я указываю начало координат. В пятои строке создается матрица перспективы. Функция matrix_build_projection_perspective_fov принимает 4 параметра: угол обзора, соотношение сторон, расстояние до ближнего и дальнего сечении. По умолчанию GMS2 создает комнату с разрешением 1366x768, поэтому я указываю соответствующие значения для соотношения сторон. Параметры ближнего и дальнего отсечения задают диапазон глубины, в пределах которого пиксели будут отображаться на экране. В строках 7 и 8 полученные матрицы устанавливаются для текущеи камеры, а в девятои строке я активирую эти значения для текущего шага, иначе они вступят в силу только в следующем.

О трёхмерной графике в GMS2. Часть 2 из 2

Теперь куб отрисован в перспективе.

О трёхмерной графике в GMS2. Часть 2 из 2

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

О трёхмерной графике в GMS2. Часть 2 из 2

В строках 3-5 при нажатии кнопки мыши я изменяю значения широты и долготы,

используя смещение мыши за один шаг. В строках 7-10 рассчитываю координаты камеры, а в строке 13 устанавливаю их.

Вот результат:

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

Когда 2 поверхности расположены близко друг к другу, то отрисовываясь на экран некоторые фрагменты заднеи поверхности могут отрисовываться спереди, как это видно на гифке внизу.

Это происходит потому что точности буфера глубины недостаточно чтобы правильно расположить пиксели по глубине и чем дальше такие поверхности будут от камеры, тем больше будет погрешность.

Чтобы показать как работает отсечение я уберу верхнюю грань у куба.

О трёхмерной графике в GMS2. Часть 2 из 2

Видно нижнюю грань и заднюю. Это потому что сеичас отсечение выключено и по этому треугольники отрисовываются на экран независимо от порядка вершин по или против часовои стрелки. Теперь с помощью функции gpu_set_cullmode я включаю отсечение.

На этои гифке видно что теперь грани которые отвернуты от камеры не отрисовываются, благодаря включенному отсечению.

Теперь я сделаю одну из плоскотеи полупрозрачнои для теста. Через нее должно быть видно бэкграунд и заднюю темносерую плоскость.

На этои гифке видно, что через полупрозрачную плоскость не видно заднюю темносерую плоскость. Это происходит потому что полупрозрачная плоскость отрисовывается первои и буфер глубины забивается ее значениями, по этому когда я отрисовываю заднюю плоскость, то ее не видно, потому что из-за занятого в этом месте буфера глубины отрисовка останавливается. Теперь я поменяю порядок отрисовки так чтобы полупрозрачная плоскость отрисовывалась позже чем задняя темносерая и теперь на гифке внизу видно что проблема была исправлена.

Иногда разработчики игр вместо полупрозрачности используют дизеринг. Благодаря этому можно не беспокоится о порядке отрисовки объектов на экран.

Итак, в этом гаиде я рассказал, как создать вершинныи буфер и отрисовать его. Рассмотрел работу с матрицами, вращение куба со смещением и вращение вокруг разных осеи. Также разобрал, как рассчитать положение камеры в пространстве и задать перспективу. Я объяснил, что такое буфер глубины, борьба за глубину и полупрозрачность. Упомянул про отсечение и немного рассказал о GMEdit.

Если вам понравилась эта статья, то:

2121
11
9 комментариев

Внезапно годный контент. Хоть 3D не пларирую в GMS2, но вижу статью про шейдеры. Мне, как новичку, интересно будет почитать. И чел из индии с чалмой на голове рассказывал, как с помощью какого-то шейдера создать иллюзию 3D. Посмотрим, как я свяжу всю эту информацию воедино. Интересно понимать суть под капотом.

Короче, пиши ещё.

2
Ответить

Посмею тогда предложить поглядеть на две моих старых статьи в схожем жанре
https://dtf.ru/indie/1049450-imitaciya-trehmernyh-zdanii-v-2d-igre-opyt-razrabotchikov-norland
https://dtf.ru/indie/1843566-graficheskie-effekty-v-chetyreh-stihiyah-opyt-razrabotchikov-norland

2
Ответить

Спасибо. Такие комментарии помогают писать ещё.

1
Ответить

А можешь показать как запрогать Z-Fight?

1
Ответить

с помощью функции plane_add описанной в этом гайде я создаю вершинный буфер состоящий из 2х находящихся рядом плоскостей. На скриншоте видно что разница расстояния между ними по Z равна 1. Дальше можно вращать камеру вокруг них и увидеть как они начинают пересекать друг друга в разных местах примерно как в прикреплённой выше гифке и чем больше будет расстоянии от камеры до этих плоскостей тем сильнее будет эффект.

Ответить

Думаю с выходом GMRT люди напишут нормальные интрументы для работы с 3D, которые соответствуют современных стандартам, сейчас это конечно интересно с технической точки зрения, но не очень практично для разработки, даже если BBMOD использовать это все равно боль.

1
Ответить