WEB

【超簡単!】three.jsではじめる3Dコンテンツ ~glTFのインポート~

こんにちは!
WebデザイナーのNK細胞です!
今日はThree.jsを使って、簡単な3DモデルをWebページに表示する方法について解説します。デモサイトはこちら

NK細胞
NK細胞
今回はglTF(.glb)というファイル形式を使います!glTFの書き出しについては、下記の記事で詳しく書いてます~
【超簡単!】three.jsではじめる3Dコンテンツ ~glTFの書き出し編~こんにちは! WebデザイナーのNK細胞です! と思うことはありませんか? ということでthree.jsを使ってW...

Three.jsとは

Three.jsとは、WebGLを簡単に扱うためにJavascriptのライブラリで、3Dコンテンツを手軽に実装できます。下記が、Three.jsの公式ドキュメントになります。

解説

1. htmlの基本構造

まず、HTMLファイルを作成し、基本的な構造を設定します。この段階で、Three.jsを含むいくつかのスクリプトを読み込む必要があります。今回はCDNから以下3つのscriptを読み込みます。

Three.min.js Three.jsの主要なライブラリ。3Dシーンの作成、カメラの設定、ライトの追加、モデルのレンダリングなどが可能。
OrbitControls.js Three.jsの追加モジュールで、ユーザーがマウス操作でシーンを回転、ズーム、パンできるようになる。インタラクティブなカメラコントロールが可能。
GTLFLoader.js Three.jsの追加モジュールで、GLTF/GLBフォーマットの3Dモデルをロードを可能とする。
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>タイトルを入力</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        #myCanvas {
            display: block;
        }
    </style>
</head>

<body>
    <canvas id="myCanvas"></canvas>

    <!-- Three.jsと必要なライブラリをCDNから読み込みます -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.js"></script>
    <script>
        // JavaScriptのコードはここに記述します
    </script>
</body>

</html>

2. Three.js基本設定

Three.jsの基本設定を行います。シーン、カメラ、レンダラーを設定し、レンダリングを行う準備をします。

シーンの作成

Three.jsでは、まずシーン(THREE.Scene)を作成します。シーンは、すべての3Dオブジェクトやライトが配置されるコンテナです。

    // シーンの作成
    const scene = new THREE.Scene();
    //シーンの背景色を指定
    scene.background = new THREE.Color(0x000000);

カメラの作成

カメラ(THREE.Camera)は、シーン内のオブジェクトをどのように見るかを決定します。一般的に、パースペクティブカメラ(THREE.PerspectiveCamera)を使用します。

    // カメラの作成
    const camera = new THREE.PerspectiveCamera(30, width / height, 1, 500);
    camera.position.set(60, 15, 30);

レンダラーの作成

レンダラー(THREE.WebGLRenderer)は、シーンとカメラをもとに描画を行います。

    // レンダラーの設定
    const canvasElement = document.querySelector('#myCanvas');
    const renderer = new THREE.WebGLRenderer({
        antialias: true,
        canvas: canvasElement,
    });

    //レンダラーのピクセル比
    renderer.setPixelRatio(window.devicePixelRatio);
    //サイズ
    renderer.setSize(width, height);
    //影の投影
    renderer.shadowMap.enabled = true;
    //物理的なライティング
    renderer.physicallyCorrectLights = true;
    //sRGBエンコーディング(色の調整)
    renderer.outputEncoding = THREE.sRGBEncoding;
    //トーンマッピング(色の調整)
    renderer.toneMapping = THREE.ACESFilmicToneMapping;

カメラコントローラーの設定

カメラの操作を簡単にするために、OrbitControlsを設定します。

    // カメラコントローラーの作成
    const controls = new THREE.OrbitControls(camera, canvasElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.2;

3. ライトの作成

シーンに光源を追加して、モデルを見やすくします。今回は、主光源はモデルから読み込むため、環境光源(ambientLight)のみ追加します。

    // 環境光源の作成
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    scene.add(ambientLight);

4. ウインドウのリサイズ対応

ウィンドウサイズが変更されたときに、レンダラーとカメラのアスペクト比を更新します。

    // ウィンドウサイズ変更時の対応
    window.addEventListener('resize', () => {
        const width = window.innerWidth;
        const height = window.innerHeight;
        renderer.setSize(width, height);
        camera.aspect = width / height;
        camera.updateProjectionMatrix();
    });

5. 3Dモデルの読み込み

GLTFLoaderの使用

今回はGLTFファイルを読み込むために、GLTFLoaderを使用して、モデルをロードします。

    // 3Dモデルの読み込み
    const gltfLoader = new THREE.GLTFLoader();
    gltfLoader.load('your/path.glb', (gltf) => {
        const model = gltf.scene;//your/path.glbにglbファイルのパスを挿入

        // モデルの設定
        model.traverse((child) => {
            if (child instanceof THREE.Mesh) {
                child.material.side = THREE.DoubleSide;
                child.castShadow = true;
                child.receiveShadow = true;
            }
        });

        // モデルをシーンに追加
        scene.add(model);
        model.scale.set(1, 1, 1);
        model.position.set(0, -7, 0);
    }, undefined, (error) => {
        console.error('GLBモデルの読み込み中にエラーが発生しました', error);
    });

モデル内のライトの読み込み

モデル内のライト(今回はPointLight)を読み込み、明るさや陰影の設定を行います。モデル内にライトを設定していなければ、この工程は必要ありません。

        // モデル内のライトをリストに収集
        model.traverse((obj) => {
            if (obj.isMesh) {
                obj.castShadow = true;
                obj.receiveShadow = true;
            }
            if (obj.isLight) {
                lights.push(obj);
            }
        });

        // GLBファイル内のライトのプロパティをもとに新しいライトを作成してシーンに追加
        lights.forEach((light) => {
            let newLight = new THREE.PointLight(light.color, light.intensity, light.distance, light.decay);
            newLight.position.copy(light.position);
            newLight.castShadow = true;
            newLight.shadow.mapSize.width = 1024;
            newLight.shadow.mapSize.height = 1024;
            newLight.shadow.radius = 30;

            // 明るさ(intensity)の調整
            newLight.intensity = light.intensity = 400;
            scene.add(newLight);
        });

6. アニメーションループの作成

カメラのコントロールを更新し、シーンをレンダリングするためのアニメーションループを作成します。

    // アニメーションループ
    function tick() {
        controls.update();
        renderer.render(scene, camera);
        requestAnimationFrame(tick);
    }

    tick(); // 初回呼び出し
}

コード全体

完成したコードになります。glTFファイルを”your/path.glb”としているので、使用するモデルのパスを入力してください。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>タイトル</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        #myCanvas {
            display: block;
        }
    </style>
</head>

<body>
    <canvas id="myCanvas"></canvas>

    <!-- cdnの読み込み -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/GLTFLoader.js"></script>
    <script>

        //init 関数を実行するイベントリスナーを設定     
        window.addEventListener("DOMContentLoaded", init);

        function init() {

            //ウィンドウの幅と高さを取得し、width と height という変数に格納
            const width = window.innerWidth;
            const height = window.innerHeight;

            // レンダラーの設定
            const canvasElement = document.querySelector('#myCanvas');
            const renderer = new THREE.WebGLRenderer({
                antialias: true,
                canvas: canvasElement,
            });

            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize(width, height);
            renderer.shadowMap.enabled = true;
            renderer.physicallyCorrectLights = true;
            renderer.outputEncoding = THREE.sRGBEncoding;
            renderer.toneMapping = THREE.ACESFilmicToneMapping;

            // シーンの作成
            const scene = new THREE.Scene();
            scene.background = new THREE.Color(0x000000);

            // カメラの作成
            const camera = new THREE.PerspectiveCamera(30, width / height, 1, 500);
            camera.position.set(60, 15, 30);

            // カメラコントローラーの作成
            const controls = new THREE.OrbitControls(camera, canvasElement);
            controls.enableDamping = true;
            controls.dampingFactor = 0.2;

            // 環境光源の作成
            const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
            scene.add(ambientLight);
            
            let model; // モデルを格納する変数
            const lights = []; // ライトを格納する配列

            // ウィンドウサイズ変更時の対応
            window.addEventListener('resize', () => {
                const width = window.innerWidth;
                const height = window.innerHeight;
                renderer.setSize(width, height);
                camera.aspect = width / height;
                camera.updateProjectionMatrix();
            });

            // 3Dモデルの読み込み
            const gltfLoader = new THREE.GLTFLoader();
            gltfLoader.load('your/path.glb', (gltf) => {
                model = gltf.scene;

                // モデル内のライトをリストに収集
                model.traverse((obj) => {
                    if (obj.isMesh) {
                        obj.castShadow = true;
                        obj.receiveShadow = true;
                    }
                    if (obj.isLight) {
                        lights.push(obj);
                    }
                });

                // GLBファイル内のライトのプロパティをもとに新しいライトを作成してシーンに追加
                lights.forEach((light) => {
                    let newLight = new THREE.PointLight(light.color, light.intensity, light.distance, light.decay);
                    newLight.position.copy(light.position);
                    newLight.castShadow = true;
                    newLight.shadow.mapSize.width = 1024;
                    newLight.shadow.mapSize.height = 1024;
                    newLight.shadow.radius = 30;

                    // 明るさ(intensity)の調整
                    newLight.intensity = light.intensity = 400;
                    scene.add(newLight);
                });

                // モデルをシーンに追加
                scene.add(model);
                model.scale.set(1, 1, 1);
                model.position.set(0, -7, 0);


            }, undefined, (error) => {
                console.error('GLBモデルの読み込み中にエラーが発生しました', error);
            });

            // アニメーションループ
            function tick() {
                controls.update();
                renderer.render(scene, camera);
                requestAnimationFrame(tick);
            }

            tick(); // 初回呼び出し
        }
    </script>
</body>

</html>

まとめ

今回は、Three.jsを使用して3DモデルをWebページに表示する手順を詳しく解説しました。これを基に、さらに複雑な3Dシーンやインタラクティブな要素を追加して、独自のWebGLプロジェクトを作成してみてください!また、私自身も、Three.jsの初学者なので、「もっとこうしたほうがいい!!」などがあれば、ぜひコメントをお願いします!

参考サイト

 

NK細胞
株式会社GRIのWebデザイナー