BabylonJS系列:方向?qū)Ш胶?3.添加點(diǎn)擊歸位事件

添加點(diǎn)擊歸位事件芯丧,也就是鼠標(biāo)點(diǎn)到導(dǎo)航盒的某一個(gè)面,讓攝像機(jī)運(yùn)動(dòng)到對(duì)準(zhǔn)那個(gè)面的軸上世曾,這涉及到以下幾個(gè)問題:
1.如何獲取點(diǎn)擊事件缨恒?
2.如何獲取點(diǎn)到的面?
3.如何獲取點(diǎn)到面的法線谴咸?
4.如何將攝像機(jī)移動(dòng)到法線對(duì)應(yīng)的軸?

我們依次解決這幾個(gè)問題骗露,首先我們使用scene.onPointerDown來獲取檢測(cè)岭佳,因?yàn)楦眻?chǎng)景的scene是獨(dú)立的,可以直接使用這個(gè)API去獲取點(diǎn)擊事件萧锉,不會(huì)和主場(chǎng)景的檢測(cè)沖突珊随,因?yàn)檫@個(gè)功能是加在副場(chǎng)景的scene上,我們并不需要在dispose中對(duì)這個(gè)功能進(jìn)行注銷處理柿隙。

//注冊(cè)鼠標(biāo)點(diǎn)擊事件
    registPointDownEvent() {
        this.scene.onPointerDown = (evt, pi) => {
            console.log(1);
            if (!pi.pickedMesh) return;
            const pickMesh = pi.pickedMesh;
            if (!pickMesh) return;
            console.log(pi);
        }
    }
    //https://playground.babylonjs.com/?#ENABP9#11

通過打印pickInfo叶洞,我們發(fā)現(xiàn)我們可以獲取到碰撞點(diǎn)的faceId,根據(jù)faceId,可以找到該面的三個(gè)頂點(diǎn)的索引號(hào),因?yàn)閯?chuàng)建網(wǎng)格的時(shí)候禀崖,拋開八個(gè)角面衩辟,同一個(gè)平面上面的點(diǎn)相對(duì)于其他面都是獨(dú)立存在的,點(diǎn)的法線就代表著所處平面的法線波附,這樣第二三個(gè)問題迎刃而解艺晴。

 //獲取頂點(diǎn)索引
            ......
            const indices = pickMesh.getIndices();
            const p1Index = indices[pi.faceId * 3];
            // const p2Index = indices[pi.faceId * 3+1];
            // const p3Index = indices[pi.faceId * 3+2];
            //獲取normal
            const normals = pickMesh.getNormalsData();
            const normal = new BABYLON.Vector3(normals[p1Index * 3], normals[p1Index * 3 + 1], normals[p1Index * 3 + 2]);
            console.log(normal);
            //https://playground.babylonjs.com/?#ENABP9#12

此時(shí)我們已經(jīng)獲取了法線,接下來我們通過法線去判定六個(gè)方向掸屡,就可以知道我們即將旋轉(zhuǎn)到的軸的方向封寞,這里可以準(zhǔn)備一個(gè)新的enum和function:

enum IDirection {
    forward,
    backward,
    right,
    left,
    up,
    down
}
......
            //獲取normal
            const normals = pickMesh.getNormalsData();
            const normal = new BABYLON.Vector3(normals[p1Index * 3], normals[p1Index * 3 + 1], normals[p1Index * 3 + 2]);
            if (normal.z === -1) {
                this.moveCameraToDirection(CameraDirection.forward)
            }
            if (normal.z === 1) {
                this.moveCameraToDirection(CameraDirection.backward)
            }
            if (normal.x === -1) {
                this.moveCameraToDirection(CameraDirection.left);
            }
            if (normal.x === 1) {
                this.moveCameraToDirection(CameraDirection.right);
            }
            if (normal.y === 1) {
                this.moveCameraToDirection(CameraDirection.up);
            }
            if (normal.y === -1) {
                this.moveCameraToDirection(CameraDirection.down);
            }
......
    //指向
    moveCameraToDirection(direction: CameraDirection) {
        
    }
......
//https://playground.babylonjs.com/?#ENABP9#13

前面的幾個(gè)問題都已經(jīng)解決,最后一個(gè)問題就是怎么移動(dòng)折晦?我們先寫一個(gè)簡(jiǎn)單的動(dòng)畫機(jī)ProcessAnimation钥星,當(dāng)然也可以直接使用gsap之類的插件沾瓦。對(duì)于ArcRotateCamera满着,最簡(jiǎn)單的移動(dòng)的方法有兩種,一種是通過插值Position,一種是通過插值A(chǔ)lpha和Beta贯莺。第一種方法簡(jiǎn)單粗暴风喇,第二種方法得去匹配對(duì)應(yīng)的alpha和beta,我們可以分開嘗試缕探。先試試通過插值Position:

    moveCameraToDirection(direction: CameraDirection) {
        const tmpV3 = B.TmpVectors.Vector3[0];
        const startPos = B.TmpVectors.Vector3[1].copyFrom(this.bindCamera.position);
        switch (direction) {
            case CameraDirection.forward:
                tmpV3.set(0, 0, -1);
                break;
            case CameraDirection.backward:
                tmpV3.set(0, 0, 1);
                break;
            case CameraDirection.right:
                tmpV3.set(1, 0, 0);
                break;
            case CameraDirection.left:
                tmpV3.set(-1, 0, 0);
                break;
            case CameraDirection.up:
                tmpV3.set(0, 1, 0);
                break;
            case CameraDirection.down:
                tmpV3.set(0, -1, 0);
                break;
        }
        //最終的Position
        tmpV3.scaleInPlace(this.bindCamera.radius).addInPlace(this.bindCamera.target);
        this.process.play(0.5, (process) => {
            B.Vector3.LerpToRef(startPos, tmpV3, process, this.bindCamera.position);
            this.bindCamera.rebuildAnglesAndRadius();
        })
    }
//https://playground.babylonjs.com/?#ENABP9#14

編寫的過程簡(jiǎn)單粗暴魂莫,效果好些也挺OK,但是多次嘗試會(huì)發(fā)現(xiàn)爹耗,點(diǎn)擊頂和底的移動(dòng)好像有點(diǎn)問題耙考,結(jié)束的時(shí)候方向總是不對(duì)或者會(huì)瞬間旋轉(zhuǎn)。這是因?yàn)橛龅筋愃迫f向死鎖的問題潭兽,當(dāng)Beta不處于0和PI時(shí)倦始,一對(duì)Beta和Alpha有唯一對(duì)應(yīng)的一對(duì)Position和Target,但是當(dāng)Beta處于0或PI時(shí)山卦,相當(dāng)于一個(gè)軸旋轉(zhuǎn)了90度鞋邑,再旋轉(zhuǎn)Alpha時(shí),會(huì)發(fā)現(xiàn)position并不會(huì)改變,也就是說此時(shí)一對(duì)Position和Target對(duì)應(yīng)著無數(shù)個(gè)Alpha枚碗,計(jì)算的alpha可能是0-2Pi中的任意一個(gè)值逾一。接下來試試使用Alpha和Beta插值的方法來進(jìn)行移動(dòng):

  moveCameraToDirection(direction: CameraDirection) {
        let alpha = 0;
        let beta = 0;
        switch (direction) {
            case CameraDirection.forward:
                alpha = - Math.PI / 2;
                beta = Math.PI / 2;
                break;
            case CameraDirection.backward:
                alpha = Math.PI / 2;
                beta = Math.PI / 2;
                break;
            case CameraDirection.right:
                alpha = 0;
                beta = Math.PI / 2;
                break;
            case CameraDirection.left:
                alpha = - Math.PI;
                beta = Math.PI / 2;
                break;
            case CameraDirection.up:
                alpha = - Math.PI / 2;
                beta = 0;
                break;
            case CameraDirection.down:
                alpha = - Math.PI / 2;
                beta = Math.PI;
                break;
        }

        let startBeta = this.bindCamera.beta;
        let startAlpha = this.bindCamera.alpha % (Math.PI * 2);
        //避免繞大圓
        if (startAlpha < 0) startAlpha += Math.PI * 2;
        if (Math.abs(alpha - startAlpha) > Math.PI) {
            alpha += Math.PI * 2;
        }
        this.process.play(0.5, (process) => {
            this.bindCamera.alpha = BABYLON.Scalar.Lerp(startAlpha, alpha, process);
            this.bindCamera.beta = BABYLON.Scalar.Lerp(startBeta, beta, process);
        })
  }

//https://playground.babylonjs.com/?#ENABP9#15

除了這兩種方法,還可以使用四元數(shù)插值直接計(jì)算矩陣來移動(dòng)視角肮雨,有興趣的小伙伴可以去研究一下遵堵。到此為止,導(dǎo)航盒的基礎(chǔ)功能已經(jīng)完成酷含,下一節(jié)將為盒子添加一個(gè)點(diǎn)擊后高亮的功能鄙早。
PS:本節(jié)結(jié)束PG(https://playground.babylonjs.com/?#ENABP9#16
PS:后續(xù)修改了部分結(jié)構(gòu)以支持八角定位(https://playground.babylonjs.com/?#ENABP9#24

下一節(jié):BabylonJS系列:方向?qū)Ш胶?4.點(diǎn)擊面高亮

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市椅亚,隨后出現(xiàn)的幾起案子限番,更是在濱河造成了極大的恐慌,老刑警劉巖呀舔,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弥虐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡媚赖,警方通過查閱死者的電腦和手機(jī)霜瘪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惧磺,“玉大人颖对,你說我怎么就攤上這事∧グ” “怎么了缤底?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)番捂。 經(jīng)常有香客問我个唧,道長(zhǎng),這世上最難降的妖魔是什么设预? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任徙歼,我火速辦了婚禮,結(jié)果婚禮上鳖枕,老公的妹妹穿的比我還像新娘魄梯。我一直安慰自己,他們只是感情好宾符,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布酿秸。 她就那樣靜靜地躺著,像睡著了一般吸奴。 火紅的嫁衣襯著肌膚如雪允扇。 梳的紋絲不亂的頭發(fā)上缠局,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音考润,去河邊找鬼狭园。 笑死,一個(gè)胖子當(dāng)著我的面吹牛糊治,可吹牛的內(nèi)容都是我干的唱矛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼井辜,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼绎谦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起粥脚,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤窃肠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后刷允,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冤留,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年树灶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纤怒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡天通,死狀恐怖泊窘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情像寒,我是刑警寧澤烘豹,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站萝映,受9級(jí)特大地震影響吴叶,放射性物質(zhì)發(fā)生泄漏阐虚。R本人自食惡果不足惜序臂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望实束。 院中可真熱鬧奥秆,春花似錦、人聲如沸咸灿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽避矢。三九已至悼瘾,卻和暖如春囊榜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背亥宿。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工卸勺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人烫扼。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓曙求,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親映企。 傳聞我的和親對(duì)象是個(gè)殘疾皇子悟狱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容