Skip to content

Commit

Permalink
Merge branch 'CesiumGS:main' into ellipsoid-inner-radius-bug-fix
Browse files Browse the repository at this point in the history
  • Loading branch information
srtrotter authored Jan 5, 2024
2 parents c4cf75a + 31293c1 commit cca7d30
Show file tree
Hide file tree
Showing 12 changed files with 586 additions and 75 deletions.
12 changes: 12 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,21 @@

#### @cesium/engine

##### Breaking Changes :mega:

- The `Cesium3DTileset.dynamicScreenSpaceError` optimization is now enabled by default, as this improves performance for street-level horizon views. Furthermore, the default settings of this feature were tuned for improved performance. `Cesium3DTileset.dynamicScreenSpaceErrorDensity` was changed from 0.00278 to 0.0002. `Cesium3DTileset.dynamicScreenSpaceErrorFactor` was changed from 4 to 24. [#11718](https://github.com/CesiumGS/cesium/pull/11718)

##### Fixes :wrench:

- Fixed a bug where the `Cesium3DTileset` constructor was ignoring the options `dynamicScreenSpaceError`, `dynamicScreenSpaceErrorDensity`, `dynamicScreenSpaceErrorFactor` and `dynamicScreenSpaceErrorHeightFalloff`. [#11677](https://github.com/CesiumGS/cesium/issues/11677)
- Fix globe materials when lighting is false. Slope/Aspect material no longer rely on turning on lighting or shadows. [#11563](https://github.com/CesiumGS/cesium/issues/11563)
- Fixed a bug where `GregorianDate` constructor would not validate the input parameters for valid date. [#10075](https://github.com/CesiumGS/cesium/pull/10075)

#### @cesium/widgets

##### Fixes :wrench:

- Fixed a bug where the 3D Tiles Inspector's `dynamicScreenSpaceErrorDensity` slider did not update the tileset [#6143](https://github.com/CesiumGS/cesium/issues/6143)

### 1.113 - 2024-01-02

Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,3 +372,5 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu
- [KOBAYASHI Ittoku](https://github.com/kittoku)
- [王康](https://github.com/yieryi)
- [孙永政](https://github.com/syzdev)
- [Subhajit Saha](https://github.com/subhajits)
- [Jared Webber](https://github.com/jaredwebber)
2 changes: 1 addition & 1 deletion packages/engine/LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright 2011-2022 CesiumJS Contributors
Copyright 2011-2024 CesiumJS Contributors

Apache License
Version 2.0, January 2004
Expand Down
85 changes: 85 additions & 0 deletions packages/engine/Source/Core/GregorianDate.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import Check from "./Check.js";
import defaultValue from "./defaultValue.js";
import DeveloperError from "./DeveloperError.js";
import isLeapYear from "./isLeapYear.js";

const daysInYear = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

/**
* Represents a Gregorian date in a more precise format than the JavaScript Date object.
* In addition to submillisecond precision, this object can also represent leap seconds.
Expand Down Expand Up @@ -25,6 +32,27 @@ function GregorianDate(
millisecond,
isLeapSecond
) {
const minimumYear = 1;
const minimumMonth = 1;
const minimumDay = 1;
const minimumHour = 0;
const minimumMinute = 0;
const minimumSecond = 0;
const minimumMillisecond = 0;

year = defaultValue(year, minimumYear);
month = defaultValue(month, minimumMonth);
day = defaultValue(day, minimumDay);
hour = defaultValue(hour, minimumHour);
minute = defaultValue(minute, minimumMinute);
second = defaultValue(second, minimumSecond);
millisecond = defaultValue(millisecond, minimumMillisecond);
isLeapSecond = defaultValue(isLeapSecond, false);
//>>includeStart('debug', pragmas.debug);
validateRange();
validateDate();
//>>includeEnd('debug');

/**
* Gets or sets the year as a whole number.
* @type {number}
Expand Down Expand Up @@ -65,5 +93,62 @@ function GregorianDate(
* @type {boolean}
*/
this.isLeapSecond = isLeapSecond;

function validateRange() {
const maximumYear = 9999;
const maximumMonth = 12;
const maximumDay = 31;
const maximumHour = 23;
const maximumMinute = 59;
const maximumSecond = 59;
const excludedMaximumMilisecond = 1000;

Check.typeOf.number.greaterThanOrEquals("Year", year, minimumYear);
Check.typeOf.number.lessThanOrEquals("Year", year, maximumYear);

Check.typeOf.number.greaterThanOrEquals("Month", month, minimumMonth);
Check.typeOf.number.lessThanOrEquals("Month", month, maximumMonth);

Check.typeOf.number.greaterThanOrEquals("Day", day, minimumDay);
Check.typeOf.number.lessThanOrEquals("Day", day, maximumDay);

Check.typeOf.number.greaterThanOrEquals("Hour", hour, minimumHour);
Check.typeOf.number.lessThanOrEquals("Hour", hour, maximumHour);

Check.typeOf.number.greaterThanOrEquals("Minute", minute, minimumMinute);
Check.typeOf.number.lessThanOrEquals("Minute", minute, maximumMinute);

Check.typeOf.bool("IsLeapSecond", isLeapSecond);

Check.typeOf.number.greaterThanOrEquals("Second", second, minimumSecond);
Check.typeOf.number.lessThanOrEquals(
"Second",
second,
isLeapSecond ? maximumSecond + 1 : maximumSecond
);

Check.typeOf.number.greaterThanOrEquals(
"Millisecond",
millisecond,
minimumMillisecond
);
Check.typeOf.number.lessThan(
"Millisecond",
millisecond,
excludedMaximumMilisecond
);
}

// Javascript date object supports only dates greater than 1901. Thus validating with custom logic
function validateDate() {
const daysInMonth =
month === 2 && isLeapYear(year)
? daysInYear[month - 1] + 1
: daysInYear[month - 1];

if (day > daysInMonth) {
throw new DeveloperError("Month and Day represents invalid date");
}
}
}
export default GregorianDate;
114 changes: 73 additions & 41 deletions packages/engine/Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import IonResource from "../Core/IonResource.js";
import JulianDate from "../Core/JulianDate.js";
import ManagedArray from "../Core/ManagedArray.js";
import CesiumMath from "../Core/Math.js";
import Matrix3 from "../Core/Matrix3.js";
import Matrix4 from "../Core/Matrix4.js";
import Resource from "../Core/Resource.js";
import RuntimeError from "../Core/RuntimeError.js";
Expand Down Expand Up @@ -75,10 +76,10 @@ import Cesium3DTilesetSkipTraversal from "./Cesium3DTilesetSkipTraversal.js";
* @property {boolean} [preloadWhenHidden=false] Preload tiles when <code>tileset.show</code> is <code>false</code>. Loads tiles as if the tileset is visible but does not render them.
* @property {boolean} [preloadFlightDestinations=true] Optimization option. Preload tiles at the camera's flight destination while the camera is in flight.
* @property {boolean} [preferLeaves=false] Optimization option. Prefer loading of leaves first.
* @property {boolean} [dynamicScreenSpaceError=false] Optimization option. Reduce the screen space error for tiles that are further away from the camera.
* @property {number} [dynamicScreenSpaceErrorDensity=0.00278] Density used to adjust the dynamic screen space error, similar to fog density.
* @property {number} [dynamicScreenSpaceErrorFactor=4.0] A factor used to increase the computed dynamic screen space error.
* @property {number} [dynamicScreenSpaceErrorHeightFalloff=0.25] A ratio of the tileset's height at which the density starts to falloff.
* @property {boolean} [dynamicScreenSpaceError=true] Optimization option. For street-level horizon views, use lower resolution tiles far from the camera. This reduces the amount of data loaded and improves tileset loading time with a slight drop in visual quality in the distance.
* @property {number} [dynamicScreenSpaceErrorDensity=2.0e-4] Similar to {@link Fog#density}, this option controls the camera distance at which the {@link Cesium3DTileset#dynamicScreenSpaceError} optimization applies. Larger values will cause tiles closer to the camera to be affected.
* @property {number} [dynamicScreenSpaceErrorFactor=24.0] A parameter that controls the intensity of the {@link Cesium3DTileset#dynamicScreenSpaceError} optimization for tiles on the horizon. Larger values cause lower resolution tiles to load, improving runtime performance at a slight reduction of visual quality.
* @property {number} [dynamicScreenSpaceErrorHeightFalloff=0.25] A ratio of the tileset's height that determines where "street level" camera views occur. When the camera is below this height, the {@link Cesium3DTileset#dynamicScreenSpaceError} optimization will have the maximum effect, and it will roll off above this value.
* @property {number} [progressiveResolutionHeightFraction=0.3] Optimization option. If between (0.0, 0.5], tiles at or above the screen space error for the reduced screen resolution of <code>progressiveResolutionHeightFraction*screenHeight</code> will be prioritized first. This can help get a quick layer of tiles down while full resolution tiles continue to load.
* @property {boolean} [foveatedScreenSpaceError=true] Optimization option. Prioritize loading tiles in the center of the screen by temporarily raising the screen space error for tiles around the edge of the screen. Screen space error returns to normal once all the tiles in the center of the screen as determined by the {@link Cesium3DTileset#foveatedConeSize} are loaded.
* @property {number} [foveatedConeSize=0.1] Optimization option. Used when {@link Cesium3DTileset#foveatedScreenSpaceError} is true to control the cone size that determines which tiles are deferred. Tiles that are inside this cone are loaded immediately. Tiles outside the cone are potentially deferred based on how far outside the cone they are and their screen space error. This is controlled by {@link Cesium3DTileset#foveatedInterpolationCallback} and {@link Cesium3DTileset#foveatedMinimumScreenSpaceErrorRelaxation}. Setting this to 0.0 means the cone will be the line formed by the camera position and its view direction. Setting this to 1.0 means the cone encompasses the entire field of view of the camera, disabling the effect.
Expand Down Expand Up @@ -166,8 +167,8 @@ import Cesium3DTilesetSkipTraversal from "./Cesium3DTilesetSkipTraversal.js";
* const tileset = await Cesium.Cesium3DTileset.fromUrl(
* "http://localhost:8002/tilesets/Seattle/tileset.json", {
* dynamicScreenSpaceError: true,
* dynamicScreenSpaceErrorDensity: 0.00278,
* dynamicScreenSpaceErrorFactor: 4.0,
* dynamicScreenSpaceErrorDensity: 2.0e-4,
* dynamicScreenSpaceErrorFactor: 24.0,
* dynamicScreenSpaceErrorHeightFalloff: 0.25
* });
* scene.primitives.add(tileset);
Expand Down Expand Up @@ -361,18 +362,18 @@ function Cesium3DTileset(options) {
this._pass = undefined; // Cesium3DTilePass

/**
* Optimization option. Whether the tileset should refine based on a dynamic screen space error. Tiles that are further
* away will be rendered with lower detail than closer tiles. This improves performance by rendering fewer
* tiles and making less requests, but may result in a slight drop in visual quality for tiles in the distance.
* The algorithm is biased towards "street views" where the camera is close to the ground plane of the tileset and looking
* at the horizon. In addition results are more accurate for tightly fitting bounding volumes like box and region.
* Optimization option. For street-level horizon views, use lower resolution tiles far from the camera. This reduces
* the amount of data loaded and improves tileset loading time with a slight drop in visual quality in the distance.
* <p>
* This optimization is strongest when the camera is close to the ground plane of the tileset and looking at the
* horizon. Furthermore, the results are more accurate for tightly fitting bounding volumes like box and region.
*
* @type {boolean}
* @default false
* @default true
*/
this.dynamicScreenSpaceError = defaultValue(
options.dynamicScreenSpaceError,
false
true
);

/**
Expand Down Expand Up @@ -416,48 +417,68 @@ function Cesium3DTileset(options) {
this.foveatedTimeDelay = defaultValue(options.foveatedTimeDelay, 0.2);

/**
* A scalar that determines the density used to adjust the dynamic screen space error, similar to {@link Fog}. Increasing this
* value has the effect of increasing the maximum screen space error for all tiles, but in a non-linear fashion.
* The error starts at 0.0 and increases exponentially until a midpoint is reached, and then approaches 1.0 asymptotically.
* This has the effect of keeping high detail in the closer tiles and lower detail in the further tiles, with all tiles
* beyond a certain distance all roughly having an error of 1.0.
* Similar to {@link Fog#density}, this option controls the camera distance at which the {@link Cesium3DTileset#dynamicScreenSpaceError}
* optimization applies. Larger values will cause tiles closer to the camera to be affected. This value must be
* non-negative.
* <p>
* The dynamic error is in the range [0.0, 1.0) and is multiplied by <code>dynamicScreenSpaceErrorFactor</code> to produce the
* final dynamic error. This dynamic error is then subtracted from the tile's actual screen space error.
* This optimization works by rolling off the tile screen space error (SSE) with camera distance like a bell curve.
* This has the effect of selecting lower resolution tiles far from the camera. Near the camera, no adjustment is
* made. For tiles further away, the SSE is reduced by up to {@link Cesium3DTileset#dynamicScreenSpaceErrorFactor}
* (measured in pixels of error).
* </p>
* <p>
* Increasing <code>dynamicScreenSpaceErrorDensity</code> has the effect of moving the error midpoint closer to the camera.
* It is analogous to moving fog closer to the camera.
* Increasing the density makes the bell curve narrower so tiles closer to the camera are affected. This is analagous
* to moving fog closer to the camera.
* </p>
* <p>
* When the density is 0, the optimization will have no effect on the tileset.
* </p>
*
* @type {number}
* @default 0.00278
* @default 2.0e-4
*/
this.dynamicScreenSpaceErrorDensity = 0.00278;
this.dynamicScreenSpaceErrorDensity = defaultValue(
options.dynamicScreenSpaceErrorDensity,
2.0e-4
);

/**
* A factor used to increase the screen space error of tiles for dynamic screen space error. As this value increases less tiles
* are requested for rendering and tiles in the distance will have lower detail. If set to zero, the feature will be disabled.
* A parameter that controls the intensity of the {@link Cesium3DTileset#dynamicScreenSpaceError} optimization for
* tiles on the horizon. Larger values cause lower resolution tiles to load, improving runtime performance at a slight
* reduction of visual quality. The value must be non-negative.
* <p>
* More specifically, this parameter represents the maximum adjustment to screen space error (SSE) in pixels for tiles
* far away from the camera. See {@link Cesium3DTileset#dynamicScreenSpaceErrorDensity} for more details about how
* this optimization works.
* </p>
* <p>
* When the SSE factor is set to 0, the optimization will have no effect on the tileset.
* </p>
*
* @type {number}
* @default 4.0
* @default 24.0
*/
this.dynamicScreenSpaceErrorFactor = 4.0;
this.dynamicScreenSpaceErrorFactor = defaultValue(
options.dynamicScreenSpaceErrorFactor,
24.0
);

/**
* A ratio of the tileset's height at which the density starts to falloff. If the camera is below this height the
* full computed density is applied, otherwise the density falls off. This has the effect of higher density at
* street level views.
* A ratio of the tileset's height that determines "street level" for the {@link Cesium3DTileset#dynamicScreenSpaceError}
* optimization. When the camera is below this height, the dynamic screen space error optimization will have the maximum
* effect, and it will roll off above this value. Valid values are between 0.0 and 1.0.
* <p>
* Valid values are between 0.0 and 1.0.
* </p>
*
* @type {number}
* @default 0.25
*/
this.dynamicScreenSpaceErrorHeightFalloff = 0.25;
this.dynamicScreenSpaceErrorHeightFalloff = defaultValue(
options.dynamicScreenSpaceErrorHeightFalloff,
0.25
);

this._dynamicScreenSpaceErrorComputedDensity = 0.0; // Updated based on the camera position and direction
// Updated based on the camera position and direction
this._dynamicScreenSpaceErrorComputedDensity = 0.0;

/**
* Determines whether the tileset casts or receives shadows from light sources.
Expand Down Expand Up @@ -1635,6 +1656,7 @@ Object.defineProperties(Cesium3DTileset.prototype, {
* <li>The glTF cannot contain morph targets, skins, or animations.</li>
* <li>The glTF cannot contain the <code>EXT_mesh_gpu_instancing</code> extension.</li>
* <li>Only meshes with TRIANGLES can be used to classify other assets.</li>
* <li>The meshes must be watertight.</li>
* <li>The <code>POSITION</code> semantic is required.</li>
* <li>If <code>_BATCHID</code>s and an index buffer are both present, all indices with the same batch id must occupy contiguous sections of the index buffer.</li>
* <li>If <code>_BATCHID</code>s are present with no index buffer, all positions with the same batch id must occupy contiguous sections of the position buffer.</li>
Expand All @@ -1644,6 +1666,9 @@ Object.defineProperties(Cesium3DTileset.prototype, {
* Additionally, classification is not supported for points or instanced 3D
* models.
* </p>
* <p>
* The 3D Tiles or terrain receiving the classification must be opaque.
* </p>
*
* @memberof Cesium3DTileset.prototype
*
Expand Down Expand Up @@ -1968,8 +1993,8 @@ Cesium3DTileset.fromIonAssetId = async function (assetId, options) {
* const tileset = await Cesium.Cesium3DTileset.fromUrl(
* "http://localhost:8002/tilesets/Seattle/tileset.json", {
* dynamicScreenSpaceError: true,
* dynamicScreenSpaceErrorDensity: 0.00278,
* dynamicScreenSpaceErrorFactor: 4.0,
* dynamicScreenSpaceErrorDensity: 2.0e-4,
* dynamicScreenSpaceErrorFactor: 24.0,
* dynamicScreenSpaceErrorHeightFalloff: 0.25
* });
* scene.primitives.add(tileset);
Expand Down Expand Up @@ -2266,6 +2291,7 @@ const scratchMatrix = new Matrix4();
const scratchCenter = new Cartesian3();
const scratchPosition = new Cartesian3();
const scratchDirection = new Cartesian3();
const scratchHalfHeight = new Cartesian3();

/**
* @private
Expand Down Expand Up @@ -2330,10 +2356,16 @@ function updateDynamicScreenSpaceError(tileset, frameState) {
direction = Cartesian3.normalize(direction, direction);
height = positionLocal.z;
if (tileBoundingVolume instanceof TileOrientedBoundingBox) {
// Assuming z-up, the last component stores the half-height of the box
const boxHeight = root._header.boundingVolume.box[11];
minimumHeight = centerLocal.z - boxHeight;
maximumHeight = centerLocal.z + boxHeight;
// Assuming z-up, the last column is the local z direction and
// represents the height of the bounding box.
const halfHeightVector = Matrix3.getColumn(
boundingVolume.halfAxes,
2,
scratchHalfHeight
);
const halfHeight = Cartesian3.magnitude(halfHeightVector);
minimumHeight = centerLocal.z - halfHeight;
maximumHeight = centerLocal.z + halfHeight;
} else if (tileBoundingVolume instanceof TileBoundingSphere) {
const radius = boundingVolume.radius;
minimumHeight = centerLocal.z - radius;
Expand Down
Loading

0 comments on commit cca7d30

Please sign in to comment.