Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Solve the issue of #11877 #11907

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
54 changes: 31 additions & 23 deletions packages/engine/Source/Scene/ScreenSpaceCameraController.js
Original file line number Diff line number Diff line change
Expand Up @@ -2855,6 +2855,7 @@ function update3D(controller) {

const scratchAdjustHeightTransform = new Matrix4();
const scratchAdjustHeightCartographic = new Cartographic();
const transformOrigin = new Cartesian3();

function adjustHeightForTerrain(controller, cameraChanged) {
controller._adjustedHeightForTerrain = true;
Expand Down Expand Up @@ -2888,31 +2889,38 @@ function adjustHeightForTerrain(controller, cameraChanged) {

let heightUpdated = false;
if (cartographic.height < controller._minimumCollisionTerrainHeight) {
const globeHeight = controller._scene.globeHeight;
if (defined(globeHeight)) {
const height = globeHeight + controller.minimumZoomDistance;
const difference = globeHeight - controller._lastGlobeHeight;
const percentDifference = difference / controller._lastGlobeHeight;

// Unless the camera has been moved by user input, to avoid big jumps during tile loads
// only make height updates when the globe height has been fairly stable across several frames
if (
cartographic.height < height &&
(cameraChanged || Math.abs(percentDifference) <= 0.1)
) {
cartographic.height = height;
if (mode === SceneMode.SCENE3D) {
ellipsoid.cartographicToCartesian(cartographic, camera.position);
} else {
projection.project(cartographic, camera.position);
let transformOriginLen = Infinity;
if (defined(transform)) {
Matrix4.getTranslation(transform, transformOrigin);
transformOriginLen = Cartesian3.magnitude(transformOrigin);
}
if (transformOriginLen > controller._minimumCollisionTerrainHeight) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about the use of controller._minimumCollisionTerrainHeight here. That value was design to be the height above the ellipsoid surface, not the absolute value.

Additionally, that put us in this strange "middle ground" where the camera still re-orients strangely, like in this example below:

const viewer = new Cesium.Viewer("cesiumContainer", {
  //globe: false
});

const url = "../../SampleData/models/CesiumAir/Cesium_Air.glb";
const position = new Cesium.Cartesian3(0.0, 100000.0, 0.0);
const orientation = new Cesium.Quaternion(0.0, 0.0, 0.0, 1.0);

const entity = viewer.entities.add({
  name: url,
  position: position,
  orientation: orientation,
  model: {
    uri: url,
  },
});

viewer.camera.lookAt(
  new Cesium.Cartesian3(0.0, 100000.0, 1), 
  new Cesium.Cartesian3(0, 50, 0));

How would you feel about instead using a percentage of the ellipsoid radius? That will ensure we scale to other ellipsoids if needed without having to manually set a value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello ,
At line 2897, the comparision: controller._minimumCollisionTerrainHeight, it seemed should not be such a value. What I thought is to put a threshold to specify the maximum centric length of cartesian3, then let any point in a centric ball with the threshold radius will not do the height adjustment (if there is a transform upon the camera).

Thanks for your advice, I am a little confused about using a percentage of the ellipsoid radius. Does it mean using percentage of ellipsoid radius as the height threshold test?

I modify the adjustHeightForTerrain function again: it will avoid the problem in your example above and issue of #11877 as well:

function adjustHeightForTerrain(controller, cameraChanged) {
  controller._adjustedHeightForTerrain = true;

  const scene = controller._scene;
  const mode = scene.mode;
  const globe = scene.globe;

  if (mode === SceneMode.SCENE2D || mode === SceneMode.MORPHING) {
    return;
  }

  const camera = scene.camera;
  const ellipsoid = defaultValue(globe?.ellipsoid, Ellipsoid.WGS84);
  const projection = scene.mapProjection;


  let transform;
  let mag;
  if (!Matrix4.equals(camera.transform, Matrix4.IDENTITY)) {
    transform = Matrix4.clone(camera.transform, scratchAdjustHeightTransform);
    mag = Cartesian3.magnitude(camera.position);
    camera._setTransform(Matrix4.IDENTITY);
  }

  const cartographic = scratchAdjustHeightCartographic;
  if (mode === SceneMode.SCENE3D) {
    ellipsoid.cartesianToCartographic(camera.position, cartographic);
  } else {
    projection.unproject(camera.position, cartographic);
  }

  let heightUpdated = false; 
  if (cartographic.height < controller._minimumCollisionTerrainHeight) {  
    if((defined(transform)&&cartographic.height>-ellipsoid.maximumRadius*0.3)||!defined(transform)){
      const globeHeight = controller._scene.globeHeight;
      if (defined(globeHeight)) {
        const height = globeHeight + controller.minimumZoomDistance;
        const difference = globeHeight - controller._lastGlobeHeight;
        const percentDifference = difference / controller._lastGlobeHeight;
  
        // Unless the camera has been moved by user input, to avoid big jumps during tile loads
        // only make height updates when the globe height has been fairly stable across several frames
        if (
          cartographic.height < height &&
          (cameraChanged || Math.abs(percentDifference) <= 0.1)
        ) {
          cartographic.height = height;
          if (mode === SceneMode.SCENE3D) {
            ellipsoid.cartographicToCartesian(cartographic, camera.position);
          } else {
            projection.project(cartographic, camera.position);
          }
          heightUpdated = true;
        }
  
        if (cameraChanged || Math.abs(percentDifference) <= 0.1) {
          controller._lastGlobeHeight = globeHeight;
        } else {
          controller._lastGlobeHeight += difference * 0.1;
        }
      }
   }  
  }

  if (defined(transform)) {
    camera._setTransform(transform);
    if (heightUpdated) {
      Cartesian3.normalize(camera.position, camera.position);
      Cartesian3.negate(camera.position, camera.direction);
      Cartesian3.multiplyByScalar(
        camera.position,
        Math.max(mag, controller.minimumZoomDistance),
        camera.position
      );
      Cartesian3.normalize(camera.direction, camera.direction);
      Cartesian3.cross(camera.direction, camera.up, camera.right);
      Cartesian3.cross(camera.right, camera.direction, camera.up);
    }
  }
}

It use this code to filter point in deep underground areas:
(defined(transform)&&cartographic.height>-ellipsoid.maximumRadius*0.3)

const globeHeight = controller._scene.globeHeight;
if (defined(globeHeight)) {
const height = globeHeight + controller.minimumZoomDistance;
const difference = globeHeight - controller._lastGlobeHeight;
const percentDifference = difference / controller._lastGlobeHeight;

// Unless the camera has been moved by user input, to avoid big jumps during tile loads
// only make height updates when the globe height has been fairly stable across several frames
if (
cartographic.height < height &&
(cameraChanged || Math.abs(percentDifference) <= 0.1)
) {
cartographic.height = height;
if (mode === SceneMode.SCENE3D) {
ellipsoid.cartographicToCartesian(cartographic, camera.position);
} else {
projection.project(cartographic, camera.position);
}
heightUpdated = true;
}
heightUpdated = true;
}

if (cameraChanged || Math.abs(percentDifference) <= 0.1) {
controller._lastGlobeHeight = globeHeight;
} else {
controller._lastGlobeHeight += difference * 0.1;
if (cameraChanged || Math.abs(percentDifference) <= 0.1) {
controller._lastGlobeHeight = globeHeight;
} else {
controller._lastGlobeHeight += difference * 0.1;
}
}
}
}
Expand Down