diff --git a/CHANGES.md b/CHANGES.md index e768969db2d..43c41636f00 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Beta Releases * Breaking changes: * * `loadArrayBuffer`, `loadBlob`, `loadJson`, `loadText`, and `loadXML` now support loading data from data URIs. +* Fixed extruded polygons rendered in the southern hemisphere. [#1490](https://github.com/AnalyticalGraphicsInc/cesium/issues/1490) * Fixed Primitive picking that have a closed appearance drawn on the surface. [#1333](https://github.com/AnalyticalGraphicsInc/cesium/issues/1333) ### b26 - 2014-03-03 diff --git a/Source/Core/PolygonGeometry.js b/Source/Core/PolygonGeometry.js index 7aad0f3aca2..45b4b293b27 100644 --- a/Source/Core/PolygonGeometry.js +++ b/Source/Core/PolygonGeometry.js @@ -393,6 +393,8 @@ define([ }); } + var createGeometryFromPositionsExtrudedPositions = []; + function createGeometryFromPositionsExtruded(ellipsoid, positions, granularity, hierarchy, perPositionHeight) { var topGeo = createGeometryFromPositions(ellipsoid, positions, granularity, perPositionHeight).geometry; var edgePoints = topGeo.attributes.position.values; @@ -433,10 +435,14 @@ define([ geos.walls = []; var outerRing = hierarchy.outerRing; - var windingOrder = PolygonPipeline.computeWindingOrder2D(outerRing); + var tangentPlane = EllipsoidTangentPlane.fromPoints(outerRing, ellipsoid); + var positions2D = tangentPlane.projectPointsOntoPlane(outerRing, createGeometryFromPositionsExtrudedPositions); + + var windingOrder = PolygonPipeline.computeWindingOrder2D(positions2D); if (windingOrder === WindingOrder.CLOCKWISE) { - outerRing = outerRing.reverse(); + outerRing.reverse(); } + var wallGeo = computeWallIndices(outerRing, granularity, perPositionHeight); geos.walls.push(new GeometryInstance({ geometry : wallGeo @@ -445,10 +451,15 @@ define([ var holes = hierarchy.holes; for (i = 0; i < holes.length; i++) { var hole = holes[i]; - windingOrder = PolygonPipeline.computeWindingOrder2D(hole); - if (windingOrder !== WindingOrder.CLOCKWISE) { - hole = hole.reverse(); + + tangentPlane = EllipsoidTangentPlane.fromPoints(hole, ellipsoid); + positions2D = tangentPlane.projectPointsOntoPlane(hole, createGeometryFromPositionsExtrudedPositions); + + windingOrder = PolygonPipeline.computeWindingOrder2D(positions2D); + if (windingOrder === WindingOrder.CLOCKWISE) { + hole.reverse(); } + wallGeo = computeWallIndices(hole, granularity); geos.walls.push(new GeometryInstance({ geometry : wallGeo diff --git a/Specs/Scene/GeometryRenderingSpec.js b/Specs/Scene/GeometryRenderingSpec.js index 9229677e1c1..d92e2edbe6e 100644 --- a/Specs/Scene/GeometryRenderingSpec.js +++ b/Specs/Scene/GeometryRenderingSpec.js @@ -1038,6 +1038,52 @@ defineSuite([ }; render3D(instance, afterView); }); + + it('renders with correct winding order in southern hemisphere', function() { + var primitive = new Primitive({ + geometryInstances : new GeometryInstance({ + geometry : PolygonGeometry.fromPositions({ + vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT, + ellipsoid : ellipsoid, + positions : ellipsoid.cartographicArrayToCartesianArray([ + Cartographic.fromDegrees(-108.0, -25.0, 500000), + Cartographic.fromDegrees(-100.0, -25.0, 500000), + Cartographic.fromDegrees(-100.0, -30.0, 500000), + Cartographic.fromDegrees(-108.0, -30.0, 500000) + ]), + perPositionHeight : true, + extrudedHeight: 0 + }), + id : 'extrudedPolygon', + attributes : { + color : new ColorGeometryInstanceAttribute(1.0, 1.0, 0.0, 1.0) + } + }), + appearance : new PerInstanceColorAppearance({ + closed : true, + translucent : false + }), + asynchronous : false + }); + + var frameState = createFrameState(); + primitive.update(context, frameState, []); + viewSphere3D(frameState.camera, primitive._boundingSphere, primitive.modelMatrix); + + var transform = Transforms.eastNorthUpToFixedFrame(primitive._boundingSphere.center); + frameState.camera.controller.rotateDown(-CesiumMath.PI_OVER_TWO, transform); + frameState.camera.controller.moveForward(primitive._boundingSphere.radius * 0.75); + + context.getUniformState().update(context, frameState); + + ClearCommand.ALL.execute(context); + expect(context.readPixels()).toEqual([0, 0, 0, 0]); + + render(context, frameState, primitive); + expect(context.readPixels()).toEqual([0, 0, 0, 0]); + + primitive = primitive && primitive.destroy(); + }); }, 'WebGL');