diff --git a/Apps/Sandcastle/gallery/development/Ground Polyline Material.html b/Apps/Sandcastle/gallery/development/Ground Polyline Material.html index 5d6348eb4ce4..ee5c8a489f78 100644 --- a/Apps/Sandcastle/gallery/development/Ground Polyline Material.html +++ b/Apps/Sandcastle/gallery/development/Ground Polyline Material.html @@ -32,6 +32,10 @@ }); var scene = viewer.scene; +if (!Cesium.GroundPolylinePrimitive.isSupported(scene)) { + throw new Cesium.RuntimeError('Polylines on terrain are not supported on this platform.'); +} + // Polyline Glow scene.groundPrimitives.add(new Cesium.GroundPolylinePrimitive({ geometryInstances : new Cesium.GeometryInstance({ diff --git a/Source/Core/GroundPolylineGeometry.js b/Source/Core/GroundPolylineGeometry.js index 3965a2dca598..de9f2485b6e2 100644 --- a/Source/Core/GroundPolylineGeometry.js +++ b/Source/Core/GroundPolylineGeometry.js @@ -51,8 +51,8 @@ define([ var PROJECTIONS = [GeographicProjection, WebMercatorProjection]; var PROJECTION_COUNT = PROJECTIONS.length; - var MITER_BREAK_SMALL = Math.cos(CesiumMath.toRadians(1.0)); - var MITER_BREAK_LARGE = Math.cos(CesiumMath.toRadians(179.0)); + var MITER_BREAK_SMALL = Math.cos(CesiumMath.toRadians(30.0)); + var MITER_BREAK_LARGE = Math.cos(CesiumMath.toRadians(150.0)); // Initial heights for constructing the wall. // Keeping WALL_INITIAL_MIN_HEIGHT near the ellipsoid surface helps @@ -78,8 +78,6 @@ define([ * @param {Number} [options.width=1.0] The screen space width in pixels. * @param {Number} [options.granularity=9999.0] The distance interval in meters used for interpolating options.points. Defaults to 9999.0 meters. Zero indicates no interpolation. * @param {Boolean} [options.loop=false] Whether during geometry creation a line segment will be added between the last and first line positions to make this Polyline a loop. - * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] Ellipsoid that input positions will be clamped to. - * @param {MapProjection} [options.projection] Map Projection for projecting coordinates to 2D. * * @exception {DeveloperError} At least two positions are required. * @@ -130,24 +128,10 @@ define([ */ this.loop = defaultValue(options.loop, false); - /** - * Ellipsoid for projecting cartographic coordinates to 3D. - * @type {Ellipsoid} - * @default Ellipsoid.WGS84 - */ - this.ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84); + this._ellipsoid = Ellipsoid.WGS84; // MapProjections can't be packed, so store the index to a known MapProjection. - var projectionIndex = 0; - if (defined(options.projection)) { - for (var i = 0; i < PROJECTION_COUNT; i++) { - if (options.projection instanceof PROJECTIONS[i]) { - projectionIndex = i; - break; - } - } - } - this._projectionIndex = projectionIndex; + this._projectionIndex = 0; this._workerName = 'createGroundPolylineGeometry'; // Used by GroundPolylinePrimitive to signal worker that scenemode is 3D only. @@ -169,6 +153,27 @@ define([ } }); + /** + * Set the GroundPolylineGeometry's projection and ellipsoid. + * Used by GroundPolylinePrimitive to signal scene information to the geometry for generating 2D attributes. + * + * @param {GroundPolylineGeometry} groundPolylineGeometry GroundPolylinGeometry describing a polyline on terrain. + * @param {Projection} mapProjection A MapProjection used for projecting cartographic coordinates to 2D. + * @private + */ + GroundPolylineGeometry.setProjectionAndEllipsoid = function(groundPolylineGeometry, mapProjection) { + var projectionIndex = 0; + for (var i = 0; i < PROJECTION_COUNT; i++) { + if (mapProjection instanceof PROJECTIONS[i]) { + projectionIndex = i; + break; + } + } + + groundPolylineGeometry._projectionIndex = projectionIndex; + groundPolylineGeometry._ellipsoid = mapProjection.ellipsoid; + }; + var cart3Scratch1 = new Cartesian3(); var cart3Scratch2 = new Cartesian3(); var cart3Scratch3 = new Cartesian3(); @@ -261,7 +266,7 @@ define([ array[index++] = value.granularity; array[index++] = value.loop ? 1.0 : 0.0; - Ellipsoid.pack(value.ellipsoid, array, index); + Ellipsoid.pack(value._ellipsoid, array, index); index += Ellipsoid.packedLength; array[index++] = value._projectionIndex; @@ -315,7 +320,7 @@ define([ result._positions = positions; result.granularity = granularity; result.loop = loop; - result.ellipsoid = ellipsoid; + result._ellipsoid = ellipsoid; result._projectionIndex = projectionIndex; result._scene3DOnly = scene3DOnly; @@ -390,7 +395,7 @@ define([ GroundPolylineGeometry.createGeometry = function(groundPolylineGeometry) { var compute2dAttributes = !groundPolylineGeometry._scene3DOnly; var loop = groundPolylineGeometry.loop; - var ellipsoid = groundPolylineGeometry.ellipsoid; + var ellipsoid = groundPolylineGeometry._ellipsoid; var granularity = groundPolylineGeometry.granularity; var projection = new PROJECTIONS[groundPolylineGeometry._projectionIndex](ellipsoid); @@ -572,11 +577,11 @@ define([ var normalStartpointScratch = new Cartesian3(); var normalEndpointScratch = new Cartesian3(); function projectNormal(projection, cartographic, normal, projectedPosition, result) { - var position = Cartographic.toCartesian(cartographic, projection.ellipsoid, normalStartpointScratch); + var position = Cartographic.toCartesian(cartographic, projection._ellipsoid, normalStartpointScratch); var normalEndpoint = Cartesian3.add(position, normal, normalEndpointScratch); var flipNormal = false; - var ellipsoid = projection.ellipsoid; + var ellipsoid = projection._ellipsoid; var normalEndpointCartographic = ellipsoid.cartesianToCartographic(normalEndpoint, endPosCartographicScratch); // If normal crosses the IDL, go the other way and flip the result. // In practice this almost never happens because the cartographic start @@ -707,7 +712,7 @@ define([ function generateGeometryAttributes(loop, projection, bottomPositionsArray, topPositionsArray, normalsArray, cartographicsArray, compute2dAttributes) { var i; var index; - var ellipsoid = projection.ellipsoid; + var ellipsoid = projection._ellipsoid; // Each segment will have 8 vertices var segmentCount = (bottomPositionsArray.length / 3) - 1; diff --git a/Source/Scene/GroundPolylinePrimitive.js b/Source/Scene/GroundPolylinePrimitive.js index 8fe301428bb5..72b2df985065 100644 --- a/Source/Scene/GroundPolylinePrimitive.js +++ b/Source/Scene/GroundPolylinePrimitive.js @@ -8,6 +8,7 @@ define([ '../Core/DeveloperError', '../Core/GeometryInstance', '../Core/GeometryInstanceAttribute', + '../Core/GroundPolylineGeometry', '../Core/isArray', '../Shaders/PolylineShadowVolumeVS', '../Shaders/PolylineShadowVolumeFS', @@ -35,6 +36,7 @@ define([ DeveloperError, GeometryInstance, GeometryInstanceAttribute, + GroundPolylineGeometry, isArray, PolylineShadowVolumeVS, PolylineShadowVolumeFS, @@ -643,8 +645,9 @@ define([ }); } - // Update each geometry for framestate.scene3DOnly = true + // Update each geometry for framestate.scene3DOnly = true and projection geometryInstance.geometry._scene3DOnly = frameState.scene3DOnly; + GroundPolylineGeometry.setProjectionAndEllipsoid(geometryInstance.geometry, frameState.mapProjection); groundInstances[i] = new GeometryInstance({ geometry : geometryInstance.geometry, diff --git a/Source/Shaders/PolylineShadowVolumeFS.glsl b/Source/Shaders/PolylineShadowVolumeFS.glsl index f1d0a8028d92..1042fe7f2c2f 100644 --- a/Source/Shaders/PolylineShadowVolumeFS.glsl +++ b/Source/Shaders/PolylineShadowVolumeFS.glsl @@ -44,7 +44,8 @@ void main(void) } // Check distance of the eye coordinate against start and end planes with normals in the right plane. - // For computing unskewed linear texture coordinate and for clipping extremely pointy miters + // For computing unskewed lengthwise texture coordinate. + // Can also be used for clipping extremely pointy miters, but in practice unnecessary because of miter breaking. // aligned plane: cross the right plane normal with miter plane normal, then cross the result with right again to point it more "forward" vec3 alignedPlaneNormal; @@ -59,15 +60,6 @@ void main(void) alignedPlaneNormal = normalize(cross(alignedPlaneNormal, v_rightPlaneEC.xyz)); distanceFromEnd = czm_planeDistance(alignedPlaneNormal, -dot(alignedPlaneNormal, v_endEcAndStartEcX.xyz), eyeCoordinate.xyz); - if (distanceFromStart < -halfMaxWidth || distanceFromEnd < -halfMaxWidth) { -#ifdef DEBUG_SHOW_VOLUME - gl_FragColor = vec4(1.0, 0.0, 0.0, 0.5); - return; -#else // DEBUG_SHOW_VOLUME - discard; -#endif // DEBUG_SHOW_VOLUME - } - #ifdef PER_INSTANCE_COLOR gl_FragColor = v_color; #else // PER_INSTANCE_COLOR diff --git a/Source/Shaders/PolylineShadowVolumeMorphFS.glsl b/Source/Shaders/PolylineShadowVolumeMorphFS.glsl index 9cf2f6b6dec8..a5995bea035b 100644 --- a/Source/Shaders/PolylineShadowVolumeMorphFS.glsl +++ b/Source/Shaders/PolylineShadowVolumeMorphFS.glsl @@ -1,5 +1,5 @@ varying vec3 v_forwardDirectionEC; -varying vec3 v_texcoordNormalization_and_halfWidth; +varying vec3 v_texcoordNormalizationAndHalfWidth; varying float v_batchId; #ifdef PER_INSTANCE_COLOR @@ -31,7 +31,7 @@ void main(void) distanceFromEnd = max(0.0, distanceFromEnd); float s = distanceFromStart / (distanceFromStart + distanceFromEnd); - s = (s * v_texcoordNormalization_and_halfWidth.x) + v_texcoordNormalization_and_halfWidth.y; + s = (s * v_texcoordNormalizationAndHalfWidth.x) + v_texcoordNormalizationAndHalfWidth.y; czm_materialInput materialInput; diff --git a/Source/Shaders/PolylineShadowVolumeMorphVS.glsl b/Source/Shaders/PolylineShadowVolumeMorphVS.glsl index 29e82a6b73bf..a2a618919953 100644 --- a/Source/Shaders/PolylineShadowVolumeMorphVS.glsl +++ b/Source/Shaders/PolylineShadowVolumeMorphVS.glsl @@ -14,7 +14,7 @@ attribute vec2 texcoordNormalization2D; attribute float batchId; varying vec3 v_forwardDirectionEC; -varying vec3 v_texcoordNormalization_and_halfWidth; +varying vec3 v_texcoordNormalizationAndHalfWidth; varying float v_batchId; // For materials @@ -91,7 +91,7 @@ void main() cleanTexcoordNormalization3D.y = rightNormalAndTextureCoordinateNormalizationY.w; cleanTexcoordNormalization3D.y = czm_branchFreeTernary(cleanTexcoordNormalization3D.y > 1.0, 0.0, abs(cleanTexcoordNormalization3D.y)); - v_texcoordNormalization_and_halfWidth.xy = mix(cleanTexcoordNormalization2D, cleanTexcoordNormalization3D, czm_morphTime); + v_texcoordNormalizationAndHalfWidth.xy = mix(cleanTexcoordNormalization2D, cleanTexcoordNormalization3D, czm_morphTime); #ifdef PER_INSTANCE_COLOR v_color = czm_batchTable_color(batchId); @@ -106,10 +106,10 @@ void main() float width = czm_batchTable_width(batchId); float halfWidth = width * 0.5; v_width = width; - v_texcoordNormalization_and_halfWidth.z = halfWidth; + v_texcoordNormalizationAndHalfWidth.z = halfWidth; #else float halfWidth = 0.5 * czm_batchTable_width(batchId); - v_texcoordNormalization_and_halfWidth.z = halfWidth; + v_texcoordNormalizationAndHalfWidth.z = halfWidth; #endif // Compute a normal along which to "push" the position out, extending the miter depending on view distance. diff --git a/Specs/Core/GroundPolylineGeometrySpec.js b/Specs/Core/GroundPolylineGeometrySpec.js index 4f15ca97543c..5a95fc1d3ff2 100644 --- a/Specs/Core/GroundPolylineGeometrySpec.js +++ b/Specs/Core/GroundPolylineGeometrySpec.js @@ -6,6 +6,7 @@ defineSuite([ 'Core/Math', 'Core/Ellipsoid', 'Core/GeographicProjection', + 'Core/WebMercatorProjection', 'Specs/createPackableSpecs' ], function( GroundPolylineGeometry, @@ -15,6 +16,7 @@ defineSuite([ CesiumMath, Ellipsoid, GeographicProjection, + WebMercatorProjection, createPackableSpecs) { 'use strict'; @@ -455,10 +457,26 @@ defineSuite([ expect(Cartesian3.equals(scratchPositions[1], groundPolylineGeometry._positions[1])).toBe(true); expect(scratch.loop).toBe(true); expect(scratch.granularity).toEqual(10.0); - expect(scratch.ellipsoid.equals(Ellipsoid.WGS84)).toBe(true); + expect(scratch._ellipsoid.equals(Ellipsoid.WGS84)).toBe(true); expect(scratch._scene3DOnly).toBe(true); }); + it('provides a method for setting projection and ellipsoid', function() { + var groundPolylineGeometry = new GroundPolylineGeometry({ + positions : Cartesian3.fromDegreesArray([ + -1.0, 0.0, + 1.0, 0.0 + ]), + loop : true, + granularity : 10.0 // no interpolative subdivision + }); + + GroundPolylineGeometry.setProjectionAndEllipsoid(groundPolylineGeometry, new WebMercatorProjection(Ellipsoid.UNIT_SPHERE)); + + expect(groundPolylineGeometry._projectionIndex).toEqual(1); + expect(groundPolylineGeometry._ellipsoid.equals(Ellipsoid.UNIT_SPHERE)).toBe(true); + }); + var positions = Cartesian3.fromDegreesArray([ 0.01, 0.0, 0.02, 0.0,