Skip to content

Latest commit

 

History

History
227 lines (95 loc) · 85.1 KB

a5.советы_по_WebGL.md

File metadata and controls

227 lines (95 loc) · 85.1 KB

Типичные советы по WebGL

Здесь собираются типичные советы по WebGL.

Ситуативные советы

Про одну камеру и одну сцену

☝️ - Имейте в виду, что в конечном счете все это будет одной 3D-сценой с одной камерой. При разработке может быть удобно иметь несколько камер, но потом все равно нужно будет все объединить. В контексте курса будет проще это сделать сейчас, пока кода мало.

Про SVG extrude

☝️ - Очевидно, что некоторые объекты поломались. Обратите внимание на направление замкнутых контуров в SVG, именно по нему определяется внутренняя часть контура для заливки цветом, или, как в нашем случае, для определения, где должны быть плоские грани объекта. Изменить направление контуров в SVG можно в любом векторном графическом редакторе. Также у метода toShapes у ShapePath в Three.js есть параметр, которым можно изменить прямое и обратное направления кривых (по крайней мере их интерпретацию в рамках текущей задачи).

Про препроцессор

💡 - Мысль на будущее: у нас тут есть препроцессор. Можно делать штуки вроде #define PI 3.1415. А потом, когда шейдер будет компилироваться, препроцессор будет подставлять нужные значения в места, где "PI" написано. Это похоже на то, как мы в каком-нибудь LESS/SASS делаем глобальные константы. В таких расчетах часто накапливаются какие-то стандартные числа, цвета, еще что-то, и препроцессор может сделать все более человеко-читаемым, не увеличивая никак нагрузку на железо. А еще это поможет избежать ситуации, когда в третьей константе на 279 строке описался, и все вроде выглядит так, что должно работать, а на деле глючит. В перспективе, в больших шейдерах это может упростить отладку.

Про прогресс от 0 до 1

💡 - И в CSS, и в SVG, и в большинстве JS библиотек у нас будет такая абстракция, как прогресс анимации. От 0 до 1. Иногда от 0% до 100%, но обычно от 0 до 1. Временные функции в шейдерах ничем не отличаются от других технологий, и мы можем тоже этот прогресс от 0 до 1 использовать. Это упрощает переиспользование формул как между технологиями, так и просто между разными шейдерами - они не завязываются на какие-то локальные представления о длительностях чего-то. Такое переиспользование не всегда нужно, но когда возникает потребность - подход с прогрессом от 0 до 1 упрощает работу.

Про множители

💡 - Бывают ситуации, когда нужно вынести коэффициенты куда-то, сделать их все человеко-понятными. Может быть в какой-то конфиг, может быть в какой-то элемент интерфейса, чтобы пользователь их менял, может еще что-то. Особенно это касается длительностей анимаций или размеров чего-то. И становится удобно иметь их все в виде слагаемых и множителей. Без делителей. Чтобы они и в нашей голове, и в коде с ними связанном, все интерпретировались по одной и той же логике. Тут может быть хорошей идеей формулы сразу форматировать в виде 0.01 * x вместо x / 100.0, чтобы у нас были именно множители везде.

Что делать, когда свет не доходит до объекта

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

Закрепленные советы

🔒 5.01 (про советы при работе с Three.js)

💡 - Первоисточник информации в мире WebGL - Khronos Group. Если возникают какие-то вопросы по синтаксису, по тому, как что должно работать - их спецификации дадут ответы на все вопросы. И, раз уж мы занимаемся шейдерами, то стоит сразу положить в закладки спецификацию OpenGL ES Shading Language.

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

💡 - И еще замечание про зависимости: фиксирование версии Three.js в package.json - это скорее хорошая идея, чем плохая. Разработчики этого инструмента часто ломают обратную совместимость. Иногда они предупреждают в консоли о том, что изменилось, а иногда - просто появляются какие-то фантомные баги, связанные с рендерингом изображения. Их исправление - очень неприятное занятие, которое может усугубляться, если у разных членов команды в какие-то моменты времени были разные версии Three.js и какие-то куски проекта хорошо работают с одними версиями, какие-то - с другими, и никто уже точно не знает, какие с какими работали. Это, наверное, самая неприятная ситуация, которая может приключиться. Так что может иметь смысл фиксировать версию Three.js и потом при желании обновлять одновременно для всей команды, с последующим тестированием всего функционала. В целом именно проблемы с обратной совместимостью и отсутствие единого контроля за экосистемой - это главные минусы Three.js, если сравнивать этот инструмент с другими в этом классе.

🔒 5.02 (про шаблонные строки, валидатор и чистый WebGL)

💡 - Написание шейдеров в шаблонных строках - решение не самое удобное. В первую очередь из-за потери подсветки синтаксиса и смешения всего в одну кучу. Альтернативно можно хранить код шейдеров в HTML, используя тег script, вроде <script id='my-vertex-shader' type='x-shader/x-vertex'>. Это может быть неплохим вариантом для небольших демок или еще чего-то, что должно работать без системы сборки. Часто можно встретить такой подход в примерах на CodePen. Там будет хоть какая-то подсветка синтаксиса. Но самый удобный и универсальный подход - хранить код шейдеров в отдельных *.glsl файлах и подставлять их содержимое в JS-скрипты при сборке с помощью плагинов для webpack или других сборщиков - там много вариантов на любой вкус и цвет. Такой подход позволяет не только иметь нормальную подсветку всего, но и в перспективе использовать glslangValidator, чтобы компилировать и проверять шейдеры отдельно, а не в реальном времени посреди проекта.

💡 - Частая задача при работе с WebGL - сделать какие-нибудь эффекты для фотографий на сайте. Волны разного рода, лупу под мышкой, какую-нибудь пикселизацию и.т.д. Там основа всего - это одна плоскость и шейдеры. В таких задачах функционал Three.js будет избыточным. Может быть 1% от него будет использоваться. В таких ситуациях может быть хорошой идеей отказаться от этого инструмента и перейти на чистый WebGL. Ну или на какую-то более легковесную библиотеку. Это положительно скажется на скорости загрузки страниц. В этом курсе мы используем Three.js в этой задаче только потому, что это промежуточный шаг, эти шейдеры потом будут использоваться для постобработки в рамках этого самого Three.js.

🔒 5.03 (про цветовые модели и стандарты)

💡 - Для общего развития полезно познакомиться также с разными цветовыми моделями, узнать разницу между ними, и добавить в свой инструментарий функции конвертации цвета из одной в другую. В генеративной графике с яркими чистыми цветами часто гораздо удобнее все делать в HS*, и только в конце конвертировать цвета в RGB для вывода на экран. Но помимо математического удобства есть сопутствующая задача, которая может возникнуть - это синхронизация цветов на канвасе с окружающей версткой. В мире дизайна интерфейсов все уверенно движется в сторону отказа от RGB и HSL в пользу вариаций на тему Lab. Например в CSS у нас уже можно сказать везде поддерживаются функции lab() и lch(). При работе с современной версткой может быть хорошей идеей и цвета на канвасе перевести в тот формат, который там, чтобы между CSS и канвасом сохранялась логика смешиваний, формирования градиентов и.т.д.

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

💡 - В работе вы можете столкнуться с тем, что ваш вроде бы работающий код иногда работает, а иногда - нет. При этом никаких ошибок. Это называется undefined behavior. В современном JS мы с этим не особо сталкиваемся, а вот в GLSL, C, C++, и.т.д. (фактически во всем семействе С) - это неопределенное поведение поджидает на каждом шагу. С подходом "чик-чик и в продакшен" мы можем легко получить программу, которая работает не всегда, не у всех пользователей. Этого нужно избегать. Такие проблемы могут зависеть от конкретных комбинаций ОС, браузера, видеокарты и.т.д. и это очень сложно отлаживать. Обращайте внимание на то, какие параметры вы передаете в стандартные функции, и, если вы не уверены, как работает какая-то штука, и что в нее нужно передавать - стоит открыть спецификацию и проверить свои предположения. Там нигде нет "защиты от дурака", поэтому корректность данных нужно всегда проверять самостоятельно.

🔒 5.04 (про хардкод)

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

🔒 5.05 (про интуицию и эксперименты)

💡 - Разработка креативных сайтов с WebGL - это область, которая отличается от "обычного" фронтенда. Здесь мы очень часто будем попадать в ситуацию, когда готовых решений нет. Просто нет. Особенно если речь идет про визуальные эффекты. При работе в своеобразном информационном вакууме начинают проявляться понимание основ компьютерной графики, как в целом строится изображение, какие там примерно алгоритмы и что может пойти не так, и математическая интуиция. Именно не знание определений, каких-то умных слов, а понимание, что на что влияет. Поэтому здесь я, не в первый и не в последний раз, подтолкну вас к тому, чтобы интересоваться всем подряд в этой области и больше экспериментировать. Пробуйте делать разные штуки и смотрите, что из этого получается. Меняйте коэффициенты и знаки в формулах, совмещайте несовместимые вещи, даже если вы не знаете, что из этого выйдет, и где конкретно пригодится тот или иной эффект. Даже не так: если вы не знаете, что выйдет - это обязательно нужно попробовать и посмотреть. Также смотрите на чужие эксперименты, например вот одна цепочка примеров на чистой WebGL и еще одна в рамках Three.js (иногда наблюдаются сбои в загрузке ресурсов с некоторых хостингов, сязанных с cloudflare, так что если вдруг картинки в демонстрациях не грузятся - попробуйте включить/выключить vpn). На CodePen люди много всего интересного публикуют. Не ограничивайте себя учебником. Чем раньше вы начнете развивать в себе интуитивное понимание вещей, тем проще потом будет в работе.

🔒 5.06 (про дискотеку у дизайнера и консультации)

💡 - Когда смотришь на эту анимацию в видео-концепте возникает впечатление, что она очень ядреная. Слишком маленькая длительность для таких изменений цвета. В подводном мире все должно быть плавным и размеренным, а там прямо дискотека. Если бы у нас был реальный проект, то это было бы поводом сходить к дизайнеру и спросить, а это ли он вообще имел в виду. Может быть и нет, просто не выспался и не заметил. Нужно помнить, что обычно мы - последнее звено в процессе разработки, и именно нам нужно проверять ошибки дизайнера, не стесняясь задавать ему глупые вопросы. Дальше - только конечные пользователи. Даже если часть наших сомнений не подтвердятся - другая часть поможет исправить странности во внешнем виде сайта или в логике его работы еще до того, как их увидят все. Обычно в мире фронтенда не принято строить процесс так, чтобы фронтендеры поправляли дизайнеров, но в мире таких рекламных проектов мы часто работаем вместе и проверяем друг друга.

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

🔒 5.07 (про WebGL Fluid Simulation, физику и фракталы)

💡 - По теме шейдеров будет полезно дополнительно познакомиться с библиотекой WebGL Fluid Simulation, если вы еще не знакомы. Это популярный инструмент, про который стоит знать. А может быть даже потом стоит разобраться, что за магия там происходит внутри. Многие подобные фоновые визуализации строятся на физических моделях, например на модели идеальной жидкости, или на основе магнитного поля. Если в перспективе вы захотите заниматься такими вещами, то нужно будет немного погрузиться в физику и посмотреть, что в этой предметной области есть. В целом у нас не так много мест, где востребованы одновременные знания и фронтенда, и физики, но там, где это нужно - людей конкретно не хватает. Так что это может быть одним из направлений дальнейшего развития, которое, если идти еще дальше, перекликается с разработкой игр.

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

🔒 6.01 (про отладку света, тени и компьютерную графику и карьеру)

☝️ - При отладке света на сцене может быть хорошей идеей сделать источники света разноцветными. Например один ядрено-зеленым, другой ядрено-розовым и.т.д. Это позволит лучше видеть световой рисунок на сцене и будет проще подобрать параметры для источников света. Я иногда в своих проектах делаю флаг для отладки, который сбрасывает все материалы в нейтрально серый цвет, включает легкий нейтральный AmbientLight и делает остальные источники света рандомно-разноцветными. Это очень помогает разобраться в сложном освещении.

☝️ - Также на время разработки можно подключить OrbitControls, чтобы крутить сцену и видеть ее с разных сторон. Это может быть полезно и при отладке света, и при расстановке объектов на сцене.

💡 - Полезно при изучении разных штук в рамках Three.js обращать внимание и на то, что скрыто внутри них. Это – библиотека, набор готовых решений каких-то задач из мира компьтерной графики, и хорошо знать, что там происходит внутри. Не только для общего развития кругозора, но и для понимания, что и почему может повлиять на производительность, куда смотреть, если на экране появляются какие-то артефакты и.т.д. Все это выходит за границы курса, но если вы хотите погрузиться в саму предметную область и решать задачи, выходящие за рамки примеров из документации, и, как следствие, претендовать на соответствующие позиции в проектах – читайте больше статей и книг по компьютерной графике. Все, до чего руки доберутся. И, что важно - от разных авторов, с разными специализациями. Математики, физики, программисты - каждый будет давать вам что-то от себя, свой контекст задач, формируя разностороннее видение отрасли. Хотя по сути все книги будут про одно и то же. Конкретные инструменты меняются, но общие принципы формирования того же 2D изображения из 3D сохраняются десятки лет. Это знания, в которые вкладываешься один раз на всю жизнь. Если говорить про рынок и перспективы в целом, то наша отрасль взрослеет и в последние годы наблюдается тенденция, что на позициях WebGL-разработчиков уровня senior/lead основы компьютерной графики становятся обязательным требованием. Конечно, можно сказать, что не во всех компаниях будут сложные задачи, где-то люди занимаются исключительно копипастой, и у них все ок, но даже там начиная с какого-то момента в карьере вам нужно будет брать ответственность за происходящее. Понимание того, как что работает, сильно поможет с оценкой сроков и вообще реалистичности реализации тех или иных вещей.

🔒 6.02 (про библиотеку моделей и материалов)

💡 - В таких проектах часто идут по пути создания отдельной библиотеки моделей, текстур, материалов и.т.д. Она в начале инициализируется сама в себе, а потом наши сцены из нее берут только то, что им нужно. Для нас часто бывает важно переиспользование ресурсов и такая библиотека помогает не создавать одно и то же много раз, если в этом нет необходимости. В качестве бонуса она же разделяет код проекта на логические части, его проще поделить на задачи для команды. И, поскольку загрузка ресурсов происходит плюс-минус в одном месте - следить за ней удобнее. Мы можем в рамках одного модуля понять, какие ресурсы откуда взялись и где используются. Или не используются. Прелоадер тот же самый с процентами - намного проще сделать, чем если код создания моделей и материалов будет размазан по всему проекту. Здесь будет много заданий про загрузку моделей разными способами и может быть полезно по ходу дела подумать над разными способами организации всего этого кода. Тут нет единственно правильного варианта проектирования такой библиотеки, но стоит по крайней мере про такой подход знать и может быть проанализировать разные варианты до того, как это придется делать в работе.

🔒 6.03 (про instancedMesh)

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

🔒 6.04 (про BufferGeometry)

💡 - Генерирование геометрий, и, в частности, полностью своих геометрий - это относительно частая задача в генеративной графике. К сожалению в учебном проекте это просто негде применить. Дизайн такой. Ничего не поделаешь. Но для своего кругозора имеет смысл потом загуглить эту тему, начав с BufferGeometry в документации к Three.js и примеров оттуда. Там есть общая для многих инструментов в мире компьютерной графики идея, что мы можем перечислить список вершин (vertices, координаты XYZ), список индексов вершин (indices, его можно грубо представить как массив массивов - это массив полигонов, каждый из которых является массивом из индексов вершин, которые в него входят), список цветов (для каждой вершины - цвет, в который ее нужно покрасить, альтернативно это будет массив координат UV, точек на текстуре, если мы хотим использовать текстуры), и список нормалей (normals, перпендикуляры к поверхности, чтобы понимать, как свет рассчитывать). В результате получится свой хитрый объект. В рамках Three.js логика формирования этих списков уже реализована для плоскостей, кубиков, сфер, и что там еще есть. Мы не задумываемся, но она там есть. А если возникнет потребность, то можно вручную сделать любую геометрию, используя те же инструменты.

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

🔒 6.05 (про кеширование материалов)

💡 - В учебном проекте объекты мало пересекаются по материалам, поэтому тут этому можно не придать значения, но подчеркну момент, что в проектах более крупных имеет смысл следить за тем, чтобы не создавались дублирующие друг друга материалы. Это может заметно повлиять на производительность страницы в целом, особенно если там идут материалы с текстурами, используется сложное освещение или мы активно меняем передаваемые в шейдеры параметры. Если у нас создается миллион объектов с одним по смыслу материалом, то было бы хорошо его создать только один раз. Или на месте, при создании объектов, или, если в архитектуре проекта есть отдельная фабрика материалов, то можно в ней предусмотреть какой-то механизм сохранения материалов для переиспользования. Внутри Three.js есть какой-то механизм кеширования, но работает он не очень предсказуемо, особенно с кастомными материалами, и его поведение меняется от версии к версии. Надежнее иметь свой.

🔒 6.06 (про расширение материалов)

☝️ - По всей видимости формулировка задания путает, но то, что вы сделали - это не совсем то, что нужно. Ваши шейдеры дают вам только текстуру на поверхности объектов. Это работает. Но по идее нужно туда же интегрировать всю логику работы материалов, которая уже есть в Three.js (свет, тени, отражения и.т.д.). Смысл расширения материалов именно в том, чтобы совместить готовое с дополнительной функциональностью, а в вашем случае получается, что вы делаете материал, в котором есть ваша логика, но полностью отсутствует логика из стандартных материалов. У вас в целом все получается, так что задание будет формально принято, но с напутствием разобраться в этой теме.

💡 - Полезно познакомиться с альтернативным решением, не упомянутом в учебнике: у материалов есть onBeforeCompile, и можно прямо перед компиляцией шейдеров для материалов их частично модифицировать. В частности интегрировать туда свои шейдерно-сгенерированные текстуры. Например как это сделано здесь. Такой подход позволяет очень сильно упростить понимание происходящего, т.к. мы сразу видим, какие части стандартных шейдеров изменены, когда и зачем. Если копипастить стандартные шейдеры к себе в проект целиком, то возникает проблема - не совсем понятно, что именно там где изменено, что это за материал был изначально, и где искать причины ошибок. Представьте, что у вас в проекте несколько десятков таких материалов, и там везде одинаковые, но не совсем, простыни кода. Это и ревьювить невозможно, и баги там искать - то еще удовольствие. Точечные модификации в явном виде всегда проще воспринимаются.

💡 - Для расширения кругозора можно познакомиться с еще одним решением этой задачи: если нужно сгенерировать текстуру и при этом воспользоваться стандартными свойствами материалов из Three.js (тени, блики и.т.д.), и если текстуру сложно сообразить в рамках одного шейдера, то можно все нарисовать на отдельном канвасе, в том числе на 2D, и использовать его как текстуру, например как в этой демонстрации. А еще так можно выводить видео на поверхность модели. А в теории можно и результат, полученный после выполнений шейдеров, сохранять и переиспользовать в других шейдерах, или даже в тех же самых. Но к этому мы еще вернемся в будущем. Важно понять идею, что текстура - это понятие очень растяжимое, по сути это картинка, а картинки можно переиспользовать в самых разных комбинациях.

🔒 6.07 (про оптимизацию моделей)

💡 - В целях общего развития может быть полезно взять какой-нибудь 3D-редактор, например Blender (он бесплатный и кроссплатформенный), и посмотреть на то, как устроены сложные модели:

💡 - На примере самолета из курса можно посмотреть пример модели, которую в контексте фронтенда нужно бы отправить на доработку. Количество вершин здесь можно уменьшить на порядок, без какого-либо влияния на видимый результат. Например такая детализация окон нам в проекте точно не нужна - самолетик слишком маленький, чтобы что-то там разглядеть. По идее нам нужно стремиться к использованию low poly моделей, и этот факт в требования нужно закладывать сразу, еще до их создания. И про контроль не стоит забывать, особенно при работе со сторонними подрядчиками. В большинстве случаев дизайнер или менеджер не может такие вещи проверить, так что это наша забота. На этом моменте можно улучшить не только размеры моделей (и скорость их загрузки по сети), но и общую производительность, т.к. значительно снизятся требования для видеокарты. Мне встречались проекты, где только оптимизация моделей позволяла увеличить средний fps на сайте с 2-3 кадров до 30-40 на ноутбуке с обычной UHD Graphics.

💡 - В ситуации экстренных правок, когда нужно действовать своими силами, можно попробовать воспользоваться автоматическими оптимизаторами. В Blender у нас есть Mesh > Clean Up > Decimate Geometry. Эта штука может попытаться уменьшить количество вершин сохранив общую форму модели. Это не в каждом случае сработает, зависит от того, как модель собиралась изначально, и результат будет не настолько впечатляющим, как при изначальном создании low poly модели, но в крайнем случае такой инструмент может хоть немного улучшить ситуацию.

🔒 6.08 (про разное управление камерой)

💡 - При сборке сцен иногда может быть удобно повключать разные варианты управления камерой. OrbitControls - это хороший вариант для простых сцен, но в более сложных, где есть объекты разного размера и их внутренности, может быть проще использовать FlyControls. Камера не будет фокусироваться на конкретном объекте, и ей можно будет летать везде. Это будет похоже на то, как камера работает в 3D-редакторах. Вообще в Three.js есть разные варианты управления камерой, можно со всеми познакомиться. Вдруг пригодится.

🔒 6.09 (про сборку и развитие)

💡 - В учебнике у вас предлагается собирать сцены прямо в браузере. Это иногда может быть уместно, если они интерактивные или если там что-то рандомизируется, так что практика лишней не будет. Но если смотреть со стороны, то в контексте сцен комнат такой выбор инструмента выглядит странно. В большинстве случаев при работе со статичными сценами их будет куда быстрее собирать в рамках 3D-редактора и загружать в уже собранном виде. В целом, если говорить про свое развитие в формате "T-shape", то умение делать какие-то такие базовые вещи в 3D-редакторах может быть очень хорошим навыком в дополнение к специализации на WebGL.

🔒 6.10 (про тени и FPS)

☝️ - Обратите внимание на то, что у нас могут пойти артефакты по всем объектам, которые принимают тени. Без знаний из мира компьютерной графики такие проблемы сложно загуглить, поэтому оставлю тут алгоритм, куда бы я смотрел, если бы увидел что-то такое в своем проекте. Ну и намекну еще раз, что базовые знания бывают нужны не только на словах. У нас есть три стандартных шага, которые можно предпринять, чтобы избавиться от артефактов: первый - увеличить размер карт теней (shadow map) для источников света и по возможности уменьшить объем пространства (frustum) в котором источники света работают. Это уберет пикселизацию теней. До бесконечности увеличивать нельзя, в браузерах есть ограничения. Плюс расчет карт теней сам по себе - операция затратная, так что тут нужно знать меру. Второй шаг - смещение теней (bias). Это такой хитрый костыль в алгоритме расчета теней, который может убрать муар. Третий - у рендерера можно выбрать тип карты теней. Иногда выбор алгоритма, по которому рассчитываются тени, может влиять на результат. Поскольку в вашем проекте артефакты теней определенно присутствуют - стоит попробовать их починить.

💡 - В проекте постепенно накапливаются вопросы по части производительности. Будет полезно узнать, что стандартные инструменты разработчика, например FPS-meter в Chrome, могут сильно привирать при работе с канвасом. По их показаниям может казаться, что все хорошо, но глазами видно, что это не так. Или наоборот - все работает хорошо, а инструмент говорит, что все плохо. Здесь все так же, как и с PageSpeed Insights, если вы понимаете, о чем я. В основном причины этого кроются в том, что у нас из браузера не так много (фактически вообще нет) возможностей получать полную и достоверную информацию о происходящем на видеокарте. В качестве альтернативы FPS-meter можно сделать какое-нибудь свое решение или взять stats.js. Кажется, что это самый популярный инструмент для отображения FPS среди разработчиков, связанных с Three.js.

☝️ - У вас в критерии Б1 говорится, что анимация должна быть сделана без сторонних библиотек, но здесь речь именно про отладку, это можно потом убрать перед защитой.

🔒 6.11 (про анимации)

💡 - Раз уж у нас все возвращается к собственно анимациям, стоит сказать, что в Three.js действительно есть своя инфраструктура для анимаций. В учебнике было пару слов про нее. У нее долгое прошлое. Что-то она умеет, что-то не умеет, в чем-то похожа на то, как это устроено в игровых движках. Но практика показывает, что люди из мира фронтенда ей редко пользуются. Обычно в проектах уже есть тот же GSAP, и нет нужды его дублировать. Главная фишка этой встроенной системы анимаций - это возможность проигрывать экспортированные анимации из 3D-редакторов. Это главная причина к ней обратиться. Но я бы здесь предостерег от поспешных выводов о ней. Там много подводных камней. Например не во всех форматах моделей можно сохранить анимации, где-то нельзя иметь большое их количество, где-то их нужно организовать особым образом и.т.д. Если вдруг возникнет возможность построить процесс разработки с перспективой что-то экспортировать и проигрывать в рамках Three.js - стоит сразу погуглить, насколько это будет реалистично, и какие на месте могут возникнуть требования к моделям, чтобы 3D-художники сразу понимали, куда все идет. Если в этом процессе что-то пойдет не так, то это может стать блокирующей проблемой в проекте.

🔒 7.01 (про скелеты)

💡 - Тут вы можете обратить внимание, что идея сделать обертки вокруг элемента для разных трансформаций, чтобы разделить сложное движение на ряд простых, не новая. Мы такое делаем и в рамках CSS, и в SVG. Часто проще рассчитывать расположение объектов относительно других объектов, а не относительно всего мира. Но в рамках компьютерной графики в целом есть еще такая популярная абстракция для вычисления расположения вершин объектов, как скелеты. Оно может по-разному называться, но оставлю ссылку на пример в рамках Three.js. Сочетание таких скелетов с вложением объектов друг в друга позволяет делать очень много всякого разного. В учебных заданиях тема скелетных анимаций не затрагивается, но в работе может пригодиться. Имеет смысл познакомиться.

🔒 7.02 (про термины и размерности)

💡 - В учебнике на этом внимание не акцентируется, но я бы добавил одну мысль: если моделируется какое-то физическое явление, какой-то известный науке объект, то может иметь смысл использовать общепринятые термины для обозначения разных величин. У самолета там будет крен, тангаж, рыскание и.т.д. Особенно польза будет заметна если они потом используются в каких-то формулах, где нужно не только понимать, что есть что, но и важны знаки. Или если какие-то из величин логически связывают разные объекты. Например у более продвинутого самолета могли бы быть визуально заметные рули, которые тоже бы поворачивались. Тут задание маленькое, поэтому пользу от такого подхода оценить сложно, но в более замороченных задачах стандартное именование всего может упростить работу.

💡 - И сопутствующая мысль, которая тоже не очень акцентируется в учебнике, но часто встречается в мире компьютерной графики: при работе с физическими явлениями очень (вот прям очень очень) удобно считать условную единицу размерности пространства (в WebGL в нашем случае) равной одному физическому метру. Это заметно упрощает понимание происходящего. Почему в учебном проекте комнаты построены не так - загадка.

🔒 7.03 (про тесты и порталы)

💡 - Если у нас есть множественные переходы между сценами в 3D, как в этом проекте, то нужно держать у себя в голове, что переходы бывают между всеми сценами. 5 сцен = 20 возможных переходов. Понятно, что они там типовые, какие-то мы можем заблокировать, но тем не менее. Важно дизайнера пинать, чтобы он описывал логику всех возможных переходов, а не только основных. Ну и реализовывать ее, соответственно. Иногда для этого могут понадобиться какие-то трюки с пространством. На примере этого проекта - мы можем перемещать сцену с замочной скважиной за спиной у камеры, чтобы она всегда была доступна для пролета камеры назад из любой комнаты. В более сложном варианте возможно создание логики порталов, когда одна сцена существует в 3D-мире больше одного раза, и за счет этого мы можем создавать эффекты в духе "пройти вперед в дверь, которая находится за спиной". Или можно взять дополнительную камеру, отрендерить сцену в нее, сохранить в текстуру, а потом использовать эту текстуру для какого-то объекта внутри этой самой сцены. В общем в вопросах перемещения камеры мы можем не только ее двигать, но и менять строение пространства вокруг. Это стоит знать, и при случае использовать.

🔒 7.04 (про запекание)

💡 - Летающие источники света с тенями - это красиво, но они требуют вычислительных мощностей для работы. Чем больше источников - тем больше это все будет требовать. Обычно в проектах со сложным освещением люди стараются уменьшить количество источников света, которые на самом деле должны двигаться, делают так, чтобы они по возможности все же стояли на месте. Это открывает путь к использованию такой штуки, как lightMap. Грубо говоря мы собираем сцену в 3D-редакторе, нажимаем кнопку, и получаем текстуру, в которой сохранена информация об освещении. Потом в реальном времени мы уже никакой свет не рассчитываем, а используем цвета из этой текстуры. Не знаю, почему в учебнике на этом не делается акцента, но такие карты света и теней крайне положительно влияют на производительность. И сопутствующая вещь - envMap. То же самое, но в эту текстуру сохраняется информация об отражениях окружающего мира на 3D-объектах. В рекламной индустрии ее часто используют для создания реалистичных отражений на товарах, вплоть до того, что катаются по улицам с 360-камерой, а потом из полученных изображений генерируют отражения для каких-нибудь моделей машин, которые никогда на этих улицах не были. Но в нашем контексте главным поводом для их использования опять же будет экономия ресурсов. Физически правильные отражения - тоже задачка требовательная. В целом этот процесс подготовки всего заранее называется запеканием (baking). Запекать можно очень много всего. Что-то запечь проще, что-то сложнее. Можно запечь нормали используя высокодетализированную модель, а потом использовать их на идентичной низкодетализированной модели. Будет казаться, что у нее больше деталей, чем есть на самом деле. В каких-то случаях, когда сцена статичная, мы можем вообще все сохранить в одну текстуру - и освещение, и отражения, и что там еще будет. И потом в реальном времени не только не рассчитывать все по отдельности, но и не хранить в виде нескольких текстур в памяти. В общем запекание - это один из основных инструментов оптимизации в нашей работе. Стоит про него знать, и когда в работе появятся подходящие задачи - загуглить, куда тыкать в тех инструментах, которые у вас будут в проекте, и воспользоваться.

🔒 7.05 (про траектории камеры и физическое моделирование)

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

💡 - В таких задачах, где что-то за чем-то должно следить, мы часто моделируем или пружины, или магниты, что-то на основе гравитации, или что-то чисто математическое, но чтобы эффект зависел от расстояния. Можно и в этой задаче поэкспериментировать с математикой и посмотреть, что будет получаться. У нас есть расстояние мыши от центра экрана и текущий угол смещения камеры. И у того, и у другого, есть пределы. Можно было бы попробовать нормализовать их и сравнить. Если угол и смещение сильно расходятся - увеличить скорость поворота камеры, если нет - уменьшить. Следующий естественный шаг - взять какую-нибудь плавную функцию от расстояния, чтобы выбор скорости не дискретно происходил. Синус для начала подойдет. Он в нуле равен нулю, что логически очень удобно - если нормализованное расстояние между значениями равно нулю, то мы ничего не делаем, ничего не смещаем. После скорости у нас естественным образом вспоминается ускорение, и тут можно бесконечно играться с логикой работы, подключая разные физические законы. Если вы никогда особо таким не занимались - может иметь смысл один раз попробовать, поиграться, и посмотреть, что будет получаться. Здесь важно иметь свой личный опыт, представления о том, какой круг визуальных эффектов можно сконструировать из этих кирпичиков. В перспективе это позволит делать живые и отзывчивые штуковины на страницах. Причем все это используется не только в рекламе или играх для развлечения пользователей, но и, например, при визуализации данных.

🔒 7.06 (про Open Gate, киноделов и target)

💡 - По идее про кадрирование лучше думать до того, как создавать сцены, а не пытаться впихнуть все в кадр уже постфактум. И вообще это работа должна проводиться дизайнером. Но тут я могу подкинуть одну мысль для расширения кругозора: в мире киноделов в последние годы модно обсуждать запись видео в режиме open gate, с разным кадрированием результата под разные социальные сети. У них можно подчерпнуть много идей по поводу того, как строить сцены, чтобы они хорошо кадрировались где-то потом.

💡 - И, раз уж речь зашла про эту индустрию, то скажу, что съемки видео, vfx, наш фронтенд с 3D-сценам - это все крайности одной и той же сущности. Мы во многих вопросах оперируем одними и теми же абстракциями, просто в нашем случае акцент больше смещен в сторону программирования. Если вы решите строить свой путь в сторону каких-то рекламно-конкурсных проектов, изучение чего-то такого может стать одним из направлений дальнейшего развития, после того, как освоитесь с текущими инструментами. Программисты могут вам рассказать, что технически можно сделать, а режиссеры и операторы - зачем это делать. Они могут и про свет рассказать (какие источники какие эффекты дают), и про цвет (мы даже их любимые пленочные LUTы можем использовать), и про движения камеры (по сути все, что было про риги в учебнике - это было про имитации слайдеров, кранов и стабилизаторов для настоящих камер), и про естественность картинки, motion blur и колебания в яркости кадров, и про разделение планов, про работу с глубиной резкости, туманом и.т.д. Некоторые вещи будут требовать слишком больших вычислительных мощностей, но очень многие идеи из кино мы все же можем адаптировать к нашим задачам. Это очень обширная область знаний, но она может быть весьма занятной и может открыть абсолютно новое видение текущих проектов. Если вам в перспективе станет интереснее развиваться больше в сторону креативного, чем в сторону технического - то стоит обратить внимание на эту область деятельности.

☝️ - Небольшая мысль/лайфхак/сравнение подходов: у объектов в Three.js есть метод lookAt, который поворачивает объект к цели (target), и свойство up, смысл которого в том, чтобы определиться, где у нас "верх". Это два инварианта, которые встречаются очень много где, во многих инструментах в мире компьютерной графики. С другой стороны у нас есть углы поворота, и мы можем их рассчитывать самостоятельно (там целый набор частично дублирующих друг друга методов, начиная с rotateOnAxis). Внутри это все в конечном счете приходит плюс-минус к одному и тому же результату, но с нашей стороны один из подходов может быть удобнее в каких-то случаях. Когда у нас происходят задачи, связанные с кадрированиями, перестроениями пространства, когда все вокруг непонятным образом смещается, может быть проще использовать подход с lookAt, а эффекты, связанные с движениями мыши, часто удобно считать вручную. Тут нет правильного или неправильного, но стоит знать про оба подхода. Замена одного на другой может в какой-то момент сделать расчеты заметно проще.

🔒 7.07 (про оптимизацию для телефонов)

💡 - Не стоит надеяться на то, что получится оптимизировать проект, который явно тормозит, при этом сохранив изначальную концепцию и красивую картинку. Если все плохо - придется жертвовать сложными для вычисления вещами. А вся красота обычно именно в них. Без теней ваш проект работает лучше, но выглядит... Не так прикольно, как с ними. И тени - это только вершина айсберга. В мире компьютерной графики много вещей требуют вычислительных мощностей для работы. Отчасти по этой причине мне кажется хорошей идеей подобные проекты делать всегда в обратную сторону - начинать с прототипа трехмерной части, смотреть, насколько она работоспособной получается, и уже потом, если все ок, верстать все остальное. Ну а если мы о чем-то не подумали заранее и все не ок, то это обнаруживается сразу, а не перед дедлайном. Есть возможность поменять концепцию в дизайне, заменить 3D на видео, или вообще от него отказаться в пользу каких-то 2D-эффектов в том же стиле. Проекты бывают разные, требования тоже, и не всегда можно вот так просто выключить освещение и решить все проблемы.

🔒 7.08 (про react-three-fiber и drei)

💡 - Когда все хайповали на тему реакта, возникла такая штука, как react-three-fiber. Можно по-разному к ней относиться, и в целом люди обычно смотрят на нее скептически. Главный (и очень хороший) аргумент против нее состоит в том, что она по сути ничего не дает. Это инструмент ради инструмента. Все то же самое можно сделать и без нее, стандартными средствами Three.js. Но там есть дополнение, про которое вспоминают не так часто - drei. Для нас эта библиотека может представлять интерес в контексте некоторых "хотелок" со стороны владельцев бизнесов. В частности там есть крайне полезные материалы, на которые есть запрос в "хотелках", но которые самому написать может быть сложно. Возможно, но нужно будет разбираться в том, как они работают, а это может занять больше времени, чем кажется на первый взгляд. Есть также drei-vanilla. Там некоторые полезные штуки уже вынесены из экосистемы реакта, чтобы их можно было использовать отдельно. Имеет смысл посмотреть, что там есть, и иметь эти инструменты у себя в закладках на случай, если вдруг что-то из них понадобится.

🔒 7.09 (про постпроцессинг и баги буфера глубины)

[ СКРИНШОТ ПРОЕКТА СТУДЕНТА (АНАЛОГИЧНАЯ КАРТИНКА ДЛЯ ПРИМЕРА) ]

☝️ - WebGL опускает нас к более низкому уровню работы с железом, мы уже не находимся в привычной песочнице javascript, в которой от железа не зависит почти ничего. И у разных браузеров на разном железе могут быть разные особенности, как в вопросах производительности, так и в плане ограничений на максимальный размер текстур или еще чего. По-хорошему проекты с WebGL нужно тестировать не только в разных браузерах, но и на разном железе (хотя, конечно, бюджет не всегда это позволяет). По крайней мере границы допустимых размеров и количеств всего стоит проверять, благо в сети достаточно сайтов со статистикой, что там поддерживается современными видеокартами. Плюс библиотека Three.js, если уж мы ее используем, накладывает сверху свою логику, в которой тоже есть не самые очевидные wtf-моменты, например добавление постобработки меняет то, как основной рендерер работает с буфером глубины. С настройками рендерера по умолчанию может произойти то, что видно на скриншоте. Причем такие проблемы могут проявляться как в виде "не работает в разных браузерах на одном компьютере", так и в виде "не работает в одинаковых браузерах на разных компьютерах". В данном случае вопрос можно решить, если руками включить логарифмический буфер глубины у рендерера. Это даст некоторый минус к производительности, но плюс к надежности. И это хороший пример ситуации, когда знания из области компьютерной графики нужны не просто на словах. Пошли артефакты по экрану, непонятно от чего зависят, проектом невозможно пользоваться, и при этом проблему очень сложно загуглить (я пробовал). Инструменты разработчика не дают абсолютно никакой полезной информации. Догадаться о том, что что-то не так с буфером глубины можно только если знать, что это такое, и как он работает.

🔒 8.01 (про розовые очки)

💡 - К последнему заданию на курсе повторю мысли о суровой реальности: мы можем запустить Unreal Engine в браузере, даже вес страницы – не такая проблема (сериалы мы смотрим как-то и не жалуемся), но вычислительные мощности, необходимые, чтобы завелся серьезный проект на таком движке, очень некислые. Это будет не рендеринг видео на ночь, это будут задачи в реальном времени. Нужна хорошая видеокарта. Будет ли она у каждого нашего клиента? Вероятнее всего нет. Минимальные системные требования для сайта – такое себе решение. Очень редко мы можем их ввести без потери клиентов, это должен быть какой-то узкоспециализированный бизнес, который рассчитывает, что у клиентов будет нужное железо, или даже сам им его организует. Этот же посыл можно применить не только к вычислительным мощностям, но и к реалиям использования инструментов со стороны разработки. Например WebGPU упоминают в вакансиях уже несколько лет, рассказывают красивые сказки про замечательное API (это как бы правда - после WebGL смотреть на WebGPU приятно), но по факту все только начинается. Плюс эта технология выходит практически в вакууме. Шейдеры на GLSL за три десятка лет, сопутствующие курсы по компьютерной графике и существующие экосистемы инструментов не перейдут сами собой на новый стек в одночасье. Или вот технология WebGL2, развитие WebGL, сейчас выглядит неплохо, но на момент выхода она вызывала очень много вопросов по части надежности. Только получившая "зеленую" поддержку технология была откровенно сыро реализована в браузерах, с кучей сложноисправляемых и абсолютно не гуглящихся багов. Стоит серьезно думать, прежде чем притягивать такого рода технологии в проект - исправить решения на стадии глубокой разработки будет очень непросто. При изучении теоретически возможных инструментов и подходов в будущем – обращайте внимание на то, насколько они вписываются в реальность здесь и сейчас.