What happened?
I tried to display my own model in Three.js, and the model just wouldn't show up, which had me stumped.
The fix turned out to be putting the object files under public.
The result
What I actually did
Directory structure
public
|- object
| |- Monkey.mtl
| |_ Monkey.obj
|_ etc...
src
package.json
The code
Here's the code for object3d.tsx.
import React, { useRef, useEffect } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';
const Object3D = () => {
const mount = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!mount.current) return;
const width = mount.current.clientWidth;
const height = mount.current.clientHeight;
// scene, camera, and renderer initialization
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
// controls for mouse rotation
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// camera position
camera.position.z = 2;
// renderer settings
const light = new THREE.PointLight(0xffffff, 1, 1000);
light.position.set(0, 0, 10); // ライトの位置を設定します(x, y, z)
// ライトをシーンに追加
scene.add(light);
// mount the renderer to the DOM
mount.current.appendChild(renderer.domElement);
// MTL and OBJ loader
const mtlLoader = new MTLLoader();
const objLoader = new OBJLoader();
const MonkeyMtl = '/Objects/Monkey.mtl';
const MonkeyObj = '/Objects/Monkey.obj';
mtlLoader.load(
MonkeyMtl,
(materials) => {
materials.preload();
objLoader.setMaterials(materials);
objLoader.load(
MonkeyObj,
(object) => {
object.position.set(0, 0, 0); // set position to center
object.scale.set(0.5, 0.5, 0.5); // scale down
scene.add(object);
console.log('Added object to scene');
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
(error) => {
console.log('An error happened', error);
}
);
},
(xhr) => {
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
(error) => {
console.log('An error happened', error);
}
);
// animation
const animate = () => {
requestAnimationFrame(animate);
// controls update
controls.update();
// rendering
renderer.render(scene, camera);
};
// start animation
animate();
// handle resize
const handleResize = () => {
if (!mount.current) return;
const width = mount.current.clientWidth;
const height = mount.current.clientHeight;
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return (
<div>
<h2>モデルテスト</h2>
<div
ref={mount}
style={{ width: '100%', height: '100vh' }}
/>
</div>
);
};
export default Object3D;