jackmiwamiwa devblog

フロントエンドをメインに行ったことをまとめていくサイトになります。

オリジナルのglTFファイルをthree.jsを使用してweb上に表示する

オリジナルの3Dオブジェクトファイルをwebに表示を行ったため、そのときのメモ。

表示するオブジェクトの用意

オリジナルで用意を行う場合、blenderのソフトから作成を行うことができますが、turbosquidのサイトからFreeで3Dオブジェクトを使用することもできるため、今回はturbosquidを使用します。

blender.jp

www.turbosquid.com

今回・使用するオブジェクトについては、以下になります。

f:id:jackswim3411:20210209232245p:plain

www.turbosquid.com

必要なパッケージ

www.npmjs.com

version: ^0.124.0

実装手順

1. レンダラー・シーンの追加

html, レンダラーの追加を初めに行います。

<canvas class="js-three"></canvas>
import * as THREE from "three"

// 画面幅の取得
const width = window.innerWidth
const height = window.innerHeight

// htmlからcanvasのclass名の取得
const canvas = document.querySelector('.js-three')

// レンダラーを作成
const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
  alpha: true
})
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(width, height)

// シーンを作成
const scene = new THREE.Scene()

// カメラを作成
const camera = new THREE.PerspectiveCamera(50, width / height, 0.1, 10000);
camera.position.set(3, 1, 1)
const controls = new OrbitControls(camera, renderer.domElement)

// ライトの作成
const light = new THREE.DirectionalLight(0xefefef, 2)
light.position.set(1, 5, 5).normalize()
scene.add(light)

// ここから下に続きます。

2. glTFのオブジェクトの読み込み

モジュールの読み込み

glTFの読み込むためには、別途モジュールが必要なため、モジュールの読み込みを行います。

// モジュールの読み込み
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"

2021.02時点では非推奨になっていますが、 three-orbitcontrols のパッケージを使う方法もあります。

www.npmjs.com

上記のパッケージにも記載してありますが、2021.02時点では threeのパッケージのみで使用することができます。

f:id:jackswim3411:20210210010926p:plain

コードの内容

// GLTFLoaderの読み込み
const loader = new GLTFLoader()
// 使用するオブジェクトのパス
const url = '/assets/img/stone.gltf'

loader.load(
 url,
 (gltf) => {
    // オブジェクトの読み込みが完了したタイミングで実行
    scene.add(gltf.scene)
  },
  (xhr) => {
    // オブジェクトを読み込んでいるタイミングで実行
    console.log( `${( xhr.loaded / xhr.total * 100 )}% loaded` );
  },
  (error) => {
    // オブジェクトの読み込みが失敗したタイミングで実行
    console.log(error)
  }
)

3. OrbitControlsを使用して、回転・拡大,縮小を行う

モジュールの読み込み

OrbitControlsについても、先ほどと同様に別途モジュールが必要なため、モジュールの読み込みを行います。

// モジュールの読み込み
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"

2021.02時点では非推奨になっていますが、 three-orbitcontrols のパッケージを使う方法もあります。

www.npmjs.com

こちらも先ほどと同様に上記のパッケージにも記載してありますが、2021.02時点では threeのパッケージのみで使用することができます。

f:id:jackswim3411:20210210010754p:plain

コードの内容

// OrbitControlsの読み込み
const controls = new OrbitControls(camera, renderer.domElement)

const tick = () => {
  controls.update()
  renderer.render(scene, camera)
  requestAnimationFrame(tick)
}
tick()

全体のコード

<canvas class="js-three"></canvas>
import * as THREE from "three"
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"

// 画面幅の取得
const width = window.innerWidth
const height = window.innerHeight

// htmlからcanvasのclass名の取得
const canvas = document.querySelector('.js-three')

// レンダラーを作成
const renderer = new THREE.WebGLRenderer({
  canvas: canvas,
  alpha: true
})
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setSize(width, height)

// シーンを作成
const scene = new THREE.Scene()

// カメラを作成
const camera = new THREE.PerspectiveCamera(50, width / height, 0.1, 10000);
camera.position.set(3, 1, 1)
const controls = new OrbitControls(camera, renderer.domElement)

// OrbitControlsの読み込み
const controls = new OrbitControls(camera, renderer.domElement)

// ライトの作成
const light = new THREE.DirectionalLight(0xefefef, 2)
light.position.set(1, 5, 5).normalize()
scene.add(light)

// GLTFLoaderの読み込み
const loader = new GLTFLoader()
// 使用するオブジェクトのパス
const url = '/assets/img/stone.gltf'

loader.load(
 url,
 (gltf) => {
    // オブジェクトの読み込みが完了したタイミングで実行
    scene.add(gltf.scene)
  },
  (xhr) => {
    // オブジェクトを読み込んでいるタイミングで実行
    console.log( `${( xhr.loaded / xhr.total * 100 )}% loaded` );
  },
  (error) => {
    // オブジェクトの読み込みが失敗したタイミングで実行
    console.log(error)
  }
)

const tick = () => {
  controls.update()
  renderer.render(scene, camera)
  requestAnimationFrame(tick)
}
tick()

詰まったところ

オブジェクトが表示されない

自分が詰まった原因として、

// カメラ
const camera = new THREE.PerspectiveCamera(50, width / height, 0.1, 10000);
camera.position.set(3, 1, 1)

// GLTFLoaderの読み込み
const loader = new GLTFLoader()
// 使用するオブジェクトのパス
const url = '/assets/img/stone.gltf'

loader.load(
 url,
 (gltf) => {
    // オブジェクトの読み込みが完了したタイミングで実行
    scene.add(gltf.scene)
  },
  (xhr) => {
    // オブジェクトを読み込んでいるタイミングで実行
    console.log( `${( xhr.loaded / xhr.total * 100 )}% loaded` );
  },
  (error) => {
    // オブジェクトの読み込みが失敗したタイミングで実行
    console.log(error)
  }
)

// ライト
const light = new THREE.DirectionalLight(0xefefef, 2)
light.position.set(1, 5, 5).normalize()
scene.add(light)

のような感じで、 「カメラ → オブジェクト → ライト」 の順番で書き込みを行っていたのが原因で表示されない場合があったため、表示されなかった場合は順番を 「カメラ →ライト →オブジェクト」 にしたら解決しました。

参考にしたサイト

codelabo.com

qiita.com