Найти тему
Иван Зотов

Загрузка 3D-моделей в формате glTF (Часть1)

Оглавление
Birds
Birds

В предыдущей главе мы создали простую модель игрушечного поезда, используя некоторые из встроенных геометрий three.js, и быстро стало ясно, что с их помощью будет сложно построить что-либо сложное или органичное. Для создания красивых 3D-моделей требуется сложная программа моделирования. Вы можете использовать three.js для создания любого 3D-приложения, однако создание приложения для моделирования с нуля потребует огромных усилий. Гораздо более простое решение - использовать существующую программу и экспортировать свою работу для использования в three.js… или, обмануть, и загрузить любую из миллионов удивительных моделей и других ресурсов сцены, которые доступны бесплатно во многих местах в Интернете.

В этой главе мы покажем вам, как загрузить некоторые модели, созданные в Blender, приложении для трехмерной графики с открытым исходным кодом, которое можно использовать для моделирования, построения сцены, создания материалов, создания анимации и многого другого. После того, как вы создали модель в Blender, вы можете экспортировать свою работу, используя 3D-формат, такой как glTF, а затем использовать плагин GLTFLoader, чтобы перенести модель в three.js.

Лучший способ отправки 3D-ресурсов через Интернет: glTF

За последние тридцать лет было много попыток создать стандартный формат обмена трехмерными активами. До недавнего времени наиболее популярными из них были форматы FBX, OBJ (Wavefront) и DAE (Collada), хотя все они имеют проблемы, препятствующие их широкому распространению. Например, OBJ не поддерживает анимацию, FBX - это закрытый формат, принадлежащий Autodesk, а спецификация Collada слишком сложна, что приводит к большим файлам, которые трудно загружать.

Однако недавно новый формат под названием glTF стал де-факто стандартным форматом для обмена 3D-ресурсами в Интернете. glTF (GL Transmission Format), иногда называемый JPEG для 3D, был создан Kronos Group, теми же людьми, которые отвечают за WebGL, OpenGL и целый ряд других графических API. Первоначально выпущенный в 2017 году, glTF теперь является лучшим форматом для обмена 3D-ресурсами в Интернете и во многих других областях. В этой книге мы всегда будем использовать glTF, и, если возможно, вы должны сделать то же самое. Он предназначен для публикации моделей в Интернете, поэтому размер файла минимален, а модели загружаются быстро.


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

Всякий раз, когда мы упоминаем glTF, мы имеем в виду glTF версии 2. Исходная версия glTF версии 1 так и не нашла широкого распространения и больше не поддерживается three.js.

Файлы glTF могут содержать модели, анимацию, геометрию, материалы, источники света, камеры или даже целые сцены. Это означает, что вы можете создать всю сцену во внешней программе, а затем загрузить ее в three.js.

Типы файлов glTF

Файлы glTF бывают стандартной и двоичной. У них разные расширения:

  • Стандартные файлы .gltf не сжаты и могут поставляться с дополнительным файлом данных .bin.
  • Двоичные файлы .glb включают все данные в один файл.

И стандартные, и двоичные файлы glTF могут содержать текстуры, встроенные в файл, или могут ссылаться на внешние текстуры. Поскольку двоичные файлы .glb значительно меньше по размеру, лучше использовать этот тип. С другой стороны, несжатые .gltf легко читаются в текстовом редакторе, поэтому они могут быть полезны для целей отладки.

Бесплатные файлы glTF в репозитории three.js

В репозитории three.js доступно множество бесплатных моделей glTF, среди которых три простые и красивые модели попугая, фламинго и аиста, созданные талантливыми людьми с сайта mirada.com. Эти три модели являются низкополигональными, что означает, что они работают даже на самых маломощных мобильных устройствах, и они даже анимированы.

Вы можете найти эти три файла в редакторе в папке assets / models /. В этой главе мы загрузим Parrot.glb, Flamingo.glb и Stork.glb, а затем добавим сетки в форме птиц, содержащиеся в каждом файле, в нашу сцену. В следующей главе мы покажем вам, как воспроизвести анимацию полета, которая есть у каждой птицы.

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

Асинхронный JavaScript

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

В этой главе мы будем использовать асинхронные функции для загрузки моделей и предположим, что вы хоть немного с ними знакомы. Если это для вас в новинку или вам нужно что-то освежить, перейдите к Асинхронный JavaScript.

Плагин GLTFLoader

Чтобы загрузить файлы glTF, сначала вам нужно добавить плагин GLTFLoader в свое приложение. Это работает так же, как добавление плагина OrbitControls. Вы можете найти загрузчик в examples / jsm / loaders / GLTFLoader.js в репозитории, и мы также включили этот файл в редактор. Идите и найдите файл сейчас.

Импорт и создание экземпляра загрузчика работает следующим образом:

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
const loader = new GLTFLoader();

Вы можете использовать один экземпляр загрузчика для загрузки любого количества файлов glTF.

Методы .load и .loadAsync

Все загрузчики three.js имеют два метода загрузки файлов: старый метод .load на основе обратного вызова и новый метод .loadAsync на основе Promise. Снова обратитесь к главе A.5, где мы подробно рассматриваем разницу между этими двумя подходами. Обещания позволяют нам использовать асинхронные функции, что, в свою очередь, приводит к более чистому коду, поэтому на протяжении всей книги мы всегда будем использовать .loadAsync.

const loader = new GLTFLoader();
const loadedData = await loader.loadAsync('path/to/yourModel.glb');

Настройте Main.js и World.js для обработки Async / Await

Ключевое слово await означает «подождите, пока модель загрузится». Если вы ранее имели дело с загрузкой моделей с помощью обратных вызовов или обещаний, то await покажется почти волшебным в своей простоте. Однако нам нужно внести несколько изменений в наш код, прежде чем мы сможем его использовать, поскольку мы можем использовать ожидание только внутри функции, которая была помечена как async:

async function loadingSuccess() {
// inside an async function: OK!
await loader.loadAsync('yourModel.glb');
}
function loadingFail() {
// not inside an async function: ERROR!
await loader.loadAsync('yourModel.glb');
}

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

class Foobazzer {
constructor() {
// constructor cannot be async: ERROR!
await loader.loadAsync('yourModel.glb');
}
async init() {
// inside an async function: OK!
await loader.loadAsync('yourModel.glb')
}
}

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

class World {
constructor() {
// synchronous setup here
// create camera, renderer, scene, etc.
}
async init() {
// asynchronous setup here
// load bird models
}
}

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

Продолжение в следующей статье...