diff --git a/Source/Scene/InvertClassification.js b/Source/Scene/InvertClassification.js index c468b7c93660..49bab43c6100 100644 --- a/Source/Scene/InvertClassification.js +++ b/Source/Scene/InvertClassification.js @@ -109,8 +109,8 @@ define([ zPass : StencilOperation.KEEP }, backFunction : StencilFunction.NEVER, - reference : 0, - mask : StencilConstants.CLASSIFICATION_MASK + reference : StencilConstants.CESIUM_3D_TILE_MASK, + mask : StencilConstants.CESIUM_3D_TILE_MASK }, stencilMask : StencilConstants.CLASSIFICATION_MASK, blending : BlendingState.ALPHA_BLEND diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js index c144bbbd9c08..92823beab81b 100644 --- a/Source/Scene/Scene.js +++ b/Source/Scene/Scene.js @@ -46,6 +46,7 @@ define([ '../Renderer/Framebuffer', '../Renderer/Pass', '../Renderer/PixelDatatype', + '../Renderer/RenderState', '../Renderer/ShaderProgram', '../Renderer/ShaderSource', '../Renderer/Texture', @@ -76,6 +77,7 @@ define([ './SceneTransitioner', './ScreenSpaceCameraController', './ShadowMap', + './StencilConstants', './SunPostProcess', './TweenCollection', './View' @@ -127,6 +129,7 @@ define([ Framebuffer, Pass, PixelDatatype, + RenderState, ShaderProgram, ShaderSource, Texture, @@ -157,6 +160,7 @@ define([ SceneTransitioner, ScreenSpaceCameraController, ShadowMap, + StencilConstants, SunPostProcess, TweenCollection, View) { @@ -322,6 +326,12 @@ define([ this._stencilClearCommand = new ClearCommand({ stencil : 0 }); + this._classificationStencilClearCommand = new ClearCommand({ + stencil : 0, + renderState : RenderState.fromCache({ + stencilMask : StencilConstants.CLASSIFICATION_MASK + }) + }); this._depthOnlyRenderStateCache = {}; this._pickRenderStateCache = {}; @@ -2146,6 +2156,7 @@ define([ var useDepthPlane = environmentState.useDepthPlane; var clearDepth = scene._depthClearCommand; var clearStencil = scene._stencilClearCommand; + var clearClassificationStencil = scene._classificationStencilClearCommand; var depthPlane = scene._depthPlane; var usePostProcessSelected = environmentState.usePostProcessSelected; @@ -2304,7 +2315,7 @@ define([ // Clear stencil set by the classification for the next classification pass if (length > 0 && context.stencilBuffer) { - clearStencil.execute(context, passState); + clearClassificationStencil.execute(context, passState); } // Draw style over classification. diff --git a/Specs/Scene/Batched3DModel3DTileContentClassificationSpec.js b/Specs/Scene/Batched3DModel3DTileContentClassificationSpec.js index 4323cda58d68..5242838719b5 100644 --- a/Specs/Scene/Batched3DModel3DTileContentClassificationSpec.js +++ b/Specs/Scene/Batched3DModel3DTileContentClassificationSpec.js @@ -104,7 +104,7 @@ defineSuite([ asynchronous : false }); - this.pass = pass; + this._pass = pass; } MockPrimitive.prototype.update = function(frameState) { @@ -114,7 +114,7 @@ defineSuite([ for (var i = startLength; i < commandList.length; ++i) { var command = commandList[i]; - command.pass = this.pass; + command.pass = this._pass; } }; diff --git a/Specs/Scene/ClassificationPrimitiveSpec.js b/Specs/Scene/ClassificationPrimitiveSpec.js index e3c278aa3470..61a0ea437152 100644 --- a/Specs/Scene/ClassificationPrimitiveSpec.js +++ b/Specs/Scene/ClassificationPrimitiveSpec.js @@ -13,11 +13,14 @@ defineSuite([ 'Core/ShowGeometryInstanceAttribute', 'Core/Transforms', 'Renderer/Pass', + 'Renderer/RenderState', + 'Scene/ClassificationType', 'Scene/InvertClassification', 'Scene/MaterialAppearance', 'Scene/PerInstanceColorAppearance', 'Scene/Primitive', 'Scene/ShadowVolumeAppearance', + 'Scene/StencilConstants', 'Specs/createScene', 'Specs/pollToPromise' ], function( @@ -35,11 +38,14 @@ defineSuite([ ShowGeometryInstanceAttribute, Transforms, Pass, + RenderState, + ClassificationType, InvertClassification, MaterialAppearance, PerInstanceColorAppearance, Primitive, ShadowVolumeAppearance, + StencilConstants, createScene, pollToPromise) { 'use strict'; @@ -48,13 +54,16 @@ defineSuite([ var ellipsoid; var rectangle; + var globeRectangle; + var tilesetRectangle; var depthColor; var boxColor; var boxInstance; var primitive; - var depthPrimitive; + var globePrimitive; + var tilesetPrimitive; beforeAll(function() { scene = createScene(); @@ -67,27 +76,69 @@ defineSuite([ scene.destroyForSpecs(); }); - function MockGlobePrimitive(primitive) { - this._primitive = primitive; - this.pass = Pass.GLOBE; + function viewCenter() { + scene.camera.setView({ destination : rectangle }); + } + + function viewGlobePrimitive() { + scene.camera.setView({ destination : globeRectangle }); + } + + function view3DTilesPrimitive() { + scene.camera.setView({ destination : tilesetRectangle }); + } + + function MockPrimitive(rectangle, pass) { + var renderState; + if (pass === Pass.CESIUM_3D_TILE) { + renderState = RenderState.fromCache({ + stencilTest : StencilConstants.setCesium3DTileBit(), + stencilMask : StencilConstants.CESIUM_3D_TILE_MASK, + depthTest : { + enabled : true + } + }); + } + var depthColorAttribute = ColorGeometryInstanceAttribute.fromColor(new Color(0.0, 0.0, 1.0, 1.0)); + depthColor = depthColorAttribute.value; + this._primitive = new Primitive({ + geometryInstances : new GeometryInstance({ + geometry : new RectangleGeometry({ + ellipsoid : Ellipsoid.WGS84, + rectangle : rectangle + }), + id : 'depth rectangle', + attributes : { + color : depthColorAttribute + } + }), + appearance : new PerInstanceColorAppearance({ + translucent : false, + flat : true, + renderState : renderState + }), + asynchronous : false + }); + + this._pass = pass; } - MockGlobePrimitive.prototype.update = function(frameState) { + MockPrimitive.prototype.update = function(frameState) { var commandList = frameState.commandList; var startLength = commandList.length; this._primitive.update(frameState); for (var i = startLength; i < commandList.length; ++i) { var command = commandList[i]; - command.pass = this.pass; + command.pass = this._pass; } }; - MockGlobePrimitive.prototype.isDestroyed = function() { + MockPrimitive.prototype.isDestroyed = function() { return false; }; - MockGlobePrimitive.prototype.destroy = function() { + MockPrimitive.prototype.destroy = function() { this._primitive.destroy(); return destroyObject(this); }; @@ -97,29 +148,12 @@ defineSuite([ scene.render(); // clear any afterRender commands rectangle = Rectangle.fromDegrees(-75.0, 25.0, -70.0, 30.0); + globeRectangle = Rectangle.fromDegrees(-75.0, 27.5, -70.0, 30.0); + tilesetRectangle = Rectangle.fromDegrees(-75.0, 25.0, -70.0, 27.5); - var depthColorAttribute = ColorGeometryInstanceAttribute.fromColor(new Color(0.0, 0.0, 1.0, 1.0)); - depthColor = depthColorAttribute.value; - var primitive = new Primitive({ - geometryInstances : new GeometryInstance({ - geometry : new RectangleGeometry({ - ellipsoid : ellipsoid, - rectangle : rectangle - }), - id : 'depth rectangle', - attributes : { - color : depthColorAttribute - } - }), - appearance : new PerInstanceColorAppearance({ - translucent : false, - flat : true - }), - asynchronous : false - }); - - // wrap rectangle primitive so it gets executed during the globe pass to lay down depth - depthPrimitive = new MockGlobePrimitive(primitive); + // wrap rectangle primitive so it gets executed during the globe pass or 3D Tiles pass to lay down depth + globePrimitive = new MockPrimitive(globeRectangle, Pass.GLOBE); + tilesetPrimitive = new MockPrimitive(tilesetRectangle, Pass.CESIUM_3D_TILE); var center = Rectangle.center(rectangle); var origin = ellipsoid.cartographicToCartesian(center); @@ -142,9 +176,11 @@ defineSuite([ }); afterEach(function() { + scene.primitives.removeAll(); scene.groundPrimitives.removeAll(); primitive = primitive && !primitive.isDestroyed() && primitive.destroy(); - depthPrimitive = depthPrimitive && !depthPrimitive.isDestroyed() && depthPrimitive.destroy(); + globePrimitive = globePrimitive && !globePrimitive.isDestroyed() && globePrimitive.destroy(); + tilesetPrimitive = tilesetPrimitive && !tilesetPrimitive.isDestroyed() && tilesetPrimitive.destroy(); }); it('default constructs', function() { @@ -328,17 +364,43 @@ defineSuite([ expect(frameState.commandList.length).toEqual(0); }); - function verifyClassificationPrimitiveRender(primitive, color) { - scene.camera.setView({ destination : rectangle }); + function expectRender(color) { + expect(scene).toRender(color); + } - scene.groundPrimitives.add(depthPrimitive); + function expectRenderBlank() { expect(scene).toRenderAndCall(function(rgba) { expect(rgba).not.toEqual([0, 0, 0, 255]); expect(rgba[0]).toEqual(0); }); + } + + function verifyClassificationPrimitiveRender(primitive, color) { + scene.primitives.add(globePrimitive); + scene.primitives.add(tilesetPrimitive); + + view3DTilesPrimitive(); + expectRenderBlank(); scene.groundPrimitives.add(primitive); - expect(scene).toRender(color); + + primitive.classificationType = ClassificationType.BOTH; + view3DTilesPrimitive(); + expectRender(color); + viewGlobePrimitive(); + expectRender(color); + + primitive.classificationType = ClassificationType.CESIUM_3D_TILE; + view3DTilesPrimitive(); + expectRender(color); + viewGlobePrimitive(); + expectRenderBlank(); + + primitive.classificationType = ClassificationType.TERRAIN; + view3DTilesPrimitive(); + expectRenderBlank(); + viewGlobePrimitive(); + expectRender(color); } it('renders in 3D', function() { @@ -450,7 +512,6 @@ defineSuite([ scene.invertClassification = true; scene.invertClassificationColor = new Color(0.25, 0.25, 0.25, 1.0); - depthPrimitive.pass = Pass.CESIUM_3D_TILE; boxInstance.attributes.show = new ShowGeometryInstanceAttribute(true); primitive = new ClassificationPrimitive({ @@ -458,7 +519,7 @@ defineSuite([ asynchronous : false }); - scene.camera.setView({ destination : rectangle }); + view3DTilesPrimitive(); var invertedColor = new Array(4); invertedColor[0] = Color.floatToByte(Color.byteToFloat(depthColor[0]) * scene.invertClassificationColor.red); @@ -466,7 +527,7 @@ defineSuite([ invertedColor[2] = Color.floatToByte(Color.byteToFloat(depthColor[2]) * scene.invertClassificationColor.blue); invertedColor[3] = 255; - scene.groundPrimitives.add(depthPrimitive); + scene.primitives.add(tilesetPrimitive); expect(scene).toRender(invertedColor); scene.groundPrimitives.add(primitive); @@ -490,7 +551,6 @@ defineSuite([ scene.invertClassification = true; scene.invertClassificationColor = new Color(0.25, 0.25, 0.25, 0.25); - depthPrimitive.pass = Pass.CESIUM_3D_TILE; boxInstance.attributes.show = new ShowGeometryInstanceAttribute(true); primitive = new ClassificationPrimitive({ @@ -498,7 +558,7 @@ defineSuite([ asynchronous : false }); - scene.camera.setView({ destination : rectangle }); + view3DTilesPrimitive(); var invertedColor = new Array(4); invertedColor[0] = Color.floatToByte(Color.byteToFloat(depthColor[0]) * scene.invertClassificationColor.red * scene.invertClassificationColor.alpha); @@ -506,7 +566,7 @@ defineSuite([ invertedColor[2] = Color.floatToByte(Color.byteToFloat(depthColor[2]) * scene.invertClassificationColor.blue * scene.invertClassificationColor.alpha); invertedColor[3] = 255; - scene.groundPrimitives.add(depthPrimitive); + scene.primitives.add(tilesetPrimitive); expect(scene).toRender(invertedColor); scene.groundPrimitives.add(primitive); @@ -530,7 +590,7 @@ defineSuite([ }); scene.groundPrimitives.add(primitive); - scene.camera.setView({ destination : rectangle }); + viewCenter(); expect(scene).toRenderAndCall(function(rgba) { expect(rgba[1]).toBeGreaterThanOrEqualTo(0); expect(rgba[1]).toBeGreaterThanOrEqualTo(0); @@ -551,7 +611,7 @@ defineSuite([ }); scene.groundPrimitives.add(primitive); - scene.camera.setView({ destination : rectangle }); + viewCenter(); expect(scene).toRenderAndCall(function(rgba) { expect(rgba[1]).toBeGreaterThanOrEqualTo(0); expect(rgba[1]).toBeGreaterThanOrEqualTo(0); @@ -969,13 +1029,14 @@ defineSuite([ appearance : new PerInstanceColorAppearance() }); - scene.camera.setView({ destination : rectangle }); - scene.groundPrimitives.add(depthPrimitive); + viewCenter(); + scene.primitives.add(tilesetPrimitive); expect(scene).toRenderAndCall(function(rgba) { expect(rgba).not.toEqual([0, 0, 0, 255]); expect(rgba[0]).toEqual(0); }); + primitive.classificationType = ClassificationType.CESIUM_3D_TILE; scene.groundPrimitives.add(primitive); expect(scene).toRender([255, 255, 0, 255]);