three.jsを使い始めて、私自身が引っ掛かった点を中心に記載した初心者用の入門編です。three.jsを利用することでブラウザ上に3Dのグラフィックを描写することができます。three.jsはWebGLを元に作られておりthree.jsを利用することでWebGLによる3Dグラフィックを”より簡単”に作成することができます。つまりWebGLのみで3Dを作成するのは少し難しいということが言えます。またWebGLはcanvas上に3Dグラフィックスを描写します。

Three.jsの基礎

Three.jsを使いこなすためには、以下の5つの概念を理解する必要があります。最初はわからない単語が出てくると思いますが、挫折せず読み進めてください。本文書を読み終えた頃には、three.jsの基礎が理解できているはずです。

Three.jsはJavascriptを使って操作するので、Javascriptの基礎がわかっていない人は理解するのは困難かもしれません。
fukidashi
  • scene(シーン)
  • camera(カメラ)
  • renderer(レンダラー)
  • object(オブジェクト)
  • light(ライト)

scene(シーン)

実際にオブジェクトを配置する空間です。撮影を行うために借りた部屋を想像してもいいかもしれません。また、Photoshopであればカンバス, Illustratorではアートボードに似た存在だと考えることもできます。

camera(カメラ)

camera(カメラ)を経由してscane(シーン)の撮影を行います。camera(カメラ)で撮影している内容のみがブラウザ上に表示されます。ブラウザの前にいるあなたが見ている画面がcamera(カメラ)が撮影している内容となります。

renderer(レンダラー)

camera(カメラ)を使って撮影したscene(シーン)の内容をブラウザに表示させる要素です。

object(オブジェクト)

scene(シーン)内に配置される物体そのものです。seane(シーン)に置かれたobject(オブジェクト)は、camera(カメラ)で撮影を行い、ブラウザで表示されます。また、object(オブジェクト)はmesh(メッシュ)ともよばれ、geometry(ジオメトリ=形状)とmetarial(マテリアル=素材)で構成されます。

light(ライト)

light(ライト)を物体に当てることでobject(オブジェクト)の色を表示させることができます。電気のない部屋にいると部屋にあるものが見えないことと同じで、light(ライト)を置くことでscene(シーン)にあるobject(オブジェクト)を見ることができます。

その他の4つとは異なり、light(ライト)は必須ではないため、本文書では設定を行いません。
fukidashi

初めてのThree.js

Three.jsのベースとなる用語の説明を行ったので次は実際に手を動かしながら、再度基礎を復習していきましょう。この時点で用語が理解できなくても問題ありません。

エディターにはVisual Studio Code(VS Code)を利用します。threeという名前のフォルダを作成してその中にindex.htmlファイルを作成します。VS CodeのExtentions(拡張機能)のLive Serverを利用することでファイルの更新内容をブラウザ上に即座に反映させることができます。

ローカルPCでthree.jsを記述したHTMLをChromeで実行してもセキュリティの関係で実行できない場合は他のブラウザであるEdge、Firefoxを利用してみてください。

公式ドキュメントに掲載されているコードを使用して動作確認してみましょう。トップページにアクセスして左上にあるdocomentationをクリックしてください。

three.jsのトップページ

three.jsのトップページ

ページの下のほうに”The result”の下に動作確認用のコードが表示されているので、こちらをコピー&ペーストしてhtmlファイルとして保存してください。

テスト動作確認用コード

テスト動作確認用コード

作成したhtmlファイルのthree.jsのパスのみ変更する必要があります。下記のようにcdnのパスへ変更を行います。


<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.js"></script>
ローカルにthree.jsを保存している場合は、cdnのパスではなく保存したthree.jsのパスを設定しても問題ありません。
fukidashi

three.jsのパスの設定変更を行った結果、動作確認に使用するコードは下記になります。6つのパートに分かれており、一見難しいそうに見えますが、一つ一つ見ていくと難しい項目はありません。


<html>
	<head>
		<title>My first three.js app</title>
		<style>
			body { margin: 0; }
		</style>
	</head>
	<body>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/99/three.js"></script>
		<script>
			/* scene(シーン)の作成 */
			var scene = new THREE.Scene();

			/* camera(カメラ)の作成 */
			var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );

			/* renderer(レンダラー)の作成 */
			var renderer = new THREE.WebGLRenderer();
			renderer.setSize( window.innerWidth, window.innerHeight );
			document.body.appendChild( renderer.domElement );
			
			/* object(オブジェクト)の作成 */
			var geometry = new THREE.BoxGeometry( 1, 1, 1 );
			var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
			var cube = new THREE.Mesh( geometry, material );
			scene.add( cube );
			
			/* camera(カメラ)の位置設定 */
			camera.position.z = 5;

			/* 繰り返しの処理 */
			var animate = function () {
				requestAnimationFrame( animate );

				cube.rotation.x += 0.01;
				cube.rotation.y += 0.01;

				renderer.render( scene, camera );
			};

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

作成したHTMLファイルを実行してみましょう。立方体が中心で回っていればプログラムは正常に動作しています。

初めてのthree.jsの結果

初めてのthree.jsの結果

three.jsの動作を確認することができたので、中身を見ていきましょう。

コードの中身を確認していこう

動作したコードは、scene(シーン)、camera(カメラ)、renderer(レンダラー)、object(オブジェクト)の4つとそれ以外の2つの計6つのパートから成り立っているので、実際のコードと各項目を比較しながら見ていきましょう。

scene(シーン)の作成

object(物体)を配置する空間の作成を行います。作成した時点では何もない空っぽの空間です。この空間に立方体を後程配置します。


var scene = new THREE.Scene();

camera(カメラ)の作成

scene(シーン)を撮影するcamera(カメラ)を作成するためには、PerspectiveCameraメソッドを使用します。いくつかの引数を設定する必要があり、引数に入った数値の大小など不明点は多いと思いますが、まずは引数の意味を掲載した図を元に理解してください。


var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera(カメラ)を作成するためには、PerspectiveCamera以外にも種類がありますが、ここでは人間と同じ視点を持つPerspectiveCameraでcamera(カメラ)の作成を行います。
fukidashi

PerspectiveCameraの書式は下記の通りになります。

PerspectiveCamera

PerspectiveCamera

FOVはfield of viewの略で下記の図の角度を表します。人間では目で見える範囲を考えると180になるかもしれませんが、ここでは75を設定しています。ASPECTはアスペクト比を表し、ここではブラウザの横幅と高さの比を設定しています。NEARはcamera(カメラ)からnear planeまでの距離を表し、FARはcamera(カメラ)からfar planeまでの距離を表します。farは日本語で遠いを意味するため、far planeは遠い面、near planeは近い面を表しています。

three.jsのcameraのイメージ

three.jsのcameraのイメージ

パラメータの値をいろいろ変更しながら値によってどのような変化があるのかを確認してみてください。

renderer(レンダラー)の作成

camera(カメラ)を使って撮影したscene(シーン)の内容をブラウザに表示する場所の確保を行っています。bodyタグの下にwindowsのサイズと同じ領域を確保しています。この領域にcamera(カメラ)で撮影したscene(シーン)の内容が表示されます。


var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

object(オブジェクト)の作成

scene(シーン)に配置するobject(オブジェクト)の作成を行い、scene(シーン)への配置まで行います。

まずは配置するオブジェクトの形状を設定します。BoxGeometryは立方体の形状を作成することができます。ここでは縦、横、奥行をすべて1に設定します。形状とは別に立方体の素材を作成します。素材は、MeshBasicMaterialで作成でき、素材の色を#00ff00に設定しています。


var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );

下記のようにGEOMETRY(形状)を作成し、MATERIAL(素材)を作成して、形状と素材でMESH(CUBE)を作成します。

立方体のBoxGeometryの他にも球体のSphereGeometry, 三角錐(さんかくすい)のConeGeometry, 円柱のCylinderGeometryもあります。
fukidashi
object(オブジェクト)の作成

object(オブジェクト)の作成

cubeを作成後、addを使用して、scene(シーン)へオブジェクトであるcubeを配置しています。

object(オブジェクト)の作成の流れは下記の通りです。

  1. GEOMETRY(形状)の作成
  2. MATERIAL(素材)の作成
  3. MESHの作成(GEOMETRY+MATERIAL)
  4. SCENEへのMESHの追加

その他の設定

scene(シーン)、camera(カメラ)、renderer(レンダラー)、object(オブジェクト)の作成が完成しましたが、cameraの位置と繰り返しの処理を行います。

camera(カメラ)の位置を設定

z軸の5のところにcameraを設置しています。


camera.position.z = 5;

z軸が5といってもどこ場所か最初は検討がつかないと思うので、カメラの場所と視点を変更します。camera(カメラ)を座標x=3, y=3, z=3の位置に移動させ、座標の中心(0,0,0)に向かって撮影を行います。座標軸が目ではっきりとわかるようにAxesHelperメソッドを使用します。引数は軸の長さを表し1などに設定することで軸の長さの変化を確認できます。


camera.position.x = 3;
camera.position.y = 3;
camera.position.z = 3;
camera.lookAt(new THREE.Vector3(0, 0, 0));
var axes = new THREE.AxesHelper(1000);

設定した場所から見ると下記のように表示されます。Y軸とZ軸が通常の座標とは逆になっています。また、立方体は場所の指定をしていないため、中心にあることがわかります。この操作によって位置と立方体のサイズ感が理解できたかと思います。

cameraの場所を変更して、中心に向けて撮影

cameraの場所を変更して、中心に向けて撮影

X軸、Y軸、Z軸の文字列は画像に後から追加しているのでブラウザ上には表示されていません。
fukidashi

座標軸を表示させたまま、z軸5から見たscene(シーン)を表示させて位置の理解を深めましょう。z軸上にcamera(カメラ)がいるのでz軸は表示されていません。

zのposition5から見たscene

zのposition5から見たscene

立方体の位置を変更したい場合には以下のようにpositionを利用して設定することができます。position.xを1に変更することでx軸に1移動した場所に立方体が表示されます。


const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.position.x = 1;
scene.add(cube);

cubeの位置の確認

cubeの位置がどこにあるのかを確認したい場合はconsole.logでcobe.positionを利用することができます。


console.log('cube position:', cube.position);
// ブラウザのコンソール
{
    "x": 0,
    "y": 0,
    "z": 0
}

その他のcubeに関する情報を確認したい場合にはconsole.logで確認することができます。


 console.log('cube:', cube);
cubeオブジェクトの中身を確認
cubeオブジェクトの中身を確認
cameraオブジェクトの中身についてもconsole.logを利用して確認することができます。cameraに関するさまざまな設定値が確認できるので一度は中身を見ることをお勧めします。
fukidashi

繰り返しの処理

scene(シーン)に置いたobject(オブジェクト)を静止したままであるなら以下の処理はrenderer.render( scene, camera )のみ必要になりますが、3Dの処理は静止画よりもダイナミックに動いたほうが見栄えもいいと思いますので、繰り返し処理を通常行います。javascriptのrequestAnimationFrameメソッドで繰り返し処理を実行させます。繰り返しの処理の中で、cubeを回転させる処理を行っています。


var animate = function () {
	requestAnimationFrame( animate );

	cube.rotation.x += 0.01;
	cube.rotation.y += 0.01;

	renderer.render( scene, camera );
};

animate();

cubeではなくcameraを回転させることもできます。


var animate = function () {
	requestAnimationFrame( animate );

	camera.rotation.x += 0.01;
	camera.rotation.y += 0.01;

	renderer.render( scene, camera );
};

animate();

まとめ

公式ドキュメントに記載されている一番簡単なコードを使用して解説を行いましたがいかがだったでしょうか。さらにthree.jsの中心要素であるscene(シーン)、camera(カメラ)、renderer(レンダラー)、object(オブジェクト)の理解を深めるために、上記で出てきたパラメータをいろいろ変更してみて動作確認するのがお勧めです。設定によってはobject(オブジェクト)が画面から消えると思いますが、再度パラメータを変更しなおして再表示することで値の大小が与える影響の理解が深まると思います。