SQLの窓 イラストAC フリー素材

2013年03月08日

Three.js では、複数のオブジェクトを一つの Object3D に追加して一括管理します。


実行ページと全体ソース

Object3D は、3Dオブジェクトの基本

Scene オブジェクトも Object3D を継承しており、オブジェクト全体を管理する上で特殊なプロパティを持っています。
THREE.Scene = function () {

	THREE.Object3D.call( this );

	this.fog = null;
	this.overrideMaterial = null;

	this.matrixAutoUpdate = false;

	this.__objects = [];
	this.__lights = [];

	this.__objectsAdded = [];
	this.__objectsRemoved = [];

};

THREE.Scene.prototype = Object.create( THREE.Object3D.prototype );

Three.js では、本体の Function に プロパティが定義されており、prototype にメソッドが定義されるので、以上のような記述でクラスの継承が行われます。追加のメソッドが必要な場合は、prototype に直接定義します。

ここで、__objects には、シーンに追加されるオブジェクトが設定され、add やら remove を使った時に自動的に処理されます。ですから、直接オブシェクトを操作したい場合は、極端な話で言うと、この配列内のオブジェクトら必要なオブジェクトをなんらかの条件によって選択して、そのオブジェクトの持つプロパティやメソッドを操作すばいい事になります。( あくまで一般的に話で、仕様が変わる可能性のある内部部分の話です )

※ 各 Object3D には children という配列があり、階層で管理されています。
( チェーン情報として parent も持っています )

また、__objectsAdded __objectsRemoved は、何故か、__objects とは別に追加したオブジェクトや削除したオブジェクトがここにセットされる事になります。さらに、WebGLRenderer と CanvasRenderer では扱いが違っていました。

Three.js の開発は WebGLRenderer 中心

WebGLRenderer では、あるタイミングで __objectsAdded や、__objectsRemoved の内部はクリアされていました。しかし、CanvasRenderer では削除しても放置状態なので、おそらく 削除しても GC の対象にはならないと思います( いずれ対応されるかもしれません )。ですが、Canvas で実行するような内容ですと、そもそも複雑なオブジェクトはレスポンス的に無理があるので、GC するまでも無いというのが実際かもしれません。

UserCube1 を Three.js の記述様式で定義する

まず、プロパティだけを Function で定義します。
THREE.UserCubes1 = function ( scene, cubeSize, cubeNum, displaySpan ) {

	// キューブの基本サイズ( 見た目は後でスケールで変化する )
	this.cubeSize = ( cubeSize !== undefined ) ? cubeSize : 20;
	// キューブの数
	this.cubeNum = ( cubeNum !== undefined ) ? cubeNum : 100;
	// 表示幅( 発生させる座標の範囲の長さ )
	this.displaySpan = ( displaySpan !== undefined ) ? displaySpan : 800;

	this.geometry = new THREE.CubeGeometry( this.cubeSize, this.cubeSize, this.cubeSize );
	this.group = null
	this.scene = scene;

	this.renew();

};
引数のデフォルト値の扱い

( cubeSize !== undefined ) ? cubeSize : 20; のような書き方は、Three.js 全体で使われている引数に対するデフォルト値の設定方法です。引数を省略すると、undefined になるので、一番右端が省略時の値になります

複数のキューブを統括する、this.group

このプロパティは、後で Object3D が設定されます。Object3D は、階層構造が可能に設計されており、その最上位が Scene であるようになっています。ここでは、変数の準備だけを行って、処理は以下のように prototype への設定となります。
THREE.UserCubes1.prototype = {
	constructor: THREE.UserCubes1,
	remove: function() {
		this.scene.remove( this.group )
		this.group = null;
	},
	renew: function() {
		if ( this.group == null ) {
			this.group = new THREE.Object3D();
			this.scene.add( this.group );
		}
		for ( var i = 0; i < this.cubeNum; i ++ ) {

			var object = new THREE.Mesh(
				this.geometry,
				new THREE.MeshBasicMaterial( {
					color: Math.random() * 0xffffff,
					transparent: true,
					opacity: 0.5 }
				)
			);

			// 正座標に発生させて、原点に半分戻す
			object.position.x = Math.random() * this.displaySpan - this.displaySpan/2;
			object.position.y = Math.random() * this.displaySpan - this.displaySpan/2;
			object.position.z = Math.random() * this.displaySpan - this.displaySpan/2;

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

			// 向きを360度ランダム
			object.rotation.x = Math.random() * 2 * Math.PI;
			object.rotation.y = Math.random() * 2 * Math.PI;
			object.rotation.z = Math.random() * 2 * Math.PI;

			this.group.add( object )

		}
	
	}
}

constructor は、常に事前に定義した Function であり、ここで実装しているメソッドは、removerenew です。renew は、UserCubes1 の持つ情報でキューブ情報を追加し続けます。remove すれば、一からですが、追加し続けた結果、記事先頭のような画像になって画面をキューブが満たして行きます。

scene から見た位置や回転は group に対して行う

個別のオブジェクトの属性を変更するメソッドは結構複雑な実装になると思いますが、全体に対して行う処理は、group が Object3D なので、普通に position や rotation や scale を group に対して実行するだけです。

※ 以下は、Chrome のコンソールで効果をテストしているところです。





posted by at 2013-03-08 00:04 | Three.js : ベーシック | このブログの読者になる | 更新情報をチェックする