Год 1 | вдохновение
В этом месяце я очень долго пыталась определиться с датасетом и идеей для его обработки. Хотя я начала думать о нем еще в мае, по факту законить удалось только через 8 месяцев (черт, я плоха), а описать проект мне удалось еще спустя месяц (оу, я чертовски плоха).
Идея проекта пришла ко мне после просмотра фильма Безумно богатые азиаты. Мне очень понравилась актриса Мишель Йео, но идея оформилась только после того, как я прочитала больше о ней и узнала, насколько она была выдающейся и крутой. Это заставило меня задуматься выдающихся женщинах, о которых я понятия не имею. И вот — возникла идея как-то это визуализировать.
1 неделя | данные
После формирования концепции, возник следующий вопрос — как собрать необходимые данные? Я быстро пришла к идее использовать Википедию, попытаться спарсить “лучших” женщин оттуда. Я понятия не имела, как определить «лучших» (просмотры страницы? длина страницы? ссылки на страницу?). Хотя я посмотрела статью на The Pudding про визуализацию на основе данных википедии, я все еще не была уверена, что хочу двигаться в эту сторону. А еще мне очень не хватало свободного времени.
Затем мне пришло в голову, что, возможно, я должна использовать фиксированный список женщин, и это каким-то образом привело меня на страницу 51 женщин-лауреатов нобелевской премии. Я не слышала о большинстве из них, и мне захотелось узнать больше. Для проекта это подходило идеально.
С этого момента я начала изучать разные методы использования API Википедии. Разобраться было непросто (я не была уверена, нужно ли мне использовать Wikidata или MediaWiki, — это те варианты, которые возникали при поиске «Wikipedia API» в Google), но, к счастью, уже упомянутая выше статья на Pudding помогла мне закрыть эти вопросы. Быстрый просмотр их репозитория wiki-billboard-data привел меня к выбору одного из скриптов с wikijs, и я могла просто воспользоваться этим пакетом.
Все, что мне нужно было сделать, это скопировать и вставить список знатных женщин-лауреатов в электронную таблицу и выполнить небольшое форматирование/чистку.
Один из самых важных уроков, которые я узнала о сборе данных — электронные таблицы отлично подходят для их очистки. Раньше я пыталась писать код для очистки данных, и это занимало у меня намного больше времени. Когда я собирала данные для проекта по Гамильтону, я буквально набирала запятые между каждой ячейкой в строке в моем CSV — настолько я была глупа.
Затем я экспортировала электронную таблицу как CSV, потом использовала онлайн-конвертер, чтобы получить данные в формате JSON.
После этого я написала простой скрипт, используя вики-страницы, чтобы получить больше информации о каждой женщине, включая количество ссылок на их страницу («обратных ссылок») и количество источников внизу, чтобы получить окончательный набор данных.
Несмотря на то, что создание идеи заняло целую вечность, сбор данных уложился всего в несколько часов.
неделя 2 | скетч
Не буду врать, я так долго думала об этом проекте, что даже не могу вспомнить все идеи, которые у меня возникали в процессе. Все, что я помню, — это то, что я просматривала номинантов премии Information is Beautiful, когда решила, что мне нужно как-то выделить те записи, которые мне действительно нравятся в моих сохранениях. Это заставило меня осознать, что я должна лучше организовать свою доску на Pinterest, так как раньше я сваливала все мои идеи и видение на одну доску. В процессе чистки, я наткнулась на эту великолепную картину с кристаллами художника Ребекки Шаперон, которую я сохранила на будущее несколько лет назад. Почти сразу я поняла, что я хочу программно воссоздать их. Ведь было бы прекрасно визуализировать этих выдающихся женщин в качестве ярких разноцветных кристаллов?
Возможно, у меня были другие идеи до этого момента (да, очень возможно), но я не могу их вспомнить — идея с кристаллами подходила идеально.
После этого я продумала другие детали: размер кристаллов должен отражать влияние женщины — количество ссылок на ее страницу в Википедии. Число граней на кристалле будет сопоставлено с количеством источников в нижней части ее страницы (поскольку она «многогранна»), а цвет будет определяться категорией премии. Единственное, что мне пока было непонятно, — это как расположить кристаллы. Я долго думала, что мне надо просто выложить их в 2-х измерениях по x / y и заставить читателя прокручивать их.
А потом я приняла участие в семинаре Мэтта ДесЛориерса по креативному кодингу, где он преподавал canvas, three.js и WebGL. Семинар открыл мне концепт третьего измерения, и я сразу поняла, что собираюсь использовать год получения награды в качестве оси z. Далее один мой друг предложил сделать потоки-нити, связывающие тех, кто сотрудничал друг с другом таким образом, чтобы их положение тоже менялось в зависимости от этого (но в итоге у меня не было времени на реализацию этой идеи).
Вся концепция пришла ко мне так быстро и естественно, что я не сделала ни одного наброска в процессе. Я просмотрела свой блокнот, но там вообще ничего нет.
неделя 3 & 4 | кодинг
Это был отличный месяц для кодинга.
В течение последних нескольких лет я хотела создать что-то с физическим воплощением, а в прошлом году я наконец решила сделать это моей целью. Но большую часть года я не знала, что это будет. Каждый раз, когда я размышляла об этом, я просто зацикливалась на двухмерных проекциях на стенах и не знала, как использовать весь объем.
И вот однажды меня осенило (я не уверена, что послужило причиной), что я не умею думать в трехмерном физическом пространстве, как раз потому, что я постоянно работаю в плоском диджитальном формате. Если бы я смогла научиться работать с 3D в цифре, то смогла бы мыслить в объеме и в физическом мире. Я добавила three.js и WebGL вверх своего списка для изучения.
В конце октября я прошла семинар Мэтта по креативному кодингу и изучила основы three.js, введение в фрагментированные и вершинные шейдеры. Я выучила правило буравчика: используйте большой палец для оси X (увеличивается вправо), указательный палец для оси Y (увеличивается вверх, что противоположно SVG и canvas) и средний палец для оси Z (для увеличения экрана и приближения его). Я узнала, что WebGL работает не в пикселях, а в единицах (похожая ассоциация — футы или метры).
Затем в ноябре я вписалась в один конкурс по WebGL. Хотя я раньше не имела с ним дела, я надеялась, что дедлайн даст мне мотивацию, необходимую для завершения проекта. Я начала 1-го декабря и поставила себе цель делать чуть-чуть каждый будний день, пока не смогу дойти до чего-то презентабельного 23-го декабря (финал конкурса).
Сперва я прочла первые две главы Руководства по программированию на WebGL, в котором рассказывалось, как настроить WebGL. Затем я повторила свои знания по three.js. После я запустила блокнот из Observable, чтобы понять минимально-необходимые настройки для рисования чего-либо в three.js (рендерер, камера и сцена, а затем вызвать renderer.render(scene, camera) для отображения ). Мне всегда нравилось понимать самые основы работы кода, так что это было очень полезно.
После настройки я решила создать форму кристалла. Я использовала PolyhedronGeometry, потому что так я могла просто определить набор вершин, а затем указать вершины, которые будут составлять треугольную грань. В первый день мне удалось создать только один треугольник.
А во второй день — кристалл (на который потребовалось две попытки, потому что в первый раз я налажала с математикой).
А потом, в конце концов, форма кристалла, который был у меня в голове.
Позже я поняла, что есть лучшие способы делать то, что я хотела (и на самом деле PolyhedronGeometry — это довольно утомительный способ делать это), но я была очень рада возможности попрактиковаться в координатах x / y / z в WebGL.
Как только я была удовлетворена созданными формами, я перешла к изучению их окрашивания в цвета. Для этого я начала играться с вершинными и фрагментными шейдерами.
Следующей задачей стало научиться использовать фрагментный шейдер для окрашивания кристалла. Здесь мне пришлось немного отклониться от плана, потому что я не могла понять, как использовать glslify (узловая модульная система для GLSL, на которой написаны шейдеры, которые я взяла в качестве образца). Вместо этого я начала изучать различные инструменты компоновки/сборки, чтобы в конечном итоге развернуть свой код в Интернете. В конце концов, я решила использовать Parcel (вместо Vue CLI, который я регулярно использую последние полгода), потому что он имеет встроенную поддержку как Vue, так и GLSL.
Вот такой кристалл с наложением того же паттерна шума у меня получился.
Результат мне не нравился, поэтому я решила, что мне нужно больше узнать о шейдерах и использовании цветов в шейдерах. Именно в этот момент я обратилась к Books of Shaders Патрисио Гонсалеса Виво и, в частности, к главе «Shaping Functions». Я узнала о синусах, косинусах, полиномах и экспонентах — функциях, которые могут брать число (или набор чисел) и выводить на их основе другие. Я также узнала о смешивании цветов и о том, как мы можем взять два цвета, и не только получить новый цвет посередине между этими двумя, но также смешивать цвета в формате RGB и создавать совершенно новые на их основе. Если мы объединим это с функциями формы, то сможем получить градиенты и формы:
Эти были получены путем смешивания синего и желтого, а также изменения значений RGB в каждой позиции с помощью степеней, синусов, абсолютных значений, шагов и сглаживаний
Как только я была удовлетворена получившимися цветами, я переключилась на работу с данными: количество ссылок в нижней части для количества сторон, количество обратных ссылок для размера, категории Нобелевской премии для цвета.
Но результат мне не понравился по двум причинам:
- Я жестко задавала формы каждой фигуры, поэтому у меня было только три разных фигуры: прямоугольник, прямоугольник с треугольником сверху и прямоугольник с треугольником сверху и снизу. Это означало, что большинство «кристаллов» были просто прямоугольниками.
- Я также хотела, чтобы цвет для каждой категории выбирался из шести базовых цветов, поэтому для каждого кристалла я использовала только один цвет. Цвета мне совсем не нравились.
Примерно в это же время я наткнулась на демо Bloom (эффект постобработки для создания свечения), и в нем были круглые, похожие на драгоценные камни объекты, которые выглядели довольно похоже на кристаллы, которые я и хотела получить:
Я посмотрела исходный код и поняла, что они использовали SphereGeometry, но с включенным flatShading — поэтому вместо рендеринга гладкой поверхности он показывал каждую отдельную грань. Я осознала, что, как я могу манипулировать и смешивать цвета, чтобы получить новые цвета, совершенно отличные от оригинала, так же я могу фактически управлять геометрическими параметрами (например, количеством граней) и получать новую геометрию, которая выглядит аналогично, но отличается от исходной.
Поэтому я заменила PolyhedronGeometry на SphereGeometry, установила высоту на 4 и ширину на свои данные, растянула фигуру, установив вертикальный масштаб в два раза больше по горизонтали, добавила jitter (дрожание) для каждой вершины, и у меня получились гораздо более интересные формы:
Теперь, когда я определилась с формами, настало время вернуться к цвету. На этот раз я использовала два цвета и смешивала их с функциями формы:
Мне нравится первый вариант — выглядит как картофель
Поскольку шейдер по умолчанию просто обтекает фигуру (по крайней мере, так мне нравится думать об этом), я потеряла четкие края. К счастью, меня научили возвращать формы обратно, вызывая computeFlatVertexNormals() на геометрию, получая нормали в вершинном шейдере и передавая его фрагментному шейдеру при этом добавляя его в цвет. Это не только сделало края четко очерченными, но также дало иллюзию света и тени:
Код для добавления нормалей сторон.
После этого я поигралась с двумя наборами градиентов: один для «гуманитарных наук» (мир, литература, экономические науки), а другой для «естественных наук» (физика, химия, медицина).
Затем занялась фоном. Я создала «пол» с помощью PlaneGeometry и случайного дрожания y-позиции каждой вершины (вдохновленной этой статьей из codrops), а также «небо», создав огромную сферу вокруг сцены. Я экспериментировала с тремя различными типами источников света: полусферой, рассеянным (чтобы создать для«неба» ощущение заката/восхода солнца), и направленным (чтобы отбрасывать тени от кристаллов на «пол»).
В конце я добавила «звездочки», которые визуализируют всех мужчин, которые выиграли премию за тот же период времени, а также аннотации для каждого кристалла и для десятилетий. Это было сложно, потому что с тем текстом, который у меня был, использовать TextGeometry было практически бесполезно. Решение, которое я нашла после поиска в интернете, — визуализировать текст в HTML5 Canvas, создать PlaneGeometry и использовать этот Canvas в качестве текстуры для заполнения PlaneGeometry. Очень интересный подход.
Мне очень понравилось, что я смогла найти реальную причину использовать третье измерение — десятилетия получения наград. Чем ближе они к переднему краю, тем более свежая по времени награда, и чем дальше они от нас, тем более старая эта награда. Но я не показываю эти десятилетия, пока пользователь не «взлетит», чтобы посмотреть на кристаллы сверху. Если они «прогуливаются» между кристаллами на уровне земли, я показываю только информацию о каждой женщине, потому что я хочу, чтобы посетитель концентрировался только на женщинах во время прогулки.
Вот ссылка на финальный результат на GitHub
И видео c демонстрацией результата:
Если вы хотите попробовать еще что-то или начать с более простых проектов:
- Создание эффекта быстрого полета сквозь космос (или падающего снега) за 10 минут на p5.js
- Как воссоздать эффект муарового узора в библиотеке p5.js для новичка (быстрый гайд)
- Наложение 2d-текстуры на 3d-объект с использованием p5.js (часть 1 — создание паттерна)
- Наложение 2d-текстуры на 3d-объект с использованием p5.js (часть 2 — наложение паттерна на куб)
- Создание треугольников после 3 часов изучения p5.js