konfigurasi 3d models dengan react-three-fiber

Konfigurasi 3D Model dengan react-three-fiber

Memuat model 3D ke dalam scene WebGL adalah salah satu aspek yang paling rumit dari rendering 3D di browser. Meskipun library seperti Three.js dan Babylon.js menyediakan API yang kuat yang membantu meringankan ketegangan dalam bekerja dengan WebGL, mereka tidak kebal terhadap prosesnya sendiri yang membosankan, seperti membuat shader dari awal dan menggunakan kembali scene.add() ketika menambahkan objek ke dalam scene.

react-three-fiber adalah sebuah React renderer untuk Three.js yang memudahkan bekerja dengan model 3D di web dengan menangani fungsi-fungsi Three.js yang sangat penting di balik layar dan menyediakan akses ke objek-objek Three.js yang primitif melalui Hooks.

R3F tidak meningkatkan atau mengurangi kinerja dasar Three.js; tetap sama karena R3F adalah perpustakaan yang dibangun di atas Three. Keduanya memiliki karakteristik yang sama, kecuali model komponen React, yang digunakan R3F untuk menyeimbangkan kompleksitas dan kinerja.

Scaling performa pada R3F jauh lebih mudah dibandingkan dengan Three.js karena R3F menyediakan pendekatan yang komprehensif dan lebih sederhana dalam mengurangi penggunaan sumber daya perangkat keras WebGL yang mahal. Sebagai contoh, mengimplementasikan pengoptimalan kinerja rendering sesuai permintaan di R3F semudah menambahkan prop frameloop dan nilai permintaan ke komponen Canvas:

<canvas frameloop="demand"></canvas>

Optimalisasi kinerja lainnya meliputi: pembuatan instance, penggunaan kembali geometri dan material, pengurangan tingkat detail pada material, regresi gerakan, dll.

Dalam artikel ini, kita akan membahas cara merender dan mengonfigurasi aset 3D yang dibuat dalam program perangkat lunak 3D seperti Blender atau Maya dalam proyek React menggunakan react-three-fiber. Di akhir artikel ini, Anda akan dapat merender model 3D di situs web Anda.

Prasyarat

Untuk mengikuti tutorial ini, Anda memerlukan pengetahuan mendasar tentang arsitektur React dan Three.js, termasuk lighting, geometri, dan canvas. Anda juga harus menginstal Node.js di mesin Anda. Mari kita mulai.

Membuat dan menyiapkan model 3D untuk web

Three.js mendukung beberapa format model 3D. Karena kerumitan dan kesulitan sebagian besar format file ini, disarankan untuk menggunakan glTF (GL Transmission Format) jika memungkinkan.

Berfokus pada pengiriman aset runtime, aset glTF dimuat dengan cepat dan dapat dikompresi menjadi ukuran yang ringkas untuk transmisi. Aset glTF disediakan dalam format JSON .gltf dan binary .glb. Setiap format file yang didukung memiliki loader masing-masing di Three.js. Misalnya, Anda akan menggunakan pemuat glTF untuk memuat file glTF atau GLB ke dalam react-three-fiber-scene.

Untuk membuat model Anda, Anda dapat menggunakan perangkat lunak pemodelan 3D pilihan Anda, tetapi menurut pengalaman saya, kebanyakan orang lebih suka Blender. Jika Anda seperti saya, dan Anda tidak memiliki pengalaman membuat model 3D, Anda dapat menggunakan file glTF domain publik dari situs seperti sketchfab.com.

Sebagian besar aset gratis di situs ini berada di bawah lisensi Creative Commons, artinya Anda dapat menggunakannya dalam proyek Anda selama Anda menyertakan atribusi ke pembuat aslinya. Sebaiknya periksa izin untuk menggunakan aset sebelum memasukkannya ke dalam proyek Anda.

Jika Anda berencana untuk menambahkan tindakan seperti animasi atau pemetaan peristiwa ke model Anda, Anda harus mendesain aset sedemikian rupa sehingga setiap bagian, atau mesh, dikelompokkan dan dipisahkan dengan benar. Sayangnya, beberapa aset gratis yang tersedia secara online telah menerapkan ini, jadi Anda harus membeli satu atau membuatnya sendiri.

Dalam tutorial ini, kita akan menggunakan aset sepatu sebagai proyek contoh, yang dibuat oleh Yuri Artiukh. Jika Anda kesulitan membuat atau menemukan model, Anda bisa mendapatkannya dari repo Three.js GitHub.

Konversi glTF ke GLB

glTF didasarkan pada JSON, yang berarti beberapa datanya disimpan secara eksternal, misalnya, geometri, shader, tekstur, dan data animasi. Namun, GLB menyimpan data ini secara internal, sehingga ukurannya jauh lebih kecil daripada glTF. Oleh karena itu, format biner .glb adalah yang terbaik untuk digunakan dalam proyek Anda. Sekarang, mari kita bahas cara mengonversi file glTF ke GLB.

Ada beberapa alat yang dapat Anda gunakan untuk operasi ini, namun, glTF-pipeline adalah salah satu pilihan terbaik. Ini adalah alat yang fleksibel untuk mengoptimalkan aset glTF yang memiliki beberapa ekstensi untuk melakukan operasi umum langsung dari alat baris perintah Anda, seperti konversi GLB ke glTF, kompresi glTF, dan banyak lagi.

Sebagai alternatif, Anda dapat menggunakan ekstensi alat glTF resmi untuk VS Code untuk melihat pratinjau, men-debug, dan mengonversi model langsung dari editor. Anda juga dapat menggunakan ekstensi ini untuk mengedit dan mengubah file glTF. Misalnya, jika mesh model Anda tidak diberi nama dengan benar, Anda dapat mengedit file dan mengganti namanya sesuai keinginan Anda.

Untuk memulai proses konversi dengan glTF-pipeline, pertama-tama kita harus menginstalnya secara global di komputer kita dengan perintah berikut:

npm install -g gltf-pipeline

Selanjutnya, letakkan file glTF di dalam folder kosong dan buka command line Anda. cd ke dalam folder tersebut dan jalankan perintah di bawah ini:

gltf-pipeline -i <source file> -o <output file>

Ganti placeholder pertama pada perintah di atas dengan nama file sumber. Ganti placeholder kedua dengan nama file keluaran pilihan Anda:

gltf-pipeline -i shoe.gltf -o shoe.glb

Setelah menjalankan perintah di atas, Anda akan melihat file GLB baru dalam folder di samping file glTF sebelumnya. Proses ini juga berlaku sebaliknya untuk mengonversi GLB ke format glTF.

Compress model

Untuk menghindari penurunan kinerja situs kita dengan ukuran aset 3D, kita akan mengompresnya sebelum memuatnya ke dalam scene. Disarankan agar ukuran file Anda tidak melebihi satu hingga dua megabyte. Kita akan menggunakan ekstensi kompresi pipeline glTF yang disebut Draco:

gltf-pipeline -i <source file> -o <output file> --draco.compressionLevel=10

Perintah di atas mirip dengan perintah yang kita gunakan sebelumnya selama proses konversi, dengan satu-satunya perbedaan adalah flag tingkat kompresi. Kompresi Draco memiliki nilai maksimum sepuluh dan nilai minimum nol. Memasukkan nilai 10 ke dalam level kompresi akan menghasilkan kompresi maksimum.

Sekarang, kita dapat menyiapkan proyek, membuat scene, dan memuat model kita.

Setting react-three-fiber

Pertama, mari kita membuat sebuah proyek React baru dengan Create React App:

npx create-react-app react-three

Setelah itu, instal react-three-fiber dengan perintah di bawah ini:

npm install three @react-three/fiber

Setelah selesai, lanjutkan dan jalankan perintah di bawah ini untuk menginstal semua dependensi yang kita perlukan untuk proyek:

npm i @react-three/drei react-colorful valtio

Perintah di atas akan menginstal dependensi berikut ini:

  • react-colorful: komponen pemilih warna untuk React
  • drei: menyediakan add-on yang berguna untuk react-three-fiber, seperti cameras, plane, dan controls
  • Valtio: alat manajemen state yang ringan dan berbasis proxy untuk React

Selanjutnya, kita akan membuat sebuah scene dalam sebuah komponen kosong. Pertama, impor dan buat kanvas kosong seperti berikut ini:

import React from "react";
import { Canvas } from "react-three-fiber";
import "./styles.css";
export default function App() {
  return <Canvas style={{ background: "#171717" }}></Canvas>;
}

Sekarang, proyek dan scene kita sudah diatur dan siap untuk mulai memuat model kita! Sebelum kita dapat memuat aset ke dalam scene dan mengonfigurasinya, kita perlu menemukan cara yang mudah untuk mengubah model kita menjadi sebuah komponen.

Mengubah model menjadi komponen React yang dapat digunakan kembali

Memuat model glTF ke dalam sebuah scene Three.js adalah pekerjaan yang sangat berat. Sebelum kita dapat mengonfigurasi atau menganimasikan meshes model kita, kita perlu melakukan iterasi pada setiap bagian dari meshes model kita dan menyimpannya secara terpisah.

Untungnya, react-three-fiber memiliki paket utilitas luar biasa yang disebut gltfjsx yang memecah model dan mengkompilasinya menjadi komponen JSX yang bersifat deklaratif dan dapat digunakan kembali.

Untuk memulai, buka alat baris perintah Anda, cd ke dalam folder di mana model glTF terkompresi Anda berada, dan jalankan perintah di bawah ini:

npx gltfjsx <glTF model source file>

Jalankan perintah di atas pada model sepatu yang telah kita unduh sebelumnya. Sekarang, kode di atas akan terlihat seperti berikut ini:

npx gltfjsx shoe-draco.gltf

Perintah di atas akan mengembalikan sebuah berkas JavaScript yang menyusun semua konten aset dalam format komponen fungsional React. Konten file tersebut akan terlihat mirip dengan kode berikut ini:

import React, { useRef } from 'react'
import { useGLTF } from '@react-three/drei/useGLTF'

function Shoe({ ...props }) {
 const group = useRef()
 const { nodes, materials } = useGLTF('/shoe-draco.glb')
 const snap = useSnapshot(state);
 return (
<group ref={group} {...props} dispose={null}>
  <group ref={group} {...props} dispose={null}>
    <mesh geometry={nodes.shoe.geometry} material={materials.laces}/>
    <mesh geometry={nodes.shoe_1.geometry} material={materials.mesh}/>
    <mesh geometry={nodes.shoe_2.geometry} material={materials.caps} />
    <mesh geometry={nodes.shoe_3.geometry} material={materials.inner} />
    <mesh geometry={nodes.shoe_4.geometry} material={materials.sole}/>
    <mesh geometry={nodes.shoe_5.geometry} material={materials.stripes}/>
    <mesh geometry={nodes.shoe_6.geometry} material={materials.band}/>
    <mesh geometry={nodes.shoe_7.geometry} material={materials.patch} />
   </group>
 </group>
)}

Nilai node dan material didestrukturisasi oleh useGLTF Hook, sementara jalur ke model kita diteruskan ke Hook sebagai parameter.

Node yang didestrukturisasi adalah sebuah objek yang berisi semua informasi dalam model kita, termasuk animasi, tekstur, dan geometri. Dalam kasus ini, node menggunakan geometri model yang telah direstrukturisasi dan diteruskan ke komponen mesh sebagai props.

Menambahkan komponen model ke dalam scene

Anda dapat meletakkan file yang baru dibuat ke dalam folder src proyek Anda sebagaimana adanya, atau Anda dapat menyalin dan menempelkan kode dari dalam file ke dalam komponen yang sudah ada dalam proyek Anda.

Untuk menambahkan model ke dalam scene, impor model seperti yang Anda lakukan pada komponen React lainnya:

import Shoe from './Shoe.js'

Selanjutnya, pindahkan berkas glTF yang telah Anda kompres sebelumnya ke folder /public. Terakhir, tambahkan komponen di dalam kanvas Anda:

import React from "react";
import { Canvas } from "react-three-fiber";
import Shoe from './Shoe.js'
import "./styles.css";

export default function App() {
  return(
<Canvas style={{ background: "#171717" }}>
   <Shoe />
</Canvas>;
)};

Anda juga dapat menambahkannya ke komponen Anda sebagai berikut:

import React, { useRef } from "react"
import { Canvas } from "react-three-fiber"
import { useGLTF } from '@react-three/drei/useGLTF'
import "./styles.css";

function Shoe({ ...props }) {
 const group = useRef()
 const { nodes, materials } = useGLTF('/shoe-draco.glb')
 return (
<group ref={group} {...props} dispose={null}>
  <group ref={group} {...props} dispose={null}>
    <mesh geometry={nodes.shoe.geometry} material={materials.laces}/>
    <mesh geometry={nodes.shoe_1.geometry} material={materials.mesh}/>
    <mesh geometry={nodes.shoe_2.geometry} material={materials.caps} />
    <mesh geometry={nodes.shoe_3.geometry} material={materials.inner} />
    <mesh geometry={nodes.shoe_4.geometry} material={materials.sole}/>
    <mesh geometry={nodes.shoe_5.geometry} material={materials.stripes}/>
    <mesh geometry={nodes.shoe_6.geometry} material={materials.band}/>
    <mesh geometry={nodes.shoe_7.geometry} material={materials.patch} />
   </group>
 </group>
)}

export default function App() {
  return(
<Canvas style={{ background: "#171717" }}>
   <Shoe />
</Canvas>;
)};

Pada titik ini, jika Anda memulai server pengembangan, React akan melemparkan kesalahan kompilasi. Komponen model bersifat asinkron, oleh karena itu, kita harus menyarangkannya di dalam komponen <Suspense> di dalam kanvas, memberikan kita kontrol atas fallback pemuatan menengah dan penanganan kesalahan.

Pertama, kita perlu mengimpor komponen model dari React, lalu membungkusnya di sekitar model di dalam canvas:

import React, { Suspense, useRef } from "react";
import { Canvas } from "react-three-fiber";
import { useGLTF } from '@react-three/drei/useGLTF'
import "./styles.css";

function Shoe({ ...props }) {
 const group = useRef()
 const { nodes, materials } = useGLTF('/shoe-draco.glb')
 return (
<group ref={group} {...props} dispose={null}>
  <group ref={group} {...props} dispose={null}>
    <mesh geometry={nodes.shoe.geometry} material={materials.laces}/>
    <mesh geometry={nodes.shoe_1.geometry} material={materials.mesh}/>
    <mesh geometry={nodes.shoe_2.geometry} material={materials.caps} />
    <mesh geometry={nodes.shoe_3.geometry} material={materials.inner} />
    <mesh geometry={nodes.shoe_4.geometry} material={materials.sole}/>
    <mesh geometry={nodes.shoe_5.geometry} material={materials.stripes}/>
    <mesh geometry={nodes.shoe_6.geometry} material={materials.band}/>
    <mesh geometry={nodes.shoe_7.geometry} material={materials.patch} />
   </group>
 </group>
)}

export default function App() {
  return(
<Canvas style={{ background: "#171717" }}>
  <Suspense fallback={null}>
     <Shoe />
  </Suspense>
</Canvas>;
)};

Kode di atas akan menghapus kesalahan, dan model kita akan berhasil ditampilkan pada browser. Namun demikian, apa pun yang kita muat ke dalam scene kita, hanya akan muncul sebagai gambar siluet model.

Saat ini, scene kita tidak memiliki sumber pencahayaan. Solusi yang umum adalah dengan menambahkan komponen ambientLight dan spotLight sebelum <Suspense> di kanvas:

<Canvas style={{ background: "#171717" }}>
<ambientLight intensity={1} />
<spotLight intensity={0.5} angle={0.1} penumbra={1} position={[10, 15, 10]} castShadow />
  <Suspense fallback={null}>
      <Shoe />
   </Suspense>
</Canvas>;

Silakan mengutak-atik intensitas, sudut, dan posisi cahaya. Jika Anda tidak puas dengan hasilnya, Anda juga bisa memposisikan cahaya dengan menambahkan penyangga pemosisian.

Konfigurasi Model

Karena model kita bersifat deklaratif, kita memiliki akses penuh ke mesh-nya, yang berarti kita dapat menambah, menghapus, dan mengubah bagian dari model kita.

Sebagai contoh, jika komponen mesh pertama dalam kode merepresentasikan tali sepatu, dan kita menghapus atau mengomentari mesh tersebut, maka tali sepatu akan hilang dalam scene. Anda dapat memutuskan untuk menganimasikan, menambahkan peristiwa, dan bahkan melakukan kondisi pada model Anda.

Untuk mengubah model, cukup ubah props. Jika kita ingin mengubah warna mesh pertama menjadi merah, tambahkan material-color=”Red” sebagai props. Di dalam scene, bagian model tersebut akan berubah menjadi merah:

<mesh material={materials.White} geometry={nodes['buffer-0-mesh-0'].geometry} material-color="Red"/>

Kita dapat melakukan hal yang sama secara dinamis dengan menggunakan Hook useState milik React, dan juga library manajemen state apa pun yang mendukung Suspense. Dalam kasus ini, kita akan menggunakan Valtio, yang telah kita instal sebelumnya.

Konfigurasi Model dengan Valtio

Lanjutkan dengan mengimpor proxy dan useSnapshot dari Valtio:

import {proxy, useSnapshot} from 'valtio'

Selanjutnya, salin kode di bawah ini dan tempelkan sebelum komponen model Anda:

const state = proxy({
  current: null,
  items: {
    laces: "#ff3",
    mesh: "#3f3",
    caps: "#3f3",
    inner: "#3f3",
    sole: "#3f3",
    stripes: "#3f3",
    band: "#3f3",
    patch: "#3f3",
  },
})

Kami membuat objek dengan dua kunci, item dan current. current memiliki nilai null, sedangkan item memiliki nilai objek dengan kunci yang mewakili setiap bagian dari model kami dan nilai warna heksa. Objek tersebut kemudian dibungkus dengan proxy.

Untuk menggunakan state di dalam komponen, kita akan membuat variabel snap konstan di dalam komponen model dan memberikannya nama useSnapshot. Setelah itu, kita akan mengoper state ke dalam snapshot sebagai parameter:

import React, { useRef, Suspense} from 'react'
import { Canvas } from "react-three-fiber";
import "./styles.css";
import { useGLTF } from '@react-three/drei/useGLTF'
import {proxy, useSnapshot} from 'valtio';

const state = proxy({
  current: null,
  items: {
    laces: "#ff3",
    mesh: "#3f3",
    caps: "#3f3",
    inner: "#3f3",
    sole: "#3f3",
    stripes: "#3f3",
    band: "#3f3",
    patch: "#3f3",
  },
})

function Shoe({ ...props }) {
 const group = useRef()
 const { nodes, materials } = useGLTF('/shoe-draco.glb')
 const snap = useSnapshot(state);
 return (
<group ref={group} {...props} dispose={null}>
  <group ref={group} {...props} dispose={null}>
    <mesh geometry={nodes.shoe.geometry} material={materials.laces}/>
    <mesh geometry={nodes.shoe_1.geometry} material={materials.mesh}/>
    <mesh geometry={nodes.shoe_2.geometry} material={materials.caps} />
    <mesh geometry={nodes.shoe_3.geometry} material={materials.inner} />
    &lt;mesh geometry={nodes.shoe_4.geometry} material={materials.sole}/>
    <mesh geometry={nodes.shoe_5.geometry} material={materials.stripes}/>
    <mesh geometry={nodes.shoe_6.geometry} material={materials.band}/>
    <mesh geometry={nodes.shoe_7.geometry} material={materials.patch} />
   </group>
 </group>
)}

export default function App() {
  return <Canvas style={{ background: "#171717" }}>
<ambientLight intensity={1} />
<spotLight intensity={0.5} angle={0.1} penumbra={1} position={[10, 15, 10]} castShadow />
  <Suspense fallback={null}>
      <Shoe />
  </Suspense>
</Canvas>;
}

Sebelum kita dapat menggunakan snapshot state dalam komponen, kita harus mengatur warna material setiap mesh ke warna variabel state. Untuk melakukannya, kita akan menambahkan props warna material ke setiap mesh seperti yang telah kita lakukan sebelumnya. Kali ini, kita akan memberikan snapshot state kita:

const state = proxy({
  current: null,
  items: {
    laces: "#ff3",
    mesh: "#3f3",
    caps: "#3f3",
    inner: "#3f3",
    sole: "#3f3",
    stripes: "#3f3",
    band: "#3f3",
    patch: "#3f3",
  },
})

function Shoe({ ...props }) {
 const group = useRef()
 const { nodes, materials } = useGLTF('/shoe-draco.glb')
 const snap = useSnapshot(state);
 return (
<group ref={group} {...props} dispose={null}>
  <group ref={group} {...props} dispose={null}>
    <mesh geometry={nodes.shoe.geometry} material={materials.laces} material-color={snap.items.laces}/>
    <mesh geometry={nodes.shoe_1.geometry} material={materials.mesh} material-color={snap.items.mesh}/>
    <mesh geometry={nodes.shoe_2.geometry} material={materials.caps} material-color={snap.items.caps}/>
    <mesh geometry={nodes.shoe_3.geometry} material={materials.inner} material-color={snap.items.inners}/>
    <mesh geometry={nodes.shoe_4.geometry} material={materials.sole} material-color={snap.items.sole}/>
    <mesh geometry={nodes.shoe_5.geometry} material={materials.stripes} material-color={snap.items.stripes}/>
    <mesh geometry={nodes.shoe_6.geometry} material={materials.band} material-color={snap.items.band}/>
    <mesh geometry={nodes.shoe_7.geometry} material={materials.patch} material-color={snap.items.patch}/>
   </group>
 </group>
  )
}

Sekarang, jika kita mengubah salah satu warna pada state item kita, bagian model tersebut akan memperbarui warnanya di scene.

Menambahkan event

Daripada mengubah state secara manual, kita dapat menambahkan event ke model kita sehingga pengguna dapat memilih setiap bagian sepatu dan mengubah warna dengan pemilih warna.

Pertama, kita akan menambahkan event onPointerDown dan onPointerMissed ke komponen grup model. Kita akan membuat fungsi event DOM yang menetapkan status ke bagian model yang diklik dan null ketika tidak ada yang dipilih:

<group ref={group} {...props} dispose={null}
 onPointerDown={(e) => {e.stopPropagation(); state.current = e.object.material.name }}
onPointerMissed={(e) =>{state.current = null} }
>

Sekarang, kita akan mengimpor HexColorPicker dari react-colorful. Kita akan membuat komponen baru yang akan menampung komponen HexColorPicker dan sebuah tag header yang menampilkan nama bagian model yang diklik:

import {HexColorPicker} from 'react-colorful'

 function ColorPicker(){
 const snap = useSnapshot(state);
  return(
   <div>
     <HexColorPicker color={snap.items[snap.current]} onChange={(color)=>(state.items[state.current] = color)}/>
     <h1>{snap.current}</h1>
   </div>
    )
  }

Segera setelah kita menyimpan kode kita, GUI pemilih warna akan muncul di browser. Sekarang, untuk mengubah warna mesh model kita, kita dapat mengkliknya dan memilih warna dengan pemilih warna. Anda juga dapat menambahkan classNames ke pemilih warna dan tag <h1>.

Menghidupkan animasi model

Saat ini, model tidak terasa seperti objek 3D. Secara khusus, model ini tidak memiliki kedalaman dan gerakan seperti gambar statis. Kita dapat memperbaikinya dengan menambahkan komponen orbitControls ke kanvas:

export default function App() {
      return (
<Canvas style={{ background: "#171717" }}>
 <spotLight intensity={0.5} angle={0.1} penumbra={1} position={[10, 15, 10]} castShadow />
 &lt;ambientLight intensity={1} />
 <Suspense fallback={null}>
          <Shoe />
 </Suspense>
       <orbitControls />
</Canvas>;
)}

Dalam react-three-fiber, model dianimasikan dengan useFrame Hook, yang mirip dengan metode JavaScript requestAnimationFrame(). Metode ini mengembalikan callback 60 kali atau lebih per detik, tergantung pada kecepatan refresh tampilan.

Jika kita menetapkan nilai rotasi model kita pada sumbu y ke “5.09” di dalam callback useFrame, model akan menerjemahkan ke atas dan ke bawah di sepanjang sumbu y sebanyak 60 kali setiap detiknya, menciptakan ilusi objek yang mengambang.

Untuk animasi yang lebih realistis, Anda dapat mengubah nilai rotasi sumbu z dan sumbu x di useFrame Hook. Untuk menghemat waktu, kita akan menggunakan kode di bawah ini:

useFrame( (state) => {
 const t = state.clock.getElapsedTime()
 ref.current.rotation.z = -0.2 - (1 + Math.sin(t / 1.5)) / 20
 ref.current.rotation.x = Math.cos(t / 4) / 8
 ref.current.rotation.y = Math.sin(t / 4) / 8
 ref.current.position.y = (1 + Math.sin(t / 1.5)) / 10
})

Ingatlah untuk mengimpor useFrame dari react-three-fiber. Kode lengkap untuk proyek kita adalah sebagai berikut:

import {HexColorPicker} from 'react-colorful'
import React, { useRef, Suspense} from 'react'
import { Canvas, useFrame } from "react-three-fiber";
import "./styles.css";
import { useGLTF } from '@react-three/drei/useGLTF'
import {proxy, useSnapshot} from 'valtio';

const state = proxy({
  current: null,
  items: {
    laces: "#ff3",
    mesh: "#3f3",
    caps: "#3f3",
    inner: "#3f3",
    sole: "#3f3",
    stripes: "#3f3",
    band: "#3f3",
    patch: "#3f3",
  },
})

function Shoe({ ...props }) {
 const group = useRef()

useFrame( (state) => {
 const t = state.clock.getElapsedTime()
 ref.current.rotation.z = -0.2 - (1 + Math.sin(t / 1.5)) / 20
 ref.current.rotation.x = Math.cos(t / 4) / 8
 ref.current.rotation.y = Math.sin(t / 4) / 8
 ref.current.position.y = (1 + Math.sin(t / 1.5)) / 10
  })

 const { nodes, materials } = useGLTF('/shoe-draco.glb')
 const snap = useSnapshot(state);
 return (
<group 
ref={group} 
{...props} 
dispose={null}
onPointerDown={(e) => {e.stopPropagation(); state.current = e.object.material.name }}
onPointerMissed={(e) =>{state.current = null} }
>
  <group ref={group} {...props} dispose={null}>
    <mesh geometry={nodes.shoe.geometry} material={materials.laces}/>
    <mesh geometry={nodes.shoe_1.geometry} material={materials.mesh}/>
    <mesh geometry={nodes.shoe_2.geometry} material={materials.caps} />
    <mesh geometry={nodes.shoe_3.geometry} material={materials.inner} />
    <mesh geometry={nodes.shoe_4.geometry} material={materials.sole}/>
    <mesh geometry={nodes.shoe_5.geometry} material={materials.stripes}/>
    <mesh geometry={nodes.shoe_6.geometry} material={materials.band}/>
    <mesh geometry={nodes.shoe_7.geometry} material={materials.patch} />
   </group>
 </group>
)}

function ColorPicker(){
 const snap = useSnapshot(state);
  return(
   <div>
     <HexColorPicker color={snap.items[snap.current]} onChange={(color)=>(state.items[state.current] = color)}/>
     <h1>{snap.current}</h1>
   </div>
    )
  }

export default function App() {
  return (
  <>
<Canvas style={{ background: "#171717" }}>
<ambientLight intensity={1} />
<spotLight intensity={0.5} angle={0.1} penumbra={1} position={[10, 15, 10]} castShadow />
  <Suspense fallback={null}>
      <Shoe />
  </Suspense>
</Canvas>;
<ColorPicker />
</>
)}

Selamat, kita telah berhasi melakukan konfigurasi 3D model dengan react-three-fiber. Sekarang kita bisa melihat 3D model kita di dalam browser. Anda dapat menerapkan langkah diatas dengan 3D model yang lainnya.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top