web-dev-qa-db-ja.com

Three.js:シーンの隅に世界座標軸を表示する

これはおそらく非常に基本的な問題ですが、私はまだ解決策を見つけておらず、それは私を悩ませています。 Mayaで行われているように、カメラの右下隅に世界座標の方向(x、y、z)を示す矢印を表示したいので、オブジェクトの周りでカメラを回転させたり、シーン内を移動したりすると、あなたはまだ世界座標の方向を特定することができます。私は2つの異なるアプローチを使用してこれを達成しようとしましたが、どちらも今のところうまくいきません。

_THREE.ArrowHelper_クラスを使用する子として3つの矢印を持つオブジェクトがあります。ここでは、それをXYZと呼びます。最初のアプローチは、XYZをシーンの子にし、カメラの現在の位置とカメラが指している方向のオフセットから計算された位置を提供し、必要なコーナーに表示されるように調整することです。画面の中央ではなくに。矢印が正しい回転を維持しているので、これはほぼ機能していますが、位置が少しおかしいので、カメラを動かすときに本当に「ぎこちない」ので、このルートを下るのをやめました。パフォーマンスの問題なのか、それとも他の問題なのかわかりません。

2番目の方法は、ローカル位置オフセットを使用してXYZをカメラの子にし、カメラの回転を逆にして、逆回転をXYZに適用してワールド座標と一致させることです。この方法を使用すると、近くにいるように見えますが、両方ではなく、正しい位置または回転のいずれかを取得できます。

現在、コードXYZ.matrix.extractRotation( camera.matrixWorldInverse );を使用してXYZの正しい方向を指定していますが、配置がオフになっています。 XYZ.matrixWorld.extractRotation( camera.matrixWorldInverse );を使用すると、位置は正常(カメラに接続)のままですが、向きは変わりません。

誰かがこれを機能させるための簡単なハックを持っているなら、それは大いにありがたいです。私が追求している方法よりも優れた方法がある場合は、それも役立ちます。

13
wackozacko

これは ここ の前に出てきました。

秘訣は、元のカメラと同じ向きで、原点から指定された距離を維持する2番目のカメラで2番目のシーンを追加することです。

camera2.position.copy( camera.position );
camera2.position.sub( controls.target );
camera2.position.setLength( CAM_DISTANCE );
camera2.lookAt( scene2.position );

編集:更新されたフィドル: http://jsfiddle.net/aqnL1mx9/

three.js r.69

18
WestLangley

新しいthree.js使用できるバージョン:

var axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );

参照: AxesHelper

14
Andres
var camera, scene, renderer, geometry, material, mesh, axisHelper, localToCameraAxesPlacement;

init();
animate();

function init() {

    scene = new THREE.Scene();

    camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
    camera.position.z = 500;
    camera.up = new THREE.Vector3(0,0,1);
    scene.add(camera);
    
    axisHelper = new THREE.AxisHelper( 0.1 )
    localToCameraAxesPlacement = new THREE.Vector3(0.45 * camera.aspect,-0.45, -2); // make sure to update this on window resize
                scene.add(axisHelper)

    geometry = new THREE.CubeGeometry(200, 200, 200);
    material = new THREE.MeshNormalMaterial();

    mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);

    renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);

    document.body.appendChild(renderer.domElement);

}

function animate() {

    requestAnimationFrame(animate);
    render();

}

var t = 0
function render() {
    t++
    
    camera.position.x = Math.cos(t/80) * 500
    camera.position.y = Math.sin(t/80) * 500
    camera.lookAt(mesh.position)
    
    camera.updateMatrixWorld()
    var axesPlacement = camera.localToWorld(localToCameraAxesPlacement.clone())
                axisHelper.position.copy(axesPlacement);

    renderer.render(scene, camera);

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/87/three.min.js"></script>

これは、追加のシーンを作成せずにAxisHelperを追加するための「迅速で汚い」方法です。これは、レンダリングのたびにカメラの前で軸ヘルパーを移動することで機能します。

// Initialize
var scene = getScene();
axisHelper = new THREE.AxisHelper( 0.1 );
var localToCameraAxesPlacement = new THREE.Vector3(0.45 * camera.aspect,-0.45,-2); // make sure to update this on window resize
scene.add(axisHelper);

// On every render
var camera = getCamera();
camera.updateMatrixWorld();
var axesPlacement = camera.localToWorld(localToCameraAxesPlacement.clone());
axisHelper.position.copy(axesPlacement);
3
seveibar

少し遅れていることはわかっていますが、複数のシーンをレンダリングするソリューションを備えたコードサンドボックスがあります https://codesandbox.io/s/eager-glade-46ung

それは少しぎこちなく、JSにとっては初めてのことかもしれません。これは threejsfundamentals のチュートリアルに基づいています。スクリーのさまざまな部分を適切にレンダリングするために、renderer.setScissor関数を使用します。これは、この設定を使用して、メインシーンを追跡しながら、ある種のデバッグウィンドウを作成できることも意味します...おそらくAxesヘルパー用のウィンドウです。

スクリプトの重要な部分は、描画が行われる領域を定義することです。これは、測定を0-1スペースで維持し、キャンバスサイズを使用して適切にスケーリングすることによって行われます。

var nleft = Math.floor(canvas.width * left);
var nbottom = Math.floor(canvas.height * bottom);
var nwidth = Math.floor(canvas.width * width);
var nheight = Math.floor(canvas.height * height);
1
9301293