BabylonJS系列:方向?qū)Ш胶?2.創(chuàng)建導(dǎo)航盒場(chǎng)景

第一節(jié)完成了模型的自定義生成,第二節(jié)開(kāi)始完成導(dǎo)航盒場(chǎng)景的制作,這里我使用多場(chǎng)景的方式制作導(dǎo)航盒,這種方式可以使導(dǎo)航盒場(chǎng)景和原場(chǎng)景解耦,避免產(chǎn)生各種各樣的光照,深度,后處理等方面的沖突。首先進(jìn)行場(chǎng)景的創(chuàng)建和初始化工作,這里會(huì)單獨(dú)會(huì)創(chuàng)建一個(gè)Scene,Camera和DirectBox。這里和主場(chǎng)景一致創(chuàng)建了一個(gè)ArcRotateCamera,方便兩個(gè)場(chǎng)景攝影機(jī)的同步,注意這個(gè)攝像機(jī)是正交攝像機(jī),radius的大小對(duì)視角的沒(méi)有影響,radius的正負(fù)會(huì)影響旋轉(zhuǎn)。

class DirectBoxScene {
......
    constructor(engine: BABYLON.Engine, bindCamera: BABYLON.ArcRotateCamera) {
        this.engine = engine;
        //創(chuàng)建導(dǎo)航盒場(chǎng)景
        this.scene = new B.Scene(engine);
        //將場(chǎng)景的自動(dòng)清除關(guān)閉,該場(chǎng)景將在主場(chǎng)景渲染結(jié)束后渲染,關(guān)閉autoClear避免將主場(chǎng)景渲染的圖像清除。
        this.scene.autoClear = false;
        // //將場(chǎng)景的clearColor設(shè)置為透明
        // this.scene.clearColor.a = 0;
        this.scene.clearColor.set(0, 0, 0, 1);
        this.selfCamera = new B.ArcRotateCamera(
            "DTC", -Math.PI / 2, Math.PI / 2, 10, B.Vector3.Zero(), this.scene
        );

        this.selfCamera.mode = B.Camera.ORTHOGRAPHIC_CAMERA;
        this.selfCamera.orthoBottom = this.selfCamera.orthoLeft = -1
        this.selfCamera.orthoTop = this.selfCamera.orthoRight = 1;
        //Box
        const directBox = DirectBoxCreator.create(this.scene, 1, 0.3);
        this.directBox = directBox.mesh;
        //因?yàn)槠聊恍?dǎo)致edge過(guò)于細(xì)
        this.directBox.edgesWidth *= 2;
        this.directBox.material.zOffset *= 5;
        ......
    }
......
}

初始化過(guò)程中有一個(gè)重點(diǎn)關(guān)注的點(diǎn),就是將副場(chǎng)景的autoClear設(shè)置為false,避免渲染副場(chǎng)景的時(shí)候?qū)⒃瓐?chǎng)景的像素信息從Buffer里面清除掉。接下來(lái)是攝像機(jī)的同步和窗口的初始化,前者將副場(chǎng)景的攝像機(jī)與主場(chǎng)景的攝像機(jī)根據(jù)旋轉(zhuǎn)方向進(jìn)行同步,后者將設(shè)置副窗口在整個(gè)頁(yè)面的位置,這里我以屏幕右上角為基準(zhǔn)進(jìn)行的計(jì)算:

class DirectBoxScene {
    //窗口大小  單位pixel
    windowSize: number = 200;
    //窗口右上角離window右上角的距離
    windowOffset: BABYLON.Vector2 = new BABYLON.Vector2(50, 50);
    ......
    constructor(engine: BABYLON.Engine, bindCamera: BABYLON.ArcRotateCamera) {
        ......
        this.alignCameraToBindCamera();
        this.resizeWindow();
        ......
    }
    ......
    //將攝像機(jī)與綁定攝像機(jī)同步
    alignCameraToBindCamera() {
        this.selfCamera.alpha = this.bindCamera.alpha;
        this.selfCamera.beta = this.bindCamera.beta;
        if (this.bindCamera.radius * this.selfCamera.radius < 0) {
            this.selfCamera.radius *= -1;
        }
    }
    //重置場(chǎng)景區(qū)域
    resizeWindow() {
        const engine = this.engine;
        const width = engine.getRenderWidth(true);
        const height = engine.getRenderHeight(true);

        this.selfCamera.viewport.x = 1 - (this.windowSize + this.windowOffset.x) / width;
        this.selfCamera.viewport.y = 1 - (this.windowSize + this.windowOffset.y) / height;

        this.selfCamera.viewport.width = this.windowSize / width;
        this.selfCamera.viewport.height = this.windowSize / height;
    }
}

這一步需要注意的是,ArcRotateCamera如果滾動(dòng)滾輪使得radius為負(fù),旋轉(zhuǎn)的方向會(huì)發(fā)生反轉(zhuǎn),所以需要對(duì)正負(fù)進(jìn)行同步,當(dāng)然也可以直接設(shè)置radius的上下界,禁止radius為負(fù)值,另外一點(diǎn)就是viewport是以屏幕左下角為原點(diǎn),它的x,y,width,height的范圍均為0-1。最后是進(jìn)行事件的綁定,一般建議寫(xiě)事件綁定的時(shí)候?qū)?yīng)著寫(xiě)一個(gè)dispose函數(shù),確保每一個(gè)事件都在銷(xiāo)毀前注銷(xiāo)掉,避免組件被銷(xiāo)毀后,事件依舊觸發(fā)導(dǎo)致報(bào)錯(cuò)崩潰。

class DirectBoxScene {
   
    ......
    //綁定攝像機(jī)旋轉(zhuǎn)Observer
    _onCameraViewMatrixChangedObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.Camera>> = null;
    //場(chǎng)景尺寸改變Observer
    _onEngineResizeObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.Engine>> = null;
    //綁定場(chǎng)景渲染Observer
    _onSceneRenderObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.Scene>> = null;
    constructor(engine: BABYLON.Engine, bindCamera: BABYLON.ArcRotateCamera) {
        ......
        //綁定攝像機(jī)矩陣改變事件
        this._onCameraViewMatrixChangedObserver = this.bindCamera.onViewMatrixChangedObservable.add((camera) => {
            this.alignCameraToBindCamera();
        })
        //綁定窗口尺寸改變事件
        this._onEngineResizeObserver = this.engine.onResizeObservable.add((engine) => {
            this.resizeWindow();
        })
        const bindScene = bindCamera.getScene();
        //場(chǎng)景渲染事件
        this._onSceneRenderObserver = bindScene.onAfterRenderObservable.add((scene) => {
            this.scene.render();
        })
        ......
    }
    ......
    dispose() {
        this.bindCamera.onViewMatrixChangedObservable.remove(this._onCameraViewMatrixChangedObserver);
        this.engine.onResizeObservable.remove(this._onEngineResizeObserver);
        this.bindCamera.getScene().onAfterRenderObservable.remove(this._onSceneRenderObserver);

        this.scene.dispose();
    }
}

至此導(dǎo)航盒場(chǎng)景已經(jīng)可以顯現(xiàn)出來(lái),之后將為導(dǎo)航盒添加新的功能。


PS:本節(jié)結(jié)束PG(https://playground.babylonjs.com/?#ENABP9#10)

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容