CesiumGS / cesium

An open-source JavaScript library for world-class 3D globes and maps :earth_americas:
https://cesium.com/cesiumjs/
Apache License 2.0
12.94k stars 3.49k forks source link

BUG? 3D Tilesets and Atmosphere cant go along? #12111

Closed worldpeaceenginelabs closed 3 months ago

worldpeaceenginelabs commented 3 months ago

What happened?

There are multiple developers complaining in various posts about issues related to Google Photorealistic, which appears to be causing errors.

Reproduction steps

Reproduction 1: Cesiums Sandcastle Examples come with the issue already Add a point entity to SANDCASTLE GOOGLE PHOTOREALISTIC example from ION Website under My Assets (which should definitly work) like this:

// Add a point entity
        viewer.entities.add({
            position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
            point: {
                pixelSize: 10,
                color: Cesium.Color.RED,
                outlineColor: Cesium.Color.WHITE,
                outlineWidth: 2
            },
            label: {
                text: 'Point Entity',
                font: '14pt sans-serif',
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                outlineWidth: 2,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                pixelOffset: new Cesium.Cartesian2(0, -9)
            }
        });

...and you end up under the globe after double clicking the entity, and all the other issues like described here (https://community.cesium.com/t/the-google-earth-3d-tileset-from-ion-is-hovering-over-the-2d-globe/33768) and here (https://community.cesium.com/t/atmosphere-and-3d-photorealistic-do-not-work-together/34348)

Reproduction 2: Combine the Cesium Examples, they dont work! Combine SANDCASTLE GOOGLE PHOTOREALISTIC example from ION in My Assets and the SANDCASTLE ATMOSPHERE example, they will crash with a typeerror which makes the globe stuck/freeze!

Sandcastle example

See reproduction steps

Environment

Browser: Chrome CesiumJS Version: 1.20 Operating System: Windows 11 Pro

javagl commented 3 months ago

In the line position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, you are calling the Cartesian3.fromDegrees function, and only passing in two arguments. This is fine, but the third argument - height - defaults to 0.0 in this case. Meaning that the point will be ~"at sea level", so to speak. (Not really, but... you can imagine it like that...)

When you change this to position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 100), the point will appear at a height of 100 meters, which should be well above the buildings here:

Cesium DEFINITIVE BUG


Regarding the second point: It's not clear what you mean when you suggest to "combine" these sandcastles. The first one passes globe: false, to the viewer constructor. The reason for that (as stated in the comment) is that the "Cesium built-in globe" should not be used, because it should display the Google Photorealistic 3D Tiles data (which is ... its own "globe" in some way...).

The second one explicitly accesses the globe in various places, for example, when setting

const globe = scene.globe;
...
globe.atmosphereLightIntensity = 20.0;

When this is executed with a viewer that was created with globe: false, then... there is no globe, meaning globe will be undefined there, and it will crash with a TypeError.

javagl commented 3 months ago

Maybe the workaround you're looking for: When creating the viewer for the Google tilesets without the globe: false part, but afterwards set viewer.scene.globe.show = false; then it will not be displayed, but most of the atmosphere stuff should still work...

worldpeaceenginelabs commented 3 months ago

In the line position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, you are calling the Cartesian3.fromDegrees function, and only passing in two arguments. This is fine, but the third argument - height - defaults to 0.0 in this case. Meaning that the point will be ~"at sea level", so to speak. (Not really, but... you can imagine it like that...)

When you change this to position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 100), the point will appear at a height of 100 meters, which should be well above the buildings here:

Cesium DEFINITIVE BUG Cesium DEFINITIVE BUG

Hi. Thank you for your suggestions! The problem with this is that if you turn the camera, it could be anything in the area (the pin wobbling around) But what i want of course is to precisely marking of a point, building, maybe a tree, like it does in the 2D map. (the 2D map seems to be 0.0 "above sealevel" and the 3D map is a few 10 to 100m above.)

worldpeaceenginelabs commented 3 months ago

Maybe the workaround you're looking for: When creating the viewer for the Google tilesets without the globe: false part, but afterwards set viewer.scene.globe.show = false; then it will not be displayed, but most of the atmosphere stuff should still work...

Thank you! I was testing that out and come back to my first conclusion: something similar to a z-index bug.

Why? With combining i meant like the Sandcastle provided here. Taking the Ion example and combining it with the atmosphere example. should work, but doesnt. (i understand the globe: false part and of course i adapted it, but the basic example should run with these adaption) Sandcastle from Cesium Ion Photorealistic Example plus Sandcastle Atmosphere

I played around with the following four, remove the // or adding the //: // globe: false, // skyAtmosphere: new Cesium.SkyAtmosphere(), // viewer.scene.globe.show = false; // viewer.scene.skyAtmosphere.show = true;

As it is set now in the above Sandcastle, from the ground you see an Atmosphere, Sun, etc. But from space, the atmosphere flickers up and then falls behind/under the 3D tileset. I did a super fast screenshot, in case you cant see it on yours because too fast or similar:

image

javagl commented 3 months ago

But what i want of course is to precisely marking of a point, building, maybe a tree, like it does in the 2D map.

Then you have to know the height of that point. And knowing that is far from trivial (and in many cases, plainly impossible).

But my gut feeling is that Scene.clampToHeightMostDetailed might be what you're looking for. I'll skip the disclaimers here, and just post that sandcastle:

https://sandcastle.cesium.com/#c=fVR/b+I4EP0qFv+UStSktJS2R6vrEa4NAtIuKd3ucVqZZEIsHDtnO0B62u9+doAsrbaHEMHz482b8bw0m+heEq5RDxTN08EEkTAEpZAWqBC5RFRwRJQCrWZ8G4M9wXEEMcmZviuDA7EEjm7QrAbFIJnfh9SnA+/5zTsdU095/Es77HkX3jL7Ou0NrrAJ+ie6X9qgZPy2ePPv+8544qz9wDsfBk9n39KRfg2eWq+F0x67YzZqDagfGKvbp8PeIPtmwMZuuB6/hcpLWRKZ8ygIi1Gw3Bi8zejBwYvVFe/Elxd6+XSRr6bia/EyaQ3Za7jy+6+bq8W0k4SFy6fyeTSr/TbjMx4KrjRaUViDNL1wWO9mgqelrT6rheW5J7gmlIOc1Rro3xlHqNlEQUIVMl+CFkzMCUNnLgooAzNI+wsaKYEiqsicAdIJ7NJsMNhZZxJWYK6BahRLkSLKNcgYJOULtKY6sTkoIprYxDLrGsWEKWjskNwS24bbyC1uCoQrtAbTDES2Skp4ThgrdjkSToDvGSGiU6GyBGRJTi2Lu8pwfTiOyaGnfrwn0HIR4RHqCZan81whOzVEpCkuNApzKU17rEAqzzIhNUS7tFjIz0amSh4hcBiJCB5puAT5oWsvJQuQBWKkAKn+r5wtdDD0z8rNiYKhBftY7sfxwZbs7/QGkTWhe/Hg7ePMDbZubG/SiOXOyseL6q1Wp91yOhZou2a4bA5nkqZU0xUoTKKovgM/rJcJZQKE1di+FDFNKUr4WVnFhYUEUPWTThu3rzqdiwY6d7BzdnnZbqBTx3Es2hYrZCTNIHrcQaqqiXecyqhAPABdJHoklHbBLD2DqP7XnszfPxkKBpiJRf0j9jbCjPwuiow0MmHWGpmLobqoZlAe6a73Uk77AtfVv8bWbLKvt4qzn4xugE3om9nOU6ext4aCCXNt+zHZE/7Sdyu/yLVRCfR+Efby4AX9j4EvNNLJNWpZ84/Sycgc2AEPDRtD6+ixbK5fNndUocTCcj46Pc/MG8Co8UQZTcc//UoXDCoeQws9sSb8pzccfr8bu9/952DojT/lVdlXIDUNCfMlXVBeQU7fmfEffhD4o8a7GfpxbPbtncar9WrVnQY6uTou269UUGvUuiXzW2v/naZWYyiXrI5xU0OaMWLSm/PcaEjjUJWL0G3uU7oRXSEa3fzijWrXUynjiXNWXu6sdtttmvh3aUyQyLzqfNOzUb4JsTS6yentcOvAGHeb5miLfszVQrA5kQe4/wE


For the second part, I'm not entirely sure what the question is. The built-in globe and the atmostphere in CesiumJS are carefully adjusted to fit each other. When loading the Google tilesets, these tilesets are "just an arbitrary pile of geometry" (from the perspective of CesiumJS). CesiumJS does not know the details, heights, and shape of this data. The fact that parts of this geometry data overlap the rendered atmosphere is nearly inevietable. I mean, you could just set tileset.modelMatrix = Cesium.Matrix4.fromUniformScale(0.99); to make earth a bit smaller and see the atmosphere, but that might lead to "undesired effects" elsewhere. I don't fully understand what the expectation is. But when it's a DEFINITIVE BUG, then there might be a way of describing that bug precisely, and maybe eventually fixing it...

worldpeaceenginelabs commented 3 months ago

@javagl, thank you so much. You were absolutely helpful pushing me in the right direction! I’ve finally understood what’s happening.

The method Scene.clampToHeightMostDetailed should do the job, but here’s why it doesn’t:

Precise Bug Description:

I’m not sure if it still qualifies as a bug, but the z-index comparison wasn’t entirely off the mark. Picture using the base globe without the 3D tiles: coordinates adhere to the base globe’s ground as intended. Now, add the atmosphere. It’s rendered on the base globe, of course. When we zoom in, the base globe’s surface transitions from space atmosphere to globe atmosphere seamlessly. So far, so good.

However, when we introduce the 3D Tileset, where does it go? It’s placed above the base globe’s surface. This layer renders the space atmosphere, which becomes invisible because the 3D tileset is positioned above the globe’s surface.

Effect:

We can’t display the space atmosphere and 3D tilesets simultaneously. I would label this as a bug, but please correct me if I’m mistaken. My goal isn’t to find bugs but to find solutions. I wanted to bring attention to this issue because it seems like a significant bug. Developers, of course, want to utilize both the atmosphere and 3D tiles, not just one or the other.

Workaround:

The workaround can be seen here: https://cloudatlas.club Initially, the atmosphere is shown; then, as you zoom in, you get a Google Photorealistic view! Zooming out brings back the atmosphere. If the transition was smooth, it would be perfect. (smoother with tileset.show = true; works like a pre-load, but looks odd) And the userlocation (green pulsating dot) gets initialized on the base globe (with and without Scene.clampToHeightMostDetailed) because i didnt deactivate it. Because i need it to show the atmosphere.

// Initialize Cesium viewer with specified configuration options
      viewer = new Viewer('cesiumContainer', {
        animation: false,
        fullscreenButton: false,
        vrButton: true,
        geocoder: false,
        homeButton: false,
        infoBox: true,
        selectionIndicator: false,
        timeline: false,
        navigationHelpButton: false,
        shouldAnimate: true,
        skyBox: false,
        contextOptions: {
        webgl: {
        alpha: true
        },
        },
        // This is a global 3D Tiles tileset so disable the
        // globe to prevent it from interfering with the data
        // globe: false,
        // Disabling the globe means we need to manually
        // re-enable the atmosphere
        // skyAtmosphere: false, // new Cesium.SkyAtmosphere(),
        // 2D and Columbus View are not currently supported
        // for global 3D Tiles tilesets
        sceneModePicker: false,
        // Imagery layers are not currently supported for
        // global 3D Tiles tilesets
        baseLayerPicker: false,
      });

      viewer.scene.backgroundColor = Cesium.Color.TRANSPARENT;

    // Load Cesium 3D Tileset from Cesium Ion using the specified asset ID (2275207=Google Photorealistic Earth)
    try {const tileset = await Cesium3DTileset.fromIonAssetId(2275207);viewer.scene.primitives.add(tileset);

// WORKAROUND START WORKAROUND START WORKAROUND START WORKAROUND START

    // Initially hide the 3D tileset
    tileset.show = false; // if true, smoother transition, but looks unclean (3dtiles show up first, then swiches to the atmosphere, but transition is smoother)

    // Set up a camera move end event listener
    viewer.camera.moveEnd.addEventListener(function () {
      const height = viewer.camera.positionCartographic.height; console.log(`Distance to ground ${Math.floor(height / 1000)} km`);

      if (height > 14000000) {
        // Show the base layer and hide the 3D tileset
        globe.show = true;
        tileset.show = false;
      } else {
        // Hide the base layer and show the 3D tileset
        globe.show = false;
        tileset.show = true;
      }
    });

    } catch (error) {console.log(error);}

// WORKAROUND END WORKAROUND END WORKAROUND END WORKAROUND END

      // Atmosphere
      const scene = viewer.scene;
        const globe = scene.globe;
        const skyAtmosphere = scene.skyAtmosphere;

        scene.highDynamicRange = true;
        globe.enableLighting = true;
        globe.atmosphereLightIntensity = 20.0;

        // Function to get the current time in ISO 8601 format
    function getCurrentTimeIso8601() {
        const now = new Date();
        return now.toISOString();
        }

    // Get the current time in ISO 8601 format and update the viewer's clock
    const currentTime = getCurrentTimeIso8601();
    viewer.clock.currentTime = JulianDate.fromIso8601(currentTime);

    const canvas = viewer.canvas;
    canvas.setAttribute("tabindex", "0"); // needed to put focus on the canvas
    canvas.onclick = function () {
    canvas.focus();
    };

    const defaultGroundAtmosphereLightIntensity =
    globe.atmosphereLightIntensity;
    const defaultGroundAtmosphereRayleighCoefficient =
    globe.atmosphereRayleighCoefficient;
    const defaultGroundAtmosphereMieCoefficient =
    globe.atmosphereMieCoefficient;
    const defaultGroundAtmosphereMieAnisotropy =
    globe.atmosphereMieAnisotropy;
    const defaultGroundAtmosphereRayleighScaleHeight =
    globe.atmosphereRayleighScaleHeight;
    const defaultGroundAtmosphereMieScaleHeight =
    globe.atmosphereMieScaleHeight;
    const defaultGroundAtmosphereHueShift = globe.atmosphereHueShift;
    const defaultGroundAtmosphereSaturationShift =
    globe.atmosphereSaturationShift;
    const defaultGroundAtmosphereBrightnessShift =
    globe.atmosphereBrightnessShift;
    const defaultLightFadeOut = globe.lightingFadeOutDistance;
    const defaultLightFadeIn = globe.lightingFadeInDistance;
    const defaultNightFadeOut = globe.nightFadeOutDistance;
    const defaultNightFadeIn = globe.nightFadeInDistance;

    const defaultSkyAtmosphereLightIntensity =
    skyAtmosphere.atmosphereLightIntensity;
    const defaultSkyAtmosphereRayleighCoefficient =
    skyAtmosphere.atmosphereRayleighCoefficient;
    const defaultSkyAtmosphereMieCoefficient =
    skyAtmosphere.atmosphereMieCoefficient;
    const defaultSkyAtmosphereMieAnisotropy =
    skyAtmosphere.atmosphereMieAnisotropy;
    const defaultSkyAtmosphereRayleighScaleHeight =
    skyAtmosphere.atmosphereRayleighScaleHeight;
    const defaultSkyAtmosphereMieScaleHeight =
    skyAtmosphere.atmosphereMieScaleHeight;
    const defaultSkyAtmosphereHueShift = skyAtmosphere.hueShift;
    const defaultSkyAtmosphereSaturationShift =
    skyAtmosphere.saturationShift;
    const defaultSkyAtmosphereBrightnessShift =
    skyAtmosphere.brightnessShift;

    const viewModel = {
    // Globe settings

    enableTerrain: false,
    enableLighting: true,
    groundTranslucency: false,

    // Ground atmosphere settings

    showGroundAtmosphere: true,
    groundAtmosphereLightIntensity: defaultGroundAtmosphereLightIntensity,
    groundAtmosphereRayleighCoefficientR:
        defaultGroundAtmosphereRayleighCoefficient.x / 1e-6,
    groundAtmosphereRayleighCoefficientG:
        defaultGroundAtmosphereRayleighCoefficient.y / 1e-6,
    groundAtmosphereRayleighCoefficientB:
        defaultGroundAtmosphereRayleighCoefficient.z / 1e-6,
    groundAtmosphereMieCoefficient:
        defaultGroundAtmosphereMieCoefficient.x / 1e-6,
    groundAtmosphereRayleighScaleHeight: defaultGroundAtmosphereRayleighScaleHeight,
    groundAtmosphereMieScaleHeight: defaultGroundAtmosphereMieScaleHeight,
    groundAtmosphereMieAnisotropy: defaultGroundAtmosphereMieAnisotropy,
    groundHueShift: defaultGroundAtmosphereHueShift,
    groundSaturationShift: defaultGroundAtmosphereSaturationShift,
    groundBrightnessShift: defaultGroundAtmosphereBrightnessShift,
    lightingFadeOutDistance: defaultLightFadeOut,
    lightingFadeInDistance: defaultLightFadeIn,
    nightFadeOutDistance: defaultNightFadeOut,
    nightFadeInDistance: defaultNightFadeIn,

    // Sky atmosphere settings

    showSkyAtmosphere: true,
    skyAtmosphereLightIntensity: defaultSkyAtmosphereLightIntensity,
    skyAtmosphereRayleighCoefficientR:
        defaultSkyAtmosphereRayleighCoefficient.x / 1e-6,
    skyAtmosphereRayleighCoefficientG:
        defaultSkyAtmosphereRayleighCoefficient.y / 1e-6,
    skyAtmosphereRayleighCoefficientB:
        defaultSkyAtmosphereRayleighCoefficient.z / 1e-6,
    skyAtmosphereMieCoefficient:
        defaultSkyAtmosphereMieCoefficient.x / 1e-6,
    skyAtmosphereRayleighScaleHeight: defaultSkyAtmosphereRayleighScaleHeight,
    skyAtmosphereMieScaleHeight: defaultSkyAtmosphereMieScaleHeight,
    skyAtmosphereMieAnisotropy: defaultSkyAtmosphereMieAnisotropy,
    skyHueShift: defaultSkyAtmosphereHueShift,
    skySaturationShift: defaultSkyAtmosphereSaturationShift,
    skyBrightnessShift: defaultSkyAtmosphereBrightnessShift,
    perFragmentAtmosphere: false,
    dynamicLighting: true,
    dynamicLightingFromSun: false,

    // Fog settings

    showFog: true,
    density: 1.0,
    minimumBrightness: 0.03,

    // Scene settings

    hdr: true,
    };
javagl commented 3 months ago

Just to clarify: I assume that these are separate (and somewhat unrelated) issues:

  1. placing some point on the surface (probably solvable with "clampToHeightMostDetailed", if the tileset is shown when the point is placed)
  2. Rendering (space) atmosphere and Google tilesets at the same time

If I understood that correctly, then the apparent "connection" between these points would be only that: You initially don't show the Google tilesets, and already want to place that "point". When zooming in, you do show the Google tileset. And you expect the point then to be at the right height. If this is indeed the main point, then ... there might be different solutions. Maybe it's possible to simply place the point on the globe, and as soon as the Google tileset is displayed, adjust the height of that point with clampToHeightMostDetailed. But ... maybe not showing the Google tileset initially was only an attempted workaround for the atmosphere question. Maybe that's just an instance of the https://en.wikipedia.org/wiki/XY_problem , or at least I don't fully understand which part of the issue is a cause and which one is an effect...


Regarding the atmosphere rendering:

We can’t display the space atmosphere and 3D tilesets simultaneously. I would label this as a bug, but please correct me if I’m mistaken. My goal isn’t to find bugs but to find solutions. I wanted to bring attention to this issue because it seems like a significant bug. Developers, of course, want to utilize both the atmosphere and 3D tiles, not just one or the other.

I am often trying to find bugs. It is a form (or actually the goal) of testing. And we can skip arguing about what constitutes a "bug", beyond the meaning that is relevant here: You're observing a behavior that differs from what you want to achieve. And I tried to capture here what I think is your main point:

Cesium Atmosphere

There's that white-ish atmosphere that comes from some form of light scattering. And then - zap! - the Google tileset pops in, and hides that.

If this is indeed the main point: I can see why someone wanted to show that atmosphere above the Google tileset. And that's a reasonable expectation.

But I think that this is something that cannot trivially be achieved.

Someone from the CesiumJS core team will have to confirm this. (Maybe @ggetz ?)

(The reason why I think that it could be difficult to render the atmosphere on top of the tileset is that the atmosphere is created in an earlier Pass, and the corresponding commands are executed before the 3D Tiles commands in executeCommands - but I might be missing a point here...)

worldpeaceenginelabs commented 3 months ago

If this is indeed the main point: I can see why someone wanted to show that atmosphere above the Google tileset. And that's a reasonable expectation.

Exactly! That’s the main point and my expectation. I want to transition from space, through the atmosphere, to the 3D tileset, similar to what is shown in Google Earth.

Placing the point is a only a side effect of this and was not the main point! (Sorry for any confusion) The issue arises with using 3D tiles instead of 2D tiles or the base globe (regardless of the atmosphere). As I explain in Cesium Community - the-google-earth-3d-tileset-from-ion-is-hovering-over-the-2d-globe:

In summary:

What now? My workaround actually does the job and with clampToHeightMostDetailed i will fix the above 3 points eventually.

Maybe you can help me making the workaround smooth? Maybe safes the Cesium team eventually the work to fix the main problem.

Problem with the Workaround: If "tileset.show = false;", when zooming in, at the (switch map at specified height point), there is a ugly empty globe with glowing edges for 2 seconds, then it ugly switches to Google Photorealistic.

If "tileset.show = true;" when zooming in , at the (switch map at specified height point), the transition goes surprisingly smooth, without a mentionable delay. But because of "true", at init, the globe in space shows first the 3D tiles., then, triggered by the workaround, pops to the atmosphere. Super Ugly!

A possible solution could be something like preloading the 3D tileset without the user seeing it.

// Initially hide the 3D tileset
    tileset.show = false; // if true, smoother transition, but looks unclean (3dtiles show up first, then swiches to the atmosphere, but transition is smoother)

    // Set up a camera move end event listener
    viewer.camera.moveEnd.addEventListener(function () {
      const height = viewer.camera.positionCartographic.height; console.log(`Distance to ground ${Math.floor(height / 1000)} km`);

      if (height > 14000000) {
        // Show the base layer and hide the 3D tileset
        globe.show = true;
        tileset.show = false;
      } else {
        // Hide the base layer and show the 3D tileset
        globe.show = false;
        tileset.show = true;
      }
    });

    } catch (error) {console.log(error);}
worldpeaceenginelabs commented 3 months ago

Or maybe we can just add the atmosphere parameters that we are adding to the globe to show the atmosphere, to the tileset instead???

javagl commented 3 months ago

For some details (or maybe more profound ideas for workarounds), the CesiumJS core developers will have to chime in. For the issue with the delay when showing the tileset: One could try to wait for the https://cesium.com/learn/cesiumjs/ref-doc/Cesium3DTileset.html#allTilesLoaded event before making it visible (but I admittedly have to check/try out whether this event is even triggered when show=false...). Another approach could involve setting a style with an alpha value of 0.0001 (i.e. making the tileset effectively invisible, but still forcing it to load). All these ideas are ... pretty quirky, though. Maybe someone has a better idea.

worldpeaceenginelabs commented 3 months ago

(but I admittedly have to check/try out whether this event is even triggered when show=false...).

We want show=true, because it makes the transition from space atmosphere to ground smoother.

Maybe the following is a good workaround. It looks pretty good. I updated https://cloudatlas.club. The load is invisible, the ready loaded 3dtiles with ready loaded atmosphere fades in, and the zooming is smooth. (need to play with transition: opacity 3s ease-in-out; though)

<script>
let isTranslucent = true;

// set cesium container translucent at init
    setTimeout(() => {
      isTranslucent = false;
    }, 5000); // 5000 milliseconds = 5 seconds
</script>

<main class={isTranslucent ? 'translucent' : 'opaque'} id="cesiumContainer"></main>

<style>
    main {
      height: 100vh;
      width: 100vw;
      margin: 0;
      padding: 0;
      transition: opacity 3s ease-in-out;
    }

    .translucent {
    opacity: 0.0;
  }

  .opaque {
    opacity: 1;
  }
</style>

There is still a delay in the switch from atmosphere to 3d tileset when zooming in. It seems like you need to stop the zooming for a moment to trigger "viewer.camera.positionCartographic.height" which triggers then the map switch. If "viewer.camera.positionCartographic.height" was giving me the height continously, the transition would be smoother.

worldpeaceenginelabs commented 3 months ago

A CesiumJS template including Spaceatmosphere, Groundatmosphere AND 3D tileset, for the Community

I was highly motivated and coded this, leading to a surprising discovery: You can force the globe to fully load in just 1 second! (😜It's a trick.) Looks awesome! https://cloudatlas.club

It seems that for the animation, the first frame is fetched without CSS, in original size, and then transformed from small to large. (the first frame seems to be the atmosphere) I set the animation delay to 1 second and the transition to 3 seconds. As a result, the globe has 4 seconds to load before it becomes interactive. However, you don't notice this, so it feels like Cesium, along with the atmosphere and 3D tileset, is fully loaded in 1 second. The 3D tileset is already ready when you zoom in.🥷 (all made in simple css, no js)

I tested it on different screen resolutions and made sure it looks like from one mold on desktop, tablet and mobile 🥷

Cheers and a big thank you to @javagl for pushing me into the right direction! *I'm still not able to glamp the points, but your Sandcastle (clampToHeightMostDetailed) was working well 😅

CSS

    main {
      width: 100%;
      height: 100vh;
      margin: 0;
      padding: 0;
    opacity: 0; /* Initial state */
    animation: fade-in-scale-up 3s ease-in-out forwards; /* Apply the fade-in animation */
    animation-delay: 1s;
    overflow: visible
    }

    :global(.cesium-button.cesium-vrButton) {
    display: block;
    width: 100%;
    height: 100%;
    margin: 0;
    border-radius: 0;
    opacity: 0;
    animation: fade-in 3s ease-in-out forwards; /* Apply the fade-in animation */
    animation-delay: 4s;
    }

    :global(.cesium-widget-credits){
    opacity: 0;
    animation: fade-in 3s ease-in-out forwards; /* Apply the fade-in animation */
    animation-delay: 4s;
    }

/* Keyframes for fade-in-scale down effect */
@keyframes fade-in-scale-down {
    from {
        opacity: 0;
        transform: scale(1.1); /* Optional: add a slight zoom-in effect */
    }
    to {
        opacity: 1;
        transform: scale(1); /* Reset to normal scale */
    }
}

/* Keyframes for fade-in-scale-up effect */
@keyframes fade-in-scale-up {
    from {
        opacity: 0;
        transform: scale(0.01); /* Optional: add a slight zoom-in effect */
    }
    to {
        opacity: 1;
        transform: scale(1); /* Reset to normal scale */
    }
}

/* Keyframes for fade-in effect */
@keyframes fade-in {
    from {
        opacity: 0;
        }
    to {
        opacity: 1;
        }
}

MARKUP

<div style="width: 100%; display: flex; justify-content: center; align-items: center;">
  <main id="cesiumContainer"></main>
</div>

JAVASCRIPT

// Initialize Cesium viewer with specified configuration options
      viewer = new Viewer('cesiumContainer', {
        animation: false,
        fullscreenButton: false,
        vrButton: true,
        geocoder: false,
        homeButton: false,
        infoBox: true,
        selectionIndicator: false,
        timeline: false,
        navigationHelpButton: false,
        shouldAnimate: true,
        skyBox: true,
        contextOptions: {
        webgl: {
        alpha: true
        },
        },

        // 2D and Columbus View are not currently supported
        // for global 3D Tiles tilesets
        sceneModePicker: false,
        // Imagery layers are not currently supported for
        // global 3D Tiles tilesets
        baseLayerPicker: false,
      });

    // Load Cesium 3D Tileset from Cesium Ion using the specified asset ID (2275207=Google Photorealistic Earth)
    try {const tileset = await Cesium3DTileset.fromIonAssetId(2275207);viewer.scene.primitives.add(tileset);

    // Initially hide the 3D tileset
    tileset.show = true;

    // Set up a camera move end event listener
    viewer.camera.moveEnd.addEventListener(function () {
      const height = viewer.camera.positionCartographic.height; console.log(`Distance to ground ${Math.floor(height / 1000)} km`);

      if (height > 6000000) {
        // Show the base layer and hide the 3D tileset
        globe.show = true;
        tileset.show = false;
      } else {
        // Hide the base layer and show the 3D tileset
        globe.show = false;
        tileset.show = true;
      }
    });

    } catch (error) {console.log(error);}
6
    // Get the current camera position in Cartographic coordinates (longitude, latitude, height)
    var cameraPosition = viewer.scene.camera.positionCartographic;

    // Update the camera's position with the new height
    viewer.scene.camera.setView({
        destination: Cesium.Cartesian3.fromRadians(
            cameraPosition.longitude,
            cameraPosition.latitude,
            20000000
        ),
        orientation: {
            heading: viewer.scene.camera.heading,
            pitch: viewer.scene.camera.pitch,
            roll: viewer.scene.camera.roll
        }
    });

      // Atmosphere
      const scene = viewer.scene;
        const globe = scene.globe;
        const skyAtmosphere = scene.skyAtmosphere;

        scene.highDynamicRange = true;
        globe.enableLighting = true;
        globe.atmosphereLightIntensity = 20.0;

        // Function to get the current time in ISO 8601 format
    function getCurrentTimeIso8601() {
        const now = new Date();
        return now.toISOString();
        }

    // Get the current time in ISO 8601 format and update the viewer's clock
    const currentTime = getCurrentTimeIso8601();
    viewer.clock.currentTime = JulianDate.fromIso8601(currentTime);

    const canvas = viewer.canvas;
    canvas.setAttribute("tabindex", "0"); // needed to put focus on the canvas
    canvas.onclick = function () {
    canvas.focus();
    };

    const defaultGroundAtmosphereLightIntensity =
    globe.atmosphereLightIntensity;
    const defaultGroundAtmosphereRayleighCoefficient =
    globe.atmosphereRayleighCoefficient;
    const defaultGroundAtmosphereMieCoefficient =
    globe.atmosphereMieCoefficient;
    const defaultGroundAtmosphereMieAnisotropy =
    globe.atmosphereMieAnisotropy;
    const defaultGroundAtmosphereRayleighScaleHeight =
    globe.atmosphereRayleighScaleHeight;
    const defaultGroundAtmosphereMieScaleHeight =
    globe.atmosphereMieScaleHeight;
    const defaultGroundAtmosphereHueShift = globe.atmosphereHueShift;
    const defaultGroundAtmosphereSaturationShift =
    globe.atmosphereSaturationShift;
    const defaultGroundAtmosphereBrightnessShift =
    globe.atmosphereBrightnessShift;
    const defaultLightFadeOut = globe.lightingFadeOutDistance;
    const defaultLightFadeIn = globe.lightingFadeInDistance;
    const defaultNightFadeOut = globe.nightFadeOutDistance;
    const defaultNightFadeIn = globe.nightFadeInDistance;

    const defaultSkyAtmosphereLightIntensity =
    skyAtmosphere.atmosphereLightIntensity;
    const defaultSkyAtmosphereRayleighCoefficient =
    skyAtmosphere.atmosphereRayleighCoefficient;
    const defaultSkyAtmosphereMieCoefficient =
    skyAtmosphere.atmosphereMieCoefficient;
    const defaultSkyAtmosphereMieAnisotropy =
    skyAtmosphere.atmosphereMieAnisotropy;
    const defaultSkyAtmosphereRayleighScaleHeight =
    skyAtmosphere.atmosphereRayleighScaleHeight;
    const defaultSkyAtmosphereMieScaleHeight =
    skyAtmosphere.atmosphereMieScaleHeight;
    const defaultSkyAtmosphereHueShift = skyAtmosphere.hueShift;
    const defaultSkyAtmosphereSaturationShift =
    skyAtmosphere.saturationShift;
    const defaultSkyAtmosphereBrightnessShift =
    skyAtmosphere.brightnessShift;

    const viewModel = {
    // Globe settings

    enableTerrain: false,
    enableLighting: true,
    groundTranslucency: false,

    // Ground atmosphere settings

    showGroundAtmosphere: true,
    groundAtmosphereLightIntensity: defaultGroundAtmosphereLightIntensity,
    groundAtmosphereRayleighCoefficientR:
        defaultGroundAtmosphereRayleighCoefficient.x / 1e-6,
    groundAtmosphereRayleighCoefficientG:
        defaultGroundAtmosphereRayleighCoefficient.y / 1e-6,
    groundAtmosphereRayleighCoefficientB:
        defaultGroundAtmosphereRayleighCoefficient.z / 1e-6,
    groundAtmosphereMieCoefficient:
        defaultGroundAtmosphereMieCoefficient.x / 1e-6,
    groundAtmosphereRayleighScaleHeight: defaultGroundAtmosphereRayleighScaleHeight,
    groundAtmosphereMieScaleHeight: defaultGroundAtmosphereMieScaleHeight,
    groundAtmosphereMieAnisotropy: defaultGroundAtmosphereMieAnisotropy,
    groundHueShift: defaultGroundAtmosphereHueShift,
    groundSaturationShift: defaultGroundAtmosphereSaturationShift,
    groundBrightnessShift: defaultGroundAtmosphereBrightnessShift,
    lightingFadeOutDistance: defaultLightFadeOut,
    lightingFadeInDistance: defaultLightFadeIn,
    nightFadeOutDistance: defaultNightFadeOut,
    nightFadeInDistance: defaultNightFadeIn,

    // Sky atmosphere settings

    showSkyAtmosphere: true,
    skyAtmosphereLightIntensity: defaultSkyAtmosphereLightIntensity,
    skyAtmosphereRayleighCoefficientR:
        defaultSkyAtmosphereRayleighCoefficient.x / 1e-6,
    skyAtmosphereRayleighCoefficientG:
        defaultSkyAtmosphereRayleighCoefficient.y / 1e-6,
    skyAtmosphereRayleighCoefficientB:
        defaultSkyAtmosphereRayleighCoefficient.z / 1e-6,
    skyAtmosphereMieCoefficient:
        defaultSkyAtmosphereMieCoefficient.x / 1e-6,
    skyAtmosphereRayleighScaleHeight: defaultSkyAtmosphereRayleighScaleHeight,
    skyAtmosphereMieScaleHeight: defaultSkyAtmosphereMieScaleHeight,
    skyAtmosphereMieAnisotropy: defaultSkyAtmosphereMieAnisotropy,
    skyHueShift: defaultSkyAtmosphereHueShift,
    skySaturationShift: defaultSkyAtmosphereSaturationShift,
    skyBrightnessShift: defaultSkyAtmosphereBrightnessShift,
    perFragmentAtmosphere: false,
    dynamicLighting: true,
    dynamicLightingFromSun: false,

    // Fog settings

    showFog: true,
    density: 1.0,
    minimumBrightness: 0.03,

    // Scene settings

    hdr: true,
    };
ggetz commented 3 months ago

Hi there, it looks like @javagl addressed the question of clamping points to 3D Tiles.

The second question, I believe, dealt with atmosphere and lighting. We have two issues open for implementing ground atmosphere and related lighting for global-scale 3D tilesets: https://github.com/CesiumGS/cesium/issues/11717 and https://github.com/CesiumGS/cesium/issues/11302.

I'm going to close your issue to keep the discussion in one place. If you have any further input on this, please post it there instead. Thanks!