はじめての「three.js」で3D雪だるまを作ろう!

UI開発者 工藤(優)

この記事はミツエーリンクスアドベントカレンダー2019の20日目の記事です。

今回はJavaScriptで手軽に3D表現ができるライブラリ「three.js」を使って雪だるまを作ります。
まずは完成品を見てみましょう。(※PC推奨)

See the Pen abzmPMv by kudo (@kudo3) on CodePen.

作成手順 5step

本記事では5つのステップに分けて作り方を説明していきます。

step1 「three.min.js」ファイルを公式サイトからダウンロード

公式サイト (https://threejs.org) から「three.min.js」ファイルをダウンロードしましょう。
サイドナビにあるCodeのdownloadを押すとすぐにダウンロードが始まります。
three.js-master.zipがダウンロードされますので、buildフォルダの「three.min.js」を使用します。

step2 htmlを作成

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

<head>
    <meta charset="utf-8">
    <title>three.js snowman</title>
</head>

<body>
    <style>
        body {
            margin: 0;
        }
    </style>
    <div id="stage"></div><!--表示する領域-->
    <script src="js/three.min.js"></script><!--three.min.jsを読み込む-->


    <script>
        (function () {
            'use strict';


//ここにthree.jsの記述を書いていきます!


        })();
    </script>
</body>
</html>

step3 three.jsの記述を追加

step2で作成したhtmlの中に下記のコードを追加します。


const width = 460;
const height = 250;


// scene
const scene = new THREE.Scene(); //3Dを表現する空間

// mesh
//直方体のジオメトリー(幅, 高さ, 奥行き)
const buttonGeometry = new THREE.BoxGeometry(5, 5, 5)

//奥行きと影があり、光沢感のないマテリアル({ color: 0xから始まる16進数カラー})
const hatMaterial = new THREE.MeshLambertMaterial({ color: 0x333333 })
const headMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff })
const buttonMaterial = new THREE.MeshLambertMaterial({ color: 0x228b22 })

//3Dを2Dの手書き風にできるマテリアル({ color: 0xから始まる16進数カラー})
const eyeMaterial = new THREE.MeshToonMaterial({ color: 0x000000 });


const hat = new THREE.Mesh(
    //円柱のジオメトリー(上面半径,下面半径,高さ,円周分割数)
    new THREE.CylinderGeometry(25, 25, 40, 30),
    hatMaterial
);
hat.position.set(0, 50, 0); //(x,y,z)

const hat_line = new THREE.Mesh(
    new THREE.CylinderGeometry(26, 25, 20, 30),
    new THREE.MeshLambertMaterial({ color: 0xe60033 })
);
hat_line.position.set(0, 35, 0);

const hat_collar = new THREE.Mesh(
    new THREE.CylinderGeometry(40, 40, 5, 30),
    hatMaterial
);
hat_collar.position.set(0, 32, 0);

const head = new THREE.Mesh(
    //球のジオメトリー(半径,緯度分割数,経度分割数)
    new THREE.SphereGeometry(40, 40, 20),
    headMaterial
);
head.position.set(0, 0, 0);

const right_eye = new THREE.Mesh(
    new THREE.SphereGeometry(5, 25, 40),
    eyeMaterial
);
right_eye.position.set(15, 18, 30);

const left_eye = new THREE.Mesh(
    new THREE.SphereGeometry(5, 10, 40),
    eyeMaterial
);
left_eye.position.set(-16, 18, 33);

const nose = new THREE.Mesh(
    new THREE.SphereGeometry(5, 30, 20),
    new THREE.MeshLambertMaterial({ color: 0xed9121 })
);
nose.position.set(3, 10, 35);

const body = new THREE.Mesh(
    new THREE.SphereGeometry(50, 50, 50),
    headMaterial
);
body.position.set(0, -60, 0);

const button_first = new THREE.Mesh(
    buttonGeometry,
    buttonMaterial
);
button_first.position.set(0, -30, 37);

const button_second = new THREE.Mesh(
    buttonGeometry,
    buttonMaterial
);
button_second.position.set(0, -40, 43);

const snowman = new THREE.Group(); //メッシュをグループ化
snowman.add(hat,hat_line,hat_collar,head,right_eye,left_eye,nose,body,button_first,button_second);
scene.add(snowman); //3D空間にsnowmanを配置

// light
//平行光源(ディレクショナルライト):一方向から同じ強さで平行に照らすライト(色, 光の強さ)
const light = new THREE.DirectionalLight(0xffffff, 0.9);
light.position.set(0, 50, 30); //ライトの位置(x,y,z)
scene.add(light); //シーンにディレクショナルライトを追加

//環境光源(アンビエントライト):すべてを均等に照らす、影のない、全体を明るくするライト
const ambient = new THREE.AmbientLight(0xf8f8ff, 0.9);
scene.add(ambient); //シーンにアンビエントライトを追加

// camera
//遠近感のあるカメラ(視野角,上映するスクリーンの縦横比,カメラから手前までの距離,カメラから奥までの距離)
const camera = new THREE.PerspectiveCamera(90, width / height, 1, 1000);
camera.position.set(60, 50, 140); //(x,y,z)
camera.lookAt(scene.position); //カメラの視点(注視点)

// renderer
const renderer = new THREE.WebGLRenderer({ antialias: true }); //メッシュの輪郭を滑らかに表示
renderer.setSize(width, height); //幅と高さを設定
renderer.setClearColor(0xe6e6fa); // 空間の背景色
renderer.setPixelRatio(window.devicePixelRatio); //高解像度対応
document.getElementById('stage').appendChild(renderer.domElement); //div要素にcanvasを追加
function render() {
    requestAnimationFrame(render); //再度render関数を実行
    renderer.render(scene, camera); //シーン, カメラをもとに描画
    snowman.rotation.y += 0.01; //反時計周りにsnowmanを回転
}
render();

step4 three.jsの知識

three.jsには、5つの要素があります。 各要素の役割についてみてみましょう。

  • 1.scene:3Dを表現する空間
  • 2.mesh:物体(geometryとmaterialを組み合わせたもの)
    • geometry:物体の形状(円柱、球、直方体、ドーナツ型など)
    • material:物体の素材(光沢感や影、色など)

  • 3.light:光源
  • 4.camera:視点
  • 5.renderer:画面に表示

5つの要素を図で考えると、

three.jsの要素図

薄紫の背景(1.scene)に配置された雪だるま(2.mesh)を太陽(3.light)が照らし、その様子をカメラ(4.camera)で撮影しながらサンタクロース(5.renderer)がディスプレイに投影する仕組みです。

step5 マウスでカメラを操作

three.jsには、カメラを操作する機能があります。
現在のままだと、反時計回りに雪だるまが動くだけになりますので、 遊び心を加えて、いろいろな角度から雪だるまを見られるようにしましょう!

OrbitControls.jsファイルを準備

最初にダウンロードした、 three.js-master.zipの中にある「OrbitControls.js」を使用します。

htmlに記述を2つ追加

1.OrbitControls.jsを読み込む記述を追加

<script src="js/OrbitControls.js"></script>

2.OrbitControlsを追加 第二引数にcanvas要素を渡します。

var controls = new THREE.OrbitControls(camera, renderer.domElement);

これで完成です!

終わりに

今回は、円柱(CylinderGeometry)・球(SphereGeometry)・直方体(BoxGeometry)の3種のmeshを組み合わせて、3D雪だるまを作りました。

three.jsでは、この他にも

  • 3D文字を作ること
  • 3D空間に粒子を散らすこと(Particleと言います)
  • 3Dオブジェクトの表面に画像を張り付けること などのさまざまな表現をすることができます。

みなさまもこの冬、three.jsで遊んでみてはいかがでしょうか。

参考文献

ありがとうございました。