Skip to content

Draping Imagery on 3D Tiles #12567

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

Merged
merged 82 commits into from
May 30, 2025
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
af6a769
Minor formatting of shader string
javagl Mar 19, 2025
0b67e70
Minor JSDoc fix
javagl Mar 19, 2025
d9907b3
Drafts of draping-related classes
javagl Mar 19, 2025
927d55d
Basic comments (unrelated to draping)
javagl Mar 19, 2025
76a4f9a
Drafts for wiring in the draping-related classes
javagl Mar 19, 2025
9defb46
Set up structures for wiring draping into model
javagl Apr 3, 2025
b59b323
Cleanups and comments, wiring in the draping
javagl Apr 11, 2025
2bd118a
Merge remote-tracking branch 'origin/main' into draping-3d-tiles
javagl Apr 11, 2025
6c1791d
Define ImageryInput. Minor cleanups.
javagl Apr 12, 2025
f1c5768
Compute proper imagery coverage
javagl Apr 12, 2025
34680af
Properly handle primitive node transform
javagl Apr 12, 2025
8590207
Handle quantized positions
javagl Apr 13, 2025
61dcb2a
Do not access private variables
javagl Apr 13, 2025
6bc30cf
Proper quantization handling. Some debug handling.
javagl Apr 16, 2025
96a2524
Apply suggestions from code review
javagl Apr 22, 2025
a5821d6
Minor wrap-ups, but omitting upsampling experiments
javagl Apr 30, 2025
f1034d6
Merge branch 'draping-3d-tiles' of https://github.com/CesiumGS/cesium…
javagl Apr 30, 2025
4c3a45b
Cleanups, omitting upsampling
javagl May 8, 2025
d1f2593
Basic TSDoc fixes
javagl May 14, 2025
7053786
Preliminarily omit TS generation
javagl May 14, 2025
7fed864
Add file extensions in import
javagl May 14, 2025
ff41e22
More file extensions for imports
javagl May 14, 2025
9865317
Add step to build docs
javagl May 14, 2025
74adba5
Ignore omitted TS file
javagl May 14, 2025
19fe968
Omit other TS file
javagl May 14, 2025
9ece74d
Cleanups, omitting upsampling
javagl May 16, 2025
1b2a151
Remove debug string
javagl May 20, 2025
59e691b
Cleanups. Error handling. Make allocations explicit.
javagl May 20, 2025
99e7003
Add flag to optionally wait for imagery
javagl May 20, 2025
40b25d3
Merge remote-tracking branch 'origin/main' into draping-3d-tiles
javagl May 21, 2025
19969bc
Slightly more elaborate warning message
javagl May 21, 2025
fa09975
Minor inlined comment update
javagl May 21, 2025
b6d0156
Track modifications to draped imagery layers
javagl May 21, 2025
99a44d8
Add experimental tag, and private to internal classes
javagl May 21, 2025
89fb5c6
Reactivate TS generation
javagl May 21, 2025
f7be876
Minor cleanup for preliminary ModelReaderSpec
javagl May 21, 2025
2d972b4
Merge remote-tracking branch 'origin/main' into draping-3d-tiles
javagl May 21, 2025
4fe3c9a
Convert texture from SRGB to linear
javagl May 23, 2025
b381139
Include TS files in ZIP
javagl May 23, 2025
1d16174
Update Cesium3DTileset imageryLayers documentation
javagl May 23, 2025
483d0e3
Define type for component reader
javagl May 23, 2025
0292545
Merge branch 'draping-3d-tiles' of https://github.com/CesiumGS/cesium…
javagl May 23, 2025
59f3603
Define type for components reader
javagl May 23, 2025
ca3a8c3
Mark properties as private
javagl May 23, 2025
341e0e2
Proper handling of imagery layers listener
javagl May 23, 2025
7d8eaa9
Update comment for imagery layers
javagl May 23, 2025
b960dd7
Add details and example in imageryLayers documentation
javagl May 23, 2025
ed87411
Make imagery layers as read-only
javagl May 23, 2025
c65f2c5
Update description of experimental feature
javagl May 23, 2025
ed35a61
Mark getter as readonly
javagl May 23, 2025
9d5f8e9
Mark getter as readonly
javagl May 23, 2025
2d987c2
Mark class as private
javagl May 23, 2025
47c872b
Remove part of inlined comment
javagl May 23, 2025
8d49670
Mark class as private
javagl May 23, 2025
b0d22cf
Mark class as private
javagl May 23, 2025
8678b6c
Move functions into ImageryCoverage class
javagl May 23, 2025
1f0b0d1
Merge branch 'draping-3d-tiles' of https://github.com/CesiumGS/cesium…
javagl May 23, 2025
3b873c1
Add type information to return documentation
javagl May 23, 2025
d33ef0b
Make ImageryCoverage immutable
javagl May 23, 2025
8abec54
Merge branch 'draping-3d-tiles' of https://github.com/CesiumGS/cesium…
javagl May 23, 2025
7ab376c
Rename internal function
javagl May 23, 2025
2694de3
Remove unused function
javagl May 23, 2025
373e02a
Minor update in comment
javagl May 23, 2025
71fbb0f
Add file extensions for imports
javagl May 23, 2025
f29a182
Move documentation to public getter
javagl May 24, 2025
017b160
Removed unused function. Add comments.
javagl May 24, 2025
59e2b03
Undo moving functions into utility class
javagl May 27, 2025
5ae1be1
Cleanups of unused functions and comments
javagl May 27, 2025
7cf03b4
Small updates for unit square spec data
javagl May 27, 2025
28c6458
First pass of specs
javagl May 27, 2025
2d01840
Add missing spec data file
javagl May 27, 2025
e159ecd
Proper path to spec data file
javagl May 27, 2025
df4570d
Even more proper path to spec data file
javagl May 27, 2025
3f998aa
Omit specs that require WebGL2
javagl May 27, 2025
b4b522f
Minor update of comment
javagl May 28, 2025
5e71bb4
Additional specs
javagl May 28, 2025
f08887f
Minor comment update
javagl May 29, 2025
0e3a836
Work around imagery reference counter handling
javagl May 29, 2025
baa2145
Additional specs
javagl May 29, 2025
275c8ed
Update CHANGES.md
javagl May 29, 2025
0faeb6c
Update docs
ggetz May 29, 2025
6b95f87
Merge remote-tracking branch 'origin/main' into draping-3d-tiles
javagl May 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion packages/engine/Source/Scene/Cesium3DTileset.js
Original file line number Diff line number Diff line change
Expand Up @@ -1097,6 +1097,25 @@ Object.defineProperties(Cesium3DTileset.prototype, {
},
},

/**
* The {@link ImageryLayerCollection} that should be draped on the contents of this tileset.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* The {@link ImageryLayerCollection} that should be draped on the contents of this tileset.
* The collection of <code>ImageryLayer</code> objects providing 2D georeferenced
* image data that will be rendered over the tileset.
* @see ImageryLayer

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add an @example here? And add a 3D Tiles @example to the documentation for ImageryLayer as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Technically, although uncommon, 3D Tiles content can include GeoJSON data and experimental vector data– I believe neither of those will work with overlays.

GeoJSON should work. (I just tried it with basic examples, and... these are just Model instances, eventually). Not sure about vector data. I3DM is tricky.... it ""works"", but all instances have the same texture, so it's not really "draped" (based on the instance position).

I now listed the types explicitly:

"The imagery will be draped over glTF, B3DM, PNTS, or GeoJSON tile content."

Do we also want to document the limitation on level of detail due to upsampling, which will land later?

I'm not sure whether this is the right place. It's may not be "relevant" for users insofar that they cannot change the behavior. One could say something like
"The imagery level will be picked based on the bounding box size of the cartographic positions of the model primitives"
or so, but ... I think that those who understand this information don't really need it 😆

Can we add an @example here? And add a 3D Tiles @example to the documentation for ImageryLayer as well?

I have added an @example here. But the ImageryLayer has nothing to do with the Cesium3DTileset. (Yes, the tileset can use the imagery layers, but ... I'm thinking about the "direction of dependency" here...).

One could consider to change the existing examples in ImageryLayer from
scene.imageryLayers.add(imageryLayer);
to
imageryLayers.add(imageryLayer);
or even
imageryLayerCollection.add(imageryLayer);

Otherwise, that change would be to just duplicate one of the existing examples, and replacing scene. with tileset.....

Copy link
Contributor Author

@javagl javagl May 23, 2025

Choose a reason for hiding this comment

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

Oh. That @example was not intentional. I know your pain. One of my GitHub names is "gpu", and there are often things that are happening @gpu ("at the GPU")....

*
* @memberof Cesium3DTileset.prototype
*
* @type {ImageryLayerCollection}
*/
imageryLayers: {
// TODO_DRAPING Attach a listener that will set some
// `tileset._imageryLayersDirty` flag that is passed to the
// models, so that the models can be updated for new imagery
get: function () {
return this._imageryLayers;
},
set: function (value) {
this._imageryLayers = value;
},
},

/**
* Gets the tileset's properties dictionary object, which contains metadata about per-feature properties.
* <p>
Expand Down Expand Up @@ -2811,7 +2830,8 @@ function addTileDebugLabel(tile, tileset, position) {
let attributes = 0;

if (tileset.debugShowGeometricError) {
labelString += `\nGeometric error: ${tile.geometricError}`;
// XXX_DRAPING Show SSE as well....
labelString += `\nGeometric error: ${tile.geometricError} SSE ${tile._screenSpaceError}`;
attributes++;
}

Expand Down
9 changes: 4 additions & 5 deletions packages/engine/Source/Scene/GlobeSurfaceShaderSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -409,17 +409,16 @@ GlobeSurfaceShaderSet.prototype.getShaderProgram = function (options) {
u_dayTextureTexCoordsRectangle[${i}],\n\
u_dayTextureTranslationAndScale[${i}],\n\
${applyAlpha ? `u_dayTextureAlpha[${i}]` : "1.0"},\n\
${applyDayNightAlpha ? `u_dayTextureNightAlpha[${i}]` : "1.0"},\n${
applyDayNightAlpha ? `u_dayTextureDayAlpha[${i}]` : "1.0"
},\n${applyBrightness ? `u_dayTextureBrightness[${i}]` : "0.0"},\n\
${applyDayNightAlpha ? `u_dayTextureNightAlpha[${i}]` : "1.0"},\n\
${applyDayNightAlpha ? `u_dayTextureDayAlpha[${i}]` : "1.0"},\n\
${applyBrightness ? `u_dayTextureBrightness[${i}]` : "0.0"},\n\
${applyContrast ? `u_dayTextureContrast[${i}]` : "0.0"},\n\
${applyHue ? `u_dayTextureHue[${i}]` : "0.0"},\n\
${applySaturation ? `u_dayTextureSaturation[${i}]` : "0.0"},\n\
${applyGamma ? `u_dayTextureOneOverGamma[${i}]` : "0.0"},\n\
${applySplit ? `u_dayTextureSplit[${i}]` : "0.0"},\n\
${colorToAlpha ? `u_colorsToAlpha[${i}]` : "vec4(0.0)"},\n\
nightBlend\
);\n`;
nightBlend\);\n`;
if (hasImageryLayerCutout) {
computeDayColor +=
"\
Expand Down
19 changes: 17 additions & 2 deletions packages/engine/Source/Scene/ImageryLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ ImageryLayer.prototype.getImageryRectangle = function () {
*
* @private
*
* @param {Tile} tile The terrain tile.
* @param {QuadtreeTile} tile The terrain tile.
* @param {TerrainProvider|undefined} terrainProvider The terrain provider associated with the terrain tile.
* @param {number} insertionPoint The position to insert new skeletons before in the tile's imagery list.
* @returns {boolean} true if this layer overlaps any portion of the terrain tile; otherwise, false.
Expand Down Expand Up @@ -1068,13 +1068,28 @@ ImageryLayer.prototype._calculateTextureTranslationAndScale = function (

const scaleX = terrainWidth / imageryRectangle.width;
const scaleY = terrainHeight / imageryRectangle.height;
return new Cartesian4(
const result = new Cartesian4(
(scaleX * (terrainRectangle.west - imageryRectangle.west)) / terrainWidth,
(scaleY * (terrainRectangle.south - imageryRectangle.south)) /
terrainHeight,
scaleX,
scaleY,
);

/*
// XXX_DRAPING: The above is just a convoluted way of writing this:
const invImageryWidth = 1.0 / imageryRectangle.width;
const invImageryHeight = 1.0 / imageryRectangle.height;
const deltaWest = terrainRectangle.west - imageryRectangle.west;
const deltaSouth = terrainRectangle.south - imageryRectangle.south;
const offsetX = deltaWest * invImageryWidth;
const offsetY = deltaSouth * invImageryHeight;
const scaleX = terrainRectangle.width * invImageryWidth;
const scaleY = terrainRectangle.height * invImageryHeight;
// which, in turn, could be a generic "Rectangle.relativize" function
*/

return result;
};

/**
Expand Down
23 changes: 23 additions & 0 deletions packages/engine/Source/Scene/Model/ImageryConfiguration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* A class containing a the values that affect the appearance of
* an <code>ImageryLayer</code>.
*
* This is used in the <code>ModelImagery</code> to detect changes in
* the imagery settings: The <code>ModelImagery</code> stores one
* instance per imagery layer. During the <code>update</code>
* call, it checks whether any of the settings was changed.
* If this is the case, the draw commands of the model are reset.
*/
class ImageryConfiguration {
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is a simple, flat object intended to group properties, would it make sense to define this with a @typedef in ModelImagery.js?

Copy link
Contributor

Choose a reason for hiding this comment

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

It should also be marked @private.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See comment above

constructor(imageryLayer) {
this.alpha = imageryLayer.alpha;
this.brightness = imageryLayer.brightness;
this.contrast = imageryLayer.contrast;
this.hue = imageryLayer.hue;
this.saturation = imageryLayer.saturation;
this.gamma = imageryLayer.gamma;
this.colorToAlpha = imageryLayer.colorToAlpha;
}
}

export default ImageryConfiguration;
70 changes: 70 additions & 0 deletions packages/engine/Source/Scene/Model/ImageryCoverage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* A structure containing information about a piece of imagery.
*
* This represents the result of computing the imagery tiles that
* are covered by a given <code>Rectangle</code> (and which part
* of that imagery is covered, in terms of texture coordinates).
*
* It is used by the <code>ModelPrimitiveImagery</code>, to
* represent the imagery tiles that are covered by the cartographic
* bounding rectangle of the primitive positions.
*
* TODO_DRAPING: Implementation note for ImageryCoverage:
* This roughly corresponds to the <code>TileImagery</code> that is
* created in my favorite draping-related time sink, namely in
* <code>ImageryLayer._createTileImagerySkeletons</code>.
* But in contrast to the <code>TileImagery</code>, this describes
* <i>which</i> imagery tile is used, does not store the ("loading"
* and "ready"...) imagery <i>itself</i>.
*/
class ImageryCoverage {
/**
* Creates a new instance
*
* @param {number} x x-coordinate of the imagery tile
* @param {number} y y-coordinate of the imagery tile
* @param {number} level level of the imagery tile
* @param {Cartesian4} textureCoordinateRectangle The texture coordinate
* rectangle from the imagery tile that is covered, i.e. the
* (minU, minV, maxU, maxV) coordinate range.
*/
constructor(x, y, level, textureCoordinateRectangle) {
/**
* The x-coordinate of the imagery tile
*
* @type {number}
* @readonly
*/
this.x = x;

/**
* The x-coordinate of the imagery tile
*
* @type {number}
* @readonly
*/
this.y = y;

/**
* The x-coordinate of the imagery tile
*
* @type {number}
* @readonly
*/
this.level = level;

/**
* The texture coordinate range that is covered from the
* imagery tile.
*
* This is a <code>Cartesian4</code> that contains the
* (minU, minV, maxU, maxV) coordinate range.
*
* @type {Cartesian4}
* @readonly
*/
this.textureCoordinateRectangle = textureCoordinateRectangle;
}
}

export default ImageryCoverage;
Loading
Loading