Skip to content
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

Z-Ordering #2960

Merged
merged 8 commits into from Aug 24, 2015
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
310 changes: 189 additions & 121 deletions Apps/Sandcastle/gallery/development/Ground Primitive.html
Expand Up @@ -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();
Expand Down
9 changes: 9 additions & 0 deletions CHANGES.md
Expand Up @@ -12,6 +12,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`.

Expand Down
16 changes: 16 additions & 0 deletions Source/Scene/Scene.js
Expand Up @@ -215,6 +215,7 @@ define([
this._context = context;
this._globe = undefined;
this._primitives = new PrimitiveCollection();
this._groundPrimitives = new PrimitiveCollection();

this._tweens = new TweenCollection();

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1606,6 +1620,7 @@ define([
}

scene._primitives.update(context, frameState, commandList);
scene._groundPrimitives.update(context, frameState, commandList);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think we should do this before _primitives.update so all ground primitives are drawn below all primitives if both were to have GroundPrimitives?

}

function callAfterRenderFunctions(frameState) {
Expand Down Expand Up @@ -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();
Expand Down