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

Http://christmasexperiments.com/2016/20/the-legend-of-the-icecoon/

Рождественские эксперименты были инициированы Дэвидом Ронаи в 2012 году с целью проведения отличных экспериментов и выделения лучших веб-креативщиков, а также новичков.
Я использовал множество передовых методов, которыми хотел бы поделиться со всеми.
Чтобы все знали, это моя первая запись в блоге!

Я постараюсь быть описательным, не стесняйтесь задавать любые вопросы, если есть какие-то размытые части.
Если я ошибаюсь насчет концепции, я буду более чем рад услышать от вас :)

(Спасибо, Элвин за исправление моего французско-английского)
#EXCUSEMYFRENCH

Краткое техническое описание

Построение бесконечного алмазного туннеля, в которое вы погружаетесь, с использованием света, окружающей среды и карты нормалей / постобработки цветов / возможность переключать графику и путешествовать по мирам + переходы с плавным переходом , « пытается» сохранить 60 кадров в секунду на дисплее Retina, даже на мобильном устройстве.

Для меня это звучит как небольшая проблема, я пойду шаг за шагом.

И я начну с… ..

Строительство бесконечного туннеля

В распределении положений туннеля нет секрета, оно основано на TubeGeometry. Https://threejs.org/docs/#Reference/Geometries/TubeBufferGeometry
Идея состоит в том, чтобы создать геометрию трубы из кривой и извлечь положение вершин, разместить повернутую сетку на каждой из них, сядь и посмотри.

Что касается движения камеры, это уже было сделано отличным zz85.

Https://threejs.org/examples/#webgl_geometry_extrude_splines

Никакого колдовства.

Проблема в том, что такой рендеринг будет стоить вам большого количества вызовов отрисовки (количество видимых сеток = количество вызовов отрисовки), а вызовы отрисовки - одно из узких мест в графическом рендеринге.

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

Создание экземпляра геометрии

Чтобы уменьшить количество вызовов отрисовки, мы будем использовать Экземпляр геометрии.
Это плохо документировано на THREE.JS, но вы можете найти пример здесь.
https : //threejs.org/examples/#webgl_interactive_instances_gpu

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

Экземплярная сетка имеет некоторые атрибуты, общие для всей геометрии, и свои собственные InstancedAttributes, специфичные для текущего экземпляра.

Атрибуты
Все экземпляры единого меша имеют один и тот же набор атрибутов, таких как положение (описывает структуру геометрии), нормали, uvs и т. Д.
Ничего особенного, чем обычно буферы здесь.

InstancedAttribute
И у вас могут быть индивидуальные атрибуты, такие как смещение (для смещения геометрии в пространстве), масштаб, цвет, идентификатор, так что каждый экземпляр может иметь разное смещение смещения, уникальный вид и т. Д.

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

И использование in-shader.

Пример экземпляров геометрии + GPGPU

Теперь мы можем визуализировать весь туннель за один вызов отрисовки.

В моем случае имеется 5320 экземпляров (количество вершин в геометрии трубы) * 12 вершин (60 индексированных вершин) = 63840 вершин и столько же обращений к вершинному шейдеру.

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

Поэтому мне нужно только 1024 сетки в моем экземпляре геометрии вместо 5320.

Текстура геометрии

Как компьютерный фанат, я использовал решение, которое позволяет мне визуализировать то, что видно только передо мной в туннеле, используя то, что мы называем текстурой геометрии.

Геометрическая текстура - это текстура, которая описывает один или несколько компонентов геометрии (положения вершин, uvs).

Использование текстур и компонентов RGBA для записи данных, которые не должны отображаться на экране, является хорошо известной техникой.

GPGPU (универсальный графический процессор) - хороший пример того, что мы можем делать с текстурами данных. Вы можете узнать больше об этом в отличном сообщении в блоге Николя Баррадо. Http://barradeau.com/blog/?p=621

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

X = R
Y = G
Z = B

В моем случае мне нужно сохранить 5320 позиций (количество позиций геометрии трубки).

Для поддержки старых графических процессоров (не уверен, что это все еще актуально сегодня, возможно, нет), для уменьшения потребления памяти графического процессора и заполнения текстур в графическом процессоре (вы можете найти некоторые материалы для чтения и обсуждения по этому поводу)….
… Я предпочитаю хранить данные в степени 2 текстуры.

Заявление об ограничении ответственности: я буду рад услышать об этом, если кто-то узнает больше ..

Мы определим наименьший размер, который мы можем использовать для хранения этих позиций.

128 * 128 = 16384

64 * 64 = 4096

128 * 64 = 8192

16384 слишком много, 4096 слишком мало, 8192 нормально!

И поскольку нам повезло, все вершины геометрии генерируются встроенными как Slinky ...

… Каждая позиция будет сохранена как одна строка в dataTexture.

Будет много пустых пикселей (8192 - 5320 = 2872), мы просто установим их равными нулю, потому что мы их все равно не будем использовать.

Этот массив содержит данные нашего DataTexture.
https://github.com/mrdoob/three.js/blob/master/src/textures/DataTexture.js

Как только мы получим нашу геометрическую текстуру, описывающую всю геометрию трубы, мы отправим эту текстуру как sampler2D в шейдер.

Вот как выглядит dataTexture:

PS: Вы можете взглянуть на превосходного FBOHelper и инспектора, созданного Jaume Sanchez Elias
«https://github.com/spite/THREE.FBOHelper женщина

А как у нас выглядит:

Считывание текстуры геометрии в шейдере

Мы хотим, чтобы каждый экземпляр был уникальным, и чтобы они знали, что они уникальны.
Для этого мы просто установим уникальный идентификатор для каждого экземпляра в InstancedAttribute. 0, 1, 2…. , 1022, 1023.

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

Нам нужно будет отправить DataTexture

Нам нужно будет установить размер текстуры данных как единый. [128, 64]

Нам понадобится длина вершин, транспонированная в текстуру [5320].

Камера движется и зацикливается внутри трубы.
Напоминаем:
https://threejs.org/examples/#webgl_geometry_extrude_splines
Шейдеру необходимо знать, как в данный момент движется камера внутри трубки (начало - 0, конец - 1).

Идея состоит в том, чтобы заменить уникальный идентификатор экземпляра текущим перемещением камеры в туннеле.

Преобразуйте 1-размерную координату displacedID в 2D нормализованную строку, col, на основе измерения текстуры.

Затем считайте текстуру данных по этой координате.

Чтобы показать вам, как это работает, вот что я могу увидеть, если отобразить uvToRead как цвет.
Мы можем ясно видеть, как красный канал / координата X uv зацикливается от 0 до 1, и оттенок зеленого канала / координаты Y uv увеличивается по мере продвижения.

Потому что… Значение X uvToRead циклически изменяется от 0 до 1 на основе 128 индексов, и каждые 128 индексов значение Y увеличивается на бит.

Вот снимок того, как это выглядит, когда последовательность действий повторяется!

Теперь у меня есть геометрия из 1024 экземпляров, которая сама по себе трансформируется и меняет положение, один вызов отрисовки, с одним материалом.
Единственное, что осталось сделать, чтобы она работала сейчас, - это обновить значение currentLoopDisplacement с 0 до 1 в зависимости от положения камеры.
Сетка полностью независима, нет обновления атрибутов / рабочей нагрузки процессора / нет данных или загрузки текстур в графический процессор = ОГРОМНАЯ ВЫИГРЫША.

Это невероятно производительность и действительно гладкая работа на многих компьютерах / графических процессорах / мобильных устройствах. Даже MacBook Air 13 дюймов с дешевым чипсетом / iPhone5. Я просто сохранил некоторую обработку и могу сосредоточиться на внешнем виде и ощущениях!

Продолжение следует… (Постобработка + переходное затухание).

А пока можете посетить мое портфолио:

Http://samsy.ninja

Или / И / Следуй за мной в твиттере :)

Https://twitter.com/Samsyyyy

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

И большие похвалы моему брату, любимому дизайнеру и одному из моих лучших друзей:

Http://stevenmengin.com/

Https://twitter.com/steven_mengin