Оригинальное видео: https://youtu.be/IjiE3bRdMTk

В сегодняшнем эпизоде ​​мы продолжим наш курс three.js, импортировав экспортированный файл блендера в наш проект Webflow.

Несколько недель назад мы рассмотрели, как хранить внешние активы Webflow, это могут быть CSS, JavaScript. В этом случае мы собираемся загружать наши файлы Blender или, точнее, наши файлы GLTF в эти внешние хранилища, а затем мы собираемся импортировать их в нашу сцену three.js.

Типы 3D-файлов

Когда дело доходит до three.js и 3D в целом, существуют буквально сотни различных типов файлов, и все они имеют свои плюсы и минусы. Некоторые из них основаны на производительности, некоторые — буквально на информации, содержащейся в этих файлах. Многие из них хранятся в формате JSON, независимо от того, встраиваете ли вы текстуры или ссылаетесь на внешние.

Это становится грязным.

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

GLTFLoader

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

В нашем импорте здесь мы хотим добавить новую строку кода и сопоставить «три/аддоны» с…

https://unpkg.com/three@<version>/examples/jsm/

Вы захотите заменить ‹версию›, которая соответствует версии three.js, которую вы используете (мы используем 0.149.0).

Net нам нужно его загрузить.

import { GLTFLoader } from "three/addons/loaders/GLTFLoader";

Редактор Three.js

Мы не будем рассказывать, как экспортировать файлы GLTF из блендера. Вместо этого следуйте этому руководству, но, думаю, стоит упомянуть, что если вы перейдете на threejs.org/editor. Вы можете импортировать свои файлы в этот очень простой редактор three.js. Это хороший способ проверить, действительно ли файл работает. Вы также можете манипулировать вещами, добавлять новые материалы или просто менять положение вещей. Редактор three.js — это действительно хороший способ просто добавить последние штрихи к вашему файлу или, возможно, изменить его без привлечения дизайнера.

Преобразование GLTF

GLTF Transform сжимает и оптимизирует ваши файлы GLTF, чтобы сделать их меньше, и многое другое. В основном я использую его для сжатия текстур Webp. Поэтому после установки инструмента CLI вы можете еще больше сжать файл.

gltf-transform webp [LINK-TO-FILE]

У меня есть образцы моделей Fox the Kronos Group, и я выбрал эту 1, потому что к ней привязаны некоторые анимации. Я загрузил это на AWS и получил общедоступную ссылку. Смотрите другое наше видео на тему выбор хранилища.

Загрузка нашего файла GLTF

Мы создадим функцию loadFox и вызовем ее из нашего конструктора.

// constructor 
this.loadFox() 
// class level 
loadFox() { }

Затем нам нужно создать экземпляр загрузчика GLTF и загрузить нашу лису с помощью метода загрузки и вставить наш URL-адрес в наш файл GLTF.

// loadFox 
const gltfLoader = new GLTFLoader() 
gltfLoader.load('<url-to-asset>')

Получаем доступ к 3 функциям. Первая функция зависит от успешности загрузки. Второй функцией будет прогресс, и это может быть удобно для панели загрузки. Третья 1 будет на ошибке.

Внутри функции успеха мы получаем доступ к загружаемому объекту. Регистрация объекта, это то, с чем мы собираемся работать. Это лиса.

gltfLoader.load( '<url-to-asset>', 
  (gltf) => console.log('success', gltf), 
  () => console.log('progress'), 
  () => console.log('error'))

Добавление к нашей сцене

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

Теперь добавим его на нашу сцену.

this.scene.add(gltf.scene)

Нам также нужно добавить немного света. Так что мы просто добавим немного окружающего света. Окружающий свет — это просто свет со всех сторон.

// constructor 
this.addLights(); 
// class-level 
addLights() { 
  const ambientLight = new THREE.AmbientLight() 
  this.scene.add(ambientLight) 
}

А теперь вы можете увидеть нашу лису. И он огромен.

Группы

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

Давайте пока разберемся с масштабом этой лисы.

gltf.scene.scale.set(0.03, 0.03, 0.03)

Это более управляемый размер. Теперь мы собираемся создать нашу группу для коробки.

// createBox 
this.group = new THREE.Group() 
// + 
this.group.add(this.box) 
this.scene.add(this.group) 
// - this.scene.add(this.box)

При обновлении вы не должны увидеть никаких изменений. Идеальный. А теперь идем к этой лисе в группу и немного подвинем ту лису.

// addFox 
// + 
gltf.scene.position.y = 0.5 
this.group.add(gltf.scene) 
// - this.scene.add(gltf.scene)

Теперь нам нужно вращать группу, а не только коробку, что совершенно практично.

// animate 
// + 
gsap.to(this.group.rotation, { 
// - gsap.to(this.box.rotation, ( ...

Микшер анимации

Давайте теперь посмотрим на анимации, к которым у нас есть доступ в файле fox GLTF.

Чтобы иметь возможность переходить между анимациями, нам нужен микшер и добавьте в него наш файл GLTF, так как он содержит анимации.

gltf.load('<asset>', (gltf) => { 
  // success method 
  this.mixer = new THREE.AnimationMixer(gltf.scene) 
})

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

// gltf success method 
this.mixer = new THREE.AnimationMixer(gltf.scene) 
this.action1 = this.mixer.clipAction(gltf.animations[0]) 
this.action2 = this.mixer.clipAction(gltf.animations[1]) 
this.action1.play()

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

// constructor 
this.clock = new THREE.Clock() 

// animate 
if (this.mixer) { 
  this.mixer.update(this.clock.getDelta()) 
}

Теперь у нас что-то играет!

Смешивание между анимациями

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

// class-level 
fadeToAction(action, duration = 0.2) { }

Нам нужно установить текущее активное действие, чтобы установить предыдущее действие и выстроить новое действие.

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

// gltf success method 
this.mixer = new THREE.AnimationMixer(gltf.scene) 
this.action1 = this.mixer.clipAction(gltf.animations[0]) 
this.action2 = this.mixer.clipAction(gltf.animations[1]) 
// + 
this.activeAction = this.action1 
this.activeAction.play() 
// - this.action1.play()

Теперь, когда мы отслеживаем текущее активное действие, мы можем установить новое действие внутри метода fade как переданное и затемнить предыдущее текущее действие с заданной продолжительностью.

Затем нам нужно исчезнуть в newAction.

fadeToAction(action, duration = 0.2) { 
  const previousAction = this.activeAction
  this.activeAction = action
 
  if (previousAction !== this.activeAction) {
    previousAction.fadeOut(duration)
  } 

  this.activeAction.reset()
    .setEffectiveTimeScale(1)
    .setEffectiveWeight(1)
    .fadeIn(duration)
    .play() 
}

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

// setEvents 
const titles = Array.from(document.querySelectorAll("h2"))
titles.forEach((title) => {
  title.addEventListener("mouseover", () => {
    this.fadeToAction(this.action2)
    this.isHovering = true
  })
  title.addEventListener("mouseleave", () => {
    this.fadeToAction(this.action1)
    this.isHovering = false
  })
})

Ознакомьтесь с окончательным кодом здесь.

Первоначально опубликовано на https://thefullstackagency.xyz 4 мая 2023 г.