第一節(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)
