Sky and Terrain issues with camera altitudes equal or less than 0

Hi,

There is a weird behaviour when the camera altitude reaches or goes below 0, making the sky and the globe disappear.
This becomes a problem for me in certain places of the globe where the altitude is below 0.

For now I just clamp the altitude value but it breaks the UX, is there any way to solve this issue?

Best,
André Santos

Hi André - can you provide steps to reproduce this?

Thanks,

Patrick

Hi Patrick,

This is a code example for Sandcastle (a plane going up and down) so you can see the problem in action:

//Sandcastle demo ------>
var viewer = new Cesium.Viewer('cesiumContainer');

var scene = viewer.scene;
scene.globe.enableLighting = true;
scene.moon=undefined;
scene.sun=undefined;

scene.globe.depthTestAgainstTerrain = true;
scene.globe.maximumScreenSpaceError=5; // higher values better performance, less quality

var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
    url : '//cesiumjs.org/stk-terrain/tilesets/world/tiles'
});

scene.terrainProvider = cesiumTerrainProviderMeshes;

var ellipsoid = scene.globe.ellipsoid;
var camera = scene.camera;
camera.constrainedAxis = undefined;

var lat = 24.55614032199081, lng = -81.75323724746704, alt = 5, heading = -0.01, tilt = -0.05, roll = 0;
var cameraLat = 24.555703630093575, cameraLng = -81.75323188304901, cameraAlt = 10, cameraHeading = 0, cameraTilt = 1.5, cameraRoll = 0;

var getAltitude = function (lat, lng) {
    var position = Cesium.Cartesian3.fromDegrees(lng, lat, 0, ellipsoid, new Cesium.Cartesian3());
    var altitude = scene.globe.getHeight(Cesium.Ellipsoid.WGS84.cartesianToCartographic(position));
    
    if(altitude <= 0) altitude = 0.1;
    
    return altitude;
}

var positionCamera = function(model, lat, lng, alt, heading, tilt, roll) {
    var position = Cesium.Cartesian3.fromDegrees(lng, lat, alt, ellipsoid, new Cesium.Cartesian3());
    var transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);
    camera.transform = transform;
    var yDir = Cesium.Matrix4.multiplyByPointAsVector(model.modelMatrix, Cesium.Cartesian3.UNIT_Y, new Cesium.Cartesian3());
    Cesium.Matrix4.multiplyByPointAsVector(camera.inverseTransform, yDir, yDir);
    Cesium.Cartesian3.negate(yDir, yDir);
    Cesium.Cartesian3.normalize(yDir, yDir); // yDir's magnitude might not be exactly 1 after the rotation
    
    camera.lookAt(
        yDir,
        Cesium.Cartesian3.ZERO,
        Cesium.Cartesian3.UNIT_Z
    );

    var transform = camera.transform;
    camera.setTransform(Cesium.Matrix4.IDENTITY);
    camera.heading = -heading;
    
    var angle = ((Math.PI/2)-tilt) - camera.tilt;
    camera.look(camera.right, angle);
    
    camera.setTransform(transform);
    camera.twistLeft(roll);
}

var setModelPosition = function(model, lat, lng, alt, heading, tilt, roll) {
    var position = Cesium.Cartesian3.fromDegrees(lng, lat, alt, ellipsoid, new Cesium.Cartesian3());
    var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
    
    var currentTranslation = new Cesium.Cartesian3();
    var currentRotation = new Cesium.Matrix3();
    Cesium.Matrix4.getRotation(modelMatrix, currentRotation);
    
    var position = Cesium.Cartesian3.fromDegrees(lng, lat, alt, ellipsoid, new Cesium.Cartesian3());
    var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position);
    Cesium.Matrix4.getTranslation(modelMatrix, currentTranslation);

    var rotateQuat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Z, -heading);
    var turnQuat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_X, -tilt);
    var rollQuat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Y, -roll);

    var finalQuat = Cesium.Quaternion.multiply(rotateQuat, turnQuat, new Cesium.Quaternion());
    Cesium.Quaternion.multiply(finalQuat, rollQuat, finalQuat);

    var rM = new Cesium.Matrix3();
    Cesium.Matrix3.fromQuaternion(finalQuat, rM);

    Cesium.Matrix3.multiply(currentRotation, rM, currentRotation);

    Cesium.Matrix4.fromRotationTranslation(
        currentRotation,
        currentTranslation,
        model.modelMatrix
    );
}

var setClock = function(model) {
    var invert = -1;
    
    viewer.clock.onTick.addEventListener(function() {
        var altitude = getAltitude(lat, lng);
        
        if(altitude) {
            setModelPosition(model, lat, lng, altitude ? altitude+alt : alt, heading, tilt, roll);
            positionCamera(model, cameraLat, cameraLng, altitude ? altitude+cameraAlt : cameraAlt, cameraHeading, cameraTilt, cameraRoll);
        }//if
        
        alt+=0.05*invert;
        cameraAlt+=0.05*invert;
        
        cameraAlt < -10 || cameraAlt > 10 ? invert*=-1 : invert;
    });
}

var loadModel = function(url) {
    var model = scene.primitives.add(Cesium.Model.fromGltf({
        url : url
    }));

    model.readyToRender.addEventListener(function(modelObj) {
        setClock(model);
    });
}

loadModel("https://youbeq.s3.amazonaws.com/Commercial_Airbus-A321-200_Air-Canada.gltf");
//<------ Sandcastle demo

Thanks for the code example. I submitted issue #2271.

The sky disappearing needs more investigation, but to work around the terrain, change Line 414 of GlobeSurfaceTileProvider.js to

if (false) {

to disappear horizon culling. This will have a performance impact since more terrain tiles will be rendered. In the final solution, we will most likely only horizon cull when the camera is high enough.

Patrick

Hi André,

This issue was fixed and will be in the next release on October 1.

Dan