React Three.js で Obj や gltf の表示で詰まったこと

どうしたの?

自作のモデルをThree.jsで表示させようとした際に、モデルが表示されず困ってしまいました。

対処法としてはオブジェクトを public の下に配置することで解決しました。

完成したもの

実際の作業

ディレクトリ構成

public
  |- object
  |  |- Monkey.mtl
  |  |_ Monkey.obj
  |_ etc...
src
package.json

コード

以下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;

コイアイちゃん Avatar

この記事を書いたのは


Comments

Leave a Reply

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

CAPTCHA