How to create a Google-earth style 3D map

Hello

I am developing a 3D map viewer with a Google-earth style camera.

for example, this is the sort of thing I am hoping to create: Ghost Recon Wildlands - A World With No Heroes

I have created a playground with basic meshes to show how I currently move the camera: https://playground.babylonjs.com/#9BETDS#1

I would like my camera to behave in a similar fashion - tilting when zooming in, being able to pan around with some easing to make it smoother and adding boundaries to the edges.

Any ideas on how to recreate these behaviours would be really appreciated!

Thanks

cc @PolygonalSun as he knows everything about our cameras :slight_smile:

Since you’re using an ArcRotateCamera, it shouldn’t be too difficult to accomplish what you’re trying to do.

The tilting as you zoom in could be as simple as modifying your camera’s beta with respect to your camera’s radius. You could even use a Scalar.Lerp to a smoother transition. You can also use your upper and lower beta limits to prevent the camera from moving to an undesired angle.

For panning, the ArcRotateCamera does have built-in panning and I believe also has a flag for map panning, which should eliminate any vertical movement. By default, panning is handled with a Right-click drag. If you want to that behavior to be with left-click instead, you could just change your attachControl call to something like

// First param doesn't matter, second is for noPreventDefault, third is for using ctrl for panning, and the fourth is to change your panning button to left click
camera.attachControl(canvas, true, false, 0);

For adding a limit, you may need to either use a custom solution that checks for the target’s position before moving or possibly add an observer/callback to one of the camera’s observables like onViewMatrixChangedObservable to zero out the inertialPanningX and/or inertialPanningY values if the target gets to a specific boundary (these inertial panning values are used to smoothly move the camera with inertia if input is received; zero-ing them is effectively the same as cancelling any remaining movement).

These are just a couple of things that come to mind so hopefully, this gives you a starting place.

1 Like

Hello,

Thanks for your response, yeah this gives me a good starting point thank you man. Will try it and come back with any questions

Just thought I’d let you know how I got on. Your suggestions for the panning worked well and I also used the built-in panningDistanceLimit to create the boundary. The map I am panning around is quite square so the limit works nicely.

I am going to work on adding the tilting/radius today. I am wondering how best to implement that feature - is there an observable I could use?

Hi @callumdotexe,

Here’s a solution that uses the onBeforeRenderObservable to run an update loop. It modifies the camera’s beta property based on its radius (i.e the current zoom level).

    const camRadiusTilStart = 60;               // Camera radius (i.e zoom) at which the tilt effect begins
    const camRadiusTiltEnd = 10;                // Camera radius at which the tolt reaches its maximum
    const cameraBetaStart = camera.beta;        // Controls the tilt effect when camera is zoomed out
    const cameraBetaEnd = camera.beta * 2.2;    // Controls the tilt effect when camera is zoomed in
    scene.onBeforeRenderObservable.add(() => {
        // InverseLerp allows us to smoothly interpolate when camera radius is inbetween start/end
        const t = BABYLON.Scalar.InverseLerp(camRadiusTilStart, camRadiusTiltEnd, camera.radius);

        // Lerp to produce a smooth beta value between the tilt start/end values
        const beta = BABYLON.Scalar.Lerp(cameraBetaStart, cameraBetaEnd, t);
        
        // Assign new beta value to camera
        camera.beta = beta;

    });

Modification added to your playground:

Camera movement with mouse click and drag | Babylon.js Playground (babylonjs.com)

Mark

2 Likes