Babylon.js and Cesium demo bug

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Cesium和Babylonjs结合使用demo</title>
    <meta name="description" content=""/>
    <link rel="stylesheet" href="https://www.3dyzt.com/00/Build/Apps/CesiumViewer/CesiumViewer.css" media="screen" />
    <style>
        html, body {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
        }

        #cesiumContainer {
            width: 100%;
            height: 100%;
        }

        #canvas {
            width: 100%;
            height: 100%;
            position: absolute;
            left: 0;
            top: 0;
            pointer-events: none;
        }
    </style>
</head>

<body>
    <!-- 绘制 cesium.js ,会放在最低层-->
    <div id="cesiumContainer" class="fullWindow"></div>
    <canvas id="canvas" touch-action="none"></canvas>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.2/dat.gui.min.js"></script>
    <script src="https://assets.babylonjs.com/generated/Assets.js"></script>
    <script src="https://cdn.babylonjs.com/recast.js"></script>
    <script src="https://cdn.babylonjs.com/ammo.js"></script>
    <script src="https://cdn.babylonjs.com/havok/HavokPhysics_umd.js"></script>
    <script src="https://cdn.babylonjs.com/cannon.js"></script>
    <script src="https://cdn.babylonjs.com/Oimo.js"></script>
    <script src="https://cdn.babylonjs.com/earcut.min.js"></script>
    <script src="https://cdn.babylonjs.com/babylon.js"></script>
    <script src="https://cdn.babylonjs.com/materialsLibrary/babylonjs.materials.min.js"></script>
    <script src="https://cdn.babylonjs.com/proceduralTexturesLibrary/babylonjs.proceduralTextures.min.js"></script>
    <script src="https://cdn.babylonjs.com/postProcessesLibrary/babylonjs.postProcess.min.js"></script>
    <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.js"></script>
    <script src="https://cdn.babylonjs.com/serializers/babylonjs.serializers.min.js"></script>
    <script src="https://cdn.babylonjs.com/gui/babylon.gui.min.js"></script>
    <script src="https://cdn.babylonjs.com/inspector/babylon.inspector.bundle.js"></script>
    <!-- 引入 cesium 会用到的js -->
    <script src="https://www.3dyzt.com/00/Build/Cesium/Cesium.js"></script>
<script>

// 记录 cesium 和 babylon 的相关对象,后续会通过这些对象,进行适配
const _this = {};

let canvas = document.getElementById("canvas");

// 纬度
let LNG = -122.4175;
// 精度
let LAT = 37.655;

// 初始化 Cesium
async function initCesium() {

    // 实例 Cesium 对象
    const viewer = new Cesium.Viewer(
        'cesiumContainer',
        {
            // 为地球仪提供曲面几何图形的地形提供程序。
            terrainProvider: await Cesium.createWorldTerrainAsync(),
            useDefaultRenderLoop: false,
        }
    );

    // 将相机飞向指定的坐标
    viewer.camera.flyTo({
        // 相机在WGS84(世界)坐标或从上到下可见的矩形中的最终位置。
        destination : Cesium.Cartesian3.fromDegrees(LNG, LAT, 300),
        /**
         * 包含方向和向上特性或航向、俯仰和滚转特性的对象。
         * 默认情况下,该方向在三维视图中将指向帧的中心,在哥伦布视图中将指向负z方向。
         * 向上的方向将指向3D中的局部北方,并指向哥伦布视图中的正y方向。
         * 在无限滚动模式下,2D中不使用方向。
         * 
         */
        orientation : {
            // 类似左右角度
            heading : Cesium.Math.toRadians(0.0),
            // 类似上下角度, -90 为朝下
            pitch : Cesium.Math.toRadians(-90.0),
        }
    });

    // Cesium 对象
    _this.viewer = viewer;

    // 基点
    _this.base_point = cart2vec(Cesium.Cartesian3.fromDegrees(LNG, LAT, 50));
    // 朝上基点
    _this.base_point_up = cart2vec(Cesium.Cartesian3.fromDegrees(LNG, LAT, 300));

    // console.log(
    //     "_this.base_point", _this.base_point,
    //     "_this.base_point_up", _this.base_point_up
    // );
    
    // 初始化 babylon
    initBabylon();

    // babylon 的渲染事件,每帧会被调用
    _this.engine.runRenderLoop(() => {

        // 渲染
        _this.viewer.render();
        // 计算让babylon的相机适应Cesium的相机
        moveBabylonCamera();
        // babylon 渲染
        _this.scene.render();

    });

}

// 初始化 babylon
function initBabylon() {

    // 初始化 BABYLON 3D engine
    const engine = new BABYLON.Engine(canvas);
    // 实例场景
    const scene = new BABYLON.Scene(engine);
    // 场景的背景颜色
    scene.clearColor = BABYLON.Color4(0, 0, 0, 0);

    // 创建相机
    const camera = new BABYLON.FreeCamera("camera", new BABYLON.Vector3(0, 0, -10), scene);

    // 添加灯光
    var light = new BABYLON.HemisphericLight("light1", new BABYLON.Vector3(0, 1, 0), scene);

    // 亮度
    light.intensity = 1;
    
    _this.root_node = new BABYLON.TransformNode("BaseNode", scene);
    
    _this.root_node.lookAt(
        _this.base_point_up.subtract(_this.base_point)
    );
    
    _this.root_node.addRotation(Math.PI / 2, 0, 0);
    
    const box = BABYLON.MeshBuilder.CreateBox("box", {size: 10}, scene);
    const material = new BABYLON.StandardMaterial("Material", scene);
    material.emissiveColor = new BABYLON.Color3(1, 0, 0);
    material.alpha = 0.5;
    box.material = material;
    // 将整个物体绑定在 与 Cesium 经纬度一致的对象上
    box.parent = _this.root_node;

    const ground = BABYLON.MeshBuilder.CreateGround("ground", {
        width: 100,
        height: 100
    }, scene);
    ground.material = material;

    // 将整个物体绑定在 与 Cesium 经纬度一致的对象上
    ground.parent = _this.root_node;

    // 异步加载
    BABYLON.SceneLoader.LoadAssetContainerAsync("https://www.3dyzt.com/00/Build/Cesium/08/", "ceshi.glb", scene).then(function (container) {
        
        var meshes = container.meshes;
        var materials = container.materials;
        
        // 将整个物体绑定在 与 Cesium 经纬度一致的对象上
        meshes[0].parent = _this.root_node;

        // 缩放
        meshes[0].scaling.setAll(10);
        // 坐标
        meshes[0].position.set(0, 10, 0);
        
        // 将添加的容器内容从场景中删除
        container.removeAllFromScene();
        // 将模型添加到场景中
        container.addAllToScene();


    });
    
    _this.engine = engine;
    _this.scene = scene;
    _this.camera = camera;

    // 监听浏览器改变大小的事件,通过调用engine.resize()来自适应窗口大小
    window.addEventListener("resize", function () {
        engine.resize();
    });

}

/**
 * 这里会通过算法,让babylon 的相机, 和 Cesium 的相机匹配
 */
function moveBabylonCamera() {

    // console.log(
    //     "_this.viewer.camera", _this.viewer.camera.position
    // );
    
    let fov = Cesium.Math.toDegrees(_this.viewer.camera.frustum.fovy)
    _this.camera.fov = fov / 180 * Math.PI;

    let civm = _this.viewer.camera.inverseViewMatrix;
    let camera_matrix = BABYLON.Matrix.FromValues(
        civm[0 ], civm[1 ], civm[2 ], civm[3 ],
        civm[4 ], civm[5 ], civm[6 ], civm[7 ],
        civm[8 ], civm[9 ], civm[10], civm[11],
        civm[12], civm[13], civm[14], civm[15]
    );

    let scaling = BABYLON.Vector3.Zero(), rotation = BABYLON.Vector3.Zero(), transform = BABYLON.Vector3.Zero();
    camera_matrix.decompose(scaling, rotation, transform);
    let camera_pos = cart2vec(transform),
        camera_direction = cart2vec(_this.viewer.camera.direction),
        camera_up = cart2vec(_this.viewer.camera.up);

    let rotation_y = Math.atan(camera_direction.z / camera_direction.x);
    if (camera_direction.x < 0) rotation_y += Math.PI;
    rotation_y = Math.PI / 2 - rotation_y;
    let rotation_x = Math.asin(-camera_direction.y);
    let camera_up_before_rotatez = new BABYLON.Vector3(-Math.cos(rotation_y), 0, Math.sin(rotation_y));
    let rotation_z = Math.acos(camera_up.x * camera_up_before_rotatez.x + camera_up.y * camera_up_before_rotatez.y + camera_up.z * camera_up_before_rotatez.z);
    rotation_z = Math.PI / 2 - rotation_z;
    if (camera_up.y < 0) rotation_z = Math.PI - rotation_z;

    _this.camera.position.x = camera_pos.x - _this.base_point.x;
    _this.camera.position.y = camera_pos.y - _this.base_point.y;
    _this.camera.position.z = camera_pos.z - _this.base_point.z;
    _this.camera.rotation.x = rotation_x;
    _this.camera.rotation.y = rotation_y;
    _this.camera.rotation.z = rotation_z;
}

function cart2vec(cart) {
    return new BABYLON.Vector3(cart.x, cart.z, cart.y);
}

initCesium();



</script>

</body>

</html>



bug:

The mountain cannot be obstructed

It is expected, the demo only synchronise the cesium camera to babylon camera, depth is not taken into consideration, so the babylon part will always before the cesium part.

1 Like

Babylon.js and Cesium.js 3d world demo