Назад

Оленёнок в лесу

Оленёнок бродит по лесу исполинских японских кедров в духе Якусимы: он сгенерирован и автоматически отриггован в Tripo, лес полностью процедурный, а объёмные лучи света, мягкие тени, смена дня и ночи и ветер рендерятся в реальном времени — с записью видео прямо на странице.

Автор: 希彼赫
Попробовать онлайн
Оленёнок в лесуПопробовать онлайн

О проекте

«Оленёнок в лесу» — сцена на three.js в реальном времени, которая работает в браузере: оленёнок бродит по лесу исполинских японских кедров в духе Якусимы, солнечный свет пробивается сквозь просветы в кронах, трава колышется на ветру, а бабочки порхают у цветов. Выведите его на прогулку, соберите световые огоньки, переключайтесь между днём и лунной ночью — или доверьте его кинематографической камере и запишите видео прямо на странице.

Оленёнок создан с помощью Tripo API — генерация, умный low-poly, проверка пригодности к риггингу и автоматический риггинг четвероногого — и экспортирован как отриггованный GLB; лес полностью процедурный. Текстуры — Poly Haven (CC0).

Лучше всего сцена раскрывается в десктопном браузере с клавиатурой; на телефоне коснитесь земли, чтобы отправить оленёнка в путь, и перетаскивайте, чтобы вращать камеру.

Ключевые моменты

  1. Ведите оленёнка клавишами WASD или кликните по земле, чтобы отправить его туда; удерживайте Shift, чтобы перейти на рысь, и перетаскивайте, чтобы вращать камеру
  2. Пройдите сквозь светящиеся огоньки, чтобы собрать их, — соберите все девять, и зазвучит перелив колокольчиков, а световые столбы вспыхнут; нажмите E или кликните по оленёнку, и он поднимет на вас взгляд
  3. Нажмите R, чтобы переключаться между днём и лунной ночью, или G — налетит порыв ветра, пригнёт траву и разгонит бабочек
  4. Нажмите C для кинематографической камеры и V, чтобы записать видео со звуком прямо на странице; H скрывает панель клавиш

Технический разбор

  • Оленёнок · Сгенерирован и автоматически отриггован в Tripo

    Оленёнок выходит из пайплайна на Tripo API — генерация модели, умный low-poly, проверка пригодности к риггингу и автоматический риггинг четвероногого — и поставляется как GLB примерно из 15 000 треугольников со скелетом четвероногого из 41 кости и PBR-текстурами. Страница загружает его через GLTFLoader и масштабирует до высоты головы около 1,55 м — роста пятнистого оленя.

    Риг Tripo аккуратно поименован: каждая нога разбита на сегменты от Limb_0 до Limb_3, а позвоночник, шея и голова пронумерованы по порядку, поэтому код находит каждую ногу, позвоночник и шею по имени и управляет ими напрямую — без ручного сопоставления костей одна за другой. Шейдер окрашивает шерсть в рыжевато-бурый летний мех пятнистого оленя и рассыпает вдоль спины цепочку светлых пятен; пятна привязаны к координатам bind pose, поэтому не скользят по шкуре, когда оленёнок идёт, а в контровом свете по краю шерсти проступает тёплый ореол.

  • Походка · Шаг, рассчитанный прямо на риге

    Походка рассчитывается при загрузке страницы с помощью IK прямо на этом риге. Сначала задаются траектории копыт: на земле каждое копыто уходит назад ровно со скоростью тела, в воздухе — приподнимается, выносится вперёд и опускается. Ноги шагают в порядке: левая задняя, левая передняя, правая задняя, правая передняя, каждая около 70 % времени на земле, а тело лишь слегка покачивается вверх-вниз и с боку на бок. Каждая нога решается трёхсегментной IK, которая держит верхний и нижний сегменты под углом bind pose, а при подъёме передней ноги запястье дополнительно подгибается. Вся походка запекается в цикл из 48 кадров и передаётся в AnimationMixer.

    Скорость воспроизведения равна скорости тела, делённой на скорость, с которой копыта уходят назад, поэтому идёт ли оленёнок неспешно или бежит рысью с зажатым Shift, его копыта никогда не скользят. Когда он стоит на месте, код поворачивает четыре кости от верхней части спины до головы: оленёнок какое-то время щиплет траву, поднимает голову, чтобы посмотреть в сторону, и снова опускает её — а стоит ему тронуться с места, шея поднимается.

  • Лес · Целиком выращен в коде

    Кроме оленёнка, всё в лесу генерируется кодом; единственные текстуры — CC0-наборы Poly Haven для коры кедра, замшелого камня и лесной подстилки. Исполинские кедры поднимаются примерно на 44 м: главные деревья на переднем плане получают собственные меши, а ряды позади рисуются пакетно через InstancedMesh, причём изгиб стволов считается по одной формуле и в шейдере, и в JS, так что ветви не отрываются от изогнутых стволов. Между гигантами растёт ярус молодых деревьев высотой 8–17 м, а кустарник, папоротники, камни и упавшие стволы заполняют подлесок.

    Землю покрывают 120 000 инстансированных травинок, которые колышутся в вершинном шейдере; нажмите G — налетит шестисекундный порыв ветра, пригнёт траву и разгонит бабочек. Трава к тому же знает, где оленёнок, и расступается вокруг него. Восемнадцать бабочек лениво порхают у цветов, пока оленёнок не подойдёт и не спугнёт их, а 70 падающих листьев, с черешками и прожилками, кружась, опускаются вниз и вспыхивают, пролетая сквозь лучи.

  • Свет · Объёмные лучи и солнечные блики

    Крона собрана из нескольких сотен сплющенных пучков листвы; при размещении каждый проецируется на землю вдоль солнечных лучей и отодвигается от 29 заранее заданных точек падения лучей, поэтому свет падает отдельными столбами. Объёмный свет шагает вдоль каждого луча зрения, сэмплируя карту теней солнца в половинном разрешении, а затем смешивается с дальним туманом, тонмаппингом ACES, свечением (bloom) и FXAA.

    Тени переписаны как мягкие тени PCSS — чем дальше от заслоняющего объекта, тем мягче край, — а солнечные пятна, пробивающиеся сквозь крону, рассчитываются в пространстве света, так что трава, кора, оленёнок и световые столбы делят один и тот же рисунок. Пыль в воздухе светится только внутри лучей и почти исчезает в тени. Нажмите R — и за три секунды сцена переходит в ночь: солнце сменяется холодным лунным светом, лучи тускнеют, а огоньки мерцают, как светлячки.

  • Камера и запись · Снимайте прямо на странице

    Нажмите C для кинематографической камеры: она медленно облетает оленёнка, поднимаясь и опускаясь, а весь интерфейс скрыт. Нажмите V, чтобы начать запись, — MediaRecorder захватывает WebGL-холст вместе со звуком при 60 fps и 16 Мбит/с, сохраняя MP4, если браузер его поддерживает, а иначе WebM; уровень качества на время записи фиксируется, чтобы разрешение не скакало посреди ролика.

    Все звуки синтезируются на лету через Web Audio: за каждый собранный огонёк звенит колокольчик ветра, поднимаясь по пентатонике, а при порыве ветра слышится шум. Разрешение подстраивается под частоту кадров и снижается на ступень при просадках, а клавиши 1 / 2 / 3 вручную фиксируют низкое, среднее или высокое качество.