2017-05-25 59 views
1

當鼠標移動時,我想將hud位置更新爲3d位置。由於它可能有大量的3D對象投影到屏幕位置,所以我遇到了性能問題。如何在從3D到屏幕更新雜亂位置時加速計算(hud)

有沒有什麼方法可以加速計算?以下是我如何計算2D屏幕上的3D物體位置。

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';創建一個並重用它。函數返回時不要實例化新對象。每次調用時不要重新計算寬度/高度哈爾夫。並且不要調用'obj.updateMatrixWorld()'。渲染器爲你調用每一幀。 – WestLangley

+0

@WestLangley你測試了你的解決方案嗎?我不認爲這可以解決我的問題,當它在場景中有超過100多個hud對象來計算2D屏幕中的位置時。因爲我現在沒有使用object3d,只需計算object3d的中心點,就像你剛纔說的Vector3一樣。 –

+0

@WestLangley寫的幾乎是普遍真實的,並且會在一定程度上改善你的表現。雖然可能還不夠。另一個可能的優化是'.project()' - 調用。這在內部必須計算相機的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移動到第二個渲染通道,讓它保持「頂部」。

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元素。不需要額外的計算。另外,我可以以像素單位方便地指定HUD元素的大小和位置(使用透視相機也是一樣,只需要更多三角函數即可)。

+0

100%同意此回答的後半部分。在主場景中操作HUD元素將會很昂貴(正如Leo所見)。將它們移動到二級場景/渲染通道使其成爲一件小事。 – TheJim01

+0

實際上,我有2個選項可用於hud implication.1:使用另一個場景和正交相機。2在webgl畫布上使用另一個div,它的工作原理非常好。問題不在於如何渲染HUD層,主要的問題是計算每個位置。我會測試你的解決方案@MartinSchuhfuß,thx提前! –