本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
最近使用Babylon.js开发一款在线编辑器,需要使用到视图助手。网上找了下,Three.js的demo比较多,用Babylon实现的视图助手没有,所以自己实现一个。效果和threeJs在线编辑器的视图助手一样.
实现Demo基于BabylonJs官方的Playground
思路
对于Babylon来说,我了解到的可以实现的思路主要有2个:
- 多场景,单独创建一个Scene用于存放助手,渲染的时候2个场景一起渲染
- 多画布,在主画布上面覆盖一层画布,用于渲染不怎么变化的物体
这里选择第一张方案,实现起来比较简单
多场景渲染实现
- 先创建一个新的Playground,生成初始代码
var createScene = function () {
// This creates a basic Babylon Scene object (non-mesh)
var scene = new BABYLON.Scene(engine);
// This creates and positions a free camera (non-mesh)
var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
// This targets the camera to scene origin
camera.setTarget(BABYLON.Vector3.Zero());
// This attaches the camera to the canvas
camera.attachControl(canvas, true);
// This creates a light, aiming 0,1,0 - to the sky (non-mesh)
var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
// Default intensity is 1. Let's dim the light a small amount
light.intensity = 0.7;
// Our built-in 'sphere' shape.
var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {diameter: 2, segments: 32}, scene);
// Move the sphere upward 1/2 its height
sphere.position.y = 1;
// Our built-in 'ground' shape.
var ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 6, height: 6}, scene);
return scene;
};
在这个基础上,实现一个多场景渲染的代码.
初始化辅助场景
//这里需要注意的是
1. 辅助场景的autoClear需要关闭
2. 因为是Playground环境,渲染代码需要写出
setTimeout(function() {
engine.stopRenderLoop();
engine.runRenderLoop(function () {
scene.render();
sceneHelper.render();
});
}, 500);
3.把辅助场景的相机视口设置到右上角
sceneHelper.activeCamera.viewport=new BABYLON.Viewport(0.8, 0.8, 0.2, 0.2);
4.此外,把相机改成ArcRotateCamera
辅助场景和主场景相机同步
主要是在主场景更新的时候,将主相机的数据传递给辅助相机 实现效果
scene.onAfterRenderObservable.add(()=>{
const activeCamera =sceneHelper.activeCamera;
activeCamera.alpha = camera.alpha;
activeCamera.beta = camera.beta;
})
实现助手实体
用一个圆柱体作为轴,xyz标记一直需要面向用户,所以用Babylon.GUI作为标记实体 以X轴为例
const labelRoot = new BABYLON.TransformNode(
`x-root`,
sceneHelper
);
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI(
"UI",
true,
sceneHelper
);
const height = 1;
const Red = "#ff3653";
const Green = "#8adb00";
const Blue = "#2c8fff";
const axesLabel = new BABYLON.GUI.Ellipse();
axesLabel.isPointerBlocker = true;
axesLabel.width = "120px";
axesLabel.height = "120px";
axesLabel.thickness = 4;
axesLabel.color = Red;
axesLabel.background = Red;
const label = new BABYLON.GUI.TextBlock("x", "X");
label.fontSize = 70;
label.fontWeight = "400";
label.color = "#000000";
axesLabel.addControl(label);
advancedTexture.addControl(axesLabel);
axesLabel.linkWithMesh(labelRoot);
const option = { diameter: 0.05, height, tessellation: 96 };
//x-line
const xl = BABYLON.CylinderBuilder.CreateCylinder("x-line", option, sceneHelper);
xl.position.x += -height / 2;
xl.rotation.z = -Math.PI / 2;
const xMlt = new BABYLON.StandardMaterial("", sceneHelper);
xMlt.diffuseColor = BABYLON.Color3.FromHexString(Red);
xl.material = xMlt;
const activeCamera = sceneHelper.activeCamera;
axesLabel.onPointerClickObservable.add((info) => {
activeCamera.restoreState();
camera.setPosition(new BABYLON.Vector3(5));
activeCamera.setPosition(new BABYLON.Vector3(5));
});
总结
这篇文章仅实现了视图助手的x部分,其余读者如果有兴趣可以自行实现。 下篇文章预计实现 本地模型上传生成截图保存至后端