mirror of https://github.com/CesiumGS/cesium.git
Merge pull request #12743 from CesiumGS/update-draped-imagery-visibility
Update draped imagery visibility
This commit is contained in:
commit
7a9df5014d
|
|
@ -6,10 +6,11 @@
|
|||
|
||||
#### Fixes :wrench:
|
||||
|
||||
- Fixes material flashing when changing properties [#1640](https://github.com/CesiumGS/cesium/issues/1640), [#12716](https://github.com/CesiumGS/cesium/issues/12716)
|
||||
- Fixed an issue where draped imagery on tilesets was not updated based on the visibility of the imagery layer [#12742](https://github.com/CesiumGS/cesium/issues/12742)
|
||||
- Fixes an exception when removing a Gaussian splat tileset from the scene primitives when it has more than one tile. [#12726](https://github.com/CesiumGS/cesium/pull/12726)
|
||||
- Fixes rendering of Gaussian splats when they are scaled by the glTF transform, tileset transform, or model matrix. [#12721](https://github.com/CesiumGS/cesium/issues/12721), [#12718](https://github.com/CesiumGS/cesium/issues/12718)
|
||||
- Updated the type of many properties and functions of `Scene` to clarify that they may be `undefined`. For the full list check PR: [#12736](https://github.com/CesiumGS/cesium/pull/12736)
|
||||
- Fixes material flashing when changing properties. [#1640](https://github.com/CesiumGS/cesium/issues/1640), [12716](https://github.com/CesiumGS/cesium/issues/12716)
|
||||
|
||||
#### Additions :tada:
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
class ImageryConfiguration {
|
||||
constructor(imageryLayer) {
|
||||
this.show = imageryLayer.show;
|
||||
this.alpha = imageryLayer.alpha;
|
||||
this.brightness = imageryLayer.brightness;
|
||||
this.contrast = imageryLayer.contrast;
|
||||
|
|
|
|||
|
|
@ -109,7 +109,9 @@ class ImageryPipelineStage {
|
|||
);
|
||||
|
||||
// This can happen when none of the imagery textures could
|
||||
// be obtained, because they had all been INVALID/FAILED.
|
||||
// be obtained, because they had all been INVALID/FAILED,
|
||||
// or when none of the imagery layers is actually visible
|
||||
// according to `show==true`
|
||||
// Bail out in this case
|
||||
if (imageryInputs.length === 0) {
|
||||
return;
|
||||
|
|
@ -758,7 +760,8 @@ class ImageryPipelineStage {
|
|||
* pipeline stage for draping the given imagery layers over the primitive
|
||||
* that is described by the given model primitive imagery.
|
||||
*
|
||||
* This will obtain the <code>ImageryCoverage</code> objects that are provided by
|
||||
* For each imagery layer that is currently visible (as of `show==true`), this
|
||||
* will obtain the <code>ImageryCoverage</code> objects that are provided by
|
||||
* the given model primitive imagery (and that describe the imagery tiles
|
||||
* that are covered by the primitive), and create one <code>ImageryInput</code> for
|
||||
* each of them.
|
||||
|
|
@ -791,6 +794,9 @@ class ImageryPipelineStage {
|
|||
|
||||
for (let i = 0; i < imageryLayers.length; i++) {
|
||||
const imageryLayer = imageryLayers.get(i);
|
||||
if (!imageryLayer.show) {
|
||||
continue;
|
||||
}
|
||||
const imageryTexCoordAttributeSetIndex =
|
||||
imageryTexCoordAttributeSetIndices[i];
|
||||
const mappedPositions =
|
||||
|
|
|
|||
|
|
@ -335,6 +335,9 @@ class ModelImagery {
|
|||
const imageryLayer = imageryLayers.get(i);
|
||||
const imageryConfiguration = imageryConfigurations[i];
|
||||
|
||||
if (imageryLayer.show !== imageryConfiguration.show) {
|
||||
return true;
|
||||
}
|
||||
if (imageryLayer.alpha !== imageryConfiguration.alpha) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
import {
|
||||
defined,
|
||||
ResourceCache,
|
||||
ShaderBuilder,
|
||||
ImageryPipelineStage,
|
||||
} from "../../../index.js";
|
||||
import createScene from "../../../../../Specs/createScene.js";
|
||||
import loadTilesetWithImagery from "./loadTilesetWithImagery.js";
|
||||
|
||||
describe("Scene/Model/ImageryPipelineStage", function () {
|
||||
let scene;
|
||||
|
||||
beforeAll(function () {
|
||||
scene = createScene();
|
||||
});
|
||||
|
||||
afterAll(function () {
|
||||
scene.destroyForSpecs();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
scene.primitives.removeAll();
|
||||
ResourceCache.clearForSpecs();
|
||||
});
|
||||
|
||||
// A mock `FrameState` object, extracted from other specs, for
|
||||
// the ImageryPipelineStage.process call
|
||||
const mockFrameState = {
|
||||
context: {
|
||||
defaultTexture: {},
|
||||
defaultNormalTexture: {},
|
||||
defaultEmissiveTexture: {},
|
||||
},
|
||||
};
|
||||
|
||||
// Create a mock `PrimitiveRenderResources` object, extracted from
|
||||
// other specs, for the ImageryPipelineStage.process call
|
||||
function mockRenderResources(model, primitive) {
|
||||
const count = defined(primitive.indices)
|
||||
? primitive.indices.count
|
||||
: primitive.attributes[0].count;
|
||||
|
||||
return {
|
||||
attributes: [],
|
||||
shaderBuilder: new ShaderBuilder(),
|
||||
attributeIndex: 1,
|
||||
count: count,
|
||||
model: model,
|
||||
runtimeNode: {
|
||||
node: {},
|
||||
},
|
||||
uniformMap: {},
|
||||
runtimePrimitive: {},
|
||||
};
|
||||
}
|
||||
|
||||
it("does not create imagery inputs for imagery layers that are not shown", async function () {
|
||||
// The prerequisites for computing the imagery inputs are not
|
||||
// met without a GL context: The "mappedPositions" cannot be
|
||||
// computed without fetching the primitive POSITION data from
|
||||
// the GPU
|
||||
if (!scene.context.webgl2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Part of a "regression test" test against https://github.com/CesiumGS/cesium/issues/12742
|
||||
const tileset = await loadTilesetWithImagery(scene);
|
||||
|
||||
// Drill a hole through the loaded structures and create some
|
||||
// mock data for the ImageryPipelineStage.process call
|
||||
const imageryLayers = tileset.imageryLayers;
|
||||
const root = tileset.root;
|
||||
const content = root.content;
|
||||
const model = content._model;
|
||||
const modelImagery = model._modelImagery;
|
||||
const modelPrimitiveImagery = modelImagery._modelPrimitiveImageries[0];
|
||||
const primitive = model.sceneGraph.components.nodes[0].primitives[0];
|
||||
const primitiveRenderResources = mockRenderResources(model, primitive);
|
||||
const imageryTexCoordAttributeSetIndices = [0];
|
||||
const frameState = mockFrameState;
|
||||
ImageryPipelineStage.process(
|
||||
primitiveRenderResources,
|
||||
primitive,
|
||||
frameState,
|
||||
);
|
||||
|
||||
// Initially, the imagery layers are visible, as of show===true,
|
||||
// and there should be at least one ImageryInput be generated
|
||||
// to be sent to the shader
|
||||
const imageryInputsA = ImageryPipelineStage._createImageryInputs(
|
||||
imageryLayers,
|
||||
modelPrimitiveImagery,
|
||||
imageryTexCoordAttributeSetIndices,
|
||||
);
|
||||
expect(imageryInputsA.length).not.toBe(0);
|
||||
|
||||
// For specs: Hide the imagery layer by setting show = false
|
||||
imageryLayers.get(0).show = false;
|
||||
|
||||
// No more ImageryInput objects should be generated now
|
||||
const imageryInputsB = ImageryPipelineStage._createImageryInputs(
|
||||
imageryLayers,
|
||||
modelPrimitiveImagery,
|
||||
imageryTexCoordAttributeSetIndices,
|
||||
);
|
||||
expect(imageryInputsB.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,76 +1,7 @@
|
|||
import {
|
||||
Cartesian3,
|
||||
ResourceCache,
|
||||
Transforms,
|
||||
ModelImagery,
|
||||
ImageryLayer,
|
||||
TileCoordinatesImageryProvider,
|
||||
HeadingPitchRoll,
|
||||
WebMercatorTilingScheme,
|
||||
} from "../../../index.js";
|
||||
import { ResourceCache, ModelImagery } from "../../../index.js";
|
||||
|
||||
import createScene from "../../../../../Specs/createScene.js";
|
||||
import pollToPromise from "../../../../../Specs/pollToPromise.js";
|
||||
import Cesium3DTilesTester from "../../../../../Specs/Cesium3DTilesTester.js";
|
||||
|
||||
const tileset_unitSquare_fourPrimitives_plain_url =
|
||||
"./Data/Models/glTF-2.0/unitSquare/tileset_unitSquare_fourPrimitives_plain.json";
|
||||
|
||||
/**
|
||||
* Wait until the root tile of the given tileset is loaded
|
||||
*
|
||||
* @param {Cesium3DTileset} tileset The tileset
|
||||
* @param {Scene} scene The scene
|
||||
*/
|
||||
async function waitForRootLoaded(tileset, scene) {
|
||||
scene.renderForSpecs();
|
||||
const root = tileset.root;
|
||||
await pollToPromise(() => {
|
||||
scene.renderForSpecs();
|
||||
return root.contentFailed || root.contentReady;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and return a test tileset that defines an imagery layer,
|
||||
* waiting until the root of that tileset is loaded.
|
||||
*
|
||||
* This means that the resulting <code>tileset.root.content._model._modelImagery</code>
|
||||
* (including the <code>ModelPrimitiveImagery</code> instances) will be defined and ready.
|
||||
*
|
||||
* @param {Scene} scene The scene
|
||||
* @returns {Cesium3DTileset} The tileset
|
||||
*/
|
||||
async function loadTestTilesetWithImagery(scene) {
|
||||
const url = tileset_unitSquare_fourPrimitives_plain_url;
|
||||
const tileset = await Cesium3DTilesTester.loadTileset(scene, url);
|
||||
|
||||
// Create a non-trivial transform for the tileset
|
||||
const transform = Transforms.eastNorthUpToFixedFrame(
|
||||
Cartesian3.fromDegrees(-120.0, 40.0, 1.0),
|
||||
);
|
||||
tileset.modelMatrix = transform;
|
||||
|
||||
// Set a view that fully shows the tile content
|
||||
// (a unit square at the position given above)
|
||||
scene.camera.setView({
|
||||
destination: new Cartesian3(
|
||||
-2446354.452726738,
|
||||
-4237211.248955036,
|
||||
4077988.0921552004,
|
||||
),
|
||||
orientation: new HeadingPitchRoll(Math.PI * 2, -Math.PI / 2, 0),
|
||||
});
|
||||
|
||||
const imageryProvider = new TileCoordinatesImageryProvider({
|
||||
tilingScheme: new WebMercatorTilingScheme(),
|
||||
});
|
||||
const imageryLayer = new ImageryLayer(imageryProvider);
|
||||
tileset.imageryLayers.add(imageryLayer);
|
||||
|
||||
await waitForRootLoaded(tileset, scene);
|
||||
return tileset;
|
||||
}
|
||||
import loadTilesetWithImagery from "./loadTilesetWithImagery.js";
|
||||
|
||||
describe("Scene/Model/ModelImagery", function () {
|
||||
let scene;
|
||||
|
|
@ -96,7 +27,7 @@ describe("Scene/Model/ModelImagery", function () {
|
|||
});
|
||||
|
||||
it("properly reports _hasImagery", async function () {
|
||||
const tileset = await loadTestTilesetWithImagery(scene);
|
||||
const tileset = await loadTilesetWithImagery(scene);
|
||||
|
||||
const root = tileset.root;
|
||||
const content = root.content;
|
||||
|
|
@ -114,7 +45,7 @@ describe("Scene/Model/ModelImagery", function () {
|
|||
});
|
||||
|
||||
it("properly reports _allImageryLayersReady", async function () {
|
||||
const tileset = await loadTestTilesetWithImagery(scene);
|
||||
const tileset = await loadTilesetWithImagery(scene);
|
||||
|
||||
const root = tileset.root;
|
||||
const content = root.content;
|
||||
|
|
@ -137,7 +68,7 @@ describe("Scene/Model/ModelImagery", function () {
|
|||
return;
|
||||
}
|
||||
|
||||
const tileset = await loadTestTilesetWithImagery(scene);
|
||||
const tileset = await loadTilesetWithImagery(scene);
|
||||
|
||||
const root = tileset.root;
|
||||
const content = root.content;
|
||||
|
|
@ -161,8 +92,37 @@ describe("Scene/Model/ModelImagery", function () {
|
|||
expect(modelImagery._imageryConfigurationsModified()).toBeFalse();
|
||||
});
|
||||
|
||||
it("considers the show flag as part of the imageryConfigurations", async function () {
|
||||
if (!scene.context.webgl2) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tileset = await loadTilesetWithImagery(scene);
|
||||
|
||||
const root = tileset.root;
|
||||
const content = root.content;
|
||||
const model = content._model;
|
||||
const modelImagery = model._modelImagery;
|
||||
const imageryLayer = tileset.imageryLayers.get(0);
|
||||
|
||||
// Initially, _imageryConfigurationsModified is false (it was just updated)
|
||||
expect(modelImagery._imageryConfigurationsModified()).toBeFalse();
|
||||
|
||||
// For spec: Modify imagery configuration
|
||||
imageryLayer.show = false;
|
||||
|
||||
// Now, _imageryConfigurationsModified is true
|
||||
expect(modelImagery._imageryConfigurationsModified()).toBeTrue();
|
||||
|
||||
// Trigger an update
|
||||
modelImagery._checkForModifiedImageryConfigurations();
|
||||
|
||||
// Now, _imageryConfigurationsModified is false again
|
||||
expect(modelImagery._imageryConfigurationsModified()).toBeFalse();
|
||||
});
|
||||
|
||||
it("creates one ModelPrimitiveImagery for each primitive", async function () {
|
||||
const tileset = await loadTestTilesetWithImagery(scene);
|
||||
const tileset = await loadTilesetWithImagery(scene);
|
||||
|
||||
const root = tileset.root;
|
||||
const content = root.content;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
import {
|
||||
Cartesian3,
|
||||
HeadingPitchRoll,
|
||||
ImageryLayer,
|
||||
TileCoordinatesImageryProvider,
|
||||
Transforms,
|
||||
WebMercatorTilingScheme,
|
||||
} from "../../../index.js";
|
||||
import pollToPromise from "../../../../../Specs/pollToPromise";
|
||||
import Cesium3DTilesTester from "../../../../../Specs/Cesium3DTilesTester.js";
|
||||
|
||||
// A currently hard-wired tileset to be loaded for imagery draping tests
|
||||
const tileset_unitSquare_fourPrimitives_plain_url =
|
||||
"./Data/Models/glTF-2.0/unitSquare/tileset_unitSquare_fourPrimitives_plain.json";
|
||||
|
||||
/**
|
||||
* Wait until the root tile of the given tileset is loaded
|
||||
*
|
||||
* @param {Cesium3DTileset} tileset The tileset
|
||||
* @param {Scene} scene The scene
|
||||
*/
|
||||
async function waitForRootLoaded(tileset, scene) {
|
||||
scene.renderForSpecs();
|
||||
const root = tileset.root;
|
||||
await pollToPromise(() => {
|
||||
scene.renderForSpecs();
|
||||
return root.contentFailed || root.contentReady;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and return a test tileset that defines an imagery layer,
|
||||
* waiting until the root of that tileset is loaded.
|
||||
*
|
||||
* This means that the resulting <code>tileset.root.content._model._modelImagery</code>
|
||||
* (including the <code>ModelPrimitiveImagery</code> instances) will be defined and ready.
|
||||
*
|
||||
* @param {Scene} scene The scene
|
||||
* @returns {Cesium3DTileset} The tileset
|
||||
*/
|
||||
async function loadTilesetWithImagery(scene) {
|
||||
const url = tileset_unitSquare_fourPrimitives_plain_url;
|
||||
const tileset = await Cesium3DTilesTester.loadTileset(scene, url);
|
||||
|
||||
// Create a non-trivial transform for the tileset
|
||||
const transform = Transforms.eastNorthUpToFixedFrame(
|
||||
Cartesian3.fromDegrees(-120.0, 40.0, 1.0),
|
||||
);
|
||||
tileset.modelMatrix = transform;
|
||||
|
||||
// Set a view that fully shows the tile content
|
||||
// (a unit square at the position given above)
|
||||
scene.camera.setView({
|
||||
destination: new Cartesian3(
|
||||
-2446354.452726738,
|
||||
-4237211.248955036,
|
||||
4077988.0921552004,
|
||||
),
|
||||
orientation: new HeadingPitchRoll(Math.PI * 2, -Math.PI / 2, 0),
|
||||
});
|
||||
|
||||
const imageryProvider = new TileCoordinatesImageryProvider({
|
||||
tilingScheme: new WebMercatorTilingScheme(),
|
||||
});
|
||||
const imageryLayer = new ImageryLayer(imageryProvider);
|
||||
tileset.imageryLayers.add(imageryLayer);
|
||||
|
||||
await waitForRootLoaded(tileset, scene);
|
||||
return tileset;
|
||||
}
|
||||
|
||||
export default loadTilesetWithImagery;
|
||||
Loading…
Reference in New Issue