マウスクリック座標からWebGL 3Dスペースでオブジェクトを取得する方法
-
28-10-2019 - |
質問
WebGLでボードゲームを構築しています。ボードを回転/ズームすることができます。 Canvas要素(x、y)のクリックを3D空間(x、y、z)の関連ポイントに変換する方法が必要です。最終的な結果は、ユーザーに最も近いオブジェクトに触れるポイントを含む(x、y、z)座標を知りたいということです。たとえば、ユーザーはピースをクリックし、ピースとゲームボードの両方を通過する3Dスペースを移動するレイを想像しますが、ピースの(x、y、z)座標が必要な時点で、触れた。
これは非常に一般的な問題であるに違いないと思いますが、グーグルに解決策を見つけることができないようです。 3Dスペースの現在のビューを2Dに投影するには、2Dスペースの各ポイントを3Dスペースの関連ポイントにマッピングできるようにする方法が必要です。ボード上のスペースの上にネズミをマウスし、スポットを変更できるようにしたいと考えています。
解決
画面座標をカメラの位置から3Dワールドにレイキャストに変換する不定関数を探しています。次に、光線と三角形の交差点テストを実行して、カメラに最も近い三角形を見つける必要があります。
で利用可能な未処理の例があります jax/camera.js#l568 - ただし、レイ/トライアングルの交差点を実装する必要があります。私はそれを実装しています jax/triangle.js#l113.
ただし、「ピッキング」と呼ばれるよりシンプルで(通常)より高速な代替品があります。オブジェクト全体(たとえば、チェスピース)を選択する場合、およびマウスが実際にクリックした場所を気にしない場合は、これを使用してください。これを行うWebGlの方法は、シーン全体をさまざまな青の色合い(青はキーであり、赤と緑がシーン内のオブジェクトの一意のIDに使用されます)でテクスチャにレンダリングし、からのピクセルを読み返します。そのテクスチャー。 RGBをオブジェクトのIDにデコードすると、クリックされたオブジェクトが表示されます。繰り返しますが、私はこれを実装しました、そしてそれはで利用可能です jax/world.js#l82. 。 (146、162、175という行も参照してください。)
どちらのアプローチにも長所と短所があります(議論されています ここ そして、その後のいくつかのコメントで)そして、あなたはあなたのニーズに最適なアプローチを把握する必要があります。ピッキングは巨大なシーンで遅くなりますが、純粋なJSでの紹介は非常に遅いです(JS自体がそれほど速くないため)。私の最善の推奨事項は両方を試すことです。
参考までに、GLUプロジェクトと不定コードを見ることもできます。 http://www.opengl.org/wiki/gluproject_and_gluunproject_code
他のヒント
私は現在この問題に取り組んでいます - 私が取っているアプローチは
- オブジェクトをレンダリングして、それぞれを一意の色で選択します
- バッファピクセルを読み取り、選択したオブジェクトに戻ります
- 各ピクセル色でバッファーに選択したオブジェクトをz-depthの関数でバッファーします
- バッファピクセルを読み取り、Z-Depthに戻ります
- ピック座標のオブジェクトと近似Zを選択しました
これが機能するデモです
function onMouseUp(event) {
event.preventDefault();
x_pos = (event.clientX / window.innerWidth) * 2 - 1;
y_pos = -(event.clientY / window.innerHeight) * 2 + 1;
z_pos = 0.5;
var vector = new THREE.Vector3( x_pos , y_pos , z_pos );
var projector = new THREE.Projector();
projector.unprojectVector(vector, camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(intersectObjects);
if (intersects.length > 0) {
xp = intersects[0].point.x.toFixed(2);
yp = intersects[0].point.y.toFixed(2);
zp = intersects[0].point.z.toFixed(2);
destination = new THREE.Vector3( xp , yp , zp );
radians = Math.atan2( ( driller.position.x - xp) , (driller.position.z - zp));
radians += 90 * (Math.PI / 180);
console.log(radians);
var tween = new TWEEN.Tween(driller.rotation).to({ y : radians },200).easing(TWEEN.Easing.Linear.None).start();
}
weissner-doors.de/drone/
スレッドの1つから栽培されています。 (x、y、z)についてはわかりませんが、 canvas(x,y)
使用
getBoundingClientRect()
function getCanvasCoord(){
var mx = event.clientX;
var my = event.clientY;
var canvas = document.getElementById('canvasId');
var rect = canvas.getBoundingClientRect();// check if your browser supports this
mx = mx - rect.left;
my = my - rect.top;
return {x: mx , y: my};
}