このセクションでは、three.jsを簡単に紹介します。まず、回転するキューブを描画することから始めます。困った時には、ページの下にあるサンプルコードを参考にしてみてください。
three.jsを使う前に、表示するための場所が必要です。以下のHTMLをPCのファイルに保存して、そのHTMLを保存したディレクトリにjs/ディレクトリを作成し[link:https://threejs.org/build/three.js three.js]のコピーを保存しておいてください。その後、保存したHTMLをブラウザで開いてください。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script>
// Our Javascript will go here.
</script>
</body>
</html>
これで完了です。下のコードは全て空の<script>タグに挿入されます。
実際にthree.jsで何かものを表示できるようにするには、scene、camera、rendererの3つが必要です。
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
この時点でscene、camera、rendererの設定が完了したことになります。
three.jsにはcameraには種類がありますが、今回はPerspectiveCameraを使ってみましょう。
最初の属性は、field of viewです。FOV(field of view)は、任意の瞬間にディスプレイ上で見られるシーンの範囲で、単位は度数です。
2つ目はアスペクト比です。アスペクト比は要素の幅を高さで割ったもので、描画する際には、アスペクト比を使うことが多いと思います。そうしないと、ワイドスクリーンのテレビで古い映画を再生したときと同じようになってしまいます。
次の2つの属性は、nearとfarです。この二つの値を設定することで、farの値よりもカメラから離れたオブジェクトやnearの値よりも近いオブジェクトはレンダリングされなくなります。今回はこのことを気にする必要はありませんが、より良いパフォーマンスを得るために、アプリで変更するということがあるかもしれません。
次はrendererです。ここでmagicが起きます。ここで使用しているWebGLRendererの他にも、three.jsにはいくつかの機能があり、古いブラウザを使用しているユーザーや、何らかの理由でWebGLをサポートしていないユーザーのための後方互換として使用されています。
rendererのインスタンスを作成することに加えて、アプリを描画するサイズを設定する必要があります。アプリで塗りつぶしたい領域の幅と高さを使用することをお勧めします(この場合、ブラウザウィンドウの幅と高さ)。パフォーマンスを重視するアプリの場合、setSizeにwindow.innerWidth/2やwindow.innerHeight/2のような小さな値を与えることもできます。こうすることでアプリは半分のサイズでレンダリングされます。
アプリのサイズを維持しつつ、より低い解像度でレンダリングしたい場合は、updateStyle (3番目の引数)としてfalseを指定して setSize を呼び出すことで行うことができます。例えば、setSize(window.innerWidth/2, window.innerHeight/2, false)は、<canvas>の幅と高さが100%の場合、アプリを半分の解像度でレンダリングします。
最後に、HTMLドキュメントに renderer 要素を追加します。これは、rendererがシーンを表示するために使用する <canvas> 要素です。
"それはそれとして、冒頭で言っていたキューブはどこにあるの?" いますぐ追加しましょう。
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
キューブを作成するには、BoxGeometryが必要です。これは、キューブのすべての点 (頂点) および塗りつぶし(面)を含むオブジェクトです。これについては、今後さらに詳しく説明していきます。
形状を表すジオメトリに加えて、色をつけるためのマテリアルが必要です。Three.jsにはいくつかのマテリアルが付属していますが、ここではMeshBasicMaterialだけを使うことにします。すべてのマテリアルは、それらに適用されるプロパティのオブジェクトを取ります。物事を非常にシンプルに保つために、0x00ff00のcolor属性を与えるだけにします。これは、CSSやPhotoshopで色が動作するのと同じ方法で動作します(hex colors)。
3番目に必要なのは、メッシュです。メッシュとは、ジオメトリを受け取り、それにマテリアルを適用するオブジェクトのことで、シーンに挿入して自由に動作させることができます。
デフォルトでは、scene.add() を呼び出すと、追加したものが座標 (0,0,0) に追加されます。これにより、カメラとキューブの両方が互いに内側になってしまいます。これを回避するために、カメラを少しずらします。
先ほど作成したHTMLファイルに上のコードをコピーしても何も表示されません。これは、実際にはまだ何も描画していないからです。そのためには、レンダリングまたはアニメーションループと呼ばれるものが必要です。
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
このコードでは、画面が更新されるたびにrendererがシーンを描画するループを作成しています(一般的な画面では、これは1秒間に60回を意味します)。ブラウザでゲームを書くのが初めての方は、「なぜ setIntervalでやらないのか」と言うかもしれません。おそらく最も重要なのは、ユーザーが別のブラウザタブに移動するときに一時停止し、貴重な処理能力とバッテリー寿命を無駄にしないことです。
始める前に作成したファイルに上記のコードをすべて挿入すると、緑色のボックスが表示されるはずです。これを回転させて少し面白くしてみましょう。
animate 関数の中でrenderer.render を呼び出している箇所のすぐ上に以下のコードを追加します。
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
これはフレームごとに実行され(通常は1秒間に60回)、キューブに素敵な回転アニメーションを与えます。基本的に、アプリの実行中に移動または変更したいものはすべて、アニメーションループを通過する必要があります。もちろん、そこから他の関数を呼び出すこともできます。
おめでとうございます。これで初めてのthree.jsアプリが完成しました。簡単なことですが、誰でもはじめは初心者です。
今回使用したコードは[link:https://jsfiddle.net/mkba0ecu/ live example]にあり編集可能です。紹介したコードがどうやって動作するかをより理解するために、それを使って遊んでみてください。
<!DOCTYPE html>
<html>
<head>
<title>My first three.js app</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<script src="js/three.js"></script>
<script>
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
const animate = function () {
requestAnimationFrame( animate );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
};
animate();
</script>
</body>
</html>