The problem use cesium-babylonjs with ArcRotateCamera

Hi:
developers , I draw model with babylonjs and I have to show the model on ceisumjs canvas. I reference this example to intergated cesium and babylon Babylon.js docs

however the different between my code and this doc cesium-babylonjs is that I use ArcRotateCamera, other code is the same; it failed to combine. when I rotate or scale the Cesium map, the model drawn by babylon is not rotate or scale as well. so what is the problem ? I debug the code and find the new position after call moveBabylonCamera Function which is the same with the old position before rotate. is the camera wrong ?

this is my camera

const camera = new BABYLON.ArcRotateCamera(
    'mainCamera',
    -Math.PI / 2,
    Math.PI / 2,
    12,
    new BABYLON.Vector3(0, 0, 0),
    scene
  )

I can only assume you are not attaching the camera to the canvas OR that the host is removing the pointer events babylon is registering. But without a reproduction there is little we can do

the main code is the same with the example; the different is the camera ; I use ArcRotateCamera

const _this = {}

const canvas = document.getElementsByTagName("canvas")[0]
const LNG = -122.4175, LAT = 37.655

function initCesium() {
  const viewer = new Cesium.Viewer('cesiumContainer', {
    // terrainProvider: Cesium.createWorldTerrain(),
    useDefaultRenderLoop: false
  })

  viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(LNG, LAT, 300),
    orientation: {
      heading: Cesium.Math.toRadians(0.0),
      pitch: Cesium.Math.toRadians(-90.0),
    }
  })

  _this.viewer = viewer
  _this.base_point = cart2vec(Cesium.Cartesian3.fromDegrees(LNG, LAT, 50))
  _this.base_point_up = cart2vec(Cesium.Cartesian3.fromDegrees(LNG, LAT, 300))

  viewer.scene.screenSpaceCameraController.zoomEventTypes = [Cesium.CameraEventType.WHEEL, Cesium.CameraEventType.PINCH]
  viewer.scene.screenSpaceCameraController.tiltEventTypes = [Cesium.CameraEventType.PINCH, Cesium.CameraEventType.RIGHT_DRAG]
}
function initBabylon() {
  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)

  const camera = new BABYLON.ArcRotateCamera(
    'mainCamera',
    -Math.PI / 2,
    Math.PI / 2,
    12,
    new BABYLON.Vector3(0, 0, 0),
    scene
  )
  camera.wheelPrecision = 50
  camera.attachControl(canvas, true)
  camera.target = new BABYLON.Vector3(0, 0, 0) // 摄像机目标点

  _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 light = new BABYLON.HemisphericLight(
    'light1',
    new BABYLON.Vector3(0, 1, 0),
    scene
  )
  light.groundColor = new BABYLON.Color3(0, 0, 0)

  const box = BABYLON.MeshBuilder.CreateBox("box", {
    size: 1,
    faceColors: [
      new BABYLON.Color3(1, 0, 0),
      new BABYLON.Color4(0, 0, 1, 1),
      new BABYLON.Color4(0, 1, 1, 1),
      new BABYLON.Color4(1, 0, 1, 0.57),
      new BABYLON.Color4(1, 0.5, 0.5, 1),
      new BABYLON.Color4(1, 1, 0, 1)
    ]
  }, scene)

  const material = new BABYLON.StandardMaterial("Material", scene)
  material.emissiveColor = new BABYLON.Color3(1, 0, 0)
  material.alpha = 0.5

  // box.material = material
  box.parent = _this.root_node

  const ground = BABYLON.MeshBuilder.CreateGround("ground", {
    width: 5,
    height: 5
  }, scene)
  ground.material = material
  ground.parent = _this.root_node

  _this.engine = engine
  _this.scene = scene
  _this.camera = camera
}

function moveBabylonCamera() {
  let fov = Cesium.Math.toDegrees(_this.viewer.camera.frustum.fovy)
  _this.camera.fov = fov / 180 * Math.PI
  console.log('_this.viewer.camera', _this.viewer.camera)
  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()
  let rotation = BABYLON.Vector3.Zero()
  let transform = BABYLON.Vector3.Zero()
  camera_matrix.decompose(scaling, rotation, transform)

  const camera_pos = cart2vec(transform)
  const camera_direction = cart2vec(_this.viewer.camera.direction)
  const 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

  // _this.camera.radius = _this.base_point.z - camera_pos.z
  // _this.camera.alpha = rotation_y
  // _this.camera.beta = rotation_x
}

function cart2vec(cart) {
  return new BABYLON.Vector3(cart.x, cart.z, cart.y)
}
initCesium()
initBabylon()
_this.engine.runRenderLoop(() => {
  _this.viewer.render()
  // _this.engin.wipeCaches(true)
  moveBabylonCamera()
  _this.scene.render()
})```

The original docs were written in 2021, and have not been revisited since. There might be something else needed here, but i’ll be honest and say I have no experience with ceisum.
Now, a working example might help us be able to debug this, otherwise it is very hard to say what the issues is.

I think @sharp had some skills on that topic (I could be wrong though)

2 Likes

Hi,

I don’t know Cesium but it looks like it works like Mapbox

  • the thing is the camera is not controlled (I mean the inputs with your mouse) by the Babylon Camera but by the Cesium Camera. This is very important to understand because what you want to do is to synchronise the Babylon camera with the the Cesium camera. Babylon is just a layer rendered on top of Cesium. So there’s no point to declare an ArcRotateCamera or a FreeCamera, you just need a Camera.
  • So what you want to do first is to use an Arc Rotate Camera from Cesium and I think I found how here : Control the Camera – Cesium and there is a demo.
1 Like

So in the original code I think what you first need to change - and it could be enough - is the set up of your Cesium scene to use an an ‘Orbit around point’ camera.

One last point you may have to do scene.detachControl(); where scene is the Babylon scene, to be sure that babylon won’t watch mouse events (only Cesium should do it)

thanks for replay . I think this is a subject we should to try . I use another solution . draw the model and the map on the same canvas . it is not very good , but the camera rotate looks better than the bjs doc . and the model can display normally.

show my code

export const _this = {}

// const canvas = document.getElementsByTagName("canvas")[0]
const LNG = -122.4175, LAT = 37.655

export function initCesium() {
  const viewer = new Cesium.Viewer('cesiumContainer', {
    // terrainProvider: Cesium.createWorldTerrain(),
    useDefaultRenderLoop: false
  })

  viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(LNG, LAT, 300),
    orientation: {
      heading: Cesium.Math.toRadians(0.0),
      pitch: Cesium.Math.toRadians(0.0),
    }
  })

  _this.viewer = viewer
  // _this.base_point = cart2vec(Cesium.Cartesian3.fromDegrees(LNG, LAT, 50))
  // _this.base_point_up = cart2vec(Cesium.Cartesian3.fromDegrees(LNG, LAT, 300))

  viewer.scene.screenSpaceCameraController.zoomEventTypes = [Cesium.CameraEventType.WHEEL] // 只允许滚轮缩放
  viewer.scene.screenSpaceCameraController.tiltEventTypes = [Cesium.CameraEventType.LEFT_DRAG] // 只允许右键拖拽倾斜
  viewer.scene.screenSpaceCameraController.rotateEventTypes = [Cesium.CameraEventType.RIGHT_DRAG] // 只允许左键拖拽旋转


  // viewer.scene.screenSpaceCameraController.zoomEventTypes = [Cesium.CameraEventType.WHEEL, Cesium.CameraEventType.PINCH]
  // viewer.scene.screenSpaceCameraController.tiltEventTypes = [Cesium.CameraEventType.PINCH, Cesium.CameraEventType.RIGHT_DRAG]
  _this.canvas = viewer.canvas
}
export function initBabylon() {
  const engine = new BABYLON.Engine(_this.canvas)
  const scene = new BABYLON.Scene(engine)
  scene.clearColor = BABYLON.Color4(0, 0, 0, 0)
  scene.autoClear = false

  // const camera = new BABYLON.FreeCamera("camera", new BABYLON.Vector3(0, 0, -10), scene)

  const camera = new BABYLON.ArcRotateCamera(
    'mainCamera',
    -Math.PI / 2,
    Math.PI / 2,
    12,
    new BABYLON.Vector3(0, 0, 0),
    scene
  )
  camera.wheelPrecision = 50
  camera.attachControl(_this.canvas, true)
  camera.target = new BABYLON.Vector3(0, 0, 0) // 摄像机目标点

  _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 light = new BABYLON.HemisphericLight(
    'light1',
    new BABYLON.Vector3(1, 1, 0),
    scene
  )
  light.groundColor = new BABYLON.Color3(0, 0, 0)

  const box = BABYLON.MeshBuilder.CreateBox("box", {
    size: 1,
    faceColors: [
      new BABYLON.Color3(1, 0, 0),
      new BABYLON.Color4(0, 0, 1, 1),
      new BABYLON.Color4(0, 1, 1, 1),
      new BABYLON.Color4(1, 0, 1, 0.57),
      new BABYLON.Color4(1, 0.5, 0.5, 1),
      new BABYLON.Color4(1, 1, 0, 1)
    ]
  }, scene)

  const material = new BABYLON.StandardMaterial("Material", scene)
  material.emissiveColor = new BABYLON.Color3(1, 0, 0)
  material.alpha = 0.5
  // box.material = material

  box.parent = _this.root_node
  box.actionManager = new BABYLON.ActionManager(scene)
  box.actionManager.registerAction(
    new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPointerOverTrigger, function () {
      console.log('OnPickDownTrigger event')
    })
  )

  // box.actionManager.registerAction(
  //   new BABYLON.SetValueAction(
  //     BABYLON.ActionManager.OnPointerOverTrigger, box.material, "emissiveColor", BABYLON.Color3.White()
  //   )
  // )

  const ground = BABYLON.MeshBuilder.CreateGround("ground", {
    width: 5,
    height: 5
  }, scene)
  ground.material = material
  ground.parent = _this.root_node

  _this.engine = engine
  _this.scene = scene
  _this.camera = camera
}

export const initFrame = () => {
  console.log('call initFrame')
  initCesium()
  initBabylon()

  _this.engine.runRenderLoop(() => {
    _this.engine.wipeCaches(true)
    _this.viewer.render()
    // moveBabylonCamera()
    _this.scene.render()
  })
}

initFrame ()

if I use scene.detachControl(). the babylon camera is useless . when I rotate the map of cesium. the model did not rotate , it become static