+ * Requires the EXT_frag_depth WebGL extension to render properly. If the extension is not supported, + * there may be artifacts. + *
+ * @type {MaterialProperty} + * @default undefined + */ + depthFailMaterial : createMaterialPropertyDescriptor('depthFailMaterial'), + /** * Gets or sets the Property specifying the array of {@link Cartesian3} * positions that define the line strip. @@ -123,7 +136,7 @@ define([ * @default Cesium.Math.RADIANS_PER_DEGREE */ granularity : createPropertyDescriptor('granularity'), - + /** * Get or sets the enum Property specifying whether the polyline * casts or receives shadows from each light source. @@ -153,6 +166,7 @@ define([ } result.show = this.show; result.material = this.material; + result.depthFailMaterial = this.depthFailMaterial; result.positions = this.positions; result.width = this.width; result.followSurface = this.followSurface; @@ -177,6 +191,7 @@ define([ this.show = defaultValue(this.show, source.show); this.material = defaultValue(this.material, source.material); + this.depthFailMaterial = defaultValue(this.depthFailMaterial, source.depthFailMaterial); this.positions = defaultValue(this.positions, source.positions); this.width = defaultValue(this.width, source.width); this.followSurface = defaultValue(this.followSurface, source.followSurface); diff --git a/Source/DataSources/StaticGeometryColorBatch.js b/Source/DataSources/StaticGeometryColorBatch.js index eca570d7a0ef..4e6e7aa2fcfc 100644 --- a/Source/DataSources/StaticGeometryColorBatch.js +++ b/Source/DataSources/StaticGeometryColorBatch.js @@ -9,6 +9,8 @@ define([ '../Core/ShowGeometryInstanceAttribute', '../Scene/Primitive', './BoundingSphereState', + './ColorMaterialProperty', + './MaterialProperty', './Property' ], function( AssociativeArray, @@ -20,15 +22,20 @@ define([ ShowGeometryInstanceAttribute, Primitive, BoundingSphereState, + ColorMaterialProperty, + MaterialProperty, Property) { 'use strict'; var colorScratch = new Color(); var distanceDisplayConditionScratch = new DistanceDisplayCondition(); - function Batch(primitives, translucent, appearanceType, closed, shadows) { + function Batch(primitives, translucent, appearanceType, depthFailAppearanceType, depthFailMaterialProperty, closed, shadows) { this.translucent = translucent; this.appearanceType = appearanceType; + this.depthFailAppearanceType = depthFailAppearanceType; + this.depthFailMaterialProperty = depthFailMaterialProperty; + this.depthFailMaterial = undefined; this.closed = closed; this.shadows = shadows; this.primitives = primitives; @@ -43,8 +50,31 @@ define([ this.subscriptions = new AssociativeArray(); this.showsUpdated = new AssociativeArray(); this.itemsToRemove = []; + this.invalidated = false; + + var removeMaterialSubscription; + if (defined(depthFailMaterialProperty)) { + removeMaterialSubscription = depthFailMaterialProperty.definitionChanged.addEventListener(Batch.prototype.onMaterialChanged, this); + } + this.removeMaterialSubscription = removeMaterialSubscription; } + Batch.prototype.onMaterialChanged = function() { + this.invalidated = true; + }; + + Batch.prototype.isMaterial = function(updater) { + var material = this.depthFailMaterialProperty; + var updaterMaterial = updater.depthFailMaterialProperty; + if (updaterMaterial === material) { + return true; + } + if (defined(material)) { + return material.equals(updaterMaterial); + } + return false; + }; + Batch.prototype.add = function(updater, instance) { var id = updater.entity.id; this.createPrimitive = true; @@ -107,9 +137,24 @@ define([ if (defined(originalAttributes.color)) { originalAttributes.color.value = attributes.color; } + if (defined(originalAttributes.depthFailColor)) { + originalAttributes.depthFailColor.value = attributes.depthFailColor; + } } } + var depthFailAppearance; + if (defined(this.depthFailAppearanceType)) { + if (defined(this.depthFailMaterialProperty)) { + this.depthFailMaterial = MaterialProperty.getValue(time, this.depthFailMaterialProperty, this.depthFailMaterial); + } + depthFailAppearance = new this.depthFailAppearanceType({ + material : this.depthFailMaterial, + translucent : this.translucent, + closed : this.closed + }); + } + primitive = new Primitive({ asynchronous : true, geometryInstances : geometries, @@ -117,6 +162,7 @@ define([ translucent : this.translucent, closed : this.closed }), + depthFailAppearance : depthFailAppearance, shadows : this.shadows }); primitives.add(primitive); @@ -142,6 +188,12 @@ define([ primitives.remove(this.oldPrimitive); this.oldPrimitive = undefined; } + + if (defined(this.depthFailAppearanceType) && !(this.depthFailMaterialProperty instanceof ColorMaterialProperty)) { + this.depthFailMaterial = MaterialProperty.getValue(time, this.depthFailMaterialProperty, this.depthFailMaterial); + this.primitive.depthFailAppearance.material = this.depthFailMaterial; + } + var updatersWithAttributes = this.updatersWithAttributes.values; var length = updatersWithAttributes.length; var waitingOnCreate = this.waitingOnCreate; @@ -167,6 +219,15 @@ define([ } } + if (defined(this.depthFailAppearanceType) && this.depthFailAppearanceType instanceof ColorMaterialProperty && (!updater.depthFailMaterialProperty.isConstant || waitingOnCreate)) { + var depthFailColorProperty = updater.depthFailMaterialProperty.color; + depthFailColorProperty.getValue(time, colorScratch); + if (!Color.equals(attributes._lastDepthFailColor, colorScratch)) { + attributes._lastDepthFailColor = Color.clone(colorScratch, attributes._lastDepthFailColor); + attributes.depthFailColor = ColorGeometryInstanceAttribute.toValue(colorScratch, attributes.depthFailColor); + } + } + var show = updater.entity.isShowing && (updater.hasConstantFill || updater.isFilled(time)); var currentShow = attributes.show[0] === 1; if (show !== currentShow) { @@ -250,80 +311,170 @@ define([ } }; + Batch.prototype.destroy = function() { + var primitive = this.primitive; + var primitives = this.primitives; + if (defined(primitive)) { + primitives.remove(primitive); + } + var oldPrimitive = this.oldPrimitive; + if (defined(oldPrimitive)) { + primitives.remove(oldPrimitive); + } + if(defined(this.removeMaterialSubscription)) { + this.removeMaterialSubscription(); + } + }; + /** * @private */ - function StaticGeometryColorBatch(primitives, appearanceType, closed, shadows) { - this._solidBatch = new Batch(primitives, false, appearanceType, closed, shadows); - this._translucentBatch = new Batch(primitives, true, appearanceType, closed, shadows); + function StaticGeometryColorBatch(primitives, appearanceType, depthFailAppearanceType, closed, shadows) { + this._solidItems = []; + this._translucentItems = []; + this._primitives = primitives; + this._appearanceType = appearanceType; + this._depthFailAppearanceType = depthFailAppearanceType; + this._closed = closed; + this._shadows = shadows; } StaticGeometryColorBatch.prototype.add = function(time, updater) { + var items; + var translucent; var instance = updater.createFillGeometryInstance(time); if (instance.attributes.color.value[3] === 255) { - this._solidBatch.add(updater, instance); + items = this._solidItems; + translucent = false; } else { - this._translucentBatch.add(updater, instance); + items = this._translucentItems; + translucent = true; } - }; - StaticGeometryColorBatch.prototype.remove = function(updater) { - if (!this._solidBatch.remove(updater)) { - this._translucentBatch.remove(updater); + var length = items.length; + for (var i = 0; i < length; i++) { + var item = items[i]; + if (item.isMaterial(updater)) { + item.add(updater, instance); + return; + } } + var batch = new Batch(this._primitives, translucent, this._appearanceType, this._depthFailAppearanceType, updater.depthFailMaterialProperty, this._closed, this._shadows); + batch.add(updater, instance); + items.push(batch); }; - StaticGeometryColorBatch.prototype.update = function(time) { - var i; - var updater; + function removeItem(items, updater) { + var length = items.length; + for (var i = length - 1; i >= 0; i--) { + var item = items[i]; + if (item.remove(updater)) { + if (item.updaters.length === 0) { + items.splice(i, 1); + item.destroy(); + return true; + } + } + } + return false; + } - //Perform initial update - var isUpdated = this._solidBatch.update(time); - isUpdated = this._translucentBatch.update(time) && isUpdated; + StaticGeometryColorBatch.prototype.remove = function(updater) { + if (!removeItem(this._solidItems, updater)) { + removeItem(this._translucentItems, updater); + } + }; - //If any items swapped between solid/translucent, we need to - //move them between batches - var itemsToRemove = this._solidBatch.itemsToRemove; - var solidsToMoveLength = itemsToRemove.length; - if (solidsToMoveLength > 0) { - for (i = 0; i < solidsToMoveLength; i++) { - updater = itemsToRemove[i]; - this._solidBatch.remove(updater); - this._translucentBatch.add(updater, updater.createFillGeometryInstance(time)); + function moveItems(batch, items, time) { + var itemsMoved = false; + var length = items.length; + for (var i = 0; i < length; ++i) { + var item = items[i]; + var itemsToRemove = item.itemsToRemove; + var itemsToMoveLength = itemsToRemove.length; + if (itemsToMoveLength > 0) { + for (i = 0; i < itemsToMoveLength; i++) { + var updater = itemsToRemove[i]; + item.remove(updater); + batch.add(time, updater); + itemsMoved = true; + } } } + return itemsMoved; + } - itemsToRemove = this._translucentBatch.itemsToRemove; - var translucentToMoveLength = itemsToRemove.length; - if (translucentToMoveLength > 0) { - for (i = 0; i < translucentToMoveLength; i++) { - updater = itemsToRemove[i]; - this._translucentBatch.remove(updater); - this._solidBatch.add(updater, updater.createFillGeometryInstance(time)); + function updateItems(batch, items, time, isUpdated) { + var length = items.length; + for (i = length - 1; i >= 0; i--) { + var item = items[i]; + if (item.invalidated) { + items.splice(i, 1); + var updaters = item.updaters.values; + var updatersLength = updaters.length; + for (var h = 0; h < updatersLength; h++) { + batch.add(time, updaters[h]); + } + item.destroy(); } } + length = items.length; + for (var i = 0; i < length; ++i) { + isUpdated = items[i].update(time) && isUpdated; + } + return isUpdated; + } + + StaticGeometryColorBatch.prototype.update = function(time) { + //Perform initial update + var isUpdated = updateItems(this, this._solidItems, time, true); + isUpdated = updateItems(this, this._translucentItems, time, isUpdated) && isUpdated; + + //If any items swapped between solid/translucent, we need to + //move them between batches + var solidsMoved = moveItems(this, this._solidItems, time); + var translucentsMoved = moveItems(this, this._translucentItems, time); + //If we moved anything around, we need to re-build the primitive - if (solidsToMoveLength > 0 || translucentToMoveLength > 0) { - isUpdated = this._solidBatch.update(time) && isUpdated; - isUpdated = this._translucentBatch.update(time) && isUpdated; + if (solidsMoved || translucentsMoved) { + isUpdated = updateItems(this, this._solidItems, time, isUpdated) && isUpdated; + isUpdated = updateItems(this, this._translucentItems, time, isUpdated)&& isUpdated; } return isUpdated; }; - StaticGeometryColorBatch.prototype.getBoundingSphere = function(entity, result) { - if (this._solidBatch.contains(entity)) { - return this._solidBatch.getBoundingSphere(entity, result); - } else if (this._translucentBatch.contains(entity)) { - return this._translucentBatch.getBoundingSphere(entity, result); + function getBoundingSphere(items, entity, result) { + var length = items.length; + for (var i = 0; i < length; i++) { + var item = items[i]; + if(item.contains(entity)){ + return item.getBoundingSphere(entity, result); + } } return BoundingSphereState.FAILED; + } + + StaticGeometryColorBatch.prototype.getBoundingSphere = function(entity, result) { + var boundingSphere = getBoundingSphere(this._solidItems, entity, result); + if (boundingSphere === BoundingSphereState.FAILED) { + return getBoundingSphere(this._translucentItems, entity, result); + } + return boundingSphere; }; + function removeAllPrimitives(items) { + var length = items.length; + for (var i = 0; i < length; i++) { + items[i].destroy(); + } + items.length = 0; + } + StaticGeometryColorBatch.prototype.removeAllPrimitives = function() { - this._solidBatch.removeAllPrimitives(); - this._translucentBatch.removeAllPrimitives(); + removeAllPrimitives(this._solidItems); + removeAllPrimitives(this._translucentItems); }; return StaticGeometryColorBatch; diff --git a/Source/DataSources/StaticGeometryPerMaterialBatch.js b/Source/DataSources/StaticGeometryPerMaterialBatch.js index df16c8ebf9cc..527c6690130c 100644 --- a/Source/DataSources/StaticGeometryPerMaterialBatch.js +++ b/Source/DataSources/StaticGeometryPerMaterialBatch.js @@ -1,32 +1,40 @@ /*global define*/ define([ '../Core/AssociativeArray', + '../Core/Color', + '../Core/ColorGeometryInstanceAttribute', '../Core/defined', '../Core/DistanceDisplayCondition', '../Core/DistanceDisplayConditionGeometryInstanceAttribute', '../Core/ShowGeometryInstanceAttribute', '../Scene/Primitive', './BoundingSphereState', + './ColorMaterialProperty', './MaterialProperty', './Property' ], function( AssociativeArray, + Color, + ColorGeometryInstanceAttribute, defined, DistanceDisplayCondition, DistanceDisplayConditionGeometryInstanceAttribute, ShowGeometryInstanceAttribute, Primitive, BoundingSphereState, + ColorMaterialProperty, MaterialProperty, Property) { 'use strict'; var distanceDisplayConditionScratch = new DistanceDisplayCondition(); - function Batch(primitives, appearanceType, materialProperty, closed, shadows) { + function Batch(primitives, appearanceType, materialProperty, depthFailAppearanceType, depthFailMaterialProperty, closed, shadows) { this.primitives = primitives; this.appearanceType = appearanceType; this.materialProperty = materialProperty; + this.depthFailAppearanceType = depthFailAppearanceType; + this.depthFailMaterialProperty = depthFailMaterialProperty; this.closed = closed; this.shadows = shadows; this.updaters = new AssociativeArray(); @@ -35,6 +43,7 @@ define([ this.oldPrimitive = undefined; this.geometry = new AssociativeArray(); this.material = undefined; + this.depthFailMaterial = undefined; this.updatersWithAttributes = new AssociativeArray(); this.attributes = new AssociativeArray(); this.invalidated = false; @@ -42,6 +51,7 @@ define([ this.subscriptions = new AssociativeArray(); this.showsUpdated = new AssociativeArray(); } + Batch.prototype.onMaterialChanged = function() { this.invalidated = true; }; @@ -49,13 +59,15 @@ define([ Batch.prototype.isMaterial = function(updater) { var material = this.materialProperty; var updaterMaterial = updater.fillMaterialProperty; - if (updaterMaterial === material) { + var depthFailMaterial = this.depthFailMaterialProperty; + var updaterDepthFailMaterial = updater.depthFailMaterialProperty; + + if (updaterMaterial === material && updaterDepthFailMaterial === depthFailMaterial) { return true; } - if (defined(material)) { - return material.equals(updaterMaterial); - } - return false; + var equals = defined(material) && material.equals(updaterMaterial); + equals = ((!defined(depthFailMaterial) && !defined(updaterDepthFailMaterial)) || (defined(depthFailMaterial) && depthFailMaterial.equals(updaterDepthFailMaterial))) && equals; + return equals; }; Batch.prototype.add = function(time, updater) { @@ -89,6 +101,8 @@ define([ return this.createPrimitive; }; + var colorScratch = new Color(); + Batch.prototype.update = function(time) { var isUpdated = true; var primitive = this.primitive; @@ -120,10 +134,30 @@ define([ if (defined(originalAttributes.color)) { originalAttributes.color.value = attributes.color; } + if (defined(originalAttributes.depthFailColor)) { + originalAttributes.depthFailColor.value = attributes.depthFailColor; + } } } this.material = MaterialProperty.getValue(time, this.materialProperty, this.material); + + var depthFailAppearance; + if (defined(this.depthFailMaterialProperty)) { + var translucent; + if (this.depthFailMaterialProperty instanceof MaterialProperty) { + this.depthFailMaterial = MaterialProperty.getValue(time, this.depthFailMaterialProperty, this.depthFailMaterial); + translucent = this.depthFailMaterial.isTranslucent(); + } else { + translucent = this.material.isTranslucent(); + } + depthFailAppearance = new this.depthFailAppearanceType({ + material : this.depthFailMaterial, + translucent : translucent, + closed : this.closed + }); + } + primitive = new Primitive({ asynchronous : true, geometryInstances : geometries, @@ -132,6 +166,7 @@ define([ translucent : this.material.isTranslucent(), closed : this.closed }), + depthFailAppearance : depthFailAppearance, shadows : this.shadows }); @@ -161,6 +196,11 @@ define([ this.material = MaterialProperty.getValue(time, this.materialProperty, this.material); this.primitive.appearance.material = this.material; + if (defined(this.depthFailAppearanceType) && !(this.depthFailMaterialProperty instanceof ColorMaterialProperty)) { + this.depthFailMaterial = MaterialProperty.getValue(time, this.depthFailMaterialProperty, this.depthFailMaterial); + this.primitive.depthFailAppearance.material = this.depthFailMaterial; + } + var updatersWithAttributes = this.updatersWithAttributes.values; var length = updatersWithAttributes.length; for (i = 0; i < length; i++) { @@ -174,6 +214,15 @@ define([ this.attributes.set(instance.id.id, attributes); } + if (defined(this.depthFailAppearanceType) && this.depthFailAppearanceType instanceof ColorMaterialProperty && !updater.depthFailMaterialProperty.isConstant) { + var depthFailColorProperty = updater.depthFailMaterialProperty.color; + depthFailColorProperty.getValue(time, colorScratch); + if (!Color.equals(attributes._lastDepthFailColor, colorScratch)) { + attributes._lastDepthFailColor = Color.clone(colorScratch, attributes._lastDepthFailColor); + attributes.depthFailColor = ColorGeometryInstanceAttribute.toValue(colorScratch, attributes.depthFailColor); + } + } + var show = entity.isShowing && (updater.hasConstantFill || updater.isFilled(time)); var currentShow = attributes.show[0] === 1; if (show !== currentShow) { @@ -238,7 +287,7 @@ define([ return BoundingSphereState.DONE; }; - Batch.prototype.destroy = function(time) { + Batch.prototype.destroy = function() { var primitive = this.primitive; var primitives = this.primitives; if (defined(primitive)) { @@ -254,13 +303,15 @@ define([ /** * @private */ - function StaticGeometryPerMaterialBatch(primitives, appearanceType, closed, shadows) { + function StaticGeometryPerMaterialBatch(primitives, appearanceType, depthFailAppearanceType, closed, shadows) { this._items = []; this._primitives = primitives; this._appearanceType = appearanceType; + this._depthFailAppearanceType = depthFailAppearanceType; this._closed = closed; this._shadows = shadows; } + StaticGeometryPerMaterialBatch.prototype.add = function(time, updater) { var items = this._items; var length = items.length; @@ -271,7 +322,7 @@ define([ return; } } - var batch = new Batch(this._primitives, this._appearanceType, updater.fillMaterialProperty, this._closed, this._shadows); + var batch = new Batch(this._primitives, this._appearanceType, updater.fillMaterialProperty, this._depthFailAppearanceType, updater.depthFailMaterialProperty, this._closed, this._shadows); batch.add(time, updater); items.push(batch); }; diff --git a/Source/Scene/FXAA.js b/Source/Scene/FXAA.js index 783bb7485c49..46f1342678a1 100644 --- a/Source/Scene/FXAA.js +++ b/Source/Scene/FXAA.js @@ -12,8 +12,13 @@ define([ '../Renderer/Renderbuffer', '../Renderer/RenderbufferFormat', '../Renderer/RenderState', + '../Renderer/Sampler', '../Renderer/Texture', - '../Shaders/PostProcessFilters/FXAA' + '../Renderer/TextureMagnificationFilter', + '../Renderer/TextureMinificationFilter', + '../Renderer/TextureWrap', + '../Shaders/PostProcessFilters/FXAA', + '../ThirdParty/Shaders/FXAA3_11' ], function( BoundingRectangle, Cartesian2, @@ -27,14 +32,19 @@ define([ Renderbuffer, RenderbufferFormat, RenderState, + Sampler, Texture, - FXAAFS) { + TextureMagnificationFilter, + TextureMinificationFilter, + TextureWrap, + FXAAFS, + FXAA3_11) { 'use strict'; /** * @private */ - function FXAA(context) { + function FXAA() { this._texture = undefined; this._depthStencilTexture = undefined; this._depthStencilRenderbuffer = undefined; @@ -50,6 +60,8 @@ define([ owner : this }); this._clearCommand = clearCommand; + + this._qualityPreset = 39; } function destroyResources(fxaa) { @@ -85,7 +97,13 @@ define([ width : width, height : height, pixelFormat : PixelFormat.RGBA, - pixelDatatype : PixelDatatype.UNSIGNED_BYTE + pixelDatatype : PixelDatatype.UNSIGNED_BYTE, + sampler : new Sampler({ + wrapS : TextureWrap.CLAMP_TO_EDGE, + wrapT : TextureWrap.CLAMP_TO_EDGE, + minificationFilter : TextureMinificationFilter.LINEAR, + magnificationFilter : TextureMagnificationFilter.LINEAR + }) }); if (context.depthTexture) { @@ -119,7 +137,12 @@ define([ } if (!defined(this._command)) { - this._command = context.createViewportQuadCommand(FXAAFS, { + var fs = + '#define FXAA_QUALITY_PRESET ' + this._qualityPreset + '\n' + + FXAA3_11 + '\n' + + FXAAFS; + + this._command = context.createViewportQuadCommand(fs, { owner : this }); } @@ -137,13 +160,13 @@ define([ if (textureChanged) { var that = this; - var step = new Cartesian2(1.0 / this._texture.width, 1.0 / this._texture.height); + var rcpFrame = new Cartesian2(1.0 / this._texture.width, 1.0 / this._texture.height); this._command.uniformMap = { u_texture : function() { return that._texture; }, - u_step : function() { - return step; + u_fxaaQualityRcpFrame : function() { + return rcpFrame; } }; } diff --git a/Source/Scene/MapboxImageryProvider.js b/Source/Scene/MapboxImageryProvider.js index fd17812a3d9d..4e725a2023f9 100644 --- a/Source/Scene/MapboxImageryProvider.js +++ b/Source/Scene/MapboxImageryProvider.js @@ -65,7 +65,7 @@ define([ this._url = url; this._mapId = mapId; this._accessToken = MapboxApi.getAccessToken(options.accessToken); - this._accessTokenErrorCredit = MapboxApi.getErrorCredit(options.key); + this._accessTokenErrorCredit = MapboxApi.getErrorCredit(options.accessToken); var format = defaultValue(options.format, 'png'); if (!/\./.test(format)) { format = '.' + format; diff --git a/Source/Scene/Primitive.js b/Source/Scene/Primitive.js index 8dac7a799c42..9b1afab234ce 100644 --- a/Source/Scene/Primitive.js +++ b/Source/Scene/Primitive.js @@ -35,6 +35,9 @@ define([ '../ThirdParty/when', './BatchTable', './CullFace', + './DepthFunction', + './Material', + './PolylineMaterialAppearance', './PrimitivePipeline', './PrimitiveState', './SceneMode', @@ -75,6 +78,9 @@ define([ when, BatchTable, CullFace, + DepthFunction, + Material, + PolylineMaterialAppearance, PrimitivePipeline, PrimitiveState, SceneMode, @@ -207,7 +213,7 @@ define([ this.geometryInstances = options.geometryInstances; /** - * The {@link Appearance} used to shade this primitive. Each geometry + * The {@link Appearance} used to shade this primitive. Each geometry * instance is shaded with the same appearance. Some appearances, like * {@link PerInstanceColorAppearance} allow giving each instance unique * properties. @@ -220,6 +226,29 @@ define([ this._appearance = undefined; this._material = undefined; + /** + * The {@link Appearance} used to shade this primitive when it fails the depth test. Each geometry + * instance is shaded with the same appearance. Some appearances, like + * {@link PerInstanceColorAppearance} allow giving each instance unique + * properties. + * + *+ * When using an appearance that requires a color attribute, like PerInstanceColorAppearance, + * add a depthFailColor per-instance attribute instead. + *
+ * + *+ * Requires the EXT_frag_depth WebGL extension to render properly. If the extension is not supported, + * there may be artifacts. + *
+ * @type Appearance + * + * @default undefined + */ + this.depthFailAppearance = options.depthFailAppearance; + this._depthFailAppearance = undefined; + this._depthFailMaterial = undefined; + /** * The 4x4 transformation matrix that transforms the primitive (all geometry instances) from model to world coordinates. * When this is the identity matrix, the primitive is drawn in world coordinates, i.e., Earth's WGS84 coordinates. @@ -325,6 +354,11 @@ define([ this._backFaceRS = undefined; this._sp = undefined; + this._depthFailAppearance = undefined; + this._spDepthFail = undefined; + this._frontFaceDepthFailRS = undefined; + this._backFaceDepthFailRS = undefined; + this._pickRS = undefined; this._pickSP = undefined; this._pickIds = []; @@ -794,10 +828,10 @@ define([ return renamedVS + '\n' + showMain; }; - Primitive._updateColorAttribute = function(primitive, vertexShaderSource) { + Primitive._updateColorAttribute = function(primitive, vertexShaderSource, isDepthFail) { // some appearances have a color attribute for per vertex color. // only remove if color is a per instance attribute. - if (!defined(primitive._batchTableAttributeIndices.color)) { + if (!defined(primitive._batchTableAttributeIndices.color) && !defined(primitive._batchTableAttributeIndices.depthFailColor)) { return vertexShaderSource; } @@ -805,9 +839,19 @@ define([ return vertexShaderSource; } + //>>includeStart('debug', pragmas.debug); + if (isDepthFail && !defined(primitive._batchTableAttributeIndices.depthFailColor)) { + throw new DeveloperError('A depthFailColor per-instance attribute is required when using a depth fail appearance that uses a color attribute.'); + } + //>>includeEnd('debug'); + var modifiedVS = vertexShaderSource; modifiedVS = modifiedVS.replace(/attribute\s+vec4\s+color;/g, ''); - modifiedVS = modifiedVS.replace(/(\b)color(\b)/g, '$1czm_batchTable_color(batchId)$2'); + if (!isDepthFail) { + modifiedVS = modifiedVS.replace(/(\b)color(\b)/g, '$1czm_batchTable_color(batchId)$2'); + } else { + modifiedVS = modifiedVS.replace(/(\b)color(\b)/g, '$1czm_batchTable_depthFailColor(batchId)$2'); + } return modifiedVS; }; @@ -947,6 +991,44 @@ define([ return [attributeDecl, globalDecl, modifiedVS, compressedMain].join('\n'); } + function depthClampVS(vertexShaderSource) { + var modifiedVS = ShaderSource.replaceMain(vertexShaderSource, 'czm_non_depth_clamp_main'); + modifiedVS += + '#ifdef GL_EXT_frag_depth\n' + + 'varying float v_WindowZ;\n' + + '#endif\n' + + 'void main() {\n' + + ' czm_non_depth_clamp_main();\n' + + ' vec4 position = gl_Position;\n' + + '#ifdef GL_EXT_frag_depth\n' + + ' v_WindowZ = (0.5 * (position.z / position.w) + 0.5) * position.w;\n' + + '#endif\n' + + ' position.z = min(position.z, position.w);\n' + + ' gl_Position = position;' + + '}\n'; + return modifiedVS; + } + + function depthClampFS(fragmentShaderSource) { + var modifiedFS = ShaderSource.replaceMain(fragmentShaderSource, 'czm_non_depth_clamp_main'); + modifiedFS += + '#ifdef GL_EXT_frag_depth\n' + + 'varying float v_WindowZ;\n' + + '#endif\n' + + 'void main() {\n' + + ' czm_non_depth_clamp_main();\n' + + '#ifdef GL_EXT_frag_depth\n' + + ' gl_FragDepthEXT = min(v_WindowZ * gl_FragCoord.w, 1.0);\n' + + '#endif\n' + + '}\n'; + modifiedFS = + '#ifdef GL_EXT_frag_depth\n' + + '#extension GL_EXT_frag_depth : enable\n' + + '#endif\n' + + modifiedFS; + return modifiedFS; + } + function validateShaderMatching(shaderProgram, attributeLocations) { // For a VAO and shader program to be compatible, the VAO must have // all active attribute in the shader program. The VAO may have @@ -1315,6 +1397,25 @@ define([ primitive._pickRS = RenderState.fromCache(rs); } } + + if (defined(primitive._depthFailAppearance)) { + renderState = primitive._depthFailAppearance.getRenderState(); + rs = clone(renderState, false); + rs.depthTest.func = DepthFunction.GREATER; + if (twoPasses) { + rs.cull = { + enabled : true, + face : CullFace.BACK + }; + primitive._frontFaceDepthFailRS = RenderState.fromCache(rs); + + rs.cull.face = CullFace.FRONT; + primitive._backFaceDepthFailRS = RenderState.fromCache(rs); + } else { + primitive._frontFaceDepthFailRS = RenderState.fromCache(rs); + primitive._backFaceDepthFailRS = primitive._frontFaceRS; + } + } } function createShaderProgram(primitive, frameState, appearance) { @@ -1325,7 +1426,7 @@ define([ var vs = primitive._batchTable.getVertexShaderCallback()(appearance.vertexShaderSource); vs = Primitive._appendShowToShader(primitive, vs); vs = Primitive._appendDistanceDisplayConditionToShader(primitive, vs, frameState.scene3DOnly); - vs = Primitive._updateColorAttribute(primitive, vs); + vs = Primitive._updateColorAttribute(primitive, vs, false); vs = modifyForEncodedNormals(primitive, vs); vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly); var fs = appearance.getFragmentShaderSource(); @@ -1360,12 +1461,30 @@ define([ attributeLocations : attributeLocations }); validateShaderMatching(primitive._sp, attributeLocations); - } - var modifiedModelViewScratch = new Matrix4(); - var rtcScratch = new Cartesian3(); + if (defined(primitive._depthFailAppearance)) { + vs = primitive._batchTable.getVertexShaderCallback()(primitive._depthFailAppearance.vertexShaderSource); + vs = Primitive._appendShowToShader(primitive, vs); + vs = Primitive._appendDistanceDisplayConditionToShader(primitive, vs, frameState.scene3DOnly); + vs = Primitive._updateColorAttribute(primitive, vs, true); + vs = modifyForEncodedNormals(primitive, vs); + vs = Primitive._modifyShaderPosition(primitive, vs, frameState.scene3DOnly); + vs = depthClampVS(vs); - function createCommands(primitive, appearance, material, translucent, twoPasses, colorCommands, pickCommands, frameState) { + fs = depthClampFS(primitive._depthFailAppearance.getFragmentShaderSource()); + + primitive._spDepthFail = ShaderProgram.replaceCache({ + context : context, + shaderProgram : primitive._spDepthFail, + vertexShaderSource : vs, + fragmentShaderSource : fs, + attributeLocations : attributeLocations + }); + validateShaderMatching(primitive._spDepthFail, attributeLocations); + } + } + + function getUniforms(primitive, appearance, material, frameState) { // Create uniform map by combining uniforms from the appearance and material if either have uniforms. var materialUniformMap = defined(material) ? material._uniforms : undefined; var appearanceUniformMap = {}; @@ -1398,9 +1517,26 @@ define([ }; } + return uniforms; + } + + var modifiedModelViewScratch = new Matrix4(); + var rtcScratch = new Cartesian3(); + + function createCommands(primitive, appearance, material, translucent, twoPasses, colorCommands, pickCommands, frameState) { + var uniforms = getUniforms(primitive, appearance, material, frameState); + + var depthFailUniforms; + if (defined(primitive._depthFailAppearance)) { + depthFailUniforms = getUniforms(primitive, primitive._depthFailAppearance, primitive._depthFailAppearance.material, frameState); + } + var pass = translucent ? Pass.TRANSLUCENT : Pass.OPAQUE; - colorCommands.length = primitive._va.length * (twoPasses ? 2 : 1); + var multiplier = twoPasses ? 2 : 1; + multiplier *= defined(primitive._depthFailAppearance) ? 2 : 1; + + colorCommands.length = primitive._va.length * multiplier; pickCommands.length = primitive._va.length; var length = colorCommands.length; @@ -1409,6 +1545,40 @@ define([ for (var i = 0; i < length; ++i) { var colorCommand; + if (defined(primitive._depthFailAppearance)) { + if (twoPasses) { + colorCommand = colorCommands[i]; + if (!defined(colorCommand)) { + colorCommand = colorCommands[i] = new DrawCommand({ + owner : primitive, + primitiveType : primitive._primitiveType + }); + } + colorCommand.vertexArray = primitive._va[vaIndex]; + colorCommand.renderState = primitive._backFaceDepthFailRS; + colorCommand.shaderProgram = primitive._spDepthFail; + colorCommand.uniformMap = depthFailUniforms; + colorCommand.pass = pass; + + ++i; + } + + colorCommand = colorCommands[i]; + if (!defined(colorCommand)) { + colorCommand = colorCommands[i] = new DrawCommand({ + owner : primitive, + primitiveType : primitive._primitiveType + }); + } + colorCommand.vertexArray = primitive._va[vaIndex]; + colorCommand.renderState = primitive._frontFaceDepthFailRS; + colorCommand.shaderProgram = primitive._spDepthFail; + colorCommand.uniformMap = depthFailUniforms; + colorCommand.pass = pass; + + ++i; + } + if (twoPasses) { colorCommand = colorCommands[i]; if (!defined(colorCommand)) { @@ -1515,8 +1685,12 @@ define([ var castShadows = ShadowMode.castShadows(primitive.shadows); var receiveShadows = ShadowMode.receiveShadows(primitive.shadows); var colorLength = colorCommands.length; + + var factor = twoPasses ? 2 : 1; + factor *= defined(primitive._depthFailAppearance) ? 2 : 1; + for (var j = 0; j < colorLength; ++j) { - var sphereIndex = twoPasses ? Math.floor(j / 2) : j; + var sphereIndex = Math.floor(j / factor); var colorCommand = colorCommands[j]; colorCommand.modelMatrix = modelMatrix; colorCommand.boundingVolume = boundingSpheres[sphereIndex]; @@ -1622,6 +1796,19 @@ define([ createSP = true; } + var depthFailAppearance = this.depthFailAppearance; + var depthFailMaterial = defined(depthFailAppearance) ? depthFailAppearance.material : undefined; + + if (this._depthFailAppearance !== depthFailAppearance) { + this._depthFailAppearance = depthFailAppearance; + this._depthFailMaterial = depthFailMaterial; + createRS = true; + createSP = true; + } else if (this._depthFailMaterial !== depthFailMaterial) { + this._depthFailMaterial = depthFailMaterial; + createSP = true; + } + var translucent = this._appearance.isTranslucent(); if (this._translucent !== translucent) { this._translucent = translucent; diff --git a/Source/Shaders/CompositeOITFS.glsl b/Source/Shaders/CompositeOITFS.glsl index b2efbceba787..dbe6c46d5801 100644 --- a/Source/Shaders/CompositeOITFS.glsl +++ b/Source/Shaders/CompositeOITFS.glsl @@ -3,7 +3,7 @@ * - http://jcgt.org/published/0002/02/09/ * - http://casual-effects.blogspot.com/2014/03/weighted-blended-order-independent.html */ - + uniform sampler2D u_opaque; uniform sampler2D u_accumulation; uniform sampler2D u_revealage; @@ -15,12 +15,17 @@ void main() vec4 opaque = texture2D(u_opaque, v_textureCoordinates); vec4 accum = texture2D(u_accumulation, v_textureCoordinates); float r = texture2D(u_revealage, v_textureCoordinates).r; - + #ifdef MRT vec4 transparent = vec4(accum.rgb / clamp(r, 1e-4, 5e4), accum.a); #else vec4 transparent = vec4(accum.rgb / clamp(accum.a, 1e-4, 5e4), r); #endif - + gl_FragColor = (1.0 - transparent.a) * transparent + transparent.a * opaque; + + if (opaque != czm_backgroundColor) + { + gl_FragColor.a = 1.0; + } } diff --git a/Source/Shaders/PostProcessFilters/FXAA.glsl b/Source/Shaders/PostProcessFilters/FXAA.glsl index edd2b911e4be..09067f48970e 100644 --- a/Source/Shaders/PostProcessFilters/FXAA.glsl +++ b/Source/Shaders/PostProcessFilters/FXAA.glsl @@ -1,245 +1,21 @@ -/** - * @license - * Copyright (c) 2011 NVIDIA Corporation. All rights reserved. - * - * TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED - * *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS - * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, NONINFRINGEMENT,IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA - * OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS - * OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY - * OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, - * EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -/* -FXAA_PRESET - Choose compile-in knob preset 0-5. ------------------------------------------------------------------------------- -FXAA_EDGE_THRESHOLD - The minimum amount of local contrast required - to apply algorithm. - 1.0/3.0 - too little - 1.0/4.0 - good start - 1.0/8.0 - applies to more edges - 1.0/16.0 - overkill ------------------------------------------------------------------------------- -FXAA_EDGE_THRESHOLD_MIN - Trims the algorithm from processing darks. - Perf optimization. - 1.0/32.0 - visible limit (smaller isn't visible) - 1.0/16.0 - good compromise - 1.0/12.0 - upper limit (seeing artifacts) ------------------------------------------------------------------------------- -FXAA_SEARCH_STEPS - Maximum number of search steps for end of span. ------------------------------------------------------------------------------- -FXAA_SEARCH_THRESHOLD - Controls when to stop searching. - 1.0/4.0 - seems to be the best quality wise ------------------------------------------------------------------------------- -FXAA_SUBPIX_TRIM - Controls sub-pixel aliasing removal. - 1.0/2.0 - low removal - 1.0/3.0 - medium removal - 1.0/4.0 - default removal - 1.0/8.0 - high removal - 0.0 - complete removal ------------------------------------------------------------------------------- -FXAA_SUBPIX_CAP - Insures fine detail is not completely removed. - This is important for the transition of sub-pixel detail, - like fences and wires. - 3.0/4.0 - default (medium amount of filtering) - 7.0/8.0 - high amount of filtering - 1.0 - no capping of sub-pixel aliasing removal -*/ - -#ifndef FXAA_PRESET - #define FXAA_PRESET 3 -#endif -#if (FXAA_PRESET == 3) - #define FXAA_EDGE_THRESHOLD (1.0/8.0) - #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0) - #define FXAA_SEARCH_STEPS 16 - #define FXAA_SEARCH_THRESHOLD (1.0/4.0) - #define FXAA_SUBPIX_CAP (3.0/4.0) - #define FXAA_SUBPIX_TRIM (1.0/4.0) -#endif -#if (FXAA_PRESET == 4) - #define FXAA_EDGE_THRESHOLD (1.0/8.0) - #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0) - #define FXAA_SEARCH_STEPS 24 - #define FXAA_SEARCH_THRESHOLD (1.0/4.0) - #define FXAA_SUBPIX_CAP (3.0/4.0) - #define FXAA_SUBPIX_TRIM (1.0/4.0) -#endif -#if (FXAA_PRESET == 5) - #define FXAA_EDGE_THRESHOLD (1.0/8.0) - #define FXAA_EDGE_THRESHOLD_MIN (1.0/24.0) - #define FXAA_SEARCH_STEPS 32 - #define FXAA_SEARCH_THRESHOLD (1.0/4.0) - #define FXAA_SUBPIX_CAP (3.0/4.0) - #define FXAA_SUBPIX_TRIM (1.0/4.0) -#endif - -#define FXAA_SUBPIX_TRIM_SCALE (1.0/(1.0 - FXAA_SUBPIX_TRIM)) - -// Return the luma, the estimation of luminance from rgb inputs. -// This approximates luma using one FMA instruction, -// skipping normalization and tossing out blue. -// FxaaLuma() will range 0.0 to 2.963210702. -float FxaaLuma(vec3 rgb) { - return rgb.y * (0.587/0.299) + rgb.x; -} - -vec3 FxaaLerp3(vec3 a, vec3 b, float amountOfA) { - return (vec3(-amountOfA) * b) + ((a * vec3(amountOfA)) + b); -} - -vec4 FxaaTexOff(sampler2D tex, vec2 pos, ivec2 off, vec2 rcpFrame) { - float x = pos.x + float(off.x) * rcpFrame.x; - float y = pos.y + float(off.y) * rcpFrame.y; - return texture2D(tex, vec2(x, y)); -} - -// pos is the output of FxaaVertexShader interpolated across screen. -// xy -> actual texture position {0.0 to 1.0} -// rcpFrame should be a uniform equal to {1.0/frameWidth, 1.0/frameHeight} -vec3 FxaaPixelShader(vec2 pos, sampler2D tex, vec2 rcpFrame) -{ - vec3 rgbN = FxaaTexOff(tex, pos.xy, ivec2( 0,-1), rcpFrame).xyz; - vec3 rgbW = FxaaTexOff(tex, pos.xy, ivec2(-1, 0), rcpFrame).xyz; - vec3 rgbM = FxaaTexOff(tex, pos.xy, ivec2( 0, 0), rcpFrame).xyz; - vec3 rgbE = FxaaTexOff(tex, pos.xy, ivec2( 1, 0), rcpFrame).xyz; - vec3 rgbS = FxaaTexOff(tex, pos.xy, ivec2( 0, 1), rcpFrame).xyz; - - float lumaN = FxaaLuma(rgbN); - float lumaW = FxaaLuma(rgbW); - float lumaM = FxaaLuma(rgbM); - float lumaE = FxaaLuma(rgbE); - float lumaS = FxaaLuma(rgbS); - float rangeMin = min(lumaM, min(min(lumaN, lumaW), min(lumaS, lumaE))); - float rangeMax = max(lumaM, max(max(lumaN, lumaW), max(lumaS, lumaE))); - - float range = rangeMax - rangeMin; - if(range < max(FXAA_EDGE_THRESHOLD_MIN, rangeMax * FXAA_EDGE_THRESHOLD)) - { - return rgbM; - } - - vec3 rgbL = rgbN + rgbW + rgbM + rgbE + rgbS; - - float lumaL = (lumaN + lumaW + lumaE + lumaS) * 0.25; - float rangeL = abs(lumaL - lumaM); - float blendL = max(0.0, (rangeL / range) - FXAA_SUBPIX_TRIM) * FXAA_SUBPIX_TRIM_SCALE; - blendL = min(FXAA_SUBPIX_CAP, blendL); - - vec3 rgbNW = FxaaTexOff(tex, pos.xy, ivec2(-1,-1), rcpFrame).xyz; - vec3 rgbNE = FxaaTexOff(tex, pos.xy, ivec2( 1,-1), rcpFrame).xyz; - vec3 rgbSW = FxaaTexOff(tex, pos.xy, ivec2(-1, 1), rcpFrame).xyz; - vec3 rgbSE = FxaaTexOff(tex, pos.xy, ivec2( 1, 1), rcpFrame).xyz; - rgbL += (rgbNW + rgbNE + rgbSW + rgbSE); - rgbL *= vec3(1.0/9.0); - - float lumaNW = FxaaLuma(rgbNW); - float lumaNE = FxaaLuma(rgbNE); - float lumaSW = FxaaLuma(rgbSW); - float lumaSE = FxaaLuma(rgbSE); - - float edgeVert = - abs((0.25 * lumaNW) + (-0.5 * lumaN) + (0.25 * lumaNE)) + - abs((0.50 * lumaW ) + (-1.0 * lumaM) + (0.50 * lumaE )) + - abs((0.25 * lumaSW) + (-0.5 * lumaS) + (0.25 * lumaSE)); - float edgeHorz = - abs((0.25 * lumaNW) + (-0.5 * lumaW) + (0.25 * lumaSW)) + - abs((0.50 * lumaN ) + (-1.0 * lumaM) + (0.50 * lumaS )) + - abs((0.25 * lumaNE) + (-0.5 * lumaE) + (0.25 * lumaSE)); - - bool horzSpan = edgeHorz >= edgeVert; - float lengthSign = horzSpan ? -rcpFrame.y : -rcpFrame.x; - - if(!horzSpan) - { - lumaN = lumaW; - lumaS = lumaE; - } - - float gradientN = abs(lumaN - lumaM); - float gradientS = abs(lumaS - lumaM); - lumaN = (lumaN + lumaM) * 0.5; - lumaS = (lumaS + lumaM) * 0.5; - - if (gradientN < gradientS) - { - lumaN = lumaS; - lumaN = lumaS; - gradientN = gradientS; - lengthSign *= -1.0; - } - - vec2 posN; - posN.x = pos.x + (horzSpan ? 0.0 : lengthSign * 0.5); - posN.y = pos.y + (horzSpan ? lengthSign * 0.5 : 0.0); - - gradientN *= FXAA_SEARCH_THRESHOLD; - - vec2 posP = posN; - vec2 offNP = horzSpan ? vec2(rcpFrame.x, 0.0) : vec2(0.0, rcpFrame.y); - float lumaEndN = lumaN; - float lumaEndP = lumaN; - bool doneN = false; - bool doneP = false; - posN += offNP * vec2(-1.0, -1.0); - posP += offNP * vec2( 1.0, 1.0); - - for(int i = 0; i < FXAA_SEARCH_STEPS; i++) { - if(!doneN) - { - lumaEndN = FxaaLuma(texture2D(tex, posN.xy).xyz); - } - if(!doneP) - { - lumaEndP = FxaaLuma(texture2D(tex, posP.xy).xyz); - } - - doneN = doneN || (abs(lumaEndN - lumaN) >= gradientN); - doneP = doneP || (abs(lumaEndP - lumaN) >= gradientN); - - if(doneN && doneP) - { - break; - } - if(!doneN) - { - posN -= offNP; - } - if(!doneP) - { - posP += offNP; - } - } - - float dstN = horzSpan ? pos.x - posN.x : pos.y - posN.y; - float dstP = horzSpan ? posP.x - pos.x : posP.y - pos.y; - bool directionN = dstN < dstP; - lumaEndN = directionN ? lumaEndN : lumaEndP; - - if(((lumaM - lumaN) < 0.0) == ((lumaEndN - lumaN) < 0.0)) - { - lengthSign = 0.0; - } - - - float spanLength = (dstP + dstN); - dstN = directionN ? dstN : dstP; - float subPixelOffset = (0.5 + (dstN * (-1.0/spanLength))) * lengthSign; - vec3 rgbF = texture2D(tex, vec2( - pos.x + (horzSpan ? 0.0 : subPixelOffset), - pos.y + (horzSpan ? subPixelOffset : 0.0))).xyz; - return FxaaLerp3(rgbL, rgbF, blendL); -} +varying vec2 v_textureCoordinates; uniform sampler2D u_texture; -uniform vec2 u_step; +uniform vec2 u_fxaaQualityRcpFrame; -varying vec2 v_textureCoordinates; +const float fxaaQualitySubpix = 0.5; +const float fxaaQualityEdgeThreshold = 0.125; +const float fxaaQualityEdgeThresholdMin = 0.0833; void main() { - gl_FragColor = vec4(FxaaPixelShader(v_textureCoordinates, u_texture, u_step), 1.0); + vec4 color = FxaaPixelShader( + v_textureCoordinates, + u_texture, + u_fxaaQualityRcpFrame, + fxaaQualitySubpix, + fxaaQualityEdgeThreshold, + fxaaQualityEdgeThresholdMin); + float alpha = texture2D(u_texture, v_textureCoordinates).a; + gl_FragColor = vec4(color.rgb, alpha); } diff --git a/Source/ThirdParty/Shaders/FXAA3_11.glsl b/Source/ThirdParty/Shaders/FXAA3_11.glsl new file mode 100644 index 000000000000..3499e14f1cfa --- /dev/null +++ b/Source/ThirdParty/Shaders/FXAA3_11.glsl @@ -0,0 +1,648 @@ +/** + * @license + * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of NVIDIA CORPORATION nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// NVIDIA GameWorks Graphics Samples GitHub link: https://github.com/NVIDIAGameWorks/GraphicsSamples +// Original FXAA 3.11 shader link: https://github.com/NVIDIAGameWorks/GraphicsSamples/blob/master/samples/es3-kepler/FXAA/FXAA3_11.h + +// Steps used to integrate into Cesium: +// * The following defines are set: +// #define FXAA_PC 1 +// #define FXAA_WEBGL_1 1 +// #define FXAA_GREEN_AS_LUMA 1 +// #define FXAA_EARLY_EXIT 1 +// #define FXAA_GLSL_120 1 +// * All other preprocessor directives besides the FXAA_QUALITY__P* directives were removed. +// * Double underscores are invalid for preprocessor directives so replace them with a single underscore. Replace +// /FXAA_QUALITY__P(.*)/g with /FXAA_QUALITY__P$1/. +// * There are no implicit conversions from ivec* to vec* so replace: +// #define FxaaInt2 ivec2 +// with +// #define FxaaInt2 vec2 +// * The texture2DLod function is only available in vertex shaders so replace: +// #define FxaaTexTop(t, p) texture2DLod(t, p, 0.0) +// #define FxaaTexOff(t, p, o, r) texture2DLod(t, p + (o * r), 0.0) +// with +// #define FxaaTexTop(t, p) texture2D(t, p) +// #define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r)) +// * FXAA_QUALITY_PRESET is prepended in the javascript code. We may want to expose that setting in the future. +// * The following parameters to FxaaPixelShader are unused and can be removed: +// fxaaConsolePosPos +// fxaaConsoleRcpFrameOpt +// fxaaConsoleRcpFrameOpt2 +// fxaaConsole360RcpFrameOpt2 +// fxaaConsoleEdgeSharpness +// fxaaConsoleEdgeThreshold +// fxaaConsoleEdgeThresholdMi +// fxaaConsole360ConstDir + +// +// Choose the quality preset. +// This needs to be compiled into the shader as it effects code. +// Best option to include multiple presets is to +// in each shader define the preset, then include this file. +// +// OPTIONS +// ----------------------------------------------------------------------- +// 10 to 15 - default medium dither (10=fastest, 15=highest quality) +// 20 to 29 - less dither, more expensive (20=fastest, 29=highest quality) +// 39 - no dither, very expensive +// +// NOTES +// ----------------------------------------------------------------------- +// 12 = slightly faster then FXAA 3.9 and higher edge quality (default) +// 13 = about same speed as FXAA 3.9 and better than 12 +// 23 = closest to FXAA 3.9 visually and performance wise +// _ = the lowest digit is directly related to performance +// _ = the highest digit is directly related to style +// +//#define FXAA_QUALITY_PRESET 12 + + +#if (FXAA_QUALITY_PRESET == 10) + #define FXAA_QUALITY_PS 3 + #define FXAA_QUALITY_P0 1.5 + #define FXAA_QUALITY_P1 3.0 + #define FXAA_QUALITY_P2 12.0 +#endif +#if (FXAA_QUALITY_PRESET == 11) + #define FXAA_QUALITY_PS 4 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 3.0 + #define FXAA_QUALITY_P3 12.0 +#endif +#if (FXAA_QUALITY_PRESET == 12) + #define FXAA_QUALITY_PS 5 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 4.0 + #define FXAA_QUALITY_P4 12.0 +#endif +#if (FXAA_QUALITY_PRESET == 13) + #define FXAA_QUALITY_PS 6 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 4.0 + #define FXAA_QUALITY_P5 12.0 +#endif +#if (FXAA_QUALITY_PRESET == 14) + #define FXAA_QUALITY_PS 7 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 2.0 + #define FXAA_QUALITY_P5 4.0 + #define FXAA_QUALITY_P6 12.0 +#endif +#if (FXAA_QUALITY_PRESET == 15) + #define FXAA_QUALITY_PS 8 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 2.0 + #define FXAA_QUALITY_P5 2.0 + #define FXAA_QUALITY_P6 4.0 + #define FXAA_QUALITY_P7 12.0 +#endif +#if (FXAA_QUALITY_PRESET == 20) + #define FXAA_QUALITY_PS 3 + #define FXAA_QUALITY_P0 1.5 + #define FXAA_QUALITY_P1 2.0 + #define FXAA_QUALITY_P2 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 21) + #define FXAA_QUALITY_PS 4 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 22) + #define FXAA_QUALITY_PS 5 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 23) + #define FXAA_QUALITY_PS 6 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 2.0 + #define FXAA_QUALITY_P5 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 24) + #define FXAA_QUALITY_PS 7 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 2.0 + #define FXAA_QUALITY_P5 3.0 + #define FXAA_QUALITY_P6 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 25) + #define FXAA_QUALITY_PS 8 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 2.0 + #define FXAA_QUALITY_P5 2.0 + #define FXAA_QUALITY_P6 4.0 + #define FXAA_QUALITY_P7 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 26) + #define FXAA_QUALITY_PS 9 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 2.0 + #define FXAA_QUALITY_P5 2.0 + #define FXAA_QUALITY_P6 2.0 + #define FXAA_QUALITY_P7 4.0 + #define FXAA_QUALITY_P8 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 27) + #define FXAA_QUALITY_PS 10 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 2.0 + #define FXAA_QUALITY_P5 2.0 + #define FXAA_QUALITY_P6 2.0 + #define FXAA_QUALITY_P7 2.0 + #define FXAA_QUALITY_P8 4.0 + #define FXAA_QUALITY_P9 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 28) + #define FXAA_QUALITY_PS 11 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 2.0 + #define FXAA_QUALITY_P5 2.0 + #define FXAA_QUALITY_P6 2.0 + #define FXAA_QUALITY_P7 2.0 + #define FXAA_QUALITY_P8 2.0 + #define FXAA_QUALITY_P9 4.0 + #define FXAA_QUALITY_P10 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 29) + #define FXAA_QUALITY_PS 12 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.5 + #define FXAA_QUALITY_P2 2.0 + #define FXAA_QUALITY_P3 2.0 + #define FXAA_QUALITY_P4 2.0 + #define FXAA_QUALITY_P5 2.0 + #define FXAA_QUALITY_P6 2.0 + #define FXAA_QUALITY_P7 2.0 + #define FXAA_QUALITY_P8 2.0 + #define FXAA_QUALITY_P9 2.0 + #define FXAA_QUALITY_P10 4.0 + #define FXAA_QUALITY_P11 8.0 +#endif +#if (FXAA_QUALITY_PRESET == 39) + #define FXAA_QUALITY_PS 12 + #define FXAA_QUALITY_P0 1.0 + #define FXAA_QUALITY_P1 1.0 + #define FXAA_QUALITY_P2 1.0 + #define FXAA_QUALITY_P3 1.0 + #define FXAA_QUALITY_P4 1.0 + #define FXAA_QUALITY_P5 1.5 + #define FXAA_QUALITY_P6 2.0 + #define FXAA_QUALITY_P7 2.0 + #define FXAA_QUALITY_P8 2.0 + #define FXAA_QUALITY_P9 2.0 + #define FXAA_QUALITY_P10 4.0 + #define FXAA_QUALITY_P11 8.0 +#endif + +#define FxaaBool bool +#define FxaaFloat float +#define FxaaFloat2 vec2 +#define FxaaFloat3 vec3 +#define FxaaFloat4 vec4 +#define FxaaHalf float +#define FxaaHalf2 vec2 +#define FxaaHalf3 vec3 +#define FxaaHalf4 vec4 +#define FxaaInt2 vec2 +#define FxaaTex sampler2D + +#define FxaaSat(x) clamp(x, 0.0, 1.0) +#define FxaaTexTop(t, p) texture2D(t, p) +#define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r)) + +FxaaFloat FxaaLuma(FxaaFloat4 rgba) { return rgba.y; } + +FxaaFloat4 FxaaPixelShader( + // + // Use noperspective interpolation here (turn off perspective interpolation). + // {xy} = center of pixel + FxaaFloat2 pos, + // + // Input color texture. + // {rgb_} = color in linear or perceptual color space + // if (FXAA_GREEN_AS_LUMA == 0) + // {___a} = luma in perceptual color space (not linear) + FxaaTex tex, + // + // Only used on FXAA Quality. + // This must be from a constant/uniform. + // {x_} = 1.0/screenWidthInPixels + // {_y} = 1.0/screenHeightInPixels + FxaaFloat2 fxaaQualityRcpFrame, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY_SUBPIX define. + // It is here now to allow easier tuning. + // Choose the amount of sub-pixel aliasing removal. + // This can effect sharpness. + // 1.00 - upper limit (softer) + // 0.75 - default amount of filtering + // 0.50 - lower limit (sharper, less sub-pixel aliasing removal) + // 0.25 - almost off + // 0.00 - completely off + FxaaFloat fxaaQualitySubpix, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY_EDGE_THRESHOLD define. + // It is here now to allow easier tuning. + // The minimum amount of local contrast required to apply algorithm. + // 0.333 - too little (faster) + // 0.250 - low quality + // 0.166 - default + // 0.125 - high quality + // 0.063 - overkill (slower) + FxaaFloat fxaaQualityEdgeThreshold, + // + // Only used on FXAA Quality. + // This used to be the FXAA_QUALITY_EDGE_THRESHOLD_MIN define. + // It is here now to allow easier tuning. + // Trims the algorithm from processing darks. + // 0.0833 - upper limit (default, the start of visible unfiltered edges) + // 0.0625 - high quality (faster) + // 0.0312 - visible limit (slower) + // Special notes when using FXAA_GREEN_AS_LUMA, + // Likely want to set this to zero. + // As colors that are mostly not-green + // will appear very dark in the green channel! + // Tune by looking at mostly non-green content, + // then start at zero and increase until aliasing is a problem. + FxaaFloat fxaaQualityEdgeThresholdMin +) { +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posM; + posM.x = pos.x; + posM.y = pos.y; + FxaaFloat4 rgbyM = FxaaTexTop(tex, posM); + #define lumaM rgbyM.y + FxaaFloat lumaS = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 0), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaN = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 0,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 0), fxaaQualityRcpFrame.xy)); +/*--------------------------------------------------------------------------*/ + FxaaFloat maxSM = max(lumaS, lumaM); + FxaaFloat minSM = min(lumaS, lumaM); + FxaaFloat maxESM = max(lumaE, maxSM); + FxaaFloat minESM = min(lumaE, minSM); + FxaaFloat maxWN = max(lumaN, lumaW); + FxaaFloat minWN = min(lumaN, lumaW); + FxaaFloat rangeMax = max(maxWN, maxESM); + FxaaFloat rangeMin = min(minWN, minESM); + FxaaFloat rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold; + FxaaFloat range = rangeMax - rangeMin; + FxaaFloat rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled); + FxaaBool earlyExit = range < rangeMaxClamped; +/*--------------------------------------------------------------------------*/ + if(earlyExit) + return rgbyM; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1, 1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaNE = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2( 1,-1), fxaaQualityRcpFrame.xy)); + FxaaFloat lumaSW = FxaaLuma(FxaaTexOff(tex, posM, FxaaInt2(-1, 1), fxaaQualityRcpFrame.xy)); +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNS = lumaN + lumaS; + FxaaFloat lumaWE = lumaW + lumaE; + FxaaFloat subpixRcpRange = 1.0/range; + FxaaFloat subpixNSWE = lumaNS + lumaWE; + FxaaFloat edgeHorz1 = (-2.0 * lumaM) + lumaNS; + FxaaFloat edgeVert1 = (-2.0 * lumaM) + lumaWE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNESE = lumaNE + lumaSE; + FxaaFloat lumaNWNE = lumaNW + lumaNE; + FxaaFloat edgeHorz2 = (-2.0 * lumaE) + lumaNESE; + FxaaFloat edgeVert2 = (-2.0 * lumaN) + lumaNWNE; +/*--------------------------------------------------------------------------*/ + FxaaFloat lumaNWSW = lumaNW + lumaSW; + FxaaFloat lumaSWSE = lumaSW + lumaSE; + FxaaFloat edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2); + FxaaFloat edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2); + FxaaFloat edgeHorz3 = (-2.0 * lumaW) + lumaNWSW; + FxaaFloat edgeVert3 = (-2.0 * lumaS) + lumaSWSE; + FxaaFloat edgeHorz = abs(edgeHorz3) + edgeHorz4; + FxaaFloat edgeVert = abs(edgeVert3) + edgeVert4; +/*--------------------------------------------------------------------------*/ + FxaaFloat subpixNWSWNESE = lumaNWSW + lumaNESE; + FxaaFloat lengthSign = fxaaQualityRcpFrame.x; + FxaaBool horzSpan = edgeHorz >= edgeVert; + FxaaFloat subpixA = subpixNSWE * 2.0 + subpixNWSWNESE; +/*--------------------------------------------------------------------------*/ + if(!horzSpan) lumaN = lumaW; + if(!horzSpan) lumaS = lumaE; + if(horzSpan) lengthSign = fxaaQualityRcpFrame.y; + FxaaFloat subpixB = (subpixA * (1.0/12.0)) - lumaM; +/*--------------------------------------------------------------------------*/ + FxaaFloat gradientN = lumaN - lumaM; + FxaaFloat gradientS = lumaS - lumaM; + FxaaFloat lumaNN = lumaN + lumaM; + FxaaFloat lumaSS = lumaS + lumaM; + FxaaBool pairN = abs(gradientN) >= abs(gradientS); + FxaaFloat gradient = max(abs(gradientN), abs(gradientS)); + if(pairN) lengthSign = -lengthSign; + FxaaFloat subpixC = FxaaSat(abs(subpixB) * subpixRcpRange); +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posB; + posB.x = posM.x; + posB.y = posM.y; + FxaaFloat2 offNP; + offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x; + offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y; + if(!horzSpan) posB.x += lengthSign * 0.5; + if( horzSpan) posB.y += lengthSign * 0.5; +/*--------------------------------------------------------------------------*/ + FxaaFloat2 posN; + posN.x = posB.x - offNP.x * FXAA_QUALITY_P0; + posN.y = posB.y - offNP.y * FXAA_QUALITY_P0; + FxaaFloat2 posP; + posP.x = posB.x + offNP.x * FXAA_QUALITY_P0; + posP.y = posB.y + offNP.y * FXAA_QUALITY_P0; + FxaaFloat subpixD = ((-2.0)*subpixC) + 3.0; + FxaaFloat lumaEndN = FxaaLuma(FxaaTexTop(tex, posN)); + FxaaFloat subpixE = subpixC * subpixC; + FxaaFloat lumaEndP = FxaaLuma(FxaaTexTop(tex, posP)); +/*--------------------------------------------------------------------------*/ + if(!pairN) lumaNN = lumaSS; + FxaaFloat gradientScaled = gradient * 1.0/4.0; + FxaaFloat lumaMM = lumaM - lumaNN * 0.5; + FxaaFloat subpixF = subpixD * subpixE; + FxaaBool lumaMLTZero = lumaMM < 0.0; +/*--------------------------------------------------------------------------*/ + lumaEndN -= lumaNN * 0.5; + lumaEndP -= lumaNN * 0.5; + FxaaBool doneN = abs(lumaEndN) >= gradientScaled; + FxaaBool doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P1; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P1; + FxaaBool doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P1; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P1; +/*--------------------------------------------------------------------------*/ + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P2; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P2; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P2; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P2; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 3) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P3; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P3; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P3; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P3; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 4) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P4; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P4; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P4; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P4; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 5) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P5; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P5; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P5; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P5; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 6) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P6; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P6; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P6; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P6; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 7) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P7; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P7; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P7; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P7; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 8) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P8; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P8; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P8; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P8; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 9) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P9; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P9; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P9; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P9; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 10) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P10; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P10; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P10; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P10; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 11) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P11; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P11; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P11; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P11; +/*--------------------------------------------------------------------------*/ + #if (FXAA_QUALITY_PS > 12) + if(doneNP) { + if(!doneN) lumaEndN = FxaaLuma(FxaaTexTop(tex, posN.xy)); + if(!doneP) lumaEndP = FxaaLuma(FxaaTexTop(tex, posP.xy)); + if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5; + if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5; + doneN = abs(lumaEndN) >= gradientScaled; + doneP = abs(lumaEndP) >= gradientScaled; + if(!doneN) posN.x -= offNP.x * FXAA_QUALITY_P12; + if(!doneN) posN.y -= offNP.y * FXAA_QUALITY_P12; + doneNP = (!doneN) || (!doneP); + if(!doneP) posP.x += offNP.x * FXAA_QUALITY_P12; + if(!doneP) posP.y += offNP.y * FXAA_QUALITY_P12; +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } + #endif +/*--------------------------------------------------------------------------*/ + } +/*--------------------------------------------------------------------------*/ + FxaaFloat dstN = posM.x - posN.x; + FxaaFloat dstP = posP.x - posM.x; + if(!horzSpan) dstN = posM.y - posN.y; + if(!horzSpan) dstP = posP.y - posM.y; +/*--------------------------------------------------------------------------*/ + FxaaBool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero; + FxaaFloat spanLength = (dstP + dstN); + FxaaBool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero; + FxaaFloat spanLengthRcp = 1.0/spanLength; +/*--------------------------------------------------------------------------*/ + FxaaBool directionN = dstN < dstP; + FxaaFloat dst = min(dstN, dstP); + FxaaBool goodSpan = directionN ? goodSpanN : goodSpanP; + FxaaFloat subpixG = subpixF * subpixF; + FxaaFloat pixelOffset = (dst * (-spanLengthRcp)) + 0.5; + FxaaFloat subpixH = subpixG * fxaaQualitySubpix; +/*--------------------------------------------------------------------------*/ + FxaaFloat pixelOffsetGood = goodSpan ? pixelOffset : 0.0; + FxaaFloat pixelOffsetSubpix = max(pixelOffsetGood, subpixH); + if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign; + if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign; + return FxaaFloat4(FxaaTexTop(tex, posM).xyz, lumaM); +} diff --git a/Specs/DataSources/GeometryVisualizerSpec.js b/Specs/DataSources/GeometryVisualizerSpec.js index 285d295be647..9157d46e4aab 100644 --- a/Specs/DataSources/GeometryVisualizerSpec.js +++ b/Specs/DataSources/GeometryVisualizerSpec.js @@ -22,6 +22,8 @@ defineSuite([ 'DataSources/StaticGeometryPerMaterialBatch', 'DataSources/StaticGroundGeometryColorBatch', 'DataSources/StaticOutlineGeometryBatch', + 'DataSources/PolylineGeometryUpdater', + 'DataSources/PolylineGraphics', 'Scene/GroundPrimitive', 'Scene/ShadowMode', 'Specs/createDynamicProperty', @@ -50,6 +52,8 @@ defineSuite([ StaticGeometryPerMaterialBatch, StaticGroundGeometryColorBatch, StaticOutlineGeometryBatch, + PolylineGeometryUpdater, + PolylineGraphics, GroundPrimitive, ShadowMode, createDynamicProperty, @@ -348,6 +352,174 @@ defineSuite([ return createAndRemoveGeometryWithShadows(ShadowMode.RECEIVE_ONLY); }); + it('Creates and removes static color material and static color depth fail material', function() { + var objects = new EntityCollection(); + var visualizer = new GeometryVisualizer(PolylineGeometryUpdater, scene, objects); + + var polyline = new PolylineGraphics(); + polyline.positions = new ConstantProperty([Cartesian3.fromDegrees(0.0, 0.0), Cartesian3.fromDegrees(0.0, 1.0)]); + polyline.material = new ColorMaterialProperty(); + polyline.depthFailMaterial = new ColorMaterialProperty(); + + var entity = new Entity(); + entity.position = new ConstantPositionProperty(new Cartesian3(1234, 5678, 9101112)); + entity.polyline = polyline; + objects.add(entity); + + return pollToPromise(function() { + scene.initializeFrame(); + var isUpdated = visualizer.update(time); + scene.render(time); + return isUpdated; + }).then(function() { + var primitive = scene.primitives.get(0); + var attributes = primitive.getGeometryInstanceAttributes(entity); + expect(attributes).toBeDefined(); + expect(attributes.show).toEqual(ShowGeometryInstanceAttribute.toValue(true)); + expect(attributes.color).toEqual(ColorGeometryInstanceAttribute.toValue(Color.WHITE)); + expect(attributes.depthFailColor).toEqual(ColorGeometryInstanceAttribute.toValue(Color.WHITE)); + expect(primitive.appearance).toBeInstanceOf(PolylineGeometryUpdater.perInstanceColorAppearanceType); + expect(primitive.depthFailAppearance).toBeInstanceOf(PolylineGeometryUpdater.perInstanceColorAppearanceType); + + objects.remove(entity); + + return pollToPromise(function() { + scene.initializeFrame(); + expect(visualizer.update(time)).toBe(true); + scene.render(time); + return scene.primitives.length === 0; + }).then(function(){ + visualizer.destroy(); + }); + }); + }); + + it('Creates and removes static color material and static depth fail material', function() { + var objects = new EntityCollection(); + var visualizer = new GeometryVisualizer(PolylineGeometryUpdater, scene, objects); + + var polyline = new PolylineGraphics(); + polyline.positions = new ConstantProperty([Cartesian3.fromDegrees(0.0, 0.0), Cartesian3.fromDegrees(0.0, 1.0)]); + polyline.material = new ColorMaterialProperty(); + polyline.depthFailMaterial = new GridMaterialProperty(); + + var entity = new Entity(); + entity.position = new ConstantPositionProperty(new Cartesian3(1234, 5678, 9101112)); + entity.polyline = polyline; + objects.add(entity); + + return pollToPromise(function() { + scene.initializeFrame(); + var isUpdated = visualizer.update(time); + scene.render(time); + return isUpdated; + }).then(function() { + var primitive = scene.primitives.get(0); + var attributes = primitive.getGeometryInstanceAttributes(entity); + expect(attributes).toBeDefined(); + expect(attributes.show).toEqual(ShowGeometryInstanceAttribute.toValue(true)); + expect(attributes.color).toEqual(ColorGeometryInstanceAttribute.toValue(Color.WHITE)); + expect(attributes.depthFailColor).toBeUndefined(); + expect(primitive.appearance).toBeInstanceOf(PolylineGeometryUpdater.perInstanceColorAppearanceType); + expect(primitive.depthFailAppearance).toBeInstanceOf(PolylineGeometryUpdater.materialAppearanceType); + + objects.remove(entity); + + return pollToPromise(function() { + scene.initializeFrame(); + expect(visualizer.update(time)).toBe(true); + scene.render(time); + return scene.primitives.length === 0; + }).then(function(){ + visualizer.destroy(); + }); + }); + }); + + it('Creates and removes static material and static depth fail material', function() { + var objects = new EntityCollection(); + var visualizer = new GeometryVisualizer(PolylineGeometryUpdater, scene, objects); + + var polyline = new PolylineGraphics(); + polyline.positions = new ConstantProperty([Cartesian3.fromDegrees(0.0, 0.0), Cartesian3.fromDegrees(0.0, 1.0)]); + polyline.material = new GridMaterialProperty(); + polyline.depthFailMaterial = new GridMaterialProperty(); + + var entity = new Entity(); + entity.position = new ConstantPositionProperty(new Cartesian3(1234, 5678, 9101112)); + entity.polyline = polyline; + objects.add(entity); + + return pollToPromise(function() { + scene.initializeFrame(); + var isUpdated = visualizer.update(time); + scene.render(time); + return isUpdated; + }).then(function() { + var primitive = scene.primitives.get(0); + var attributes = primitive.getGeometryInstanceAttributes(entity); + expect(attributes).toBeDefined(); + expect(attributes.show).toEqual(ShowGeometryInstanceAttribute.toValue(true)); + expect(attributes.color).toBeUndefined(); + expect(attributes.depthFailColor).toBeUndefined(); + expect(primitive.appearance).toBeInstanceOf(PolylineGeometryUpdater.materialAppearanceType); + expect(primitive.depthFailAppearance).toBeInstanceOf(PolylineGeometryUpdater.materialAppearanceType); + + objects.remove(entity); + + return pollToPromise(function() { + scene.initializeFrame(); + expect(visualizer.update(time)).toBe(true); + scene.render(time); + return scene.primitives.length === 0; + }).then(function(){ + visualizer.destroy(); + }); + }); + }); + + it('Creates and removes static material and static color depth fail material', function() { + var objects = new EntityCollection(); + var visualizer = new GeometryVisualizer(PolylineGeometryUpdater, scene, objects); + + var polyline = new PolylineGraphics(); + polyline.positions = new ConstantProperty([Cartesian3.fromDegrees(0.0, 0.0), Cartesian3.fromDegrees(0.0, 1.0)]); + polyline.material = new GridMaterialProperty(); + polyline.depthFailMaterial = new ColorMaterialProperty(); + + var entity = new Entity(); + entity.position = new ConstantPositionProperty(new Cartesian3(1234, 5678, 9101112)); + entity.polyline = polyline; + objects.add(entity); + + return pollToPromise(function() { + scene.initializeFrame(); + var isUpdated = visualizer.update(time); + scene.render(time); + return isUpdated; + }).then(function() { + var primitive = scene.primitives.get(0); + var attributes = primitive.getGeometryInstanceAttributes(entity); + expect(attributes).toBeDefined(); + expect(attributes.show).toEqual(ShowGeometryInstanceAttribute.toValue(true)); + expect(attributes.color).toBeUndefined(); + expect(attributes.depthFailColor).toEqual(ColorGeometryInstanceAttribute.toValue(Color.WHITE)); + expect(primitive.appearance).toBeInstanceOf(PolylineGeometryUpdater.materialAppearanceType); + expect(primitive.depthFailAppearance).toBeInstanceOf(PolylineGeometryUpdater.perInstanceColorAppearanceType); + + objects.remove(entity); + + return pollToPromise(function() { + scene.initializeFrame(); + expect(visualizer.update(time)).toBe(true); + scene.render(time); + return scene.primitives.length === 0; + }).then(function(){ + visualizer.destroy(); + }); + }); + }); + it('Correctly handles geometry changing batches', function() { var objects = new EntityCollection(); var visualizer = new GeometryVisualizer(EllipseGeometryUpdater, scene, objects); @@ -533,7 +705,7 @@ defineSuite([ }); it('StaticGeometryPerMaterialBatch handles shared material being invalidated', function() { - var batch = new StaticGeometryPerMaterialBatch(scene.primitives, EllipseGeometryUpdater.materialAppearanceType, false, ShadowMode.DISABLED); + var batch = new StaticGeometryPerMaterialBatch(scene.primitives, EllipseGeometryUpdater.materialAppearanceType, undefined, false, ShadowMode.DISABLED); var ellipse = new EllipseGraphics(); ellipse.semiMajorAxis = new ConstantProperty(2); @@ -580,7 +752,7 @@ defineSuite([ }); it('StaticGeometryColorBatch updates color attribute after rebuilding primitive', function() { - var batch = new StaticGeometryColorBatch(scene.primitives, EllipseGeometryUpdater.materialAppearanceType, false, ShadowMode.DISABLED); + var batch = new StaticGeometryColorBatch(scene.primitives, EllipseGeometryUpdater.materialAppearanceType, undefined, false, ShadowMode.DISABLED); var entity = new Entity({ position : new Cartesian3(1234, 5678, 9101112), diff --git a/Specs/DataSources/PolylineGeometryUpdaterSpec.js b/Specs/DataSources/PolylineGeometryUpdaterSpec.js index 5dc3db3d66ef..2b871c8371ba 100644 --- a/Specs/DataSources/PolylineGeometryUpdaterSpec.js +++ b/Specs/DataSources/PolylineGeometryUpdaterSpec.js @@ -91,6 +91,7 @@ defineSuite([ expect(updater.isClosed).toBe(false); expect(updater.fillEnabled).toBe(false); expect(updater.fillMaterialProperty).toBe(undefined); + expect(updater.depthFailMaterialProperty).toBe(undefined); expect(updater.outlineEnabled).toBe(false); expect(updater.hasConstantFill).toBe(true); expect(updater.hasConstantOutline).toBe(true); @@ -131,6 +132,7 @@ defineSuite([ expect(updater.isClosed).toBe(false); expect(updater.fillEnabled).toBe(true); expect(updater.fillMaterialProperty).toEqual(new ColorMaterialProperty(Color.WHITE)); + expect(updater.depthFailMaterialProperty).toBe(undefined); expect(updater.outlineEnabled).toBe(false); expect(updater.hasConstantFill).toBe(true); expect(updater.hasConstantOutline).toBe(true); @@ -147,6 +149,13 @@ defineSuite([ expect(updater.fillMaterialProperty).toBe(entity.polyline.material); }); + it('Polyline depth fail material is correctly exposed.', function() { + var entity = createBasicPolyline(); + var updater = new PolylineGeometryUpdater(entity, scene); + entity.polyline.depthFailMaterial = new ColorMaterialProperty(); + expect(updater.depthFailMaterialProperty).toBe(entity.polyline.depthFailMaterial); + }); + it('A time-varying positions causes geometry to be dynamic', function() { var entity = createBasicPolyline(); var updater = new PolylineGeometryUpdater(entity, scene); @@ -198,6 +207,7 @@ defineSuite([ var polyline = entity.polyline; polyline.show = new ConstantProperty(options.show); polyline.material = options.material; + polyline.depthFailMaterial = options.depthFailMaterial; polyline.width = new ConstantProperty(options.width); polyline.followSurface = new ConstantProperty(options.followSurface); @@ -221,6 +231,11 @@ defineSuite([ } else { expect(attributes.color).toBeUndefined(); } + if (options.depthFailMaterial && options.depthFailMaterial instanceof ColorMaterialProperty) { + expect(attributes.depthFailColor.value).toEqual(ColorGeometryInstanceAttribute.toValue(options.depthFailMaterial.color.getValue(time))); + } else { + expect(attributes.depthFailColor).toBeUndefined(); + } expect(attributes.show.value).toEqual(ShowGeometryInstanceAttribute.toValue(options.show)); if (options.distanceDisplayCondition) { expect(attributes.distanceDisplayCondition.value).toEqual(DistanceDisplayConditionGeometryInstanceAttribute.toValue(options.distanceDisplayCondition)); @@ -237,6 +252,28 @@ defineSuite([ }); }); + it('Creates expected per-color geometry with color depth fail appearance', function() { + validateGeometryInstance({ + show : true, + material : new ColorMaterialProperty(Color.RED), + depthFailMaterial : new ColorMaterialProperty(Color.BLUE), + width : 3, + followSurface : false, + granularity : 1.0 + }); + }); + + it('Creates expected per-color geometry with material depth fail appearance', function() { + validateGeometryInstance({ + show : true, + material : new ColorMaterialProperty(Color.RED), + depthFailMaterial : new GridMaterialProperty(), + width : 3, + followSurface : false, + granularity : 1.0 + }); + }); + it('Creates expected per-material geometry', function() { validateGeometryInstance({ show : true, @@ -247,6 +284,28 @@ defineSuite([ }); }); + it('Creates expected per-material geometry with color depth fail appearance', function() { + validateGeometryInstance({ + show : true, + material : new GridMaterialProperty(), + depthFailMaterial : new ColorMaterialProperty(Color.BLUE), + width : 4, + followSurface : true, + granularity : 0.5 + }); + }); + + it('Creates expected per-material geometry with color depth fail appearance', function() { + validateGeometryInstance({ + show : true, + material : new GridMaterialProperty(), + depthFailMaterial : new GridMaterialProperty(), + width : 4, + followSurface : true, + granularity : 0.5 + }); + }); + it('Creates expected distance display condition geometry', function() { validateGeometryInstance({ show : true, diff --git a/Specs/DataSources/PolylineGraphicsSpec.js b/Specs/DataSources/PolylineGraphicsSpec.js index 4e303b179e35..a41a146c47dd 100644 --- a/Specs/DataSources/PolylineGraphicsSpec.js +++ b/Specs/DataSources/PolylineGraphicsSpec.js @@ -22,6 +22,7 @@ defineSuite([ it('creates expected instance from raw assignment and construction', function() { var options = { material : Color.BLUE, + depthFailMaterial : Color.RED, positions : [], show : true, width : 1, @@ -33,6 +34,7 @@ defineSuite([ var polyline = new PolylineGraphics(options); expect(polyline.material).toBeInstanceOf(ColorMaterialProperty); + expect(polyline.depthFailMaterial).toBeInstanceOf(ColorMaterialProperty); expect(polyline.positions).toBeInstanceOf(ConstantProperty); expect(polyline.show).toBeInstanceOf(ConstantProperty); expect(polyline.width).toBeInstanceOf(ConstantProperty); @@ -42,6 +44,7 @@ defineSuite([ expect(polyline.distanceDisplayCondition).toBeInstanceOf(ConstantProperty); expect(polyline.material.color.getValue()).toEqual(options.material); + expect(polyline.depthFailMaterial.color.getValue()).toEqual(options.depthFailMaterial); expect(polyline.positions.getValue()).toEqual(options.positions); expect(polyline.show.getValue()).toEqual(options.show); expect(polyline.width.getValue()).toEqual(options.width); @@ -54,6 +57,7 @@ defineSuite([ it('merge assigns unassigned properties', function() { var source = new PolylineGraphics(); source.material = new ColorMaterialProperty(); + source.depthFailMaterial = new ColorMaterialProperty(); source.positions = new ConstantProperty(); source.width = new ConstantProperty(); source.show = new ConstantProperty(); @@ -65,6 +69,7 @@ defineSuite([ var target = new PolylineGraphics(); target.merge(source); expect(target.material).toBe(source.material); + expect(target.depthFailMaterial).toBe(source.depthFailMaterial); expect(target.positions).toBe(source.positions); expect(target.width).toBe(source.width); expect(target.show).toBe(source.show); @@ -77,6 +82,7 @@ defineSuite([ it('merge does not assign assigned properties', function() { var source = new PolylineGraphics(); source.material = new ColorMaterialProperty(); + source.depthFailMaterial = new ColorMaterialProperty(); source.positions = new ConstantProperty(); source.width = new ConstantProperty(); source.show = new ConstantProperty(); @@ -86,6 +92,7 @@ defineSuite([ source.distanceDisplayCondition = new ConstantProperty(); var color = new ColorMaterialProperty(); + var depthFailColor = new ColorMaterialProperty(); var positions = new ConstantProperty(); var width = new ConstantProperty(); var show = new ConstantProperty(); @@ -96,6 +103,7 @@ defineSuite([ var target = new PolylineGraphics(); target.material = color; + target.depthFailMaterial = depthFailColor; target.positions = positions; target.width = width; target.show = show; @@ -106,6 +114,7 @@ defineSuite([ target.merge(source); expect(target.material).toBe(color); + expect(target.depthFailMaterial).toBe(depthFailColor); expect(target.positions).toBe(positions); expect(target.width).toBe(width); expect(target.show).toBe(show); @@ -118,6 +127,7 @@ defineSuite([ it('clone works', function() { var source = new PolylineGraphics(); source.material = new ColorMaterialProperty(); + source.depthFailMaterial = new ColorMaterialProperty(); source.width = new ConstantProperty(); source.positions = new ConstantProperty(); source.show = new ConstantProperty(); @@ -128,6 +138,7 @@ defineSuite([ var result = source.clone(); expect(result.material).toBe(source.material); + expect(result.depthFailMaterial).toBe(source.depthFailMaterial); expect(result.positions).toBe(source.positions); expect(result.width).toBe(source.width); expect(result.show).toBe(source.show); @@ -147,6 +158,7 @@ defineSuite([ it('raises definitionChanged when a property is assigned or modified', function() { var property = new PolylineGraphics(); testMaterialDefinitionChanged(property, 'material', Color.RED, Color.BLUE); + testMaterialDefinitionChanged(property, 'depthFailMaterial', Color.RED, Color.BLUE); testDefinitionChanged(property, 'show', true, false); testDefinitionChanged(property, 'positions', [], []); testDefinitionChanged(property, 'width', 3, 4); diff --git a/Specs/Scene/PrimitiveSpec.js b/Specs/Scene/PrimitiveSpec.js index ca981609044b..69e6faa53780 100644 --- a/Specs/Scene/PrimitiveSpec.js +++ b/Specs/Scene/PrimitiveSpec.js @@ -156,6 +156,7 @@ defineSuite([ primitive = new Primitive(); expect(primitive.geometryInstances).not.toBeDefined(); expect(primitive.appearance).not.toBeDefined(); + expect(primitive.depthFailAppearance).not.toBeDefined(); expect(primitive.modelMatrix).toEqual(Matrix4.IDENTITY); expect(primitive.show).toEqual(true); expect(primitive.vertexCacheOptimize).toEqual(false); @@ -171,11 +172,13 @@ defineSuite([ it('Constructs with options', function() { var geometryInstances = {}; var appearance = {}; + var depthFailAppearance = {}; var modelMatrix = Matrix4.fromUniformScale(5.0); primitive = new Primitive({ geometryInstances : geometryInstances, appearance : appearance, + depthFailAppearance : depthFailAppearance, modelMatrix : modelMatrix, show : false, vertexCacheOptimize : true, @@ -190,6 +193,7 @@ defineSuite([ expect(primitive.geometryInstances).toEqual(geometryInstances); expect(primitive.appearance).toEqual(appearance); + expect(primitive.depthFailAppearance).toEqual(depthFailAppearance); expect(primitive.modelMatrix).toEqual(modelMatrix); expect(primitive.show).toEqual(false); expect(primitive.vertexCacheOptimize).toEqual(true); @@ -433,6 +437,60 @@ defineSuite([ scene._camera = camera; }); + it('renders with depth fail appearance', function() { + var rect = Rectangle.fromDegrees(-1.0, -1.0, 1.0, 1.0); + var translation = Cartesian3.multiplyByScalar(Cartesian3.normalize(ellipsoid.cartographicToCartesian(Rectangle.center(rect)), new Cartesian3()), 100.0, new Cartesian3()); + var rectInstance = new GeometryInstance({ + geometry : new RectangleGeometry({ + vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT, + ellipsoid : ellipsoid, + rectangle : rect + }), + modelMatrix : Matrix4.fromTranslation(translation, new Matrix4()), + id : 'rect', + attributes : { + color : new ColorGeometryInstanceAttribute(1.0, 1.0, 0.0, 1.0) + } + }); + var p0 = new Primitive({ + geometryInstances : rectInstance, + appearance : new PerInstanceColorAppearance({ + translucent : false + }), + asynchronous : false + }); + + var rectInstance2 = new GeometryInstance({ + geometry : new RectangleGeometry({ + vertexFormat : PerInstanceColorAppearance.VERTEX_FORMAT, + ellipsoid : ellipsoid, + rectangle : rect + }), + id : 'rect2', + attributes : { + color : new ColorGeometryInstanceAttribute(1.0, 0.0, 0.0, 1.0), + depthFailColor : new ColorGeometryInstanceAttribute(1.0, 0.0, 1.0, 1.0) + } + }); + var p1 = new Primitive({ + geometryInstances : rectInstance2, + appearance : new PerInstanceColorAppearance({ + translucent : false + }), + depthFailAppearance : new PerInstanceColorAppearance({ + translucent : false + }), + asynchronous : false + }); + + scene.primitives.add(p0); + scene.primitives.add(p1); + scene.camera.setView({ destination : rect }); + scene.renderForSpecs(); + + expect(scene).toRender([255, 0, 255, 255]); + }); + it('RTC throws with more than one instance', function() { expect(function() { return new Primitive({ diff --git a/gulpfile.js b/gulpfile.js index 45a2f61da48c..13be1624c703 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -81,6 +81,7 @@ var filesToClean = ['Source/Cesium.js', 'Build', 'Instrumented', 'Source/Shaders/**/*.js', + 'Source/ThirdParty/Shaders/*.js', 'Specs/SpecList.js', 'Apps/Sandcastle/jsHintOptions.js', 'Apps/Sandcastle/gallery/gallery-index.js', @@ -957,7 +958,7 @@ function glslToJavaScript(minify, minifyStateFilePath) { // we still are using from the set, then delete any files remaining in the set. var leftOverJsFiles = {}; - globby.sync(['Source/Shaders/**/*.js']).forEach(function(file) { + globby.sync(['Source/Shaders/**/*.js', 'Source/ThirdParty/Shaders/*.js']).forEach(function(file) { leftOverJsFiles[path.normalize(file)] = true; }); @@ -965,7 +966,7 @@ function glslToJavaScript(minify, minifyStateFilePath) { var builtinConstants = []; var builtinStructs = []; - var glslFiles = globby.sync(['Source/Shaders/**/*.glsl']); + var glslFiles = globby.sync(['Source/Shaders/**/*.glsl', 'Source/ThirdParty/Shaders/*.glsl']); glslFiles.forEach(function(glslFile) { glslFile = path.normalize(glslFile); var baseName = path.basename(glslFile, '.glsl'); diff --git a/package.json b/package.json index e575d77ccd27..c3e5a93b3127 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "gulp-jshint": "^2.0.4", "gulp-rename": "^1.2.2", "gulp-replace": "^0.5.4", - "gulp-tap": "^0.1.3", + "gulp-tap": "^0.4.1", "gulp-zip": "^4.0.0", "jasmine-core": "^2.5.2", "jsdoc": "^3.4.3", diff --git a/server.js b/server.js index 6b6eca4c3767..5b8b5be287b1 100644 --- a/server.js +++ b/server.js @@ -42,8 +42,8 @@ 'application/json' : ['czml', 'json', 'geojson', 'topojson'], 'image/crn' : ['crn'], 'image/ktx' : ['ktx'], - 'model/vnd.gltf+json' : ['gltf'], - 'model/vnd.gltf.binary' : ['bgltf', 'glb'], + 'model/gltf+json' : ['gltf'], + 'model/gltf.binary' : ['bgltf', 'glb'], 'text/plain' : ['glsl'] }); diff --git a/web.config b/web.config index fcc9ea104a62..78ae51dd8fce 100644 --- a/web.config +++ b/web.config @@ -7,11 +7,11 @@