18

WebGL でボードゲームを作成しています。ボードは回転/ズームできます。キャンバス要素 (x,y) のクリックを 3D 空間の関連点 (x, y, z) に変換する方法が必要です。最終的な結果は、ユーザーに最も近いオブジェクトに触れる点を含む (x、y、z) 座標を知りたいということです。たとえば、ユーザーがピースをクリックすると、ピースとゲームボードの両方を通過する 3D 空間を光線が移動することを想像できますが、ピースがあった時点でのピースの (x、y、z) 座標が必要です。触れた。

これは非常に一般的な問題に違いないと思いますが、Google で解決策を見つけることができないようです。3D 空間の現在のビューを 2D に投影して、2D 空間の各ポイントを 3D 空間の関連するポイントにマッピングできるようにする方法が必要です。ユーザーがボード上のスペースにマウスを合わせて、スポットの色を変えられるようにしたい。

4

4 に答える 4

28

画面座標をカメラ位置から 3D 世界へのレイ キャストに変換する unproject 関数を探しています。次に、光線/三角形の交差テストを実行して、光線と交差するカメラに最も近い三角形を見つける必要があります。

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

于 2011-09-10T18:27:51.293 に答える
2

私は現在この問題に取り組んでいます-私が取っているアプローチは

  1. オブジェクトをレンダリングして、それぞれ固有の色のバッファを選択します
  2. バッファピクセルを読み取り、選択したオブジェクトにマップし直します
  3. 選択したオブジェクトをレンダリングして、各ピクセルの色をZ深度の関数でバッファリングします
  4. バッファピクセルを読み取り、Z深度にマップし直します
  5. オブジェクトを選択し、選択座標のZを近似しました
于 2011-10-16T13:44:53.787 に答える
1

これは動作デモです

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/

于 2013-06-28T08:44:33.097 に答える