- PVSM.RU - https://www.pvsm.ru -

Визуализация списка женщин-лауреатов Нобелевской премии в виде кристаллов в 3d с использованием Vue, WebGL, three.js

image

Год 1 | вдохновение

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

Идея проекта пришла ко мне после просмотра фильма Безумно богатые азиаты [1]. Мне очень понравилась актриса Мишель Йео [2], но идея оформилась только после того, как я прочитала больше о ней и узнала, насколько она была выдающейся и крутой. Это заставило меня задуматься выдающихся женщинах, о которых я понятия не имею. И вот — возникла идея как-то это визуализировать.

1 неделя | данные

После формирования концепции, возник следующий вопрос — как собрать необходимые данные? Я быстро пришла к идее использовать Википедию, попытаться спарсить “лучших” женщин оттуда. Я понятия не имела, как определить «лучших» (просмотры страницы? длина страницы? ссылки на страницу?). Хотя я посмотрела статью на The Pudding [3] про визуализацию на основе данных википедии, я все еще не была уверена, что хочу двигаться в эту сторону. А еще мне очень не хватало свободного времени.

Затем мне пришло в голову, что, возможно, я должна использовать фиксированный список женщин, и это каким-то образом привело меня на страницу 51 женщин-лауреатов нобелевской премии [4]. Я не слышала о большинстве из них, и мне захотелось узнать больше. Для проекта это подходило идеально.

image

С этого момента я начала изучать разные методы использования API Википедии. Разобраться было непросто (я не была уверена, нужно ли мне использовать Wikidata [5] или MediaWiki [6], — это те варианты, которые возникали при поиске «Wikipedia API» в Google), но, к счастью, уже упомянутая выше статья на Pudding помогла мне закрыть эти вопросы. Быстрый просмотр их репозитория wiki-billboard-data [7] привел меня к выбору одного из скриптов [8] с wikijs [9], и я могла просто воспользоваться этим пакетом.

Все, что мне нужно было сделать, это скопировать и вставить список знатных женщин-лауреатов в электронную таблицу [10] и выполнить небольшое форматирование/чистку.

Один из самых важных уроков, которые я узнала о сборе данных — электронные таблицы отлично подходят для их очистки. Раньше я пыталась писать код для очистки данных, и это занимало у меня намного больше времени. Когда я собирала данные для проекта по Гамильтону, я буквально набирала запятые между каждой ячейкой в ​​строке в моем CSV — настолько я была глупа.

Затем я экспортировала электронную таблицу как CSV, потом использовала онлайн-конвертер [11], чтобы получить данные в формате JSON [12].

После этого я написала простой скрипт [13], используя вики-страницы, чтобы получить больше информации о каждой женщине, включая количество ссылок на их страницу («обратных ссылок») и количество источников внизу, чтобы получить окончательный набор данных [14].

Несмотря на то, что создание идеи заняло целую вечность, сбор данных уложился всего в несколько часов.

неделя 2 | скетч

Не буду врать, я так долго думала об этом проекте, что даже не могу вспомнить все идеи, которые у меня возникали в процессе. Все, что я помню, — это то, что я просматривала номинантов премии Information is Beautiful [15], когда решила, что мне нужно как-то выделить те записи, которые мне действительно нравятся в моих сохранениях. Это заставило меня осознать, что я должна лучше организовать свою доску на Pinterest [16], так как раньше я сваливала все мои идеи и видение на одну доску. В процессе чистки, я наткнулась на эту великолепную картину с кристаллами художника Ребекки Шаперон [17], которую я сохранила на будущее несколько лет назад. Почти сразу я поняла, что я хочу программно воссоздать их. Ведь было бы прекрасно визуализировать этих выдающихся женщин в качестве ярких разноцветных кристаллов?

image

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

После этого я продумала другие детали: размер кристаллов должен отражать влияние женщины — количество ссылок на ее страницу в Википедии. Число граней на кристалле будет сопоставлено с количеством источников в нижней части ее страницы (поскольку она «многогранна»), а цвет будет определяться категорией премии. Единственное, что мне пока было непонятно, — это как расположить кристаллы. Я долго думала, что мне надо просто выложить их в 2-х измерениях по x / y и заставить читателя прокручивать их.

А потом я приняла участие в семинаре Мэтта ДесЛориерса по креативному кодингу [18], где он преподавал canvas, three.js и WebGL. Семинар открыл мне концепт третьего измерения, и я сразу поняла, что собираюсь использовать год получения награды в качестве оси z. Далее один мой друг предложил сделать потоки-нити, связывающие тех, кто сотрудничал друг с другом таким образом, чтобы их положение тоже менялось в зависимости от этого (но в итоге у меня не было времени на реализацию этой идеи).

Вся концепция пришла ко мне так быстро и естественно, что я не сделала ни одного наброска в процессе. Я просмотрела свой блокнот, но там вообще ничего нет.

неделя 3 & 4 | кодинг

Это был отличный месяц для кодинга.

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

И вот однажды меня осенило (я не уверена, что послужило причиной), что я не умею думать в трехмерном физическом пространстве, как раз потому, что я постоянно работаю в плоском диджитальном формате. Если бы я смогла научиться работать с 3D в цифре, то смогла бы мыслить в объеме и в физическом мире. Я добавила three.js и WebGL вверх своего списка для изучения.

В конце октября я прошла семинар Мэтта по креативному кодингу и изучила основы three.js, введение в фрагментированные и вершинные шейдеры. Я выучила правило буравчика [19]: используйте большой палец для оси X (увеличивается вправо), указательный палец для оси Y (увеличивается вверх, что противоположно SVG и canvas) и средний палец для оси Z (для увеличения экрана и приближения его). Я узнала, что WebGL работает не в пикселях, а в единицах (похожая ассоциация — футы или метры).

Затем в ноябре я вписалась в один конкурс по WebGL. Хотя я раньше не имела с ним дела, я надеялась, что дедлайн даст мне мотивацию, необходимую для завершения проекта. Я начала 1-го декабря и поставила себе цель делать чуть-чуть каждый будний день, пока не смогу дойти до чего-то презентабельного 23-го декабря (финал конкурса).

Сперва я прочла первые две главы Руководства по программированию на WebGL [20], в котором рассказывалось, как настроить WebGL. Затем я повторила свои знания по three.js. После я запустила блокнот [21] из Observable, чтобы понять минимально-необходимые настройки для рисования чего-либо в three.js (рендерер, камера и сцена, а затем вызвать renderer.render(scene, camera) для отображения ). Мне всегда нравилось понимать самые основы работы кода, так что это было очень полезно.

После настройки я решила создать форму кристалла. Я использовала PolyhedronGeometry [22], потому что так я могла просто определить набор вершин, а затем указать вершины, которые будут составлять треугольную грань. В первый день мне удалось создать только один треугольник.

image

А во второй день — кристалл (на который потребовалось две попытки, потому что в первый раз я налажала с математикой).

image

А потом, в конце концов, форма кристалла, который был у меня в голове.

image

Позже я поняла, что есть лучшие способы делать то, что я хотела (и на самом деле PolyhedronGeometry — это довольно утомительный способ делать это), но я была очень рада возможности попрактиковаться в координатах x / y / z в WebGL.

Как только я была удовлетворена созданными формами, я перешла к изучению их окрашивания в цвета. Для этого я начала играться с вершинными и фрагментными шейдерами [23].

image

Следующей задачей стало научиться использовать фрагментный шейдер для окрашивания кристалла. Здесь мне пришлось немного отклониться от плана, потому что я не могла понять, как использовать glslify [24] (узловая модульная система для GLSL, на которой написаны шейдеры, которые я взяла в качестве образца). Вместо этого я начала изучать различные инструменты компоновки/сборки, чтобы в конечном итоге развернуть свой код в Интернете. В конце концов, я решила использовать Parcel [25] (вместо Vue CLI [26], который я регулярно использую последние полгода), потому что он имеет встроенную поддержку как Vue, так и GLSL.

Вот такой кристалл с наложением того же паттерна шума у меня получился.

image

Результат мне не нравился, поэтому я решила, что мне нужно больше узнать о шейдерах и использовании цветов в шейдерах. Именно в этот момент я обратилась к Books of Shader [27]s Патрисио Гонсалеса Виво и, в частности, к главе «Shaping Functions» [28]. Я узнала о синусах, косинусах, полиномах и экспонентах — функциях, которые могут брать число (или набор чисел) и выводить на их основе другие. Я также узнала о смешивании цветов и о том, как мы можем взять два цвета, и не только получить новый цвет посередине между этими двумя, но также смешивать цвета в формате RGB и создавать совершенно новые на их основе. Если мы объединим это с функциями формы, то сможем получить градиенты и формы:

image
Эти были получены путем смешивания синего и желтого, а также изменения значений RGB в каждой позиции с помощью степеней, синусов, абсолютных значений, шагов и сглаживаний

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

image

Но результат мне не понравился по двум причинам:

  • Я жестко задавала формы каждой фигуры, поэтому у меня было только три разных фигуры: прямоугольник, прямоугольник с треугольником сверху и прямоугольник с треугольником сверху и снизу. Это означало, что большинство «кристаллов» были просто прямоугольниками.
  • Я также хотела, чтобы цвет для каждой категории выбирался из шести базовых цветов, поэтому для каждого кристалла я использовала только один цвет. Цвета мне совсем не нравились.

Примерно в это же время я наткнулась на демо Bloom [29] (эффект постобработки для создания свечения), и в нем были круглые, похожие на драгоценные камни объекты, которые выглядели довольно похоже на кристаллы, которые я и хотела получить:

image

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

Поэтому я заменила PolyhedronGeometry на SphereGeometry, установила высоту на 4 и ширину на свои данные, растянула фигуру, установив вертикальный масштаб в два раза больше по горизонтали, добавила jitter (дрожание) для каждой вершины, и у меня получились гораздо более интересные формы:

image

Теперь, когда я определилась с формами, настало время вернуться к цвету. На этот раз я использовала два цвета и смешивала их с функциями формы:

image
image
Мне нравится первый вариант — выглядит как картофель

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

image
Код для добавления нормалей сторон. [30]

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

image

Затем занялась фоном. Я создала «пол» с помощью PlaneGeometry и случайного дрожания y-позиции каждой вершины (вдохновленной этой статьей из codrops [31]), а также «небо», создав огромную сферу вокруг сцены. Я экспериментировала с тремя различными типами источников света: полусферой, рассеянным (чтобы создать для«неба» ощущение заката/восхода солнца), и направленным (чтобы отбрасывать тени от кристаллов на «пол»).

image

В конце я добавила «звездочки», которые визуализируют всех мужчин, которые выиграли премию за тот же период времени, а также аннотации для каждого кристалла и для десятилетий. Это было сложно, потому что с тем текстом, который у меня был, использовать TextGeometry было практически бесполезно. Решение, которое я нашла после поиска в интернете, — визуализировать текст в HTML5 Canvas, создать PlaneGeometry и использовать этот Canvas в качестве текстуры для заполнения PlaneGeometry. Очень интересный подход.

Мне очень понравилось, что я смогла найти реальную причину использовать третье измерение — десятилетия получения наград. Чем ближе они к переднему краю, тем более свежая по времени награда, и чем дальше они от нас, тем более старая эта награда. Но я не показываю эти десятилетия, пока пользователь не «взлетит», чтобы посмотреть на кристаллы сверху. Если они «прогуливаются» между кристаллами на уровне земли, я показываю только информацию о каждой женщине, потому что я хочу, чтобы посетитель концентрировался только на женщинах во время прогулки.

image

Вот ссылка на финальный результат на GitHub [32]

И видео c демонстрацией результата:

Если вы хотите попробовать еще что-то или начать с более простых проектов:

Автор: degenerative.art

Источник [38]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/354009

Ссылки в тексте:

[1] Безумно богатые азиаты: https://ru.wikipedia.org/wiki/%D0%91%D0%B5%D0%B7%D1%83%D0%BC%D0%BD%D0%BE_%D0%B1%D0%BE%D0%B3%D0%B0%D1%82%D1%8B%D0%B5_%D0%B0%D0%B7%D0%B8%D0%B0%D1%82%D1%8B

[2] Мишель Йео: https://ru.wikipedia.org/wiki/%D0%9C%D0%B8%D1%88%D0%B5%D0%BB%D1%8C_%D0%99%D0%B5%D0%BE

[3] статью на The Pudding: https://pudding.cool/2018/10/wiki-breakout/

[4] 51 женщин-лауреатов нобелевской премии: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%B6%D0%B5%D0%BD%D1%89%D0%B8%D0%BD_%E2%80%94_%D0%BB%D0%B0%D1%83%D1%80%D0%B5%D0%B0%D1%82%D0%BE%D0%B2_%D0%9D%D0%BE%D0%B1%D0%B5%D0%BB%D0%B5%D0%B2%D1%81%D0%BA%D0%BE%D0%B9_%D0%BF%D1%80%D0%B5%D0%BC%D0%B8%D0%B8

[5] Wikidata: https://www.wikidata.org/wiki/Wikidata:Main_Page

[6] MediaWiki: https://www.mediawiki.org/wiki/API:Main_page

[7] wiki-billboard-data: https://github.com/the-pudding/wiki-billboard-data

[8] скриптов: https://github.com/the-pudding/wiki-billboard-data/blob/54a0acb25413f02fc5938b05254239fdaa5ad8bc/scripts/current/get-people.js#L2

[9] wikijs: https://www.npmjs.com/package/wikijs

[10] электронную таблицу: https://docs.google.com/spreadsheets/d/1Y9AETF58KMmp4_S2Mp7u0opsOEjee9hA8TfcdSBkQpI/edit?usp=sharing

[11] онлайн-конвертер: https://www.csvjson.com/csv2json

[12] данные в формате JSON: https://github.com/sxywu/legends/blob/master/scripts/legends_raw.json

[13] простой скрипт: https://github.com/sxywu/legends/blob/master/scripts/getWiki.js

[14] окончательный набор данных: https://github.com/sxywu/legends/blob/master/assets/legends.json

[15] Information is Beautiful: https://www.informationisbeautifulawards.com/showcase?action=index&award=2018&controller=showcase&page=1&pcategory=short-list&type=awards

[16] доску на Pinterest: https://www.pinterest.com/shirleyxywu/

[17] Ребекки Шаперон: https://www.thechaperon.ca/gallery/tesseract-crystals

[18] креативному кодингу: https://frontendmasters.com/courses/canvas-webgl/

[19] правило буравчика: https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%BE_%D0%B1%D1%83%D1%80%D0%B0%D0%B2%D1%87%D0%B8%D0%BA%D0%B0

[20] Руководства по программированию на WebGL: https://www.amazon.com/WebGL-Programming-Guide-Interactive-Graphics/dp/0321902920

[21] блокнот: https://beta.observablehq.com/@sxywu/three-js-exploration-shapes

[22] PolyhedronGeometry: https://threejs.org/docs/index.html#api/en/geometries/PolyhedronGeometry

[23] вершинными и фрагментными шейдерами: https://github.com/sxywu/three-workshop/blob/master/noise-shader.js

[24] glslify: https://github.com/glslify/glslify

[25] Parcel: https://parceljs.org/

[26] Vue CLI: https://cli.vuejs.org/

[27] Books of Shader: https://thebookofshaders.com/

[28] главе «Shaping Functions»: https://thebookofshaders.com/05/

[29] демо Bloom: https://vanruesc.github.io/postprocessing/public/demo/#bloom

[30] Код для добавления нормалей сторон.: https://github.com/sxywu/legends/commit/fbdc2c24e20696941b694d7f4caaeb07aabf2126

[31] статьей из codrops: https://tympanus.net/codrops/2016/04/26/the-aviator-animating-basic-3d-scene-threejs/

[32] Вот ссылка на финальный результат на GitHub: https://github.com/sxywu/legends/blob/master/components/World.vue#L295-L303

[33] Создание эффекта быстрого полета сквозь космос (или падающего снега) за 10 минут на p5.js: https://habr.com/ru/post/505658/

[34] Как воссоздать эффект муарового узора в библиотеке p5.js для новичка (быстрый гайд): https://habr.com/ru/post/505190/

[35] Наложение 2d-текстуры на 3d-объект с использованием p5.js (часть 1 — создание паттерна): https://habr.com/ru/post/505226/

[36] Наложение 2d-текстуры на 3d-объект с использованием p5.js (часть 2 — наложение паттерна на куб): https://habr.com/ru/post/505402/

[37] Создание треугольников после 3 часов изучения p5.js: https://habr.com/ru/post/506268/

[38] Источник: https://habr.com/ru/post/506574/?utm_source=habrahabr&utm_medium=rss&utm_campaign=506574