From 1557e89f43a22b3a54b86a61bfad62633bee8d9e Mon Sep 17 00:00:00 2001 From: Kangning Li Date: Fri, 31 Aug 2018 10:46:11 -0400 Subject: [PATCH] fix ground primitives crossing IDL in 2D --- CHANGES.md | 2 +- Source/Scene/ClassificationPrimitive.js | 8 +- Source/Scene/ShadowVolumeAppearance.js | 54 +++++++++-- Source/Shaders/ShadowVolumeAppearanceVS.glsl | 18 ++++ Specs/Scene/GroundPrimitiveSpec.js | 32 ++++++- Specs/Scene/ShadowVolumeAppearanceSpec.js | 95 ++++++++++++++++---- 6 files changed, 180 insertions(+), 29 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 81b714be7b54..5cba97f4a549 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -45,7 +45,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) +* Fixed an issue that cause terrain entities (entities with unspecified `height`) and `GroundPrimitives` to fail when crossing the international date line. [#6951](https://github.com/AnalyticalGraphicsInc/cesium/issues/6951) * Fixed normal calculation for `CylinderGeometry` when the top radius is not equal to the bottom radius [#6863](https://github.com/AnalyticalGraphicsInc/cesium/pull/6863) ### 1.48 - 2018-08-01 diff --git a/Source/Scene/ClassificationPrimitive.js b/Source/Scene/ClassificationPrimitive.js index 675e2f9d5ef5..aa7f6d06ab3e 100644 --- a/Source/Scene/ClassificationPrimitive.js +++ b/Source/Scene/ClassificationPrimitive.js @@ -589,7 +589,7 @@ define([ vsPick = Primitive._updatePickColorAttribute(vsPick); var pickFS3D = shadowVolumeAppearance.createPickFragmentShader(false); - var pickVS3D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, false); + var pickVS3D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, false, frameState.mapProjection); classificationPrimitive._spPick = ShaderProgram.replaceCache({ context : context, @@ -605,7 +605,7 @@ define([ var pickProgram2D = context.shaderCache.getDerivedShaderProgram(classificationPrimitive._spPick, '2dPick'); if (!defined(pickProgram2D)) { var pickFS2D = shadowVolumeAppearance.createPickFragmentShader(true); - var pickVS2D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, true); + var pickVS2D = shadowVolumeAppearance.createPickVertexShader([extrudedDefine, disableGlPositionLogDepth], vsPick, true, frameState.mapProjection); pickProgram2D = context.shaderCache.createDerivedShaderProgram(classificationPrimitive._spPick, '2dPick', { vertexShaderSource : pickVS2D, @@ -640,7 +640,7 @@ define([ // Create a fragment shader that computes only required material hookups using screen space techniques var fsColorSource = shadowVolumeAppearance.createFragmentShader(false); - var vsColorSource = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, false); + var vsColorSource = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, false, frameState.mapProjection); classificationPrimitive._spColor = ShaderProgram.replaceCache({ context : context, @@ -657,7 +657,7 @@ define([ var colorProgram2D = context.shaderCache.getDerivedShaderProgram(classificationPrimitive._spColor, '2dColor'); if (!defined(colorProgram2D)) { var fsColorSource2D = shadowVolumeAppearance.createFragmentShader(true); - var vsColorSource2D = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, true); + var vsColorSource2D = shadowVolumeAppearance.createVertexShader([extrudedDefine, disableGlPositionLogDepth], vs, true, frameState.mapProjection); colorProgram2D = context.shaderCache.createDerivedShaderProgram(classificationPrimitive._spColor, '2dColor', { vertexShaderSource : vsColorSource2D, diff --git a/Source/Scene/ShadowVolumeAppearance.js b/Source/Scene/ShadowVolumeAppearance.js index 5121b96488c3..42adc5d7e093 100644 --- a/Source/Scene/ShadowVolumeAppearance.js +++ b/Source/Scene/ShadowVolumeAppearance.js @@ -36,6 +36,13 @@ define([ ShadowVolumeAppearanceFS) { 'use strict'; + var projectionExtentDefines = { + eastMostYhighDefine : '', + eastMostYlowDefine : '', + westMostYhighDefine : '', + westMostYlowDefine : '' + }; + /** * Creates shaders for a ClassificationPrimitive to use a given Appearance, as well as for picking. * @@ -183,15 +190,17 @@ define([ * @param {String[]} defines External defines to pass to the vertex shader. * @param {String} vertexShaderSource ShadowVolumeAppearanceVS with any required modifications for computing position. * @param {Boolean} columbusView2D Whether the shader will be used for Columbus View or 2D. + * @param {MapProjection} mapProjection Current scene's map projection. * @returns {String} Shader source for the vertex shader. */ - ShadowVolumeAppearance.prototype.createVertexShader = function(defines, vertexShaderSource, columbusView2D) { + ShadowVolumeAppearance.prototype.createVertexShader = function(defines, vertexShaderSource, columbusView2D, mapProjection) { //>>includeStart('debug', pragmas.debug); Check.defined('defines', defines); Check.typeOf.string('vertexShaderSource', vertexShaderSource); Check.typeOf.bool('columbusView2D', columbusView2D); + Check.defined('mapProjection', mapProjection); //>>includeEnd('debug'); - return createShadowVolumeAppearanceVS(this._colorShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, this._appearance); + return createShadowVolumeAppearanceVS(this._colorShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, this._appearance, mapProjection); }; /** @@ -200,20 +209,55 @@ define([ * @param {String[]} defines External defines to pass to the vertex shader. * @param {String} vertexShaderSource ShadowVolumeAppearanceVS with any required modifications for computing position and picking. * @param {Boolean} columbusView2D Whether the shader will be used for Columbus View or 2D. + * @param {MapProjection} mapProjection Current scene's map projection. * @returns {String} Shader source for the vertex shader. */ - ShadowVolumeAppearance.prototype.createPickVertexShader = function(defines, vertexShaderSource, columbusView2D) { + ShadowVolumeAppearance.prototype.createPickVertexShader = function(defines, vertexShaderSource, columbusView2D, mapProjection) { //>>includeStart('debug', pragmas.debug); Check.defined('defines', defines); Check.typeOf.string('vertexShaderSource', vertexShaderSource); Check.typeOf.bool('columbusView2D', columbusView2D); + Check.defined('mapProjection', mapProjection); //>>includeEnd('debug'); - return createShadowVolumeAppearanceVS(this._pickShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource); + return createShadowVolumeAppearanceVS(this._pickShaderDependencies, this._planarExtents, columbusView2D, defines, vertexShaderSource, undefined, mapProjection); }; - function createShadowVolumeAppearanceVS(shaderDependencies, planarExtents, columbusView2D, defines, vertexShaderSource, appearance) { + var longitudeExtentsCartesianScratch = new Cartesian3(); + var longitudeExtentsCartographicScratch = new Cartographic(); + var longitudeExtentsEncodeScratch = { + high : 0.0, + low : 0.0 + }; + function createShadowVolumeAppearanceVS(shaderDependencies, planarExtents, columbusView2D, defines, vertexShaderSource, appearance, mapProjection) { var allDefines = defines.slice(); + if (projectionExtentDefines.eastMostYhighDefine === '') { + var eastMostCartographic = longitudeExtentsCartographicScratch; + eastMostCartographic.longitude = CesiumMath.PI; + eastMostCartographic.latitude = 0.0; + eastMostCartographic.height = 0.0; + var eastMostCartesian = mapProjection.project(eastMostCartographic, longitudeExtentsCartesianScratch); + var encoded = EncodedCartesian3.encode(eastMostCartesian.x, longitudeExtentsEncodeScratch); + projectionExtentDefines.eastMostYhighDefine = 'EAST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1); + projectionExtentDefines.eastMostYlowDefine = 'EAST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1); + + var westMostCartographic = longitudeExtentsCartographicScratch; + westMostCartographic.longitude = -CesiumMath.PI; + westMostCartographic.latitude = 0.0; + westMostCartographic.height = 0.0; + var westMostCartesian = mapProjection.project(westMostCartographic, longitudeExtentsCartesianScratch); + encoded = EncodedCartesian3.encode(westMostCartesian.x, longitudeExtentsEncodeScratch); + projectionExtentDefines.westMostYhighDefine = 'WEST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1); + projectionExtentDefines.westMostYlowDefine = 'WEST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1); + } + + if (columbusView2D) { + allDefines.push(projectionExtentDefines.eastMostYhighDefine); + allDefines.push(projectionExtentDefines.eastMostYlowDefine); + allDefines.push(projectionExtentDefines.westMostYhighDefine); + allDefines.push(projectionExtentDefines.westMostYlowDefine); + } + if (defined(appearance) && appearance instanceof PerInstanceColorAppearance) { allDefines.push('PER_INSTANCE_COLOR'); } diff --git a/Source/Shaders/ShadowVolumeAppearanceVS.glsl b/Source/Shaders/ShadowVolumeAppearanceVS.glsl index 6dd386a7558a..0f2b1c456a3b 100644 --- a/Source/Shaders/ShadowVolumeAppearanceVS.glsl +++ b/Source/Shaders/ShadowVolumeAppearanceVS.glsl @@ -45,6 +45,24 @@ void main() #ifdef COLUMBUS_VIEW_2D vec4 planes2D_high = czm_batchTable_planes2D_HIGH(batchId); vec4 planes2D_low = czm_batchTable_planes2D_LOW(batchId); + + // If the primitive is split across the IDL (planes2D_high.x > planes2D_high.w): + // - If this vertex is on the east side of the IDL (position3DLow.y > 0.0, comparison with position3DHigh may produce artifacts) + // - existing "east" is on the wrong side of the world, far away (planes2D_high/low.w) + // - so set "east" as beyond the eastmost extent of the projection (idlSplitNewPlaneHiLow) + vec2 idlSplitNewPlaneHiLow = vec2(EAST_MOST_X_HIGH - (WEST_MOST_X_HIGH - planes2D_high.w), EAST_MOST_X_LOW - (WEST_MOST_X_LOW - planes2D_low.w)); + bool idlSplit = planes2D_high.x > planes2D_high.w && position3DLow.y > 0.0; + planes2D_high.w = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.x, planes2D_high.w); + planes2D_low.w = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.y, planes2D_low.w); + + // - else, if this vertex is on the west side of the IDL (position3DLow.y < 0.0) + // - existing "west" is on the wrong side of the world, far away (planes2D_high/low.x) + // - so set "west" as beyond the westmost extent of the projection (idlSplitNewPlaneHiLow) + idlSplit = planes2D_high.x > planes2D_high.w && position3DLow.y < 0.0; + idlSplitNewPlaneHiLow = vec2(WEST_MOST_X_HIGH - (EAST_MOST_X_HIGH - planes2D_high.x), WEST_MOST_X_LOW - (EAST_MOST_X_LOW - planes2D_low.x)); + planes2D_high.x = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.x, planes2D_high.x); + planes2D_low.x = czm_branchFreeTernary(idlSplit, idlSplitNewPlaneHiLow.y, planes2D_low.x); + vec3 southWestCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.xy), vec3(0.0, planes2D_low.xy))).xyz; vec3 northWestCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.x, planes2D_high.z), vec3(0.0, planes2D_low.x, planes2D_low.z))).xyz; vec3 southEastCorner = (czm_modelViewRelativeToEye * czm_translateRelativeToEye(vec3(0.0, planes2D_high.w, planes2D_high.y), vec3(0.0, planes2D_low.w, planes2D_low.y))).xyz; diff --git a/Specs/Scene/GroundPrimitiveSpec.js b/Specs/Scene/GroundPrimitiveSpec.js index 4e26ae7d9832..07895570f9dd 100644 --- a/Specs/Scene/GroundPrimitiveSpec.js +++ b/Specs/Scene/GroundPrimitiveSpec.js @@ -474,7 +474,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 : { @@ -600,6 +600,36 @@ defineSuite([ verifyLargerScene(largeRectanglePrimitive, [255, 255, 255, 255], largeRectangle); }); + it('renders GeometryInstances with texture classifying terrain across the IDL', function() { + if (!GroundPrimitive.isSupported(scene) || !GroundPrimitive.supportsMaterials(scene)) { + return; + } + + var whiteImageMaterial = Material.fromType(Material.DiffuseMapType); + whiteImageMaterial.uniforms.image = './Data/Images/White.png'; + + var largeRectangle = Rectangle.fromDegrees(179.0, 30.0, -179.0, 31.0); + var largeRectanglePrimitive = new GroundPrimitive({ + geometryInstances : new GeometryInstance({ + geometry : new RectangleGeometry({ + ellipsoid : ellipsoid, + rectangle : largeRectangle + }) + }), + id : 'largeRectangle', + appearance : new EllipsoidSurfaceAppearance({ + aboveGround : false, + flat : true, + material : whiteImageMaterial + }), + asynchronous : false, + classificationType : ClassificationType.TERRAIN + }); + + scene.morphToColumbusView(0); + verifyLargerScene(largeRectanglePrimitive, [255, 255, 255, 255], largeRectangle); + }); + it('renders with invert classification and an opaque color', function() { if (!GroundPrimitive.isSupported(scene)) { return; diff --git a/Specs/Scene/ShadowVolumeAppearanceSpec.js b/Specs/Scene/ShadowVolumeAppearanceSpec.js index 1e957e0d0431..8f08ce10f26f 100644 --- a/Specs/Scene/ShadowVolumeAppearanceSpec.js +++ b/Specs/Scene/ShadowVolumeAppearanceSpec.js @@ -5,6 +5,7 @@ defineSuite([ 'Core/Math', 'Core/ComponentDatatype', 'Core/Ellipsoid', + 'Core/EncodedCartesian3', 'Core/Matrix4', 'Core/WebMercatorProjection', 'Core/Rectangle', @@ -19,6 +20,7 @@ defineSuite([ CesiumMath, ComponentDatatype, Ellipsoid, + EncodedCartesian3, Matrix4, WebMercatorProjection, Rectangle, @@ -69,6 +71,29 @@ defineSuite([ flat :true }); + // Defines for projection extents + var eastMostCartographic = new Cartographic(); + var longitudeExtentsEncodeScratch = { + high : 0.0, + low : 0.0 + }; + eastMostCartographic.longitude = CesiumMath.PI; + eastMostCartographic.latitude = 0.0; + eastMostCartographic.height = 0.0; + var eastMostCartesian = projection.project(eastMostCartographic); + var encoded = EncodedCartesian3.encode(eastMostCartesian.x, longitudeExtentsEncodeScratch); + var eastMostYhighDefine = 'EAST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1); + var eastMostYlowDefine = 'EAST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1); + + var westMostCartographic = new Cartographic(); + westMostCartographic.longitude = -CesiumMath.PI; + westMostCartographic.latitude = 0.0; + westMostCartographic.height = 0.0; + var westMostCartesian = projection.project(westMostCartographic); + encoded = EncodedCartesian3.encode(westMostCartesian.x, longitudeExtentsEncodeScratch); + var westMostYhighDefine = 'WEST_MOST_X_HIGH ' + encoded.high.toFixed((encoded.high + '').length + 1); + var westMostYlowDefine = 'WEST_MOST_X_LOW ' + encoded.low.toFixed((encoded.low + '').length + 1); + it('provides attributes for computing texture coordinates from Spherical extents', function() { var attributes = largeRectangleAttributes; @@ -221,82 +246,116 @@ defineSuite([ it('creates vertex shaders for color', function() { // Check defines var sphericalTexturedAppearance = new ShadowVolumeAppearance(true, false, textureMaterialAppearance); - var shaderSource = sphericalTexturedAppearance.createVertexShader([], testVs, false); + var shaderSource = sphericalTexturedAppearance.createVertexShader([], testVs, false, projection); var defines = shaderSource.defines; expect(defines.length).toEqual(2); expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('SPHERICAL')).not.toEqual(-1); // 2D variant - shaderSource = sphericalTexturedAppearance.createVertexShader([], testVs, true); + shaderSource = sphericalTexturedAppearance.createVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(2); + expect(defines.length).toEqual(6); expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('COLUMBUS_VIEW_2D')).not.toEqual(-1); + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + // Unculled color appearance - no texcoords at all var sphericalUnculledColorAppearance = new ShadowVolumeAppearance(false, false, perInstanceColorMaterialAppearance); - shaderSource = sphericalUnculledColorAppearance.createVertexShader([], testVs, false); + shaderSource = sphericalUnculledColorAppearance.createVertexShader([], testVs, false, projection); defines = shaderSource.defines; expect(defines.length).toEqual(1); expect(defines.indexOf('PER_INSTANCE_COLOR')).not.toEqual(-1); // 2D variant - shaderSource = sphericalUnculledColorAppearance.createVertexShader([], testVs, true); + shaderSource = sphericalUnculledColorAppearance.createVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(1); + expect(defines.length).toEqual(5); + + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf('PER_INSTANCE_COLOR')).not.toEqual(-1); // Planar textured, without culling var planarTexturedAppearance = new ShadowVolumeAppearance(false, true, textureMaterialAppearance); - shaderSource = planarTexturedAppearance.createVertexShader([], testVs, false); + shaderSource = planarTexturedAppearance.createVertexShader([], testVs, false, projection); defines = shaderSource.defines; expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.length).toEqual(1); - shaderSource = planarTexturedAppearance.createVertexShader([], testVs, true); + shaderSource = planarTexturedAppearance.createVertexShader([], testVs, true, projection); defines = shaderSource.defines; expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('COLUMBUS_VIEW_2D')).not.toEqual(-1); - expect(defines.length).toEqual(2); + + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + + expect(defines.length).toEqual(6); }); it('creates vertex shaders for pick', function() { // Check defines var sphericalTexturedAppearance = new ShadowVolumeAppearance(true, false, textureMaterialAppearance); - var shaderSource = sphericalTexturedAppearance.createPickVertexShader([], testVs, false); + var shaderSource = sphericalTexturedAppearance.createPickVertexShader([], testVs, false, projection); var defines = shaderSource.defines; expect(defines.length).toEqual(2); expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('SPHERICAL')).not.toEqual(-1); // 2D variant - shaderSource = sphericalTexturedAppearance.createPickVertexShader([], testVs, true); + shaderSource = sphericalTexturedAppearance.createPickVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(2); + expect(defines.length).toEqual(6); expect(defines.indexOf('TEXTURE_COORDINATES')).not.toEqual(-1); expect(defines.indexOf('COLUMBUS_VIEW_2D')).not.toEqual(-1); + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + // Unculled color appearance - no texcoords at all var sphericalUnculledColorAppearance = new ShadowVolumeAppearance(false, false, perInstanceColorMaterialAppearance); - shaderSource = sphericalUnculledColorAppearance.createPickVertexShader([], testVs, false); + shaderSource = sphericalUnculledColorAppearance.createPickVertexShader([], testVs, false, projection); defines = shaderSource.defines; expect(defines.length).toEqual(0); // 2D variant - shaderSource = sphericalUnculledColorAppearance.createPickVertexShader([], testVs, true); + shaderSource = sphericalUnculledColorAppearance.createPickVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(0); + + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + + expect(defines.length).toEqual(4); // Planar textured, without culling var planarTexturedAppearance = new ShadowVolumeAppearance(false, true, textureMaterialAppearance); - shaderSource = planarTexturedAppearance.createPickVertexShader([], testVs, false); + shaderSource = planarTexturedAppearance.createPickVertexShader([], testVs, false, projection); defines = shaderSource.defines; expect(defines.length).toEqual(0); - shaderSource = planarTexturedAppearance.createPickVertexShader([], testVs, true); + shaderSource = planarTexturedAppearance.createPickVertexShader([], testVs, true, projection); defines = shaderSource.defines; - expect(defines.length).toEqual(0); + + expect(defines.indexOf(eastMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(eastMostYlowDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYhighDefine)).not.toEqual(-1); + expect(defines.indexOf(westMostYlowDefine)).not.toEqual(-1); + + expect(defines.length).toEqual(4); }); it('creates fragment shaders for color and pick', function() {