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.72k stars 3.44k forks source link

ScaleByDistance with NearFarScalar produces unexpected jump near edge of range #8196

Open tangtony opened 4 years ago

tangtony commented 4 years ago

When creating a PointPrimitive with the following option:

scaleByDistance: new Cesium.NearFarScalar(5000000, 5, 40000000, 1)

Everything scales nicely between the min and max distances, but as soon as you leave the defined range, the size of the point changes. In the quick demonstration below, I'm moving the camera around the 5000000 threshold. Going below that threshold causes the point size to increase, and then going above the threshold makes the point size decrease.

point

Sandcastle example: https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/#c=ZZBBT8MwDIX/StTLWqlKO8Euo5sQnTghmDSJUy5e6g2LNKmStGMg/jtpu0oDfIqf3/dkpwPLOsITWrZiGk+sREdtzV8HLZ7JoS2N9kAa7Sy5E7oLTGNIexeYEeZOokbeWKrJU4eOQ1XFV3nb3r+dxqVRCqUno+OkTxR6zBuoL6FZqMY46h1sOWWUYH14gb7hB2vqDR4toovzlOVJeoHoA9WOPjFQ84vmJCh8OG/IedASl9dnPiPYR7C7YAEbL/KhUrZI2W0+NfNE6O9+yyiNCufPCtdj8D3VjbGetVbFnGce60ZB2DDbt/IdPZfO9ViRTVBRUceoWonoz7eKiEkFzoXJoVXDASJaF1nw/8KUgYr08aVDq+DcW97m66dR5JwXWWj/U94YtQd7lfgD

Browser: Google Chrome 77.0.3865.75 (Official Build) (64-bit)

Operating System: Windows 10

emackey commented 4 years ago

I'm on mobile so haven't investigated in detail, but remember there's an optical illusion in play here. The "fixed" size is a fixed number of screen pixels. When zooming the globe, your eye expects objects to grow at the same rate the imagery is growing. Keeping a constant number of screen pixels actually tells your eye the object is shrinking.

OmarShehata commented 4 years ago

there's an optical illusion in play here

This is what I suspect as well. The other thing to remember is that at this distance, that slight camera zoom is actually moving the camera a very large amount, so that might explain the "pop" we can see here.

I think further evidence for this is just scaling everything down. You can still see a kind of "pop" in this Sandcastle but it's easier to tell that it's correct clamping the size when it's outside the range.

tangtony commented 4 years ago

Are we seeing the same thing here? I played with your example and it's even more prominent that the size changes at the boundary: dot

Just to clarify, that's me moving the camera between a height of 490 and 510 meters. So I would expect the size to be fixed at 10 pixels, but it's not and it's not because of an optical illusion.

OmarShehata commented 4 years ago

That's me moving the camera between a height of 490 and 510 meters

How are you verifying that you're actually outside the range when it changes size?

Here's a new Sandcastle with buttons for each camera height. Here the range is 500 to 5000. Notice that there's no change between the min range (500) and 490:

scale_1

Although it does look like the change right at the edge of the range is disproportionately large?

scale_2

tangtony commented 4 years ago

I was just doing console.log(viewer.camera.positionCartographic.height), but your approach is much nicer, I wish I had thought of that.

Editing your example to use heights of 499, 500, and 501 I think demonstrates it pretty clearly that there's something weird going on with the scaling when going between 500 and 501: dot

mramato commented 4 years ago

There's definitely something weird going on here, I tried moving the point off the ellipsoid expecting that to matter, but there's definitely still a jump in size. Here's a simplified reproduction and code:

Sandcastle

var viewer = new Cesium.Viewer('cesiumContainer');
var points = viewer.scene.primitives.add(new Cesium.PointPrimitiveCollection());
viewer.scene.globe.depthTestAgainstTerrain = true;

var minHeight = 500;
var maxHeight = 5000;

points.add({
    position : Cesium.Cartesian3.fromDegrees(20, 20),
    pixelSize : 10,
    scaleByDistance: new Cesium.NearFarScalar(minHeight, 10, maxHeight, 1)
});

Sandcastle.addDefaultToolbarButton('Height: ' + (minHeight - 0.1), function() {
    viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(20, 20, minHeight - 0.1)
    });
});

Sandcastle.addToolbarButton('Height: ' + (minHeight), function() {
    viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(20, 20, minHeight)
    });
});

Sandcastle.addToolbarButton('Height: ' + (minHeight + 0.1), function() {
    viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(20, 20, minHeight + 0.1)
    });
});