Hiển thị một file .jbx (modal 3d) sử dụng thư viện Three.js trong ReactJS
Để hiển thị một file .jbx (modal 3d) sử dụng thư viện Three.js trong ReactJS, chúng ta có thể tạo một React component và sử dụng thư viện three.js để tạo ra một scene 3D để hiển thị modal.
Đầu tiên, cài đặt thư viện three.js và thư viện react-three-fiber bằng cách chạy lệnh sau trong terminal:
1 2 | npm install three react-three-fiber |
Sau đó, tạo một component React với tên là “ThreeJSModal” như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useRef<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-three-fiber"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> GLTFLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"three/examples/jsm/loaders/GLTFLoader"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> OrbitControls <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"three/examples/jsm/controls/OrbitControls"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">ThreeJSModal</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>modalLoaded<span class="token punctuation">,</span> setModalLoaded<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> modalRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Sử dụng useLoader để load file .jbx</span> <span class="token keyword">const</span> gltf <span class="token operator">=</span> <span class="token function">useLoader</span><span class="token punctuation">(</span>GLTFLoader<span class="token punctuation">,</span> <span class="token string">"/path/to/your/modal.jbx"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Callback khi file đã được load</span> <span class="token keyword">const</span> <span class="token function-variable function">onModalLoaded</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setModalLoaded</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span>modalLoaded <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token comment">/* Sử dụng OrbitControls để có thể quay vật thể */</span><span class="token punctuation">}</span> <span class="token operator"><</span>OrbitControls enableDamping dampingFactor<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">0.5</span><span class="token punctuation">}</span> enableZoom<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">false</span><span class="token punctuation">}</span> ref<span class="token operator">=</span><span class="token punctuation">{</span>modalRef<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token comment">/* Hiển thị vật thể */</span><span class="token punctuation">}</span> <span class="token operator"><</span>primitive object<span class="token operator">=</span><span class="token punctuation">{</span>gltf<span class="token punctuation">.</span>scene<span class="token punctuation">}</span> onReady<span class="token operator">=</span><span class="token punctuation">{</span>onModalLoaded<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> ThreeJSModal<span class="token punctuation">;</span> |
Trong đoạn code trên, chúng ta sử dụng useLoader
để load file .jbx bằng GLTFLoader và useRef
để lưu tham chiếu đến OrbitControls. OrbitControls
cho phép người dùng xoay vật thể để xem nó từ nhiều góc độ khác nhau. Chúng ta sử dụng useState
để theo dõi khi file đã được load và chỉ hiển thị vật thể khi file đã được load hoàn tất. Cuối cùng, chúng ta sử dụng primitive
để hiển thị vật thể và onReady
để đánh dấu khi file đã được load.
Sau khi đã tạo xong component, bạn có thể sử dụng nó trong ứng dụng React của mình bằng cách import và đưa nó vào trong DOM.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">import</span> ThreeJSModal <span class="token keyword">from</span> <span class="token string">"./ThreeJSModal"</span><span class="token punctuation">;</span> <span class="token keyword">function</span> <span class="token function">App</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>ThreeJSModal <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">default</span> App<span class="token punctuation">;</span> |
Chú ý rằng bạn cần phải thay đổi đường dẫn “/path/to/your/modal.jbx” để trỏ đúng đến file .jbx của bạn.
Kết hợp với texture riêng
Để kết hợp với texture riêng dạng png, bạn có thể sử dụng TextureLoader
để load texture và gán nó vào vật thể sử dụng map
trong Three.js.
Ví dụ, giả sử bạn có một texture là file “texture.png” trong thư mục public của ứng dụng của bạn. Bạn có thể sử dụng nó như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useRef<span class="token punctuation">,</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-three-fiber"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> GLTFLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"three/examples/jsm/loaders/GLTFLoader"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> OrbitControls <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"three/examples/jsm/controls/OrbitControls"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> TextureLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"three/src/loaders/TextureLoader"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">ThreeJSModal</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>modalLoaded<span class="token punctuation">,</span> setModalLoaded<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> modalRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Sử dụng useLoader để load file .jbx</span> <span class="token keyword">const</span> gltf <span class="token operator">=</span> <span class="token function">useLoader</span><span class="token punctuation">(</span>GLTFLoader<span class="token punctuation">,</span> <span class="token string">"/path/to/your/modal.jbx"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Sử dụng TextureLoader để load texture</span> <span class="token keyword">const</span> texture <span class="token operator">=</span> <span class="token function">useLoader</span><span class="token punctuation">(</span>TextureLoader<span class="token punctuation">,</span> <span class="token string">"/texture.png"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Callback khi file đã được load</span> <span class="token keyword">const</span> <span class="token function-variable function">onModalLoaded</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setModalLoaded</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span>modalLoaded <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token comment">/* Sử dụng OrbitControls để có thể quay vật thể */</span><span class="token punctuation">}</span> <span class="token operator"><</span>OrbitControls enableDamping dampingFactor<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">0.5</span><span class="token punctuation">}</span> enableZoom<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">false</span><span class="token punctuation">}</span> ref<span class="token operator">=</span><span class="token punctuation">{</span>modalRef<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token comment">/* Hiển thị vật thể và texture */</span><span class="token punctuation">}</span> <span class="token operator"><</span>primitive object<span class="token operator">=</span><span class="token punctuation">{</span>gltf<span class="token punctuation">.</span>scene<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>meshStandardMaterial map<span class="token operator">=</span><span class="token punctuation">{</span>texture<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>primitive<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> ThreeJSModal<span class="token punctuation">;</span> |
Trong ví dụ trên, chúng ta sử dụng TextureLoader
để load file “texture.png”. Sau đó, chúng ta gán texture này vào vật thể sử dụng map
trong meshStandardMaterial
. Bằng cách này, vật thể sẽ có texture “texture.png” kết hợp với file .jbx đã load.
Run animation của modal
Để chạy animation đầu tiên trong mảng animation của file .jbx, bạn có thể sử dụng useRef
để tham chiếu đến vật thể của modal sau đó sử dụng phương thức mixer.clipAction()
của AnimationMixer
trong Three.js để chọn và chạy animation đầu tiên trong mảng animation.
Ví dụ, giả sử bạn có một file “modal.jbx” chứa một mảng các animation, và bạn muốn chạy animation đầu tiên trong mảng đó khi modal được tải lên, bạn có thể sử dụng mã sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useRef<span class="token punctuation">,</span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-three-fiber"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> GLTFLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"three/examples/jsm/loaders/GLTFLoader"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> OrbitControls <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"three/examples/jsm/controls/OrbitControls"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">ThreeJSModal</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>modalLoaded<span class="token punctuation">,</span> setModalLoaded<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> modalRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> mixerRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Sử dụng useLoader để load file .jbx</span> <span class="token keyword">const</span> gltf <span class="token operator">=</span> <span class="token function">useLoader</span><span class="token punctuation">(</span>GLTFLoader<span class="token punctuation">,</span> <span class="token string">"/path/to/your/modal.jbx"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Callback khi file đã được load</span> <span class="token keyword">const</span> <span class="token function-variable function">onModalLoaded</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setModalLoaded</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Chạy animation đầu tiên khi modal được tải lên</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>modalLoaded<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Tìm animation đầu tiên trong mảng animation</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>firstAnimation<span class="token punctuation">]</span> <span class="token operator">=</span> gltf<span class="token punctuation">.</span>animations<span class="token punctuation">;</span> <span class="token comment">// Khởi tạo mixer để chạy animation</span> mixerRef<span class="token punctuation">.</span>current <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">THREE<span class="token punctuation">.</span>AnimationMixer</span><span class="token punctuation">(</span>modalRef<span class="token punctuation">.</span>current<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Chọn animation đầu tiên và chạy nó</span> <span class="token keyword">const</span> action <span class="token operator">=</span> mixerRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">clipAction</span><span class="token punctuation">(</span>firstAnimation<span class="token punctuation">)</span><span class="token punctuation">;</span> action<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>modalLoaded<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span>modalLoaded <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token comment">/* Sử dụng OrbitControls để có thể quay vật thể */</span><span class="token punctuation">}</span> <span class="token operator"><</span>OrbitControls enableDamping dampingFactor<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">0.5</span><span class="token punctuation">}</span> enableZoom<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">false</span><span class="token punctuation">}</span> ref<span class="token operator">=</span><span class="token punctuation">{</span>modalRef<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token comment">/* Hiển thị vật thể */</span><span class="token punctuation">}</span> <span class="token operator"><</span>primitive object<span class="token operator">=</span><span class="token punctuation">{</span>gltf<span class="token punctuation">.</span>scene<span class="token punctuation">}</span> ref<span class="token operator">=</span><span class="token punctuation">{</span>modalRef<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> ThreeJSModal<span class="token punctuation">;</span> |
Trong ví dụ trên, chúng ta sử dụng useEffect
để chạy animation đầu tiên trong mảng animation khi modal được tải lên. Đầu tiên, chúng ta tìm animation đầu tiên trong mảng animation bằng cách lấy phần tử đầu tiên trong mảng gltf.animations
. Sau đó, chúng ta khởi tạo một AnimationMixer
và sử dụng mixer.clipAction()
để chọn và chạy animation đầu tiên.
Chúng ta cũng sử dụng useRef
để tham chiếu đến vật thể của modal thông qua modalRef
và tham chiếu đến AnimationMixer
thông qua mixerRef
.
Chạm để thay đổi animation
Để thay đổi animation khi người dùng nhấp vào modal 3D, bạn có thể sử dụng sự kiện onClick
của mesh
trong Three.js để chuyển đổi giữa các animation trong mảng gltf.animations
của file .jbx.
Ví dụ, giả sử bạn có một file “modal.jbx” chứa một mảng các animation, và bạn muốn chuyển đổi giữa các animation khi người dùng nhấp vào modal, bạn có thể sử dụng mã sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <span class="token keyword">import</span> React<span class="token punctuation">,</span> <span class="token punctuation">{</span> useRef<span class="token punctuation">,</span> useState<span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> useLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react-three-fiber"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> GLTFLoader <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"three/examples/jsm/loaders/GLTFLoader"</span><span class="token punctuation">;</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> OrbitControls <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"three/examples/jsm/controls/OrbitControls"</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">ThreeJSModal</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>modalLoaded<span class="token punctuation">,</span> setModalLoaded<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> modalRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> mixerRef <span class="token operator">=</span> <span class="token function">useRef</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>animationIndex<span class="token punctuation">,</span> setAnimationIndex<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Sử dụng useLoader để load file .jbx</span> <span class="token keyword">const</span> gltf <span class="token operator">=</span> <span class="token function">useLoader</span><span class="token punctuation">(</span>GLTFLoader<span class="token punctuation">,</span> <span class="token string">"/path/to/your/modal.jbx"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Callback khi file đã được load</span> <span class="token keyword">const</span> <span class="token function-variable function">onModalLoaded</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setModalLoaded</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token comment">// Chạy animation khi animationIndex thay đổi</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>modalLoaded<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Tìm animation tương ứng với animationIndex trong mảng animation</span> <span class="token keyword">const</span> animation <span class="token operator">=</span> gltf<span class="token punctuation">.</span>animations<span class="token punctuation">[</span>animationIndex<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">// Chọn animation và chạy nó</span> <span class="token keyword">const</span> action <span class="token operator">=</span> mixerRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">clipAction</span><span class="token punctuation">(</span>animation<span class="token punctuation">)</span><span class="token punctuation">;</span> action<span class="token punctuation">.</span><span class="token function">play</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>animationIndex<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Sự kiện onClick để chuyển đổi giữa các animation</span> <span class="token keyword">const</span> <span class="token function-variable function">onClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setAnimationIndex</span><span class="token punctuation">(</span><span class="token punctuation">(</span>animationIndex <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">%</span> gltf<span class="token punctuation">.</span>animations<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span>modalLoaded <span class="token operator">&&</span> <span class="token punctuation">(</span> <span class="token operator"><</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token comment">/* Sử dụng OrbitControls để có thể quay vật thể */</span><span class="token punctuation">}</span> <span class="token operator"><</span>OrbitControls enableDamping dampingFactor<span class="token operator">=</span><span class="token punctuation">{</span><span class="token number">0.5</span><span class="token punctuation">}</span> enableZoom<span class="token operator">=</span><span class="token punctuation">{</span><span class="token boolean">false</span><span class="token punctuation">}</span> ref<span class="token operator">=</span><span class="token punctuation">{</span>modalRef<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token comment">/* Sử dụng sự kiện onClick để chuyển đổi giữa các animation */</span><span class="token punctuation">}</span> <span class="token operator"><</span>mesh onClick<span class="token operator">=</span><span class="token punctuation">{</span>onClick<span class="token punctuation">}</span> ref<span class="token operator">=</span><span class="token punctuation">{</span>modalRef<span class="token punctuation">}</span><span class="token operator">></span> <span class="token operator"><</span>primitive object<span class="token operator">=</span><span class="token punctuation">{</span>gltf<span class="token punctuation">.</span>scene<span class="token punctuation">}</span> <span class="token operator">/</span><span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>mesh<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">}</span> <span class="token operator"><</span><span class="token operator">/</span><span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">default</span> ThreeJSModal<span class="token punctuation">;</span> |
Trong ví dụ trên, chúng ta sử dụng useState
để lưu trữ chỉ số của animation đang được chạy. Mỗi lần người dùng nhấp vào modal, chúng ta sẽ tăng chỉ số này lên một đơn vị và lấy phần dư với độ dài của mảng animation để chuyển đổi giữa các animation. Khi chỉ số animationIndex thay đổi, chúng ta sử dụng useEffect
để chọn animation tương ứng từ mảng animation và chạy nó bằng mixer.clipAction()
.