diff --git a/Apps/Sandcastle/gallery/development/Ground Primitive.html b/Apps/Sandcastle/gallery/development/Ground Primitive.html index ad013e0c0401..fc7dee1c106c 100644 --- a/Apps/Sandcastle/gallery/development/Ground Primitive.html +++ b/Apps/Sandcastle/gallery/development/Ground Primitive.html @@ -36,135 +36,203 @@ requestVertexNormals : true }); -// Circle geometry -scene.primitives.add(new Cesium.GroundPrimitive({ - geometryInstance: new Cesium.GeometryInstance({ - geometry : new Cesium.CircleGeometry({ - center : Cesium.Cartesian3.fromDegrees(-95.0, 45.0), - radius : 250000.0 - }), - attributes : { - color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 0.0, 0.0, 0.5)) - }, - id : 'circle' - }) -})); - -// Ellipse Geometry -scene.primitives.add(new Cesium.GroundPrimitive({ - geometryInstance: new Cesium.GeometryInstance({ - geometry : new Cesium.EllipseGeometry({ - center : Cesium.Cartesian3.fromDegrees(-105.0, 40.0), - semiMinorAxis : 300000.0, - semiMajorAxis : 400000.0 - }), - attributes : { - color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(0.0, 1.0, 1.0, 0.5)) - }, - id : 'ellipse' - }) -})); - -// Corridor Geometry -scene.primitives.add(new Cesium.GroundPrimitive({ - geometryInstance : new Cesium.GeometryInstance({ - geometry: new Cesium.CorridorGeometry({ - positions : Cesium.Cartesian3.fromDegreesArray([ - -112.0, 40.0, - -117.0, 40.0, - -117.0, 35.0 - ]), - width : 200000.0 +function offsetPositions(positions, degreeOffset) { + positions = scene.globe.ellipsoid.cartesianArrayToCartographicArray(positions); + var delta = Cesium.Math.toRadians(degreeOffset); + for (var i = 0; i < positions.length; ++i) { + var position = positions[i]; + position.latitude += delta; + position.longitude += delta; + } + return scene.globe.ellipsoid.cartographicArrayToCartesianArray(positions); +} + +function createOverlappingPolygons(withAlpha) { + var positions = [new Cesium.Cartesian3(-2358138.847340281, -3744072.459541374, 4581158.5714175375), + new Cesium.Cartesian3(-2357231.4925370603, -3745103.7886602185, 4580702.9757762635), + new Cesium.Cartesian3(-2355912.902205431, -3744249.029778454, 4582402.154378103), + new Cesium.Cartesian3(-2357208.0209552636, -3743553.4420488174, 4581961.863286629)]; + var polygonHierarchy = { positions : positions }; + + var color = Cesium.Color.RED; + if (withAlpha) { + color = color.withAlpha(0.5); + } + + scene.groundPrimitives.add(new Cesium.GroundPrimitive({ + geometryInstance : new Cesium.GeometryInstance({ + geometry : new Cesium.PolygonGeometry({ + polygonHierarchy : polygonHierarchy + }), + attributes: { + color: Cesium.ColorGeometryInstanceAttribute.fromColor(color) + }, + id : 'polygon 1' + }) + })); + + // Same polygon slightly offset and overlapping. + var positionsOffset = offsetPositions(positions, 0.01); + polygonHierarchy = { positions : positionsOffset }; + + color = Cesium.Color.GREEN; + if (withAlpha) { + color = color.withAlpha(0.5); + } + + scene.groundPrimitives.add(new Cesium.GroundPrimitive({ + geometryInstance : new Cesium.GeometryInstance({ + geometry : new Cesium.PolygonGeometry({ + polygonHierarchy : polygonHierarchy + }), + attributes: { + color: Cesium.ColorGeometryInstanceAttribute.fromColor(color) + }, + id : 'polygon 2' + }) + })); + + // Same polygon slightly offset and overlapping. + positionsOffset = offsetPositions(positions, -0.01); + polygonHierarchy = { positions : positionsOffset }; + + color = Cesium.Color.BLUE; + if (withAlpha) { + color = color.withAlpha(0.5); + } + + scene.groundPrimitives.add(new Cesium.GroundPrimitive({ + geometryInstance : new Cesium.GeometryInstance({ + geometry : new Cesium.PolygonGeometry({ + polygonHierarchy : polygonHierarchy }), - attributes : { - color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(0.0, 0.0, 1.0, 0.5)) - }, - id : 'corridor' - }) -})); - -// Rectangle geometry -scene.primitives.add(new Cesium.GroundPrimitive({ - geometryInstance : new Cesium.GeometryInstance({ - geometry : new Cesium.RectangleGeometry({ - rectangle : Cesium.Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0), - rotation : Cesium.Math.toRadians(45) - }), - attributes: { - color: Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(0.0, 1.0, 0.0, 0.5)) - }, - id : 'rectangle' - }) -})); - -// Polygon on Mount Saint Helens -var positions = [new Cesium.Cartesian3(-2358138.847340281, -3744072.459541374, 4581158.5714175375), - new Cesium.Cartesian3(-2357231.4925370603, -3745103.7886602185, 4580702.9757762635), - new Cesium.Cartesian3(-2355912.902205431, -3744249.029778454, 4582402.154378103), - new Cesium.Cartesian3(-2357208.0209552636, -3743553.4420488174, 4581961.863286629)]; -var polygonHierarchy = { positions : positions }; - -var primitive = scene.primitives.add(new Cesium.GroundPrimitive({ - geometryInstance : new Cesium.GeometryInstance({ - geometry : new Cesium.PolygonGeometry({ - polygonHierarchy : polygonHierarchy - }), - attributes: { - color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED.withAlpha(0.5)) - }, - id : 'polygon 1' - }) -})); - -// Same polygon slightly offset and overlapping. -positions = scene.globe.ellipsoid.cartesianArrayToCartographicArray(positions); -var delta = Cesium.Math.toRadians(0.01); -for (var i = 0; i < positions.length; ++i) { - var position = positions[i]; - position.latitude += delta; - position.longitude += delta; + attributes: { + color: Cesium.ColorGeometryInstanceAttribute.fromColor(color) + }, + id : 'polygon 3' + }) + })); } -positions = scene.globe.ellipsoid.cartographicArrayToCartesianArray(positions); -polygonHierarchy = { positions : positions }; - -scene.primitives.add(new Cesium.GroundPrimitive({ - geometryInstance : new Cesium.GeometryInstance({ - geometry : new Cesium.PolygonGeometry({ - polygonHierarchy : polygonHierarchy - }), - attributes: { - color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE.withAlpha(0.5)) - }, - id : 'polygon 2' - }) -})); - -Sandcastle.addToolbarButton('View Mount Saint Helens', function() { + +function viewOverlappingPolygons() { viewer.camera.lookAt(new Cesium.Cartesian3(-2354331.3069306486, -3742016.2427205616, 4581875.591571755), new Cesium.HeadingPitchRange(Cesium.Math.toRadians(20.0), Cesium.Math.toRadians(-35.0), 10000.0)); viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY); -}); +} + +var handler; -var currentObject = undefined; -var lastColor = undefined; +Sandcastle.addDefaultToolbarButton('Picking Example', function() { + createOverlappingPolygons(true); + viewOverlappingPolygons(); + + var currentObject; + var lastColor; -var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); -handler.setInputAction(function(movement) { - var pickedObject = scene.pick(movement.endPosition); - if (Cesium.defined(pickedObject) && pickedObject !== currentObject) { - if (Cesium.defined(currentObject)) { + handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); + handler.setInputAction(function(movement) { + var pickedObject = scene.pick(movement.endPosition); + if (Cesium.defined(pickedObject) && pickedObject !== currentObject) { + if (Cesium.defined(currentObject)) { + currentObject.primitive.getGeometryInstanceAttributes(currentObject.id).color = lastColor; + } + + currentObject = pickedObject; + + var attributes = currentObject.primitive.getGeometryInstanceAttributes(currentObject.id); + lastColor = attributes.color; + attributes.color = [255, 255, 0, 128]; + } else if (!Cesium.defined(pickedObject) && Cesium.defined(currentObject)) { currentObject.primitive.getGeometryInstanceAttributes(currentObject.id).color = lastColor; + currentObject = undefined; } - - currentObject = pickedObject; - - var attributes = currentObject.primitive.getGeometryInstanceAttributes(currentObject.id); - lastColor = attributes.color; - attributes.color = [255, 255, 0, 128]; - } else if (!Cesium.defined(pickedObject) && Cesium.defined(currentObject)) { - currentObject.primitive.getGeometryInstanceAttributes(currentObject.id).color = lastColor; - currentObject = undefined; - } -}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); + }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); +}); + +Sandcastle.addToolbarButton('Z-Order', function() { + createOverlappingPolygons(false); + viewOverlappingPolygons(); + + + handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); + handler.setInputAction(function(movement) { + var pickedObject = scene.pick(movement.endPosition); + if (Cesium.defined(pickedObject)) { + scene.groundPrimitives.raiseToTop(pickedObject.primitive); + } + }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); +}); + +Sandcastle.addToolbarButton('Create large polygons', function() { + // Circle geometry + scene.groundPrimitives.add(new Cesium.GroundPrimitive({ + geometryInstance: new Cesium.GeometryInstance({ + geometry : new Cesium.CircleGeometry({ + center : Cesium.Cartesian3.fromDegrees(-95.0, 45.0), + radius : 250000.0 + }), + attributes : { + color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 0.0, 0.0, 0.5)) + }, + id : 'circle' + }) + })); + + // Ellipse Geometry + scene.groundPrimitives.add(new Cesium.GroundPrimitive({ + geometryInstance: new Cesium.GeometryInstance({ + geometry : new Cesium.EllipseGeometry({ + center : Cesium.Cartesian3.fromDegrees(-105.0, 40.0), + semiMinorAxis : 300000.0, + semiMajorAxis : 400000.0 + }), + attributes : { + color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(0.0, 1.0, 1.0, 0.5)) + }, + id : 'ellipse' + }) + })); + + // Corridor Geometry + scene.groundPrimitives.add(new Cesium.GroundPrimitive({ + geometryInstance : new Cesium.GeometryInstance({ + geometry: new Cesium.CorridorGeometry({ + positions : Cesium.Cartesian3.fromDegreesArray([ + -112.0, 40.0, + -117.0, 40.0, + -117.0, 35.0 + ]), + width : 200000.0 + }), + attributes : { + color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(0.0, 0.0, 1.0, 0.5)) + }, + id : 'corridor' + }) + })); + + // Rectangle geometry + scene.groundPrimitives.add(new Cesium.GroundPrimitive({ + geometryInstance : new Cesium.GeometryInstance({ + geometry : new Cesium.RectangleGeometry({ + rectangle : Cesium.Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0), + rotation : Cesium.Math.toRadians(45) + }), + attributes: { + color: Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(0.0, 1.0, 0.0, 0.5)) + }, + id : 'rectangle' + }) + })); +}); + +Sandcastle.reset = function() { + scene.groundPrimitives.removeAll(); + handler = handler && handler.destroy(); + + //Set the camera to a US centered tilted view and switch back to moving in world coordinates. + viewer.camera.lookAt(Cesium.Cartesian3.fromDegrees(-98.0, 40.0), new Cesium.Cartesian3(0.0, -4790000.0, 3930000.0)); + viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY); +}; //Sandcastle_End Sandcastle.finishedLoading(); diff --git a/CHANGES.md b/CHANGES.md index 5fc58275302f..8a0fced0a857 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,15 @@ Change Log * Removed [es5-shim](https://github.com/kriskowal/es5-shim), which is no longer required by the unit tests. [#2933](https://github.com/AnalyticalGraphicsInc/cesium/pull/2945) * Fix issue where `JulianDate` would not parse certain dates properly. [#405](https://github.com/AnalyticalGraphicsInc/cesium/issues/405) * Added support for `GroundPrimitive` which works much like `Primitive` but it drapes the geometry over terrain. Valid geometries that can be draped on terrain are `CircleGeometry`, `CorridorGeometry`, `EllipseGeometry`, `PolygonGeometry`, and `RectangleGeometry`. +* Added `Scene.groundPrimitives`, which is a primitive collection like `Scene.primitives`, but for `GroundPrimitive`s. Use for correct z-ordering. For example: + + // draws the ellipse on top of the rectangle + var ellipse = scene.groundPrimitives.add(new Cesium.GroundPrimitive({...})); + var rectangle = scene.groundPrimitives.add(new Cesium.GroundPrimitive({...})); + + // move the rectangle to draw on top of the ellipse + scene.groundPrimitives.raise(rectangle); + * Added `BoundingSphere.isOccluded` and `OrientedBoundingBox.isOccluded` to determine if the volumes are occluded by an `Occluder`. * Added `distanceSquaredTo` and `computePlaneDistances` functions to `OrientedBoundingBox`. * Added `reverseZ` tag to `UrlTemplateImageryProvider`. diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js index 640d6d718937..5c21ff61329c 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -215,6 +215,7 @@ define([ this._context = context; this._globe = undefined; this._primitives = new PrimitiveCollection(); + this._groundPrimitives = new PrimitiveCollection(); this._tweens = new TweenCollection(); @@ -637,6 +638,19 @@ define([ } }, + /** + * Gets the collection of ground primitives. + * @memberof Scene.prototype + * + * @type {PrimitiveCollection} + * @readonly + */ + groundPrimitives : { + get : function() { + return this._groundPrimitives; + } + }, + /** * Gets the camera. * @memberof Scene.prototype @@ -1605,6 +1619,7 @@ define([ scene._globe.update(context, frameState, commandList); } + scene._groundPrimitives.update(context, frameState, commandList); scene._primitives.update(context, frameState, commandList); } @@ -2117,6 +2132,7 @@ define([ this._screenSpaceCameraController = this._screenSpaceCameraController && this._screenSpaceCameraController.destroy(); this._pickFramebuffer = this._pickFramebuffer && this._pickFramebuffer.destroy(); this._primitives = this._primitives && this._primitives.destroy(); + this._groundPrimitives = this._groundPrimitives && this._groundPrimitives.destroy(); this._globe = this._globe && this._globe.destroy(); this.skyBox = this.skyBox && this.skyBox.destroy(); this.skyAtmosphere = this.skyAtmosphere && this.skyAtmosphere.destroy(); diff --git a/Specs/Scene/GroundPrimitiveSpec.js b/Specs/Scene/GroundPrimitiveSpec.js index 6721cc1bd0a8..2aae7bef3028 100644 --- a/Specs/Scene/GroundPrimitiveSpec.js +++ b/Specs/Scene/GroundPrimitiveSpec.js @@ -164,7 +164,7 @@ defineSuite([ }); afterEach(function() { - scene.primitives.removeAll(); + scene.groundPrimitives.removeAll(); depthPrimitive = depthPrimitive && !depthPrimitive.isDestroyed() && depthPrimitive.destroy(); }); @@ -220,7 +220,7 @@ defineSuite([ }); expect(primitive.geometryInstance).toBeDefined(); - scene.primitives.add(primitive); + scene.groundPrimitives.add(primitive); scene.renderForSpecs(); expect(primitive.geometryInstance).not.toBeDefined(); }); @@ -237,7 +237,7 @@ defineSuite([ }); expect(primitive.geometryInstance).toBeDefined(); - scene.primitives.add(primitive); + scene.groundPrimitives.add(primitive); scene.renderForSpecs(); expect(primitive.geometryInstance).toBeDefined(); }); @@ -253,7 +253,7 @@ defineSuite([ asynchronous : false }); - scene.primitives.add(primitive); + scene.groundPrimitives.add(primitive); scene.renderForSpecs(); return primitive.readyPromise.then(function(param) { @@ -333,12 +333,12 @@ defineSuite([ function verifyGroundPrimitiveRender(primitive, color) { scene.camera.viewRectangle(rectangle); - scene.primitives.add(depthPrimitive); + scene.groundPrimitives.add(depthPrimitive); var pixels = scene.renderForSpecs(); expect(pixels).not.toEqual([0, 0, 0, 0]); expect(pixels[0]).toEqual(0); - scene.primitives.add(primitive); + scene.groundPrimitives.add(primitive); pixels = scene.renderForSpecs(); expect(pixels).toEqual(color); } @@ -389,7 +389,7 @@ defineSuite([ return; } - scene.primitives.add(new Primitive({ + scene.groundPrimitives.add(new Primitive({ geometryInstances : rectangleInstance, asynchronous : false, debugShowBoundingVolume : true @@ -430,9 +430,9 @@ defineSuite([ verifyGroundPrimitiveRender(primitive, rectColor); - scene.primitives.destroyPrimitives = false; - scene.primitives.removeAll(); - scene.primitives.destroyPrimitives = true; + scene.groundPrimitives.destroyPrimitives = false; + scene.groundPrimitives.removeAll(); + scene.groundPrimitives.destroyPrimitives = true; var newColor = [255, 255, 255, 255]; var attributes = primitive.getGeometryInstanceAttributes('rectangle'); @@ -456,9 +456,9 @@ defineSuite([ verifyGroundPrimitiveRender(primitive, rectColor); - scene.primitives.destroyPrimitives = false; - scene.primitives.removeAll(); - scene.primitives.destroyPrimitives = true; + scene.groundPrimitives.destroyPrimitives = false; + scene.groundPrimitives.removeAll(); + scene.groundPrimitives.destroyPrimitives = true; var attributes = primitive.getGeometryInstanceAttributes('rectangle'); expect(attributes.show).toBeDefined();