ここから、実行ページを開きます( 但し、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>
|
|
【Three.jsの最新記事】
- r69 で再チェックしました / Three.js(r53) で追加された LineDashedMaterial のサンプルを簡素化して解りやすくしました
- Three.js(r69) : Lineメソッドで使用する頂点の配列を持つ Geometry オブジェクト
- Three.js : 好きな背景透過画像を飛翔させる
- Three.js : Vector3 オブジェクトのコンストラクタ / result = x || 0; という書き方
- Three.js : WebGL限定の Cube テクスチャによる『パノラマ背景』
- Three.js : 球を使った『パノラマ背景』
- Three.js の canvas_geometry_birds の『鳥』だけを取り出して考える
- ユーザ定義の THREE.UserCubes1 オブジェクトを使って、カメラでその周りを周回する
- Three.js の点線表示の詳細( 特に Windows で WebGL では線の太さは実装なし )
- Three.js でキューブの『テクスチャ面設定』とスケール・X軸回転を jQuery のスライダーでテストする
- Three.js の座標系の向きを テクスチャを貼りつけたキューブと jQuery のスライダー で確認する
- Three.js を使って DAZStudio でレンダリングした女性をちょっと湾曲した炎の前に立たす 〜 Three.js エフェクトの可能性
- Three.js 3Dゲームワールド(を夢見て)リアルサンプル
- Three.js の webgl_geometry_minecraft.html で使われている Cube World を使って、3D モデルを乗っけてカメラを動かすとかなりいい雰囲気です
- THREE.Scene クラスの remove メソッド
- Three.js の個別ソースを使った部分カスタマイズ
- Three.js : あるスケールでの平均した座標集合の作成







この画像をテクスチャとして使って、球オブジェクトを作成して、画面内に複数のオブジェクトを追加して行きます。動作としてはクリックする毎に、その位置に表示されている立方体の手前の表面に球が埋め込まれて行くことになります。
このオブジェクトは、transparent: true が設定されており、PNG 画像が背景透過なので、画面内では口の中が奥まで見えて立方体の中に入った部分は見えたり見えなかったりします( 厳密な仕様は解りません )
※ 立方体側は、opacity: 0.5
画像は同一ドメインで
ご自分で再現する場合、ソースコードそのままでほぼ動作しますが、画像のみ同一ドメインである必要があります。WebGL での仕様だと思われますが、同一ドメインの画像を用意して下さい。( ここの画像をダウンロードして使って下さい )
ページ上の部分エリア用のクリック位置判定
Three.js の殆どのサンプルページはブラウザ上のページを全て使うので必要無いですが、実際の WEB ページでは、スクロールを考慮した DIV の位置よりクリックした位置を正確に計算する必要があります。その為、ちょっと面倒ですが以下のような処理を行っています





















