Babylon.jsでCameraをシームレスに指定の位置に移動させる
はじめに
Babylon.jsはブラウザ上でリアルタイムに動作する3Dレンダリングフレームワークの1つです。OSSとなりますので、誰でも無料で使用することができます。
今回の記事では、下図のように、Babylon.jsでCameraをシームレスに移動させる実装を目指します。
特にUnityでは実装方法わかるけど...という人におすすめです。
UnityのC#で書くとすると、以下のような実装を書きたい。
public class CameraMove: MonoBehaviour {
public Transform camera;
Vector3 currentPosition,targetPosition;
float smoothSpeed = 3.0f;
void Start(){
currentPosition = camera.position;
targetPosition = camera.position;
}
void Update(){
if(Input.GetKeyDown("a")){
targetPosition = new Vector3(0, 0, 0.05);
}else if(Input.GetKeyDown("d")){
targetPosition = new Vector3(0.05, 0, 0.15));
}
}
void LateUpdate(){
if(Vector3.Distance(currentPosition,targetPosition)<= 0.00001){
currentPosition = targetPosition;
}else{
currentPosition = Vector3.Lerp(currentPosition,targetPosition,Time.deltaTime*smoothSpeed);
camera.potision = currentPosition;
}
}
}
でも、Babylon.jsでどうやって書けば...ということで、書き方を整理していきたいと思います。
悩みポイントとしては
- 基本シーンの準備の仕方
- Update関数の準備の仕方
- キー入力の準備の仕方
- カメラ移動の実装の仕方
を見ていきたいと思います。
PlayGroundで準備
にアクセスするとWeb上でコーディングしてリアルタイムに反応されるツールを使うことができます。
基本シーンの準備の仕方
createScene
の中に
- camera
- light
- オブジェクト
を実装していきます。
var createScene = function () {
const scene = new BABYLON.Scene(engine);
camera = new BABYLON.UniversalCamera("camera", new BABYLON.Vector3(0, 0, 0.05));
camera.minZ = 0.0001;
camera.rotation.y = Math.PI;
const light = new BABYLON.HemisphericLight("light",new BABYLON.Vector3(0, 1, 0),scene);
BABYLON.SceneLoader.Append("https://raw.githubusercontent.com/BabylonJS/MeshesLibrary/master/", "boombox.glb", scene, function (scene) {
scene.createDefaultEnvironment();
});
return scene;
};
解説
Cameraの生成は
// "camera"という名前で new BABYLON.Vector3(0, 0, 0.05)に生成する
let camera = new BABYLON.UniversalCamera("camera", new BABYLON.Vector3(0, 0, 0.05));
で行います。
他にも
new BABYLON.FreeCamera()
などでも可能です。
さらに、オブジェクトを描画できるように、以下のようなコードをつけ足します。
camera.minZ = 0.0001; // near clip
camera.rotation.y = Math.PI;
camera.minZ
はNear planeといわれる値で、カメラの近くの範囲を描画する範囲になります。
デフォルトだと1
になっているので、近くのオブジェクトがほとんど描画されません。
なので
camera.minZ = 0.0001;
とすることで、近くのオブジェクトも描画してくれます。
camera.rotation.y = Math.PI;
はrotationのyの値に180度を入力する実装です。単位がラジアンになるので、Math.PIとなっています。これはオブジェクトの向きやカメラの位置によって適宜入力します。
lightの生成は
const light = new BABYLON.HemisphericLight("light",new BABYLON.Vector3(0, 1, 0),scene);
オブジェクトの追加は
BABYLON.SceneLoader.Append("https://raw.githubusercontent.com/BabylonJS/MeshesLibrary/master/", "boombox.glb", scene, function (scene) {
scene.createDefaultEnvironment(); //省略可能
});
という実装をしています。
Babylon.jsのPlayGroundでは、Githubのpublicレポジトリの上のアセットにアクセスすることができます。やり方としては
https://github.com/BabylonJS/MeshesLibrary/blob/master/boombox.glb
の3Dアセットにアクセスしたい場合は、
-
github.com
をraw.githubusercontent.com
に置き換える -
blob
を削除する
ことによって
https://raw.githubusercontent.com/BabylonJS/MeshesLibrary/master/boombox.glb
というURLでglbデータを取得することができます。
sceneに追加する関数
BABYLON.SceneLoader.Append("rootURL","sceneFileName",scene)
のように使います。
scene.createDefaultEnvironment();
は環境マップをとりあえず追加したいときに使用します。
Update関数の準備の仕方
Update関数とは、Unityでいうと描画のframeごとに呼ばれる関数です。
Babylon.jsでは
scene.registerBeforeRender(function () {
update(scene);
});
とすると、Render前のイベントを取得できます。
全体では次のような実装をしてみました。
var createScene = function () {
const scene = new BABYLON.Scene(engine);
camera = new BABYLON.UniversalCamera("camera", new BABYLON.Vector3(0, 0, 0.05));
camera.minZ = 0.0001;
camera.rotation.y = Math.PI;
const light = new BABYLON.HemisphericLight("light",new BABYLON.Vector3(0, 1, 0),scene);
BABYLON.SceneLoader.Append("https://raw.githubusercontent.com/BabylonJS/MeshesLibrary/master/", "boombox.glb", scene, function (scene) {
scene.createDefaultEnvironment();
});
scene.registerBeforeRender(function () {
update(scene);
});
return scene;
};
function update(scene){
const deltaTime = engine.getDeltaTime() / 1000;
console.log(deltaTime);
}
deltaTime (前frameから現frameまでの秒数)
を取得するためには
engine.getDeltaTime() / 1000;
と実装します。
キー入力の準備の仕方
を参考に次のように実装しました。
var createScene = function () {
//中略
scene.onKeyboardObservable.add((kbInfo) => {
switch (kbInfo.type) {
case BABYLON.KeyboardEventTypes.KEYDOWN:
switch (kbInfo.event.key) {
case "a":
case "A":
console.log("KeyDown:A");
break
case "d":
case "D":
console.log("KeyDown:D");
break
}
break;
}
});
return scene;
}
カメラ移動の実装の仕方
冒頭のUnityの実装を参考にしたのように実装しました。
let camera;
let targetPosition,currentPosition;
let smoothSpeed = 3.0
var createScene = function () {
const scene = new BABYLON.Scene(engine);
camera = new BABYLON.UniversalCamera("camera", new BABYLON.Vector3(0, 0, 0.05));
camera.minZ = 0.0001;
camera.rotation.y = Math.PI;
//初期値を設定
currentPosition = camera.position;
targetPosition = camera.position;
const light = new BABYLON.HemisphericLight("light",new BABYLON.Vector3(0, 1, 0),scene);
BABYLON.SceneLoader.Append("https://raw.githubusercontent.com/BabylonJS/MeshesLibrary/master/", "boombox.glb", scene, function (scene) {
scene.createDefaultEnvironment();
});
scene.registerBeforeRender(function () {
update(scene);
});
scene.onKeyboardObservable.add((kbInfo) => {
switch (kbInfo.type) {
case BABYLON.KeyboardEventTypes.KEYDOWN:
switch (kbInfo.event.key) {
case "a":
case "A":
// targetPositionを設定
targetPosition = new BABYLON.Vector3(0, 0, 0.05);
break
case "d":
case "D":
targetPosition = new BABYLON.Vector3(0.05, 0, 0.15);
break
}
break;
}
});
return scene;
};
function update(scene){
const deltaTime = engine.getDeltaTime() / 1000;
//距離がほぼゼロの時
if(BABYLON.Vector3.DistanceSquared(currentPosition,targetPosition) <= 0.00000001){
currentPosition = targetPosition;
camera.position = currentPosition;
}else{
currentPosition = BABYLON.Vector3.Lerp(currentPosition,targetPosition,deltaTime*smoothSpeed);
camera.position = currentPosition;
}
}
まとめ
Babylon.jsでCameraをシームレスに指定の位置に移動させる実装をしました。
参考になれば幸いです。
筆者イワケンはBabylon.jsの可能性について掘っていきたいと思いますのでよろしくお願いいたします。
参考ページ
Discussion