webpack + three.js を使用する例

この手順で前提としているライブラリとバージョンは下記のとおりです。

ライブラリ バージョン
three 0.86.0 (r86)
webpack 3.3.0

手順

1. 作業フォルダ上で npm init -y コマンドを実行して package.json を生成します。 (必要な場合は、あとで package.json を直接編集できます)

2. 作業フォルダ上で下記コマンドを実行して必要なライブラリを導入します。

  • npm install --save-dev webpack
  • npm install --save three

3. 作業フォルダ直下に webpack.config.js ファイルを作成し、下記のような内容を記載します。

const webpack = require('webpack');
const path = require('path');

module.exports = {
    devtool: 'inline-source-map',
    entry: './app.js', // 入力元のファイル名(エントリポイント)
    output: {
        filename: 'bundle.js' // 出力先のファイル名
    },
    resolve: {
        // 使用したいコントロールやレンダラを定義しておきます。(下記は一例です。使用しないものは除いておいてよいです)
        alias: {
            // トラックボール
            'three/TrackballControls': path.join(__dirname, 'node_modules/three/examples/js/controls/TrackballControls.js'),
            // 物体ドラッグ
            'three/DragControls': path.join(__dirname, 'node_modules/three/examples/js/controls/DragControls.js'),
            //// カメラ制御
            //'three/OrbitControls': path.join(__dirname, 'node_modules/three/examples/js/controls/OrbitControls.js'),
        }
    },
    plugins: [
        // THREE.Scene などの形式で three.js のオブジェクトを使用できるようにします。
        new webpack.ProvidePlugin({
            'THREE': 'three/build/three'
        }),
        // minify するようにします。(必要な場合)
        new webpack.optimize.UglifyJsPlugin()
    ]
}

※入力元、出力先のファイル名は必要に応じて変更してください。

4. 入力元(上記では app.js)に、サンプルとして下記のような内容を記載します。

(下記は公式サンプルの interactive / draggablecubes をベースにしたものです)

import 'three/TrackballControls'; // 必要なコントロール (webpack.config.js に記載したもの) を import します。
import 'three/DragControls';

var container;
var camera, controls, scene, renderer;
var objects = [];

init();
animate();

function init() {

    container = document.createElement( 'div' );
    document.body.appendChild( container );

    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.z = 1000;

    controls = new THREE.TrackballControls( camera );
    controls.rotateSpeed = 1.0;
    controls.zoomSpeed = 1.2;
    controls.panSpeed = 0.8;
    controls.noZoom = false;
    controls.noPan = false;
    controls.staticMoving = true;
    controls.dynamicDampingFactor = 0.3;

    scene = new THREE.Scene();

    scene.add( new THREE.AmbientLight( 0x505050 ) );

    var light = new THREE.SpotLight( 0xffffff, 1.5 );
    light.position.set( 0, 500, 2000 );
    light.castShadow = true;

    light.shadow = new THREE.LightShadow( new THREE.PerspectiveCamera( 50, 1, 200, 10000 ) );
    light.shadow.bias = - 0.00022;

    light.shadow.mapSize.width = 2048;
    light.shadow.mapSize.height = 2048;

    scene.add( light );

    var geometry = new THREE.BoxGeometry( 40, 40, 40 );

    for ( var i = 0; i < 200; i ++ ) {

        var object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );

        object.position.x = Math.random() * 1000 - 500;
        object.position.y = Math.random() * 600 - 300;
        object.position.z = Math.random() * 800 - 400;

        object.rotation.x = Math.random() * 2 * Math.PI;
        object.rotation.y = Math.random() * 2 * Math.PI;
        object.rotation.z = Math.random() * 2 * Math.PI;

        object.scale.x = Math.random() * 2 + 1;
        object.scale.y = Math.random() * 2 + 1;
        object.scale.z = Math.random() * 2 + 1;

        object.castShadow = true;
        object.receiveShadow = true;

        scene.add( object );

        objects.push( object );

    }

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setClearColor( 0xf0f0f0 );
    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( window.innerWidth, window.innerHeight );
    renderer.sortObjects = false;

    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFShadowMap;

    container.appendChild( renderer.domElement );

    var dragControls = new THREE.DragControls( objects, camera, renderer.domElement );
    dragControls.addEventListener( 'dragstart', function ( event ) { controls.enabled = false; } );
    dragControls.addEventListener( 'dragend', function ( event ) { controls.enabled = true; } );

    var info = document.createElement( 'div' );
    info.style.position = 'absolute';
    info.style.top = '10px';
    info.style.width = '100%';
    info.style.textAlign = 'center';
    info.innerHTML = '<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - draggable cubes';
    container.appendChild( info );

    window.addEventListener( 'resize', onWindowResize, false );

}

function onWindowResize() {

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize( window.innerWidth, window.innerHeight );

}

function animate() {

    requestAnimationFrame( animate );

    render();

}

function render() {

    controls.update();

    renderer.render( scene, camera );

}

5. Windows の場合、もし PATH に .\node_modules\.bin が含まれていなければ含むようにします。 (環境変数の編集で追加するか、使用しているコマンドプロンプト上のコマンドで set PATH=.\node_modules\.bin;%PATH% とします)

6. webpack コマンドで、出力先ファイル(前述の webpack.config.jsoutput。今回の例だと bundle.js)にファイルが生成されるか確認します。

問題なければ完了です。(下記のようなHTMLで bundle.js を読み込むことができます)

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <style>
        body {
            margin: 0px;
            overflow: hidden;
        }
    </style>
    <title></title>
</head>
<body>
    <script src="bundle.js"></script>
</body>
</html>

その他

  • ファイルの変更を監視して自動ビルドする場合は webpack --watch コマンドなどが使用できます。

参考