A globe camera controller for Unity

I’m trying to implement a “good” camera controller for an application created in Unity using Cesium.

The CameraController provided in the cesium-unity repo is not suitable for our needs. We need to handle mouse/touch controls, but the CameraController provided just handles mouse movement and doesn’t handling click & drag with the mouse/touch.

The scene camera provided in the Cesium Sandcastle demo is more what I am looking for but I find it difficult to translate the ~4K lines of JavaScript code to C# in Unity and I suspect that someone may have implemented a camera model they are willing to share?

I’m using the camera controller in Google Earth as a reference for my own camera implementation, but I’m struggling to solve a few issues. For example: How to handle cases where a user clicks & drags into space (when the drag originates or moves off the globe), or when the horizon is clicked at oblique angles can cause large changes in the camera position.

Another issue occurs where the camera will lock up at the poles, and it seems the camera controller for the Sandcastle demos doesn’t handle this case very well either. I know I can use quaternion rotations to avoid the gimbal lock, but maybe someone else has solved this issue in Unity already?

Any help with this would be appreciated.

Thanks in advance!

Hi @jpvanoosten,

I can sympathize with CesiumJS’s camera controller code being hard to follow. Unfortunately we haven’t developed a counterpart in Unity, but I’ll try and take a stab at your questions. (Though I hope other community members can chime in with their own solutions!)

How to handle cases where a user clicks & drags into space (when the drag originates or moves off the globe),

I’ve tried to do some “globe spinning” behavior before, though it only activated when the user clicked on the globe. (so drags originating off of the globe didn’t work). But this is what I tried:

  • Get the geodetic normal of the grabbed position
  • As the user is dragging, find the geodetic normal of the new position
  • Compute the angle between these normals using quaternions
  • Apply this rotation.
    • If you want the globe to keep spinning as you let go, you’ll probably have to implement some inertia-based spinning behavior, using the previously computed rotation as a sort of “max rotational speed” value.

This worked well for me because I scaled the globe and set the CesiumGeoreference to the center of the globe (ECEF [0, 0, 0]). This meant that the Unity origin was at the center of my globe, simplifying the rotation computations. But this may get complicated if your CesiumGeoreference isn’t at the globe’s center.

Another issue occurs where the camera will lock up at the poles

I’m just theorizing, but maybe a drag action can be broken into “horizontal” and “vertical” components relative to the globe, and the resulting rotations can be applied as separate quaternions?

the horizon is clicked at oblique angles can cause large changes in the camera position.

Do you have a screenshot / video of how this happens, and how it affects your controller’s behavior?

1 Like

Hi @janine, does this mean Cesium has lost the capability for geographic coordinate calculations, like globeAnchor.longitudeLatitudeHeight, and is now only used for texturing an ellipsoid? If that’s the case, wouldn’t it make more sense to simplify Cesium to just download map tiles and texture a specified object, rather than include various coordinate systems and transformations that can’t actually be utilized?

Hi @MBG,

Cesium has not lost the capability for geographic coordinate calculations – in fact, that’s the core of how the plugin interfaces with Unity’s coordinate system, so it would be a mistake to remove it. :sweat_smile:

I see that you’re having issues on another forum post. I think Kevin’s latest answer here might help with any misunderstandings.

Let’s keep talking there so the discussion can stay in one place. Thank you! :smile:

Hi @janine

Geographic coordinate transformations are not implemented in Cesium on some platforms. For example, in this Android device log, an error states: ‘The native implementation is missing, so CenteredFixedToLongitudeLatitudeHeight cannot be invoked. This is an essential feature, yet the required function is missing, preventing us from performing coordinate transformations.

adb logcat -s Unity
...
11-05 00:15:48.615 12910 12951 E Unity   :   at CesiumForUnity.CesiumGeoreference.MoveOrigin () [0x0003d] in ./Library/PackageCache/com.cesium.unity@1.13.0/Runtime/CesiumGeoreference.cs:500 
11-05 00:15:48.615 12910 12951 E Unity   :   at CesiumForUnity.CesiumGeoreference.set_originPlacement (CesiumForUnity.CesiumGeoreferenceOriginPlacement value) [0x00008] in .
11-05 00:15:48.617 12910 12951 E Unity   : NotImplementedException: The native implementation is missing so CenteredFixedToLongitudeLatitudeHeight cannot be invoked. This may be caused by a missing call to CreateImplementation in one of your constructors, or it may be that the entire native implementation shared library is missing or out of date.
11-05 00:15:48.617 12910 12951 E Unity   :   at CesiumForUnity.CesiumEllipsoid.CenteredFixedToLongitudeLatitudeHeight (Unity.Mathematics.double3 ellipsoidCenteredEllipsoidFixed) [0x0004b] in ./Library/PackageCache/com.cesium.unity@1.13.0/Runtime/generated/Reinterop.RoslynSourceGenerator/CesiumEllipsoid-generated.cs:946 
11-05 00:15:48.617 12910 12951 E Unity   :   at CesiumForUnity.CesiumGeoreference.UpdateOtherCoordinates () [0x00067] in ./Library/PackageCache/com.cesium.unity@1.13.0/Runtime/CesiumGeoreference.cs:557 
...

Hi @MBG,

That error is very surprising. That method should be implemented on Android, just the same as any other platform. A couple of questions for you:

  1. What version of Cesium for Unity are you using?
  2. How did you install Cesium for Unity? Is it from the Unity Package Manager and our registry? Or did you build it yourself?
  3. Does other functionality work on Android? If not, the most likely cause is that you’ve built for 32-bit Android. Cesium for Unity only supports 64-bit platforms. See here: Launching Cesium for Unity - #23 by Kevin_Ring

Hi @Kevin_Ring

Aha, I found the problem by checking all the settings. In my project, the Scripting Backend was switched to “Mono,” which only supports the ARMv7 architecture—even though I’m certain I changed it previously. When I reverted to the IL2CPP backend and enabled only ARM64 architecture, the globe view started working on my Android device!

Please note, Cesium can work on an ARMv7 build for local views but not for globe views. I didn’t notice the issue immediately because local Cesium maps were working on the Android device. Following the discussion thread, I assumed Cesium couldn’t work at all with an ARMv7 build, but it actually can. I suspect that when I upgraded my installed Unity builds, some settings reverted to default. I’ve been testing this with two recent Cesium versions across Unity 2021, 2022, and Unity 6, sequentially upgrading between versions. So it doesn’t appear to depend on either the Unity or Cesium versions. Would you verify this and add a note to the referenced post to help avoid similar confusion for others? Thanks.

I’m not sure what you saw, but I’m quite certain that Cesium for Unity will not work at all on 32-bit architectures. We simply don’t compile the native C++ code for that platform. If you compiled it yourself from source for a 32-bit platform, then I guess it’s possible it would run, but I’d be very surprised!

In any case, I’m glad you were able to get it working!

You don’t want to move the globe. You want to rotate a camera around the globe. I created a good globe controller for my game Glider Sim. Here is an example video of it: Cesium - Earth Browser

If you need to tilt the camera, then you could rotate based off the hit point on the Earth. I kind of do this for my other camera controller for my maps as seen here. But this controller was a bit more involved, as I translate the RayCaster across the map instead of rotating it. But all tilting and zooming is based off the hit point on the terrain. https://www.youtube.com/watch?v=YVUgMxAxgOg&t=22s

related to this thread.

recently I tried some my shabby code with Unity and result is not good :frowning:

I found that making google earth style camera is difficult to me.

as you guys know, for Cesium for Unity there is no screen space controller for camera.

I found that for Cesium for Unreal. there is screen space controller for globe camera PR and it is merged into the repository.

if there is someone who trying to implement this. check these code and video. if you succeed to implement this, please upload PR for Cesium for Unity Community I will be happy for it :pray: