BabylonJs实现一个视图助手

1,834 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

最近使用Babylon.js开发一款在线编辑器,需要使用到视图助手。网上找了下,Three.js的demo比较多,用Babylon实现的视图助手没有,所以自己实现一个。效果和threeJs在线编辑器的视图助手一样.

123.gif

实现Demo基于BabylonJs官方的Playground

思路

对于Babylon来说,我了解到的可以实现的思路主要有2个:

  • 多场景,单独创建一个Scene用于存放助手,渲染的时候2个场景一起渲染
  • 多画布,在主画布上面覆盖一层画布,用于渲染不怎么变化的物体

这里选择第一张方案,实现起来比较简单

多场景渲染实现

  1. 先创建一个新的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;
};

在这个基础上,实现一个多场景渲染的代码.

初始化辅助场景

实现具体效果

image.png

//这里需要注意的是
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));
    });

实现效果

123.gif

总结

这篇文章仅实现了视图助手的x部分,其余读者如果有兴趣可以自行实现。 下篇文章预计实现 本地模型上传生成截图保存至后端