Когда-то, изучая возможности работы с 3D-изображениями в современных браузерах, я наткнулся на Three.js — кроссбраузерную библиотеку JavaScript для создания динамичных 3D-изображений в браузере, как, например, здесь. Изучив документацию и поэкспериментировав с основными элементами библиотеки, я нашел отличный урок Кайла Уэттона How to Build a Color Customizer App.
Я решил применить инструкцию Уэттона к популярной библиотеке React с дополнением react-three-fiber — библиотеки, в которой объединены React и Three.js.
Примечание: В этой статье я не описывал разработку таких элементов интерфейса, как выбор цвета и модели, в обычном React. Их применение можно увидеть в конечном коде.
Пара слов о react-three-fiber
Библиотека react-three-fiber (R3F) позволяет создавать динамические графические изображения с так называемыми многоразовыми компонентами, а также структурировать исходный код.
Эти компоненты реагируют на изменения внутреннего состояния, интерактивны и синхронизируются с экосистемой React. К тому же, работая с react-three-fiber вы практически ничем не ограничены — все, что можно сделать с обычным Three.js, будет работать и в R3F. Производительность в таком случае определяется Three.js и GPU, поэтому R3F не медленнее, чем Three.js.
Вот ссылки на react-three-fiber:
— Repo
— API
Итак, начнем начнем наш эксперимент с подготовки параметров.
Подготовка параметров
С помощью компонентов react-three-fiber мы создадим 3D-изображение стула, стоящего на полу со всеми необходимыми бликами и тенями. Для нашей задачи мы будем использовать шаблон create-react-app.
npx create-react-app my-app npm install three react-three-fiber
Используем CanvasComponent, в котором создаются все 3D-объекты. Остальное HTML будет в виде UI.
import {Canvas} from "react-three-fiber"; <Canvas id="rtfCanvas" > <Scene/> </Canvas>
Canvas object — ваше входное окно в Three.js. Он выполняет Three.js-элементы, не выполняя при этом DOM-элементы. Мы можем установить некоторые элементы по дефолту, например, трехмерные иллюстрации проекций лучей (raycaster) или настройки камеры, через свойства Canvas, например:
<Canvas id="rtfCanvas" camera={{fov: 50}}/>
Но лучше создать компонент Scene на подуровне, в качестве «ребенка», для чистоты структуры проекта и удобства в разработке. В Canvas R3F уже по дефолту встроен THREE.Scene object, так что в Scene мы просто настроим его под себя. Установим поле значения для просмотра 50 и обновим цвет фона Scene.
Добавим немного тумана такого же цвета, чтобы скрыть края пола:
const Scene = ({newMaterialOpt}) => { const { scene, camera, gl: {domElement} } = useThree(); useEffect(() => { scene.background = new THREE.Color(0xf1f1f1); scene.fog = new THREE.Fog(0xf1f1f1, 20, 100); camera.fov = 50; }, []) return (<> </>) }
Добавим полукруг и направим свет на объект:
Добавим controls от OrbitControls.js. Функция «расширить» дополняет каталог three-fiber элементами JSX elements. Компоненты, добавленные таким образом, можно использовать в графических иллюстрациях помощью camel casing.
Стартовая конфигурация нашего 3D-изображения выглядит так:
import {extend, useThree} from "react-three-fiber"; import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls' import * as THREE from "three"; extend({OrbitControls}) const Scene = ({newMaterialOpt}) => { const { scene, camera, gl: {domElement} } = useThree(); useEffect(() => { scene.background = new THREE.Color(0xf1f1f1); scene.fog = new THREE.Fog(0xf1f1f1, 20, 100); camera.fov = 50; }, []) return ( <> <orbitControls args={[camera, domElement]}/> <hemisphereLight skycolor={new THREE.Color(0xffffff)} groundColor={new THREE.Color(0xffffff)} intensity={0.61} position={[0, 50, 0]} /> <directionalLight color={new THREE.Color(0xffffff)} intensity={0.54} position={[-8, 12, 8]} castShadow /> <Suspense fallback={null}> <ChairMesh newMaterialOpt={newMaterialOpt}/> <Floor/> </Suspense> </> ) }
Загружаем модель
Добавим компонент ChairMesh, который будет воспроизводить модель стула. Расширением модели будет .gltf — это требования открытого формата для эффективного воспроизведения и загрузки 3D-контента. Ассеты могут быть представлены как в JSON (.gltf) так и в .glb.
Загружаем модель объекта, используя GLTFLoader из three.js package:
После загрузки всей информации о переменной модели используем <primitive/>
, чтобы добавить уже созданные объекты в изображение.
Получаем следующее состояние объекта модели, используя primitive. На данном этапе наша модель выглядит так:
Теперь добавим пол, на который будет падать тень от стула:
Процесс создания 3D primitive в R3F с помощью jsx немного отличается, но суть та же, что и в обычном ThreeJs.
Во-первых, создаем трехмерную сетку, состоящую в основном из геометрических фигур и материалов.
Во-вторых, создаем planeGeometry в форме четырехугольника, затем новую meshPhongMaterial и выставляем пару опций: цвет, и блики. Phong — отличный материал, поскольку с его помощью можно регулировать отражения и блики.
Должно получиться вот так:
Перейдем к теням
Используя дополнительные настройки, создаем тени от стула на полу. Запускаем shadowMap в рендере GL в настройках нашей сцены. Также вручную добавляем shadow mapSize к directionalLight к scene children, поскольку искусственные настройки светотени не работают (на момент создания статьи):
В функции загрузки есть возможность пройтись по параметрам 3D-объекта. Для этого перейдем к функции загрузки и добавим ниже theModel: = gltf.scene
. Для каждой части 3D-объекта (ножки, подушки, и т.д.), мы применяем опцию «применить тени».
Этот метод изменения параметров будет использован позже.
Материалы объекта все еще выглядят неправдоподобно, поскольку сейчас используются стандартные материалы из дизайн-редактора (в моем случае — Blender). Во всяком случае тут есть тени:
Установим материал Phong по умолчанию:
На этом можно было бы и закончить. Но для некоторых объектов может понадобиться загрузить особый цвет или текстуру, поскольку мы не можем покрыть всю модель одним базовым цветом.
Мы будем перебирать наш 3D-объект, используя childID, чтобы найти разные части стула, и применить к ним материал. Эти childID происходят от имен, которые мы дали каждому объекту в Blender.
Под функцией загрузки добавим функцию, которая берет модель, часть объекта (тип) и материал и устанавливает материал. Также добавим к этой части новое свойство под названием nameID, чтобы использовать его позже.
Попробуем запустить эту функцию после того, как загрузим готовую модель. В useEffect hook выбираем переменную theModel как зависимость для обновления.
Также изменим цвет пола с красного на 0xeeeeee. В итоге получаем это:
В результате мы создали трехмерное изображение со светотенями и управлением мышью. Результат нашей работы можно увидеть здесь.
Этот материал – не редакционный, это – личное мнение его автора. Редакция может не разделять это мнение.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: