diff --git a/CHANGES.md b/CHANGES.md index 63014608ddef..c90f756a44b0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -42,6 +42,7 @@ Change Log * Fixed an issue where switching from 2D to 3D could cause a crash. [#6929](https://github.com/AnalyticalGraphicsInc/cesium/issues/6929) * Fixed an issue where point primitives behind the camera would appear in view. [#6904](https://github.com/AnalyticalGraphicsInc/cesium/issues/6904) * The `createGroundPolylineGeometry` web worker no longer depends on `GroundPolylinePrimitive`, making the worker smaller and potentially avoiding a hanging build in some webpack configurations. +* Fixed an issue that cause terrain entities (entities with unspecified `height`) and `GroundPrimitives` to fail when crossing the international date line in 3D. [#6951](https://github.com/AnalyticalGraphicsInc/cesium/issues/6951) ### 1.48 - 2018-08-01 diff --git a/Source/Scene/ShadowVolumeAppearance.js b/Source/Scene/ShadowVolumeAppearance.js index e18161cbc253..5121b96488c3 100644 --- a/Source/Scene/ShadowVolumeAppearance.js +++ b/Source/Scene/ShadowVolumeAppearance.js @@ -636,13 +636,27 @@ define([ // rectangle cartographic coords !== spherical because it's on an ellipsoid var southWestExtents = latLongToSpherical(boundingRectangle.south, boundingRectangle.west, ellipsoid, sphericalScratch); - // Slightly pad extents to avoid floating point error when fragment culling at edges. - var south = southWestExtents.x - CesiumMath.EPSILON5; - var west = southWestExtents.y - CesiumMath.EPSILON5; + var south = southWestExtents.x; + var west = southWestExtents.y; var northEastExtents = latLongToSpherical(boundingRectangle.north, boundingRectangle.east, ellipsoid, sphericalScratch); - var north = northEastExtents.x + CesiumMath.EPSILON5; - var east = northEastExtents.y + CesiumMath.EPSILON5; + var north = northEastExtents.x; + var east = northEastExtents.y; + + // If the bounding rectangle crosses the IDL, rotate the spherical extents so the cross no longer happens. + // This rotation must happen in the shader too. + var rotationRadians = 0.0; + if (west > east) { + rotationRadians = CesiumMath.PI - west; + west = -CesiumMath.PI; + east += rotationRadians; + } + + // Slightly pad extents to avoid floating point error when fragment culling at edges. + south -= CesiumMath.EPSILON5; + west -= CesiumMath.EPSILON5; + north += CesiumMath.EPSILON5; + east += CesiumMath.EPSILON5; var longitudeRangeInverse = 1.0 / (east - west); var latitudeRangeInverse = 1.0 / (north - south); @@ -653,6 +667,12 @@ define([ componentsPerAttribute: 4, normalize: false, value : [south, west, latitudeRangeInverse, longitudeRangeInverse] + }), + longitudeRotation : new GeometryInstanceAttribute({ + componentDatatype: ComponentDatatype.FLOAT, + componentsPerAttribute: 1, + normalize: false, + value : [rotationRadians] }) }; @@ -669,7 +689,7 @@ define([ }; ShadowVolumeAppearance.hasAttributesForSphericalExtents = function(attributes) { - return defined(attributes.sphericalExtents) && + return defined(attributes.sphericalExtents) && defined(attributes.longitudeRotation) && defined(attributes.planes2D_HIGH) && defined(attributes.planes2D_LOW) && defined(attributes.uMaxVmax) && defined(attributes.uvMinAndExtents); }; diff --git a/Source/Shaders/ShadowVolumeAppearanceFS.glsl b/Source/Shaders/ShadowVolumeAppearanceFS.glsl index 5fb3f7c4f049..6b78c130eac9 100644 --- a/Source/Shaders/ShadowVolumeAppearanceFS.glsl +++ b/Source/Shaders/ShadowVolumeAppearanceFS.glsl @@ -10,7 +10,7 @@ varying vec2 v_inversePlaneExtents; varying vec4 v_westPlane; varying vec4 v_southPlane; #endif // SPHERICAL -varying vec2 v_uvMin; +varying vec3 v_uvMinAndSphericalLongitudeRotation; varying vec3 v_uMaxAndInverseDistance; varying vec3 v_vMaxAndInverseDistance; #endif // TEXTURE_COORDINATES @@ -58,6 +58,8 @@ void main(void) #ifdef SPHERICAL // Treat world coords as a sphere normal for spherical coordinates vec2 sphericalLatLong = czm_approximateSphericalCoordinates(worldCoordinate); + sphericalLatLong.y += v_uvMinAndSphericalLongitudeRotation.z; + sphericalLatLong.y = czm_branchFreeTernary(sphericalLatLong.y < czm_pi, sphericalLatLong.y, sphericalLatLong.y - czm_twoPi); uv.x = (sphericalLatLong.y - v_sphericalExtents.y) * v_sphericalExtents.w; uv.y = (sphericalLatLong.x - v_sphericalExtents.x) * v_sphericalExtents.z; #else // SPHERICAL @@ -131,8 +133,8 @@ void main(void) // Remap texture coordinates from computed (approximately aligned with cartographic space) to the desired // texture coordinate system, which typically forms a tight oriented bounding box around the geometry. // Shader is provided a set of reference points for remapping. - materialInput.st.x = czm_lineDistance(v_uvMin, v_uMaxAndInverseDistance.xy, uv) * v_uMaxAndInverseDistance.z; - materialInput.st.y = czm_lineDistance(v_uvMin, v_vMaxAndInverseDistance.xy, uv) * v_vMaxAndInverseDistance.z; + materialInput.st.x = czm_lineDistance(v_uvMinAndSphericalLongitudeRotation.xy, v_uMaxAndInverseDistance.xy, uv) * v_uMaxAndInverseDistance.z; + materialInput.st.y = czm_lineDistance(v_uvMinAndSphericalLongitudeRotation.xy, v_vMaxAndInverseDistance.xy, uv) * v_vMaxAndInverseDistance.z; #endif czm_material material = czm_getMaterial(materialInput); diff --git a/Source/Shaders/ShadowVolumeAppearanceVS.glsl b/Source/Shaders/ShadowVolumeAppearanceVS.glsl index d15f79cd25dc..6dd386a7558a 100644 --- a/Source/Shaders/ShadowVolumeAppearanceVS.glsl +++ b/Source/Shaders/ShadowVolumeAppearanceVS.glsl @@ -20,7 +20,7 @@ varying vec2 v_inversePlaneExtents; varying vec4 v_westPlane; varying vec4 v_southPlane; #endif // SPHERICAL -varying vec2 v_uvMin; +varying vec3 v_uvMinAndSphericalLongitudeRotation; varying vec3 v_uMaxAndInverseDistance; varying vec3 v_vMaxAndInverseDistance; #endif // TEXTURE_COORDINATES @@ -40,6 +40,7 @@ void main() #ifdef TEXTURE_COORDINATES #ifdef SPHERICAL v_sphericalExtents = czm_batchTable_sphericalExtents(batchId); + v_uvMinAndSphericalLongitudeRotation.z = czm_batchTable_longitudeRotation(batchId); #else // SPHERICAL #ifdef COLUMBUS_VIEW_2D vec4 planes2D_high = czm_batchTable_planes2D_HIGH(batchId); @@ -71,7 +72,7 @@ void main() v_uMaxAndInverseDistance = vec3(uMaxVmax.xy, uvMinAndExtents.z); v_vMaxAndInverseDistance = vec3(uMaxVmax.zw, uvMinAndExtents.w); - v_uvMin = uvMinAndExtents.xy; + v_uvMinAndSphericalLongitudeRotation.xy = uvMinAndExtents.xy; #endif // TEXTURE_COORDINATES #ifdef PER_INSTANCE_COLOR diff --git a/Specs/Scene/GroundPrimitiveSpec.js b/Specs/Scene/GroundPrimitiveSpec.js index 8b292ad69eac..5a5bb859254c 100644 --- a/Specs/Scene/GroundPrimitiveSpec.js +++ b/Specs/Scene/GroundPrimitiveSpec.js @@ -118,7 +118,7 @@ defineSuite([ geometryInstances : new GeometryInstance({ geometry : new RectangleGeometry({ ellipsoid : ellipsoid, - rectangle : rectangle + rectangle : Rectangle.fromDegrees(-180 + CesiumMath.EPSILON4, -90 + CesiumMath.EPSILON4, 180 - CesiumMath.EPSILON4, 90 - CesiumMath.EPSILON4) }), id : 'depth rectangle', attributes : { @@ -362,6 +362,76 @@ defineSuite([ verifyGroundPrimitiveRender(primitive, rectColor); }); + it('renders GroundPrimitives with spherical texture coordinates across the IDL in 3D', function() { + if (!GroundPrimitive.isSupported(scene)) { + return; + } + + var rectColorAttribute = ColorGeometryInstanceAttribute.fromColor(new Color(1.0, 1.0, 0.0, 1.0)); + var bigIdlRectangle = Rectangle.fromDegrees(176.0, 30.0, -176.0, 34.0); + var bigIdlRectangleInstance = new GeometryInstance({ + geometry : new RectangleGeometry({ + ellipsoid : ellipsoid, + rectangle : bigIdlRectangle + }), + id : 'rectangle', + attributes : { + color : rectColorAttribute + } + }); + + primitive = new GroundPrimitive({ + geometryInstances : bigIdlRectangleInstance, + asynchronous : false + }); + + scene.camera.setView({ destination : bigIdlRectangle }); + + scene.groundPrimitives.add(depthPrimitive); + expect(scene).toRenderAndCall(function(rgba) { + expect(rgba).not.toEqual([0, 0, 0, 255]); + expect(rgba[0]).toEqual(0); + }); + + scene.groundPrimitives.add(primitive); + expect(scene).toRender(rectColor); + }); + + it('renders GroundPrimitives with planar texture coordinates across the IDL in 3D', function() { + if (!GroundPrimitive.isSupported(scene)) { + return; + } + + var rectColorAttribute = ColorGeometryInstanceAttribute.fromColor(new Color(1.0, 1.0, 0.0, 1.0)); + var smallIdlRectangle = Rectangle.fromDegrees(179.6, 30.0, -179.6, 30.9); + var smallIdlRectangleInstance = new GeometryInstance({ + geometry : new RectangleGeometry({ + ellipsoid : ellipsoid, + rectangle : smallIdlRectangle + }), + id : 'rectangle', + attributes : { + color : rectColorAttribute + } + }); + + primitive = new GroundPrimitive({ + geometryInstances : smallIdlRectangleInstance, + asynchronous : false + }); + + scene.camera.setView({ destination : smallIdlRectangle }); + + scene.groundPrimitives.add(depthPrimitive); + expect(scene).toRenderAndCall(function(rgba) { + expect(rgba).not.toEqual([0, 0, 0, 255]); + expect(rgba[0]).toEqual(0); + }); + + scene.groundPrimitives.add(primitive); + expect(scene).toRender(rectColor); + }); + it('renders in Columbus view when scene3DOnly is false', function() { if (!GroundPrimitive.isSupported(scene)) { return; diff --git a/Specs/Scene/ShadowVolumeAppearanceSpec.js b/Specs/Scene/ShadowVolumeAppearanceSpec.js index 773b341710ed..1e957e0d0431 100644 --- a/Specs/Scene/ShadowVolumeAppearanceSpec.js +++ b/Specs/Scene/ShadowVolumeAppearanceSpec.js @@ -81,6 +81,13 @@ defineSuite([ expect(value[1]).toEqualEpsilon(-CesiumMath.PI_OVER_FOUR, CesiumMath.EPSILON4); expect(value[2]).toEqualEpsilon(1.0 / CesiumMath.PI_OVER_TWO, CesiumMath.EPSILON4); expect(value[3]).toEqualEpsilon(1.0 / CesiumMath.PI_OVER_TWO, CesiumMath.EPSILON4); + + var longitudeRotation = attributes.longitudeRotation; + expect(longitudeRotation.componentDatatype).toEqual(ComponentDatatype.FLOAT); + expect(longitudeRotation.componentsPerAttribute).toEqual(1); + expect(longitudeRotation.normalize).toEqual(false); + value = longitudeRotation.value; + expect(value[0]).toEqualEpsilon(0.0, CesiumMath.EPSILON4); }); function checkGeometryInstanceAttributeVec3(attribute) {