three.js
オブジェクトピッキング
サーチ…
オブジェクトピッキング/レイキャスティング
レイキャスティングとは、画面上のマウスの位置からシーンに光線を投げることを意味します。これは、あなたがそれを実装している場合にどのオブジェクトをクリックするかを決定する方法です。 Threejsはオクツリーを使ってその情報を取得しますが、まだプロダクションでは各フレームまたはmousemove
イベントで結果を計算したくないかもしれませんが、要求の少ないよりアクセス可能なアプリのclick
イベントではそうです。
var raycaster, mouse = { x : 0, y : 0 };
init();
function init () {
//Usual setup code here.
raycaster = new THREE.Raycaster();
renderer.domElement.addEventListener( 'click', raycast, false );
//Next setup code there.
}
function raycast ( e ) {
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//3. compute intersections
var intersects = raycaster.intersectObjects( scene.children );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ] );
/*
An intersection has the following properties :
- object : intersected object (THREE.Mesh)
- distance : distance from camera to intersection (number)
- face : intersected face (THREE.Face3)
- faceIndex : intersected face index (number)
- point : intersection point (THREE.Vector3)
- uv : intersection point in the object's UV coordinates (THREE.Vector2)
*/
}
}
注意!あなたは、次の部分を読んでいない場合は、空白の画面を注視するあなたの時間を失うことがあります。
ライトヘルパーを検出する場合は、 raycaster.intersectObjects( scene.children );
2番目のパラメータを設定しますraycaster.intersectObjects( scene.children );
本当に。
これは、 raycaster.intersectObjects( scene.children , true);
意味しraycaster.intersectObjects( scene.children , true);
レイキャストコードはライトヘルパーのみを検出します。
軽いヘルパーと同様に通常のオブジェクトを検出したい場合は、上記のレイキャスト機能を再度コピーする必要があります。この質問を参照してください。
完全なレイキャストコードは
function raycast ( e ) {
// Step 1: Detect light helper
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//3. compute intersections (note the 2nd parameter)
var intersects = raycaster.intersectObjects( scene.children, true );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ] );
/*
An intersection has the following properties :
- object : intersected object (THREE.Mesh)
- distance : distance from camera to intersection (number)
- face : intersected face (THREE.Face3)
- faceIndex : intersected face index (number)
- point : intersection point (THREE.Vector3)
- uv : intersection point in the object's UV coordinates (THREE.Vector2)
*/
}
// Step 2: Detect normal objects
//1. sets the mouse position with a coordinate system where the center
// of the screen is the origin
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
//2. set the picking ray from the camera position and mouse coordinates
raycaster.setFromCamera( mouse, camera );
//3. compute intersections (no 2nd parameter true anymore)
var intersects = raycaster.intersectObjects( scene.children );
for ( var i = 0; i < intersects.length; i++ ) {
console.log( intersects[ i ] );
/*
An intersection has the following properties :
- object : intersected object (THREE.Mesh)
- distance : distance from camera to intersection (number)
- face : intersected face (THREE.Face3)
- faceIndex : intersected face index (number)
- point : intersection point (THREE.Vector3)
- uv : intersection point in the object's UV coordinates (THREE.Vector2)
*/
}
}
オブジェクトピッキング/ GPU
レイキャスティングを使用したオブジェクトのピッキングは、設定に応じて(例えば、セットアップのようなオクトリーがない場合など)、シーン内のオブジェクトの数に応じて、CPUにとって大変な作業です。
マウスカーソルの下にワールド座標を必要とせず、その下のオブジェクトを識別するためだけにGPUピッキングを使用することができます。
短い説明では、GPUは計算のための強力なツールになることができますが、結果を得る方法を知る必要があります。アイデアは、IDを表す色でオブジェクトをレンダリングすると、カーソルの下のピクセルの色を読み取って、選択されたオブジェクトのIDを見つけることができます。 RGBは16進数の値なので、id(整数)とcolor(16進)の間に変換が存在することを覚えておいてください。
- オブジェクトの新しいシーンと新しいレンダリングターゲットを作成する
var pickingScene = new THREE.Scene();
var pickingTexture = new THREE.WebGLRenderTarget(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
pickingTexture.texture.minFilter = THREE.LinearFilter;
- オブジェクトピッキングのための新しいシェーダマテリアルを作成します。
var vs3D = `
attribute vec3 idcolor;
varying vec3 vidcolor;
void main(){
vidcolor = idcolor;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0);
}`;
var fs3D = `
varying vec3 vidcolor;
void main(void) {
gl_FragColor = vec4(vidcolor,1.0);
}`;
var pickingMaterial = new THREE.ShaderMaterial(
{
vertexShader: vs3D,
fragmentShader: fs3D,
transparent: false,
side: THREE.DoubleSide
});
- メッシュ/線のジオメトリに、RGBでIDを表す新しい属性を追加し、同じジオメトリを使用してpickingObjectを作成してピッキングシーンに追加し、実際のメッシュをid->オブジェクト辞書に追加します
var selectionObjects = [];
for(var i=0; i<myMeshes.length; i++){
var mesh = myMeshes[i];
var positions = mesh.geometry.attributes["position"].array;
var idColor = new Float32Array(positions.length);
var color = new THREE.Color();
color.setHex(mesh.id);
for (var j=0; j< positions.length; j+=3){
idColor[j] = color.r;
idColor[j+1] = color.g;
idColor[j+2] = color.b;
}
mesh.geometry.addAttribute('idcolor', new THREE.BufferAttribute(idColor, 3));
var pickingObject = new THREE.Mesh(mesh.geometry, pickingMaterial);
pickingScene.add(pickingObject);
selectionObjects[mesh.id] = mesh;
}
- 最後に、マウスクリックハンドラで
renderer.render(pickingScene, camera, pickingTexture);
var pixelBuffer = new Uint8Array(4);
renderer.readRenderTargetPixels(pickingTexture, event.pageX, pickingTexture.height - event.pageY, 1, 1, pixelBuffer);
var id = (pixelBuffer[0] << 16) | (pixelBuffer[1] << 8) | (pixelBuffer[2]);
if (id>0){
//this is the id of the picked object
}else{
//it's 0. clicked on an empty space
}