2017-05-25 6 views
1

マウスを動かすと、3次元位置が2次元に更新されます。画面位置に投影する3Dオブジェクトが多数存在する可能性があるため、パフォーマンスの問題が発生します。3Dからスクリーンへの読み込み位置を変更するときの計算を加速する方法

計算を高速化する手段はありますか?以下は、2次元スクリーン上の3次元オブジェクトの位置を計算する方法です。

function toScreenPosition(obj) { 
    var vector = new THREE.Vector3(); 
    //calculate screen half size 
    var widthHalf = 0.5 * renderer.context.canvas.width; 
    var heightHalf = 0.5 * renderer.context.canvas.height; 
    //get 3d object position 
    obj.updateMatrixWorld(); 
    vector.setFromMatrixPosition(obj.matrixWorld); 
    vector.project(this.camera); 
    //get 2d position on screen 
    vector.x = (vector.x * widthHalf) + widthHalf; 
    vector.y = -(vector.y * heightHalf) + heightHalf; 

    return { 
     x: vector.x, 
     y: vector.y 
    }; 
} 
+0

関数が呼び出されるたびに新しい 'THREE.Vector3'をインスタンス化しないでください。それを作成して再利用してください。関数が戻るときに新しいオブジェクトをインスタンス化しないでください。すべての呼び出しで 'width/heighHalf'を再計算しないでください。また、 'obj.updateMatrixWorld()'も呼び出さないでください。レンダラーはフレームごとにそれを呼び出します。 – WestLangley

+0

@WestLangleyあなたのソリューションをテストしましたか?私はそれが私の問題を解決することができないと思う100以上の2次元の画面で位置を計算するシーンの泥オブジェクト。私は今object3dを使用していないので、object3dの中心点をVector3だけと言って計算してください。 –

+0

@WestLangleyが書いたことはほぼ普遍的に真実であり、ある程度パフォーマンスを向上させるでしょう。しかし、十分ではないかもしれません。もう一つの可能​​な最適化は '.project()' -callです。これは内部的にカメラのmatrixWorldInverseを計算する必要がありますが、これは非常に高価な操作です。フレーム全体に渡って変換行列の計算をキャッシュする方法で再実装することを検討する必要があります:https://github.com/mrdoob/three.js/blob/ae2cda96f52b763b27b9c0cf77f1a9ed498fd706/src/math/Vector3.js#L318 -L323 - あなたはJSがうまく処理できるいくつかの計算を残します –

答えて

1

ではなく、ワールド空間にカメラが移動して、あなたのカメラオブジェクトへのあなたのHUDオブジェクト(複数可)を追加し、一度だけそれらを配置するたびに、あなたのHUDを再配置します。その後、カメラが動くと、HUDはそれに沿って動きます。カメラの変形が子供たちにカスケードされるからです。

yourCamera.add(yourHUD); 
yourHUD.position.z = 10; 

このようにそれをやって(あるいはそれにあなたがいた道を配置する)シーンオブジェクトは、あなたのHUDの形状でクリップすることができ、あるいはあなたのHUDとカメラの間に表示され、HUDを曖昧にすることに注意してください。それがあなたが望むものなら、素晴らしい!そうでない場合は、HUDを2番目のレンダーパスに移動し、それを「上に」残すことができます。上記のコメントに書かれたよう

1

まず、ここでは(ほとんど)のために書き直さあなたの関数の例で最適なパフォーマンス、renderloopが明らかに呼び出す行うに説明するための単なる一例である:

var width = renderer.context.canvas.width; 
var height = renderer.context.canvas.height; 

// has to be called whenever the canvas-size changes 
function onCanvasResize() { 
    width = renderer.context.canvas.width; 
    height = renderer.context.canvas.height; 
}); 

var projMatrix = new THREE.Matrix4(); 

// renderloop-function, called per animation-frame 
function render() {  
    // just needed once per frame (even better would be 
    // once per camera-movement) 
    projMatrix.multiplyMatrices( 
    camera.projectionMatrix, 
    projMatrix.getInverse(camera.matrixWorld) 
); 

    hudObjects.forEach(function(obj) { 
    toScreenPosition(obj, projMatrix); 
    }); 
} 

// wrapped in IIFE to store the local vector-variable (this pattern 
// is used everywhere in three.js) 
var toScreenPosition = (function() { 
    var vector = new THREE.Vector3(); 

    return function __toScreenPosition(obj, projectionMatrix) { 
    // this could potentially be left away, but isn't too 
    // expensive as there are 'needsUpdate'-checks in place 
    obj.updateMatrixWorld(); 
    vector.setFromMatrixPosition(obj.matrixWorld); 
    vector.applyMatrix4(projectionMatrix); 

    vector.x = (vector.x + 1) * width/2; 
    vector.y = (1 - vector.y) * height/2; 

    // might want to consider returning a Vector3-instance 
    // instead, depends on how the result is used 
    return {x: vector.x, y: vector.y}; 
    } 
})(); 

しかし、 HUDをレンダリングしたいと考えると、メインシーンとは独立して、上記の計算をすべて廃止し、HUD要素のサイズと配置のために異なる座標系を選択することができます。

ここには例としてhttps://codepen.io/usefulthink/pen/ZKPvPBがあります。そこでは、正射投影カメラと別のシーンを使用して、3Dシーンの上にHUD-Elementsをレンダリングしました。余分な計算は必要ありません。また、HUD要素のサイズと位置をピクセル単位で指定することもできます(パースペクティブカメラを使用しても同じことができますが、これを正しく行うには三角法を必要とします)。

+0

100%がこの回答の後半に同意します。メイン・シーンのHUD要素を操作することは高価になります(レオが見たように)。セカンダリシーン/レンダーパスに移動すると、それは簡単なことです。 – TheJim01

+0

実際に私はhud implication.1の2つのオプションを持っています:webglキャンバス上でもう1つのdivを使うために別のシーンと正射カメラを使用することはかなりうまくいきます。問題は、どのように泥層をレンダリングするのではなく、主な問題は各位置の計算です。私はあなたの解決策を試します@マーティンSchuhfuß、先のthx! –