SQLの窓

2013年03月30日

Three.js(r57) : THREE.Texture のプロパティの意味

THREE.ImageUtils.loadTexture

まず、画像を loadTexture で読み込むわけですが、この際指定するのは URL です。そして、実行後返されるのが THREE.Texture になります。
CanvasRenderer で別ドメインの画像を読み込む場合は、loadTexture 実行前に、THREE.ImageUtils.crossOrigin = null; を実行して下さい
この THREE.Texture のコンストラクタの引数は、以下のようになっています。
THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
これらは、loadTexture の中で、『var texture = new THREE.Texture( image, mapping );』として処理されているので wrapS 以降はデフォルト値となります。

wrapS, wrapT

この二つの値は、テクスチャの x座標(S) と y座標(T) 方向の処理方法をセットする事ができ、その値は以下の三種類です。
// Wrapping modes

THREE.RepeatWrapping = 1000;
THREE.ClampToEdgeWrapping = 1001;
THREE.MirroredRepeatWrapping = 1002;
デフォルトは、THREE.ClampToEdgeWrapping で、テクスチャを面に対して伸縮してセットする事を意味します。THREE.RepeatWrappingTHREE.MirroredRepeatWrapping は、それぞれテクスチャを繰り返してマッピングするもので、前者は境界毎に同じものが繰り返され、後者は境界毎に反転されたものが使用されます。 但し、繰り返し指定時には、プロパティの repeat に対して x 座標方向と y座標方向に繰り返す数を set メソッドで指示する必要があります。
例) map.repeat.set( 1, 3 );
※ (注意) CanvasRenderer では、THREE.MirroredRepeatWrapping は動作しません( WebGLRenderer は動作します ) CanvasRenderer ( これはバグっぽいですね ) 正常なソースコード WebGLRenderer anisotropy このプロパティは、デフォルトでは 1 ですが、大きくする事によってテクスチャのマッピングの品質を上げます。しかし、実際は目視してもほとんど変わらない事が多いと思います。 いずれのプロパティも、3D の処理における一般的な呼び名で、Three.js 内で説明を見つける事はできませんが、インターネットでは解説の中で当たり前のように表現されています。 その他のデフォルト値 mapping : new THREE.UVMapping() magFilter : THREE.LinearFilter minFilter : THREE.LinearMipMapLinearFilter format : THREE.RGBAFormat; type : THREE.UnsignedByteType;
タグ:Three.js
posted by at 2013-03-30 02:33 | Three.js : ベーシック | このブログの読者になる | 更新情報をチェックする

2013年03月24日

Three.js の canvas_geometry_birds の『鳥』だけを取り出して考える



飛ばしている画像



こんな感じで以下で表示できます。
本来オリジナルで飛ばしているものは、8つの点からなるオブジェクトです。形は上から見ると以下のようになります。



この座標は x と z の座標軸で、通常の Three.js 空間で見たときは地面に対して平行な形です。実際の動きのアルゴリズムは良く解りませんのですが、動く際には必ずしも頭の方向が移動方向とは限らないようです。ただ、羽のはばたきは、この座標の2点を上下に動かして表現しています。(その位置の算出方法もまた良くわかりません)。ですから、この Bird オブジェクトのかわりに平面オブシェクトを使い、その上部の二点を同様に動かす事によって、飛翔する表現を自由に変更る事ができます。

飛翔する初音ミク

Bird の代わりに平面
	var image = new Image()
	image.onload = function () {

		texture = new THREE.Texture( this );
		texture.needsUpdate = true;
		material = new THREE.MeshBasicMaterial({map: texture, overdraw: true});
		material.side = 2

		for ( var i = 0; i < 200; i ++ ) {

			boid = boids[ i ] = new Boid();
			boid.position.x = Math.random() * 400 - 200;
			boid.position.y = Math.random() * 400 - 200;
			boid.position.z = Math.random() * 400 - 200;
			boid.velocity.x = Math.random() * 2 - 1;
			boid.velocity.y = Math.random() * 2 - 1;
			boid.velocity.z = Math.random() * 2 - 1;
			boid.setAvoidWalls( true );
			boid.setWorldSize( 500, 500, 400 );

			birds[ i ] = new THREE.Mesh( new THREE.PlaneGeometry(30, 30, 2, 1), material );
			bird = birds[ i ]
			bird.phase = Math.floor( Math.random() * 62.83 );
			bird.position = boids[ i ].position;
			scene.add( bird );

		}
		
	};
	image.src = "http://lh3.googleusercontent.com/-4Em5315jEAI/T_GVyEMF5BI/AAAAAAAAHBg/s78i3fY94vU/s60/Black_Eagle_Miku_Elf4.png";

後は、render の中の座標変更で x 軸を 90度 rotation して地面に対して平行にして、羽ばたく対象の頂点を設定します。

bird.geometry.vertices[ 0 ].z
bird.geometry.vertices[ 2 ].z
に、Math.sin( bird.phase ) * 15;

を設定していますが、15は係数で、オリジナルは 5 でしたが実行しながら調整しました。


posted by at 2013-03-24 02:40 | Three.js | このブログの読者になる | 更新情報をチェックする

2013年03月20日

できる限りだれでも Three.js を楽しめるように、Three.js の基本コードをできる限り簡単にして、オブジェクトやアニメーション部分をホスティングしてみました

表示したいオブジェクトのコードと、アニメーションの方法(この場合はカメラが周回する)を、Three.js の名前空間である THREE に定義して外部 JavaScript として参照して実行しています。また、ここはブログなので IFRAME にその内容を書き込んでいます。

THREE.UserCubes1 
THREE.UserPlay1 
Three.js のサンプルコードには、ピンからキリまであって、相当のプログラマでもさっぱり解らないものもあります。しかし、構成としては二つのパターンがあり、一つはその場でアニメーションや入力インターフェイスのイベントコードを全部書くものと、そのへんはコントロールクラスに任せてオブジェクトのみを書くものです。

他人が使うアプリならば、前者である必要がありますが、単にテストするだけならば後者が簡単です。ですが、後者もまだ外部のユーティリティレベルでおまけみたいなものなので、内容は中を読む必要があります。

ここでは、前者のほうを自前で切り取って、本体の部分の構成を明確にしています。結局は、カメラとシーンとレンダラーが基本で、表示するオブジェクトがあってはじめて静止画が可能になり、アニメーションループによって動きだします。

その、それぞれの役割が以下のソースでは明確になっているはずです。
<script type="text/javascript">
if ( window['loadThree'] !== true ) {
	window['loadThree'] = true;
	document.write("<"+"script type=\"text/javascript\" src=\"http://homepage2.nifty.com/lightbox/three/three.min56.js\"></"+"script>");
}
</script>
<script type="text/javascript" src="http://homepage2.nifty.com/lightbox/three/user_cubes1.js" charset="utf-8"></script>
<script type="text/javascript" src="http://homepage2.nifty.com/lightbox/three/user_play1.js" charset="utf-8"></script>

<input type="text" id="radius" value="800" /><input type="button" value="半径変更" onclick='user_play.radius = eval(document.getElementById("radius").value);console.dir(user_play)' />
<script type="text/javascript">

var w = 600;
var h = 500;
document.write("<div id=\"three_area\" style='width:"+w+"px;height:"+h+"px;'></div>");

var camera, scene, renderer;
var user_play;

build_3d_world();

function build_3d_world() {

	// カメラ
	camera = new THREE.PerspectiveCamera( 70, w / h, 1, 10000 );
	// シーン
	scene = new THREE.Scene();
	// 表示対象
	var UserCubes = new THREE.UserCubes1( scene );
	// レンダラー
	renderer = new THREE.CanvasRenderer();
	renderer.setSize( w, h );
	document.getElementById("three_area").appendChild( renderer.domElement );

	// アニメーション
	user_play = new THREE.UserPlay1( scene, camera, renderer, animate );
	user_play.start();

}
function animate() {

	requestAnimationFrame( animate );
	user_play.render();

}

</script>

ここで、THREE.UserCubes1 は、表示対象のオブジェクトの集合です。THREE.UserPlay1 は、アニメーションの方法をクラスで定義して、インスタンスで処理するようにしており、中の render メソッドに具体的な処理が書かれています。

その render メソッド内で使う変数が、THREE.UserPlay1 でインスタンスのプロパティとして定義されています。ループ処理は『仕様』上どうしてもグローバルに書く必要があるので外に出していますが、必要な処理は常に 2行です。
requestAnimationFrame( animate );
user_play.render();
render メソッドの中にバリエーションを作れば、アニメーション方法をプロパティやメソッドで変更できるように改造する事もできます。 それ以外はカメラは作るだけ。シーンも表示対象も作るだけです。レンダラーのみ、コンストラクタでサイズ指定できないので、メソッドを呼んでいます。そして、レンダラーだけでは表示できないので、表示可能なブラウザのエリアに登録します。
renderer.domElement を div へ追加
アニメーションの開始は、外部に定義した animate を呼び出せばいいのですが、整理上 UserPlay1 のメソッドして呼び出しています。 ボタンをクリックするとプロパティが変更されて、実行中のインスタンスの中でカメラと被写体との距離が変更されるようになっています。
半径 0 は、仕様で動作しません。半径 1 でシーンの中心にカメラが移動します。

x と z 軸の平面に対して、y 軸にも移動しているので、カメラの Far(10000) より少ない値で見えなくなります。
アニメーションは常に描画の繰り返しなので、変数の内容を変更するとたいていの状態変更が可能です( 中には、Three.js の内部にしか無いものがありますが、それは Three.js がまだまだ、ライブラリとして発展途上だからです )
posted by at 2013-03-20 23:23 | Three.js : ベーシック | このブログの読者になる | 更新情報をチェックする

2013年03月18日

ユーザ定義の THREE.UserCubes1 オブジェクトを使って、カメラでその周りを周回する



THREE.UserCubes1 は、複数のキューブを一つの Object3D にまとめたもので、作成メソッドと削除メソッドを持ちます。

実行ページ

コンストラクタ

❶ シーン
❷ キューブの基本サイズ ( 規定値 20 )
❸ キューブの数 ( 規定値 100 )
❹ 表示幅( 発生させる座標の範囲の長さ ) ( 規定値 : 800 )

その他

カメラのコンストラクタの最後の引数は、描画対象とする最も遠い距離で、この距離を超えた物体は描画されません。
<script type="text/javascript">
// 主となるライブラリを複数回ロードしない
if ( window['loadThree'] !== true ) {
	window['loadThree'] = true;
	document.write("<"+"script type=\"text/javascript\" src=\"http://homepage2.nifty.com/lightbox/three/three.min56.js\"></"+"script>");
}
</script>
<!-- ユーザ定義オブジェクト -->
<script type="text/javascript" src="http://homepage2.nifty.com/lightbox/three/user_cubes1.js" charset="utf-8"></script>

<script type="text/javascript">

var w = 600;
var h = 500;

// 変数から表示エリアを作成
document.write("<div id=\"three_area\" style='width:"+w+"px;height:"+h+"px;'></div>");

// お決まり『三種の神器』
var camera, scene, renderer;

// 環境作成
init();

// ループ処理
animate();

// ****************************************************************
// 表示環境の準備( 開始は animate )
// ****************************************************************
function init() {

	// ********************************************************
	// 引数について : http://mrdoob.github.com/three.js/docs/56/#Reference/Cameras/PerspectiveCamera を参照、
	// 概念について : https://github.com/landongn/three.js-tutorials/tree/master/1 の画像を参照
	// FOV について : http://ja.wikipedia.org/wiki/%E7%94%BB%E8%A7%92 を参照
	// ********************************************************

	// カメラ作成
	camera = new THREE.PerspectiveCamera( 70, w / h, 1, 10000 );

	// ********************************************************
	// http://mrdoob.github.com/three.js/docs/56/#Reference/Math/Vector3
	// x、y、z は結局 render で決定する
	// ********************************************************
	camera.position.set( 0, 0, 0 );

	// シーン作成
	scene = new THREE.Scene();

	// ********************************************************
	// メインオブジェクト作成
	// 初期値 : cubeSize:20, cubeNum:100, displaySpan:800
	// 1) キューブの基本サイズ( 見た目は後でスケールで変化する )
	// 2) キューブの数
	// 3) 表示幅( 発生させる座標の範囲の長さ )
	// ********************************************************
	var UserCubes = new THREE.UserCubes1( scene );

	// Canvas レンダラー作成
	renderer = new THREE.CanvasRenderer();
	// 表示を定義サイズと一致させる
	renderer.setSize( w, h );

	// ********************************************************
	// 指定した DOM 内に 3D 表示用の空間を作成する
	// ********************************************************
	document.getElementById("three_area").appendChild( renderer.domElement );

}

function animate() {

	requestAnimationFrame( animate );
	render();

}

var radius = 600;
var theta = 0;

// ********************************************************
// 半径 600 で シーンの中心を周回する
// ********************************************************
function render() {

	theta += 0.1;

	// ************************************************
	// x が sin で、z が cos なので、周回軌道。(上から見たら半径600の円運動)
	// 但し、y は、その時の x の値と同じ値だけ上下
	// ( カメラから見たら、被写体が上に行ったり下に行ったりする )
	// ************************************************
	camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) );
	camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) );
	camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );

	// カメラをシーンの中心に向ける
	camera.lookAt( scene.position );

	// 実際の描画
	renderer.render( scene, camera );

}

</script>
関連する記事

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

関連する情報

カメラの引数
FOV( Wikipedia )
カメラの near と far 

位置オブジェクト(Vector3)


posted by at 2013-03-18 01:45 | Three.js | このブログの読者になる | 更新情報をチェックする

2013年03月16日

TCPDF : getPageDimensions の中身

getPageDimensions は、ページ数を引数に取れますが、とりあえず省略して 
$dm = $pdf->getPageDimensions();
file_put_contents("log.txt", print_r($dm,true)); 
で出力しました。 処理としては、上下余白サイズをページの縦サイズから差し引いて座標して行く為です。
Array
(
    [MediaBox] => Array
        (
            [llx] => 0
            [lly] => 0
            [urx] => 595.276
            [ury] => 841.89
        )

    [CropBox] => Array
        (
            [llx] => 0
            [lly] => 0
            [urx] => 595.276
            [ury] => 841.89
        )

    [BleedBox] => Array
        (
            [llx] => 0
            [lly] => 0
            [urx] => 595.276
            [ury] => 841.89
        )

    [TrimBox] => Array
        (
            [llx] => 0
            [lly] => 0
            [urx] => 595.276
            [ury] => 841.89
        )

    [ArtBox] => Array
        (
            [llx] => 0
            [lly] => 0
            [urx] => 595.276
            [ury] => 841.89
        )

    [Rotate] => 0
    [PZ] => 1
    [w] => 595.276
    [h] => 841.89
    [wk] => 210.00014444444
    [hk] => 297.00008333333
    [tm] => 10.00125
    [bm] => 20.0025
    [lm] => 10.00125
    [rm] => 10.00125
    [pb] => 1
    [or] => P
    [olm] => 10.00125
    [orm] => 10.00125
)

利用サンプルソースコード



posted by at 2013-03-16 04:12 | PHP+PDF | このブログの読者になる | 更新情報をチェックする

2013年03月09日

IE10 for Windows7 を我慢できなくってインストールしたんですが、『それでも Microsoft かよ』と、思わずつぶやきたくなる件について。



ブラウザのテーブルを Microsoft の Excel にコピーした結果です。( 下にあるのは他の賢いブラウザ達 )

元のテーブルはこんなかんじ。
<table>
<tr>
<td>1</td><td>2</td><td>3</td>
</tr>
<tr>
<td>1</td><td>2</td><td>3</td>
</tr>
<tr>
<td>1</td><td>2</td><td>3</td>
</tr>
</table>

これはあんまりですよねぇ・・・。IE10 になったらてっきりうまく行くと思っていたのに、酷いです。ちなみに、IE9 では、スペースのかわりに改行が入っていたはずです。『ちょっとだけ進歩した・・・』『なんでやねん!』って一人で突っ込んでましたけど。

IE10 の言語別ダウンロード

言語を選択して、32ビットか64ビットかを選択して、すぐインストールできるファイルをダウンロードします。

で、インストールに邪魔なものは全て停止を要求するんですが、インストール中は、エクスプローラさえ強制終了しました(不安すぎる)。で、終わった後飛ばされたページがこちら。

新しいブラウザーを試しましょう

このページの meta 情報が以下。
<meta property="og:description" content="新しいブラウザー (Windows 7 用の Internet Explorer 10 Release Preview) について学びます。" />

『なんでやねん・・・・』


posted by at 2013-03-09 03:35 | IE | このブログの読者になる | 更新情報をチェックする

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 : ベーシック | このブログの読者になる | 更新情報をチェックする

2013年03月04日

Three.js の名前空間でユーザオブジェクトを作って、Three.js の基本を再確認する


実行ページ

THREE.UserCubes1

ここで、ユーザオブジェクトとしているのは、複数のキューブをシーンに追加しているだけなので、それぞれのキューブの削除や操作は実装していません。極端に言えば単に記述場所を別にしただけですが、それでも本体はとても見やすくなっているはずです。

Three.js サンプルの一般的な構成

サンプルには、ステータス等動作に関係のないものがありますが、必要な基本部品は以下の4つになります。

❶ カメラ
❷ シーン
❸ レンダラー( 描画 )
❹ オブジェクト

オブジェクトは、実際目に見えるものでいろいろなパターンがありますが、それ以外は必ずカメラとシーンとレンダラーの三点セットとなっています。

init 関数で環境作成

この部分で、❶ 〜 ❹ を作成しますが、ここで描画が行われるわけではありません。この後、ループ処理に入って初めてアニメーションとして実装されます。

init 関数は名前はなんでもいいのですが、まずカメラを作成し、シーンを作成します。この二つのオブジェクトは単独で存在し、お互いの関係を計算して描画するのがレンダラーです。

そのレンダラーがレンダラーとしての役目を実行するのはループ処理の中であって、init 関数の中ではありません。ここでは、レンダラーは作成された後に、ブラウザの描画エリアへ登録されます。
document.getElementById("three_area").appendChild( renderer.domElement );
登録されただけでは描画はされず、この後アニメーションが必要無いのであれば、静止画として以下の二行を実行する事になります。
camera.lookAt( scene.position );
renderer.render( scene, camera );
実際表示されるのは、シーンに追加されたオブジェクトなので、第❹番目の要素として、init 関数では、シーンに対して追加して行く事になります。
requestAnimationFrame でループ処理 このメソッドは、Three.js では無く、DOM のメソッドです。このメソッドによって、次の描画時に呼ばれるメソッドを登録するのですが、一回描画する毎に自分自身を登録するので結果的にループ処理を実行する事になります ( IE9 にこのメソッドが無いので、Three.js は setTimeout で代用した関数を定義してくれています ) Microsoft と Mozilla のドキュメント requestAnimationFrame メソッド (Windows) window.requestAnimationFrame - DOM | MDN
<script type="text/javascript" src="http://homepage2.nifty.com/lightbox/three/three.min56.js"></script>
<div id="three_area" style='width:600px;height:500px;'></div>

<script type="text/javascript">
// WebGL チェック
//if( !( function () { try { return !! window.WebGLRenderingContext && !! //document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )() ) {
//	document.write("<span style='font-weight:bold;font-size:30px;'>WebGLが使用できません</span>");
//	document.getElementById("three_area").style.display = 'none';
//}

// Three.js の名前空間でオブジェクト作成
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.objects = [];

	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.objects.push( object );
		scene.add( object );

	}

};


var w = 600;
var h = 500;

var camera, scene, renderer;

init();
animate();

function init() {

	// カメラ作成
	camera = new THREE.PerspectiveCamera( 70, w / h, 1, 10000 );
	camera.position.set( 0, 300, 500 );

	// シーン作成
	scene = new THREE.Scene();

	// メインオブジェクト作成
	var UserCubes = new THREE.UserCubes1( scene );

	// レンダラー作成
	renderer = new THREE.CanvasRenderer();
	renderer.setSize( w, h );

	// 配置
	document.getElementById("three_area").appendChild( renderer.domElement );

}

function animate() {

	requestAnimationFrame( animate );
	render();

}

var radius = 600;
var theta = 0;

function render() {

	theta += 0.1;

	camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) );
	camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) );
	camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
	camera.lookAt( scene.position );

	renderer.render( scene, camera );

}

</script>

コメントの WebGL チェックは、レンダラーを WebGL に変更した時に使用します。


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

2013年03月03日

Three.js : カメラが発射する Ray(光) にヒットするオブジェクトを総取りする


ここから、実行ページを開きます( 但し、WebGL でのみ動作します )

カメラを使った当たり判定

要するに、マウスクリックに対する座標を使って、3D エリア内のオブジェクトとの当たり判定を行います。

画面に対して垂直に光線が進んで行き、その光線に触れたオブジェクトが最初に接した座標が一覧として取得できるようになっています。

※ ソース内では、intersects がそれです。

当たった位置に新しいオブジェクトを作成



この画像をテクスチャとして使って、球オブジェクトを作成して、画面内に複数のオブジェクトを追加して行きます。動作としてはクリックする毎に、その位置に表示されている立方体の手前の表面に球が埋め込まれて行くことになります。

このオブジェクトは、transparent: true が設定されており、PNG 画像が背景透過なので、画面内では口の中が奥まで見えて立方体の中に入った部分は見えたり見えなかったりします( 厳密な仕様は解りません )
※ 立方体側は、opacity: 0.5

画像は同一ドメインで

ご自分で再現する場合、ソースコードそのままでほぼ動作しますが、画像のみ同一ドメインである必要があります。WebGL での仕様だと思われますが、同一ドメインの画像を用意して下さい。( ここの画像をダウンロードして使って下さい )

ページ上の部分エリア用のクリック位置判定

Three.js の殆どのサンプルページはブラウザ上のページを全て使うので必要無いですが、実際の WEB ページでは、スクロールを考慮した DIV の位置よりクリックした位置を正確に計算する必要があります。その為、ちょっと面倒ですが以下のような処理を行っています
var parent = document.getElementById("three_area")
while (parent) {
	numx += parent.offsetLeft;
	numy += parent.offsetTop;
	parent = parent.offsetParent;
}
さらに、ブラウザによってスクロール距離の取得場所が違うので、現時点で以下のように書いています。( 将来的にはどうなるか解らないので注意 ) var top = document.documentElement.scrollTop + document.body.scrollTop
<script type="text/javascript" src="http://homepage2.nifty.com/lightbox/three/three.min56.js"></script>
<div id="three_area" style='width:600px;height:500px;'></div>

<script type="text/javascript">
if( !( function () { try { return !! window.WebGLRenderingContext && !! document.createElement( 'canvas' ).getContext( 'experimental-webgl' ); } catch( e ) { return false; } } )() ) {
	document.write("<span style='font-weight:bold;font-size:30px;'>WebGLが使用できません</span>");
	document.getElementById("three_area").style.display = 'none';
}

var w = 600;
var h = 500;
var numx = 0;
var numy = 0;

var container;
var camera, scene, projector, renderer;

var texture,material;

init();
animate();

function init() {

	camera = new THREE.PerspectiveCamera( 70, w / h, 1, 10000 );
	camera.position.set( 0, 300, 500 );

	scene = new THREE.Scene();

	var geometry = new THREE.CubeGeometry( 20, 20, 20 );

	for ( var i = 0; i < 1000; i ++ ) {

		var object = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, transparent: true,opacity: 0.5 } ) );
		object.position.x = Math.random() * 800 - 400;
		object.position.y = Math.random() * 800 - 400;
		object.position.z = Math.random() * 800 - 400;

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

		object.rotation.x = Math.random() * 2 * Math.PI;
		object.rotation.y = Math.random() * 2 * Math.PI;
		object.rotation.z = Math.random() * 2 * Math.PI;

		scene.add( object );

	}

	// Ray 判定用のプロジェクター
	projector = new THREE.Projector();

	renderer = new THREE.WebGLRenderer();
	renderer.setSize( w, h );

	document.getElementById("three_area").appendChild( renderer.domElement );

	document.addEventListener( 'mousedown', onDocumentMouseDown, false );

	var image = new Image()
	image.onload = function () {

		texture = new THREE.Texture( this );
		texture.needsUpdate = true;
		material = new THREE.MeshBasicMaterial({map: texture, transparent: true});
	};
	image.src = "http://lightbox.matrix.jp/imgpatio/smile.png";

	var parent = document.getElementById("three_area")
	while (parent) {
		numx += parent.offsetLeft;
		numy += parent.offsetTop;
		parent = parent.offsetParent;
	}


}

// *********************************************
// クリックした位置の Ray 判定 
// *********************************************
function onDocumentMouseDown( event ) {

	var top = document.documentElement.scrollTop + document.body.scrollTop

	event.preventDefault();

	// 対象座標のベクタ( 0.5 は 1 でも良いはず。意味が解りやすい 0.5 が使われている )
	var vector = new THREE.Vector3( (( event.clientX - numx ) / w ) * 2 - 1, - ( (event.clientY - (numy - top) ) / h ) * 2 + 1, 0.5 );
	projector.unprojectVector( vector, camera );

	// Ray 判定の本体
	var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );

	// 対象となるオブジェクトの一覧の取得
	var intersects = raycaster.intersectObjects( scene.children );

	if ( intersects.length > 0 ) {

		var mesh = null;

		for( var i = 0; i < intersects.length; i++ ) {

			// テクスチャ付の球オブジェクト
			mesh = new THREE.Mesh(new THREE.SphereGeometry(15, 20, 20), material);
			mesh.position = intersects[ i ].point;
			mesh.rotation.y = Math.random() * Math.PI * 2;
			scene.add(mesh);

		}

	}
}

function animate() {

	requestAnimationFrame( animate );
	render();

}

var radius = 600;
var theta = 0;

function render() {

	theta += 0.1;

	camera.position.x = radius * Math.sin( THREE.Math.degToRad( theta ) );
	camera.position.y = radius * Math.sin( THREE.Math.degToRad( theta ) );
	camera.position.z = radius * Math.cos( THREE.Math.degToRad( theta ) );
	camera.lookAt( scene.position );

	renderer.render( scene, camera );

}

</script>


posted by at 2013-03-03 08:00 | Three.js | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します


Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX