Threejs【坐標轉換】如何讓annotation跟隨物體一起旋轉


現在根據鼠標點擊的屏幕位置能夠得到屏幕的坐標event.clientXevent.clientY,然后我的annotation就初始化在這個屏幕坐標的位置,那么如何綁定annotation和三維物體,使得物體旋轉的時候可以讓annotation跟隨物體一起旋轉呢?
問題一:我知道的一種方法如下:

/* 修改注解屏幕位置函數體 實時更新,實際是三維坐標向屏幕坐標的映射*/
function updateScreenPosition() {
    var canvas = renderer.domElement;

    var vector = new THREE.Vector3(50, 0, 250); // 控制annotation的位置
    vector.project(camera);
    vector.x = Math.round((0.5 + vector.x / 2) * (canvas.width / window.devicePixelRatio)); // 控制annotation跟隨物體一起旋轉
    vector.y = Math.round((0.5 - vector.y / 2) * (canvas.height / window.devicePixelRatio));

    annotation.style.top = vector.y + "px";
    annotation.style.left = vector.x + "px";
    annotation.style.opacity = spriteBehindObject ? 0.25 : 1;
}

上面的方法可以控制annotation和物體一起旋轉,但是annotation的位置確實預先設定的:

var vector = new THREE.Vector3(50, 0, 250); // 控制annotation的位置

對於上面這行代碼,Vector3是個什么坐標系下的向量呢?當我在修改Vector3中的三個坐標的時候,發現它並不是控制annotation的位置的向量,比如我把鼠標點擊位置的參數傳遞過來,然后觸發鼠標點擊事件,然后發現鼠標點擊的位置並不是annotation的位置。如何把它和鼠標點擊的屏幕坐標掛鈎呢?

問題二:如果不預先設定好這個Vector3 而是使用鼠標,而是直接傳遞event.clientXevent.clientY

function updateAnnosPosition(){
    var canvas = renderer.domElement;
    var vector = new THREE.Vector3(clientX,clientY,-1);
    vector.project(camera);
    //這個位置的寫法有問題

    annos.style.left = clientX + "px";
    annos.style.top = clientY + "px";

    annos.style.opacity = spriteBehindObject ? 0.25 : 1;
}

這樣是可以在鼠標點擊位置觸發annotation的,但是annotation卻不跟隨物體旋轉。
網上查了一下,大概是要進行屏幕坐標與三維坐標之間的轉換:

_mouse.x = ( event.clientX / _domElement.width ) * 2 - 1;
_mouse.y = - ( event.clientY / _domElement.height ) * 2 + 1;

但是還是不行,求教該如何處理。

回答:

(1)Vector3是個什么坐標系下的向量呢?

Vector3是 three.js 定義的三維空間坐標系里的向量

(2)如何把它和鼠標點擊的屏幕坐標掛鈎呢?

這個問題本質是問:如何將three.js 三維坐標轉換成屏幕二維坐標

其實updateScreenPosition()函數就是將三維坐標轉換成屏幕坐標的過程,我們可以改一下這個函數,使之更通用:

/**
* 將three.js三維坐標轉換成屏幕上的二維坐標
* @param THREE.Vector3 vector three.js三維坐標
* @return {x:int,y:int} 屏幕坐標
*/
function transToScreenCoord(vector) {
    var screenCoord = {};
    vector.project(camera); //1
    screenCoord.x = Math.round((0.5 + vector.x / 2) * (canvas.width / window.devicePixelRatio));  //2
    screenCoord.y = Math.round((0.5 - vector.y / 2) * (canvas.height / window.devicePixelRatio));
    return screenCoord;
}

有了這個函數,就可以把任意three.js三維坐標轉換成屏幕坐標。也就是實現了3維坐標和屏幕坐標掛鈎

接下來解釋一下這個轉換的過程:
vector.project(camera) 這句的意思是,將一個三維坐標,投影到相機平面上,使之變成一個二維坐標。需要注意的是,投影得到的結果是一個標准向量(或者叫單位向量),其值是限定在[-1,1]范圍內的。並且,這個向量是定義在以屏幕中心為原點的坐標系里的,這個坐標系和屏幕坐標系的關系,就像下圖一樣:

假如經過投影之后的點就是上圖中的點A(0.3,0.5),屏幕坐標系是sx-s0-sy,相機平面坐標系是tx-t0-ty,坐標系的各項參數已經標在圖上,試着求A點在屏幕坐標系中的坐標。你求一遍的話,就會理解上面這個函數的意思。

(3)如果不預先設定好這個Vector3 而是使用鼠標,而是直接傳遞event.clientXevent.clientY,該怎么處理?

處理方法就是將這個屏幕二維坐標轉three.js三維坐標,按照下面這個方法來處理:

var vector = new THREE.Vector3();
vector.x = ( event.clientX / _domElement.width ) * 2 - 1;
vector.y = - ( event.clientY / _domElement.height ) * 2 + 1;

把上面這段替換掉updateScreenPosition()函數中的:

 

var vector = new THREE.Vector3(50, 0, 250); // 控制annotation的位置

應該就可以了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM