Three.jsを使って3DモデルをWebサイトに描写する方法

 

はじめに

Three.jsのコードだけでもWebサイト上で多様な3D表現をすることが可能ですが、より複雑な3DモデルをWebサイトで表現したい時は、3DCG制作ツールを使用するほうがいいです。


また3DモデルとThree.jsを組み合わせることで面白いものがつくれます。
今回は流行りのBlenderでモデリングしたものをWebで表現する方法を書いてみます。


完成図はこちら↓

Blenderについて

Blenderは、無料でダウンロードすることができる3D制作ツールで、モデリング、ライティング、レンダリングなど、ツール一本で3DCG制作に必要なものをすべて兼ね備えている統合版ソフトです。

個人的にレンダリング技術が素晴らしいと思っており、適当にモデリングして簡単にライトとカメラを設定してレンダリングしてみると想像以上にイイ感じにしてくれます。

Three.jsについて

Three.jsは、Web上で3Dコンテンツを表現することができるJSのライブラリです。
ライブラリを導入することで手軽に3Dコンテンツを扱うことができます。
パーティクル描写など抽象的な3Dアニメーションを表現するならThree.jsのコードだけで十分だったりしますね。

2通りの方法

3DモデルをThree.jsで扱う上で下記の二通りの方法があります。

  1. 3Dファイルをそのまま読み込む

  2. ベイクした展開図をテクスチャとして扱う


前者の3Dファイルをそのまま読み込む方法はかなり楽ですが、
大抵の場合、Blenderのレンダリング結果と比べて、
Web上で描写したモデルの見た目は劣化して見えてしまいます。

これはBlenderとThree.jsのレンダリング技術の違いなどによって起こるものです。
Three.jsで調整することで、モデルの見た目をBlenderのレンダリング結果と近づけることはできますが、
そっくりそのまま反映するのは難しいでしょう。

後者のBlenderで作成したモデルの展開図を、Three.jsで貼り付ける方法だと、ライトを使わずにライトやマテリアルの質感を表現することができるため、見た目をBlenderのレンダリング結果と近づけることが可能です。

メリットは、見栄えが良い他に、Three.jsのライトを使わなくて済むのでパフォーマンスが向上します。
デメリットは、Blender側の作業が大変になります。
UV展開やベイクをしたり、見えない面を全て削除する必要があるため)


今回は楽だけどモデルのクオリティは低くなる3DファイルをそのままThree.jsで読み込む手順を紹介します。

ベイクを用いる方法についてはこちら

3Dモデルを作成(Blender)

Blenderでモデリングしたものが上記になります。

Blender上でポータル部分の白く光ってるオブジェクト名を「portal」と命名します。

(このオブジェクトだけThree.jsでひと手間加えたいので)

トップバーの「ファイル > エクスポート > glTF2.0(.glb/.gltf)」をクリックしてGLTF形式のファイルを出力します。

これでBlenderの作業は終わりです。

※Punctualライトという項目にチェックをいれることでBlenderのライトを含めることができますが、Three.jsで読み込むと明るすぎたりBlenderとライトが大きく異なるのでチェックを外します。

モデルの読み込み(Three.js)

モデルが完成したので、さっそくThree.jsで読み込んでみましょう。

Three.jsのインストール方法についてはこちら(公式)になります。

まずはHTML。<canvas>タグの領域でThree.jsの描写をします。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Test</title>
</head>
<body>
    <canvas class="project"></canvas>
</body>
</html>

次にCSS、なくても大丈夫です。

*
{
margin: 0;
padding: 0;
}


html,
body
{
overflow: hidden;
}


.project
{
position: fixed;
top: 0;
left: 0;
}
次にJSファイルです。
import './style.css'
import * as THREE from 'three'
// スクロールやドラッグで視点を操作できるように
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
// 3dファイルを読み込めるように
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import portalVertexShader from './shaders/portal/vertex.glsl'
import portalFragmentShader from './shaders/portal/fragment.glsl'



// canvas読み込み
const canvas = document.querySelector('canvas.project')


// シーンを定義
const scene = new THREE.Scene()


// 3dオブジェクトファイルを読み込むローダーを定義
const gltfLoader = new GLTFLoader()



// 3dファイルから3dオブジェクトを読み込む
gltfLoader.load(
    'portal.glb',
    (gltf) => {
        scene.add(gltf.scene)
        const portal = gltf.scene.children.find((child) => child.name === 'portal')
        portal.material = portalShader

    }
)


// シェーダーの設定
const portalShader = new THREE.ShaderMaterial({
    uniforms:
    {
        uTime: { value: 0 },
        uColorStart: { value: new THREE.Color('#34d8eb') },
        uColorEnd: { value: new THREE.Color('#3489eb') }
    },
    vertexShader: portalVertexShader,
    fragmentShader: portalFragmentShader
})



//ライトの設定
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
directionalLight.position.set(-5, 5, 3)
scene.add(directionalLight)



// ウィンドウサイズに応じて可変するように設定
const sizes = {
    width: window.innerWidth,
    height: window.innerHeight
}
window.addEventListener('resize', () => {
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight
    camera.aspect = sizes.width / sizes.height
    camera.updateProjectionMatrix()
    renderer.setSize(sizes.width, sizes.height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})


// PerspectiveCamera ⇒ 透視投影を使用するカメラ(垂直視野、アスペクト比、近景、遠景)
const camera = new THREE.PerspectiveCamera(45, sizes.width / sizes.height, 0.1, 100)
// カメラの位置を調整
camera.position.x = 4
camera.position.y = 6
camera.position.z = 6
scene.add(camera)


// ユーザー側でドラッグ等でカメラを動かせるようにする
const controls = new OrbitControls(camera, canvas)
controls.enableDamping = true


// レンダリング
const renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    // 物体の輪郭がガクガクするのを抑える
    antialias: true
})
// レンダラーの出力をsRGBに設定、これをしないと意図してない色になったりする。
renderer.outputEncoding = THREE.sRGBEncoding
renderer.setSize(sizes.width, sizes.height)
// 解像度を調整、Retinaにも対応
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))



// loopという関数を各フレームで実行する無限ループ。
// モニターのフレームレートに関与せず、1フレームごとにレンダリングを行う関数を実行する。
const clock = new THREE.Clock()
const loop = () => {
    // シェーダーを動かす
    const elapsedTime = clock.getElapsedTime()
    portalShader.uniforms.uTime.value = elapsedTime
    controls.update()
    renderer.render(scene, camera)
    window.requestAnimationFrame(loop)
}


loop()

OrbitControlsとGLTFLoaderについてですが、npmでインストールするとThree.jsライブラリの本体に含まれてるはずなので、これらを読み込みます。

・OrbitControlsを導入することでユーザーの操作によってカメラを動かすことが可能になります。(視点の回転やズームやカメラの移動など)

・GLTFLoaderはgltfファイルを読み込むために必要です。

他にportalVertexShaderportalFragmentShaderというファイルを読み込んでいますが、ポータル部分の描写を制御しています。先ほどBlenderでレンダリングした白く光ってる部分をシェーダー化しています。

難解なので今回は詳細について省略します。

最終的にWebで読み込んだものがこちら

OrbitControlsによってWebサイト上でユーザーがカメラを動かせるようになり、インタラクティブに3dモデルを体感してもらうことが可能になります。

質感やライティングなどはBlenderでレンダリングしたものより劣ってしまうので、より完成度を高めたい場合はベイクを用いる手段のほうがいいかもしれませんね。

次の機会にご紹介できればと思います。

ベイクを用いる方法についてはこちら

WEBサイト制作のお問い合わせ、お見積り依頼、ご質問は
こちらのお問い合わせフォームよりお願いいたします

メールお問い合わせはこちら

フライング・ハイ・ワークスの紹介

フライング・ハイ・ワークスは、東京都渋谷区にある2000年3月創業のシステム開発にも対応できるデザインも強いWeb制作・ホームページ制作会社です。東京都及びその近郊(首都圏)を中心として、SEO対策を意識したPC及びスマホのサイトをワンソース(レスポンシブ対応)で制作します。

実績

デザイナーチームは、グラフィックデザインやイラストの制作も得意としており、著作権を意識しない素材の提供が可能です。システム・コーディングチームでは、Laravelなどを使用したスクラッチからのオリジナルシステムの構築を始め、WordPressのカスタマイズを得意としております。

また、SEOやランディングページ(LP)、広告向けバナーなどを他社様でやっていた作業の引継ぎでも問題ありません。制作実績は多数ございますので、お客様に合わせたご提案が可能です。

500点以上のフライング・ハイ・ワークスの制作実績ページをご覧ください!

採用

FHWでWebディレクター、Webデザイナー、Webプログラマーやシステム開発者として働いてみたいと思っていただける方は、下記にて定期的に募集をしておりますので、ぜひ、ご応募ください。

WEBサイト制作のお問い合わせ、お見積り依頼、ご質問は
こちらのお問い合わせフォームよりお願いいたします

メールお問い合わせはこちら