「physics.js」による仮想物理実験室
仮想物理実験室のつくりかた

文責:遠藤理平
公開日:2017年03月02日
最終更新日:2017年03月02日

はじめに

 本項は「physics.js」を用いて物理シミュレーションを行うための手順をチュートリアル形式で紹介する記事です。 最新版「physics.js」(リビジョン14、2017年03月03日現在)をここからダウンロードしてください。以下はチュートリアルの目次です。

仮想物理実験室の実行画面と操作方法

 図1は、physics.jsで創ることのできる仮想物理実験室の実行画面(Google Chrome)です。生成した実験室内に「床オブジェクト」(※)と「軸オブジェクト」を登場させています。 グラフィックス上にて、マウスの左ボタンでマウスドラックするとカメラの位置を、右ボタンでマウスドラックするとカメラの視野中心を移動することができますので試してみてください。 また、画面左下に表示されているボタン類(HTML要素で生成)は本実験室を操作するためのインターフェースです。後ほど詳しく紹介します。

(※)オブジェクトとはプログラミング言語JavaScriptにおけるデータのまとまりを表すデータ形式です。本項では実験室に登場する仮想の物体を「○○オブジェクト」と呼びます。

(図1)仮想物理実験室の実行画面(Google Chrome)


実際の仮想物理実験室はこちら

仮想物理実験室の制御インターフェース

 仮想物理実験室を制御するためのインターフェースとして様々ボタンやスライダーがHTML要素(button要素やinput要素など)で用意されています。 具体的には上段の「▶」は実験室の時刻を進めるボタン、「■」は実験室の状態を初期状態に戻すボタン、「写真マーク」は現在表示しているグラフィックスをPNG形式の画像データとして出力するボタン、 「フィルムマーク」はこれまでにシミュレーションした結果を元にWebM形式の動画を生成するボタンです。動画生成の挙動については後述します。
 中段の表にある「時刻」のとなりスライダーは実験室が一時停止状態で表示され、つまみで指定した時刻の状態を表示することができます。
 上記のインターフェースは「一時停止状態」のものです。 「計算中状態」の場合は図2のとおり、計算停止を表す「||」ボタンのみが表示され、それ以外のボタンが非表示となります。
 なお、下段の「軌跡」「速度ベクトル」「ストロボ」は利用時に解説します。

(図2)「計算中状態」のインターフェース

動画生成時の挙動

 「動画生成ボタン」は仮想物理実験室が「初期状態」を除く「一時停止状態」の場合に表示されます。 クリックすると動画生成のための再生が、時刻0から実験室で計算済みの時刻まで実行されます。この再生時のグラフィックスが実際の動画として記録されるため、マウスドラックによるカメラ操作などが反映されます。 再生が終了して動画生成完了後、(図3)のとおり「↓」ボタンが表示されます。このボタンをクリックすると、動画を出力することができます。

(図3)「動画出力ボタン」の表示

実験室の時刻表示について

 (図1)では実験室の時刻を2箇所で表示しています。1つ目はグラフィックス左上部、2つ目は制御インターフェース内です。この2つの時刻表示には大きな違いがあります。 1つ目の時刻表示はグラフィックス内に画像として表示されているため画像が動画に出力した場合に表示されるのに対して、2つ目のものはHTML要素内にテキスト(文字)として表示しているため画像が動画には反映されません。また、1つ目の時刻表示はカメラの位置や向きに依存しません。なお、両時刻表示とも表示の有無は指定することができます。

フレームレートの表示について

 3次元グラフィックスは一般に計算負荷が大きいためにマシンパワーが必要となります。仮想物理実験室はさらに物理シミュレーションの計算も行うため、さらに計算負荷が加わります。 そして、コンピュータが処理できる計算負荷を超えると動作が重くなっていきます。3次元グラフィックスはアニメーションと同じように静止画を連続的に切り替えることで動きを表現するわけですが、 この動作が重いという状態は1秒間当たりに切り替わる回数「フレームレート」(単位は[FPS])が小さくなることを意味します。 本実験室ではフレームレートを(図4)で示したとおり左上に小さく表示しています。
 なお、フレームレートはコンピュータのディスプレイの設定にも依りますが、通常60[FPS]です。

(図4)フレームレートの表示

仮想物理実験室の設定

 仮想物理実験室の各種設定は仮想物理実験室オブジェクトの生成時に行うことができます。「example」フォルダの「stage.html」をテキストエディタで開いてみてください。 【プログラムソース1】で示した箇所が確認できると思います。この部分をプログラミング風に説明すると、PhysLabクラスのコンストラクタを用いてインスタンス(仮想物理実験室オブジェクト)を生成しているという意味になります。 このコンストラクタの引数に与えたオブジェクト(「{」から「}」まで)で仮想物理実験室の設定を行います。

【プログラムソース1】仮想物理実験室オブジェクトの生成(stage.html)
//仮想物理実験室オブジェクトの生成
PHYSICS.physLab = new PHYSICS.PhysLab({
	//計算モード(リアルタイム計算モード/プレ計算モード)
	calculateMode : PHYSICS.RealTimeMode, // (RealTimeMode | PHYSICS.PreMode)
	//ステージの設定
	stage : {
		id : null,
		width : 100, //[%]
		height : 100 //[%]
	},
	//ボタン関連
	playButtonID : "play",           //計算開始ボタンの表す要素のid名
	resetButtonID : "reset",         //リセットボタンの表す要素のid名
	pictureID : "picture",           //画面キャプチャボタンを表す要素のid名
	locusButtonID : "locus",	       //軌跡の表示ID
	strobeButtonID : "strobe",	   //ストロボ表示ID
	velocityVectorButtonID : "velocityVector",	//速度ベクトルの表示ID
	useJQuery : true,                //jQueryの利用の可否を

	//マウスドラック関連
	draggable: true,                 //マウスドラック利用の有無
	allowDrag : true,                //マウスドラックの可否

	//数値計算パラメータ
	dt: 0.001,                       //1ステップあたりの時間間隔

	//レンダラー関連パラメータ
	renderer : {
		clearColor : 0xE1FCFF,       //クリアーカラー(背景色)
	},
	//トラックボール関連パラメータ
	trackball : {
		enabled : true,              //トラックボール利用の有無
	},
	//カメラ関連パラメータ
	camera: {
		type : "Perspective",        //カメラの種類 ( Perspective | Orthographic)
		position: {x: 12, y: 12, z:5}, //カメラの位置
		target: {x:0, y:0, z:5},     //カメラの視野中心座標
	},

	//光源関連パラメータ
	light: {
		type :"Directional",         //光源の種類 ( Directional | Spot | Point)
		position: {x:-5, y:-5, z:12},  //光源位置
		target: {x:0, y:0, z:0},     //光源の向き
		color: 0xFFFFFF,             //光源色
		ambient: 0x888888,           //環境光源の光源色
	},

	//影関連パラメータ
	shadow: {
		shadowMapEnabled:    true,   //シャドーマップの利用
		shadowCameraVisible: false,  //シャドーマップの可視化
	},

	//フラグ関連
	locusFlag : false,           //軌跡の表示 (true | false | "pause" | "disabled")
	velocityVectorFlag : false,  //速度ベクトルの表示 (true | false | "pause" | "disabled")
	strobeFlag : false,          //ストロボオブジェクトの表示 (true | false | "pause" | "disabled")
	boundingBoxFlag : "dragg",   //バウンディングボックスのの表示 (true | false | "dragg")

	//時間表示
	timeID :"time",              //時刻表示用要素のid名

	//時間制御スライダー
	timeslider : {
		enabled : true,   //利用の有無
		skipRecord : 50,  //時系列データの間引数
		domID : "timeslider",
	},

	//動画生成用
	video : {
		enabled : true,          //ビデオ生成利用の有無
		makeButtonID : "video",  //動画生成ボタンID
		downloadButtonID : "downloadVideo", //ビデオダウンロードボタンID
		speed : 40,              //動画のフレームレート
		quality :0.8,            //動画の画質
		fileName : "video.webm", //動画のファイル名
		frames : {
			enabled : true,
		}
	},

	//背景指定用
	skydome : {
		enabled : true,         //スカイドーム利用の有無
		radius  : 200,           //スカイドームの半径
		topColor : 0x2E52FF,     //ドーム天頂色
		bottomColor : 0xFFFFFF,  //ドーム底面色
		exp : 0.8,               //混合指数
		offset : 20               //高さ基準点
	},

	//実験室内時刻表示ボード
	timeBoard : {
		enabled : true,  //時刻表示ボード表示の有無
		size: 10,        //時刻表示ボードの大きさ(単位はステージに対する[%])
		top : 2,         //上端からの位置(単位はステージに対する[%])
		left : 2,        //左端からの位置(単位はステージに対する[%])
		rotation : 0,    //ボードの回転角度
		fontSize : 20,   //フォントサイズ(単位はボードに対する[%])
		fontName :"Times New Roman", //フォント名(CSSで指定可能な文字列)
		textAlign : "left",          //行揃え(CSSで指定可能な文字列)
		textColor : {r: 0, g:0, b:0, a: 1 },      //文字色
		backgroundColor : { r:1, g:1, b:1, a:0 }, //背景色(RGBA値を0から1で指定)
		resolution : 9,  //テクスチャサイズ(2の乗数)
	}
});

 JavaScriptでは、データの集まりであるオブジェクトは「プロパティ:値」の組み合わせで構成され、「,(カンマ)」で区切ります。 さらに、プロパティの値にオブジェクトを与えることもできて、入れ子構造を作ることもできます。physics.jsでは、仮想物理実験室の設定はコンストラクタの引数に与えるオブジェクトのプロパティに値を与えることで行います。
 実験室の設定方法を理解するためにプロパティの値を変更してみましょう。 例えば、cameraプロパティの中のpositionプロパティのx,y,zプロパティの値を変更してみてください。3次元グラフィックスの見え方が変化したと思います。これはカメラ位置座標の初期値を表します。 他のプロパティについては、これからそれぞれ必要に応じて解説していきます。

仮想物理実験室オブジェクトを表す変数(オブジェクト)

本実験室をプログラム中で操作する場合、すべての情報は「PHYSICS.physLab」に格納されています。プログラム中での操作方法は、これから必要に応じて解説していきます。 ちなみに「PHYSICS」は「physics.js」で利用するただひとつのグローバル変数(オブジェクト)で、 今後登場する全てのプログラム中で登場する全ての変数(オブジェクト)は「PHYSICS.◯◯」という形で登場することになります(※)。

(※)JavaScriptでは、生成されたオブジェクトのプロパティへのアクセスは「.(ドット)」を用います。つまり、 【プログラムソース1】の 「PHYSICS.physLab = new PHYSICS.PhysLab({~省略~});」をプログラミング風に説明すると、 グローバル変数(オブジェクト)「PHYSICS」の「physLab」プロパティに「PhysLab」クラスのインスタンスを代入するという意味になります。


仮想物理実験室への物体の配置

 仮想物理実験室に登場する物体は「3次元オブジェクト」と総称します。図1には床オブジェクトと軸オブジェクトの2つが登場します。 全ての3次元オブジェクトは、3次元オブジェクトを生成後、仮想物理実験室オブジェクトの「objects」プロパティ(配列)に格納することで登場させることができます。

3次元オブジェクトの生成方法と実験室への配置

 床オブジェクトはFloorクラス、軸オブジェクトはAxisクラスというように3次元オブジェクトはその種類ごとにクラスが用意されています。また、実験室オブジェクトと同様にコンストラクタの引数で各種設定を行うことができます。 そして、objectsプロパティ(配列)に順番に格納していくことで実験室への配置を行うことができます。

// 床オブジェクトの準備
PHYSICS.physLab.objects[ 0 ] = new PHYSICS.Floor({ ~省略~ });
// 軸オブジェクトの準備
PHYSICS.physLab.objects[ 1 ] = new PHYSICS.Axis({ ~省略~ });

上記のように配列の要素番号を指定して代入するほかに、以下のように配列のpushメソッドを用いて代入することもできます。

PHYSICS.physLab.objects.push(
	new PHYSICS.Floor({ ~省略~ })
);
PHYSICS.physLab.objects.push(
	new PHYSICS.Axis({ ~省略~ })
);

こちらの方が配列番号を把握しておく必要が無いので実装が容易となります。

仮想物理実験室の実行開始

 実験室オブジェクトを生成後、3次元オブジェクトの配置も完了して準備が整ったら、最後に実験室の実行を開始するstartLabメソッドを実行します。 なお、このメソッドはPhysLabクラスで定義されています。

//仮想物理実験室のスタートメソッドの実行
PHYSICS.physLab.startLab();

 以上でチュートリアルの第1回目を終了します。仮想物理実験室オブジェクトや床オブジェクト、軸オブジェクトの各種パラメータについて次回以降で随時解説していきます。