相機默認會在我們我們將其綁定(attachControl)到畫布上面時,給我們自動處理操作輸入事件。你還可以使用detachControl
函數來解除事件的綁定。大多數Babylon.js的專家都使用兩步:
//第一步,設置相機的activeCamera爲你創建的相機
scene.activeCamera = myCamera;
//第二步,將相機綁定到畫布
//配置項:畫布對象canvas,不阻止默認事件noPreventDefault
scene.activeCamera.attachControl(canvas, true);
還有更簡單的版本:
myCamera.attachControl(canvas);
默認情況下,noPreventDefault
值爲false。這意味着綁定到畫布的所有的相機操作都將自動阻止默認事件。
在Babylon.js v2.4版本引入了一種不同的方式來管理相機的操作,提供了一種面向輸入可組合性的方法。你可以使用輸入管理器,並且每個輸入都可以被視爲此攝像機系列的插件,以及給定的輸入類型(鼠標,鍵盤,遊戲手柄,陀螺儀等)。
使用輸入管理器( input manager),你可以添加,刪除,啓用或者禁用相機可用的任何輸入。你可以非常輕鬆的實現自己的輸入機制或覆蓋現有的輸入機制。
例如,輸入管理器( input manager)可以用過相機的inputs
屬性來獲取:
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
var inputManager = camera.inputs;
配置你的輸入
大多數輸入提供設置自定義敏感度使相機適應你的場景。
每個輸入在管理器上提供了一個簡短的名稱。目的是爲了方便設置。
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
camera.inputs.attached.gamepad.gamepadAngularSensibility = 250;
添加現有的輸入
ArcRotateCamera和FreeCamera的輸入管理器都公開了用於添加內置輸入的簡寫函數。
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.addGamepad();
等同於
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.add(new BABYLON.FreeCameraGamepadInput());
如果需要,你還可以自定義自己的輸入方式(本節末尾處將實現自定義輸入)。
啓用或禁用輸入
當你調用相機的attachControl
時,會自動激活input manager
的所有的輸入。同樣的,調用相機的detachControl
時,將關閉所有的輸入。
如果想要暫時禁用輸入,可以直接在輸入上調用detachControl
來禁止某個操作輸入:
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.attached.mouse.detachControl();
camera.inputs.addGamepad();
如果你想再打開它,可以調用attachInput
:
camera.inputs.attachInput(camera.inputs.attached.mouse);
刪除輸入
有時,你需要一個非常具體的輸入機制。在這種情況下,最好的辦法可能是清除當前所有的默認輸入並添加需要的輸入。
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
camera.inputs.clear();
camera.inputs.addMouse();
你還可以從input Manager
裏面刪除掉某個輸入。你可以按實例或者類型名稱刪除:
var camera = new BABYLON.FreeCamera("sceneCamera", new BABYLON.Vector3(0, 1, -15), scene);
// 按照實例刪除輸入
camera.inputs.remove(camera.inputs.attached.mouse);
// 按照類型名稱刪除輸入
camera.inputs.removeByType("FreeCameraKeyboardMoveInput");
實現自己的輸入
我們實現的自己的輸入必須是一個類(構造函數)。而且還必須爲類添加多個所需的方法,這些方法將會由輸入函數對象調用:
//這個方法返回相機的類型名稱,它可用於序列化場景
getTypeName();
//這個函數返回添加到輸入管理器中的輸入的簡稱
//比如camera.inputs.attached.mouse將返回 "mouse"
getSimpleName();
//這個函數用於綁定設備事件,即使你的輸入不需要DOM元素。
// element 和noPreventDefault 爲必填項
//返回空
attachControl(element, noPreventDefault);
//解綁控制方法必須能夠停止輸入事件並解綁所有的指針,閉包和事件監聽。
//element 爲必填項
// 返回空
detachControl(element);
//如果你需要輸入與渲染同步,這個函數將在每一個渲染幀中調用。
//無須使用requestAnimationFrame方法. 如果需要這是一個需要計算的好地方。
// 返回空
checkInputs();
使用JavaScript實現
我們將改變FreeCamera
的鍵盤操作,將移動操作改爲旋轉操作。
首先刪除掉默認的鍵盤輸入:
camera.inputs.removeByType("FreeCameraKeyboardMoveInput");
創建新的構造函數FreeCameraKeyboardRotateInput
:
var FreeCameraKeyboardRotateInput = function () {
this._keys = [];
this.keysLeft = [37];
this.keysRight = [39];
this.sensibility = 0.01;
}
添加獲取名稱方法
FreeCameraKeyboardRotateInput.prototype.getTypeName = function () {
return "FreeCameraKeyboardRotateInput";
};
FreeCameraKeyboardRotateInput.prototype.getSimpleName = function () {
return "keyboardRotate";
};
然後再添加綁定事件和解綁事件的方法:
FreeCameraKeyboardRotateInput.prototype.attachControl = function (element, noPreventDefault) {
var _this = this;
if (!this._onKeyDown) {
element.tabIndex = 1;
this._onKeyDown = function (evt) {
if (_this.keysLeft.indexOf(evt.keyCode) !== -1 ||
_this.keysRight.indexOf(evt.keyCode) !== -1) {
var index = _this._keys.indexOf(evt.keyCode);
if (index === -1) {
_this._keys.push(evt.keyCode);
}
if (!noPreventDefault) {
evt.preventDefault();
}
}
};
this._onKeyUp = function (evt) {
if (_this.keysLeft.indexOf(evt.keyCode) !== -1 ||
_this.keysRight.indexOf(evt.keyCode) !== -1) {
var index = _this._keys.indexOf(evt.keyCode);
if (index >= 0) {
_this._keys.splice(index, 1);
}
if (!noPreventDefault) {
evt.preventDefault();
}
}
};
element.addEventListener("keydown", this._onKeyDown, false);
element.addEventListener("keyup", this._onKeyUp, false);
BABYLON.Tools.RegisterTopRootEvents([
{ name: "blur", handler: this._onLostFocus }
]);
}
};
FreeCameraKeyboardRotateInput.prototype.detachControl = function (element) {
if (this._onKeyDown) {
element.removeEventListener("keydown", this._onKeyDown);
element.removeEventListener("keyup", this._onKeyUp);
BABYLON.Tools.UnregisterTopRootEvents([
{ name: "blur", handler: this._onLostFocus }
]);
this._keys = [];
this._onKeyDown = null;
this._onKeyUp = null;
}
};
添加每一幀的處理檢測:
FreeCameraKeyboardRotateInput.prototype.checkInputs = function () {
if (this._onKeyDown) {
var camera = this.camera;
// Keyboard
for (var index = 0; index < this._keys.length; index++) {
var keyCode = this._keys[index];
if (this.keysLeft.indexOf(keyCode) !== -1) {
camera.cameraRotation.y += this.sensibility;
}
else if (this.keysRight.indexOf(keyCode) !== -1) {
camera.cameraRotation.y -= this.sensibility;
}
}
}
};
最後將新的輸入方法添加到相機的input Manager
:
camera.inputs.add(new FreeCameraKeyboardRotateInput());
- 在此處查看官方示例
使用TypeScript
使用TypeScript,您可以實現接口ICameraInput。
interface ICameraInput<TCamera extends BABYLON.Camera> {
// 填充輸入管理的父相機
camera: TCamera;
//這個方法返回相機的類型名稱,它可用於序列化場景
getTypeName(): string;
//這個函數返回添加到輸入管理器中的輸入的簡稱
//比如camera.inputs.attached.mouse將返回 "mouse"
getSimpleName(): string;
//這個函數用於綁定設備事件,即使你的輸入不需要DOM元素。
attachControl: (element: HTMLElement, noPreventDefault?: boolean) => void;
//解綁控制方法必須能夠停止輸入事件並解綁所有的指針,閉包和事件監聽。
detachControl: (element: HTMLElement) => void;
//如果你需要輸入與渲染同步,這個函數將在每一個渲染幀中調用。
//無須使用requestAnimationFrame方法. 如果需要這是一個需要計算的好地方。
checkInputs?: () => void;
}