diff --git a/CHANGES.md b/CHANGES.md
index 603e3b6d475e..f4041492a0e9 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -25,6 +25,7 @@ Change Log
* Fixed an issue with constant `VertexArray` attributes not being set correctly. [#4995](https://github.com/AnalyticalGraphicsInc/cesium/pull/4995)
* Add support for `Scene.pickPosition` in Columbus view and 2D. [#4990](https://github.com/AnalyticalGraphicsInc/cesium/pull/4990)
* Added `Label.scaleByDistance` to control minimum/maximum label size based on distance from the camera. [#5019](https://github.com/AnalyticalGraphicsInc/cesium/pull/5019)
+* Add support for depth picking translucent primitives when `Scene.pickTranslucentDepth` is `true`. [#4979](https://github.com/AnalyticalGraphicsInc/cesium/pull/4979)
### 1.30 - 2017-02-01
diff --git a/Source/Renderer/ShaderCache.js b/Source/Renderer/ShaderCache.js
index d4ed90bd9f7d..d02724bdfedc 100644
--- a/Source/Renderer/ShaderCache.js
+++ b/Source/Renderer/ShaderCache.js
@@ -55,7 +55,7 @@ define([
* fragmentShaderSource : fs,
* attributeLocations : attributeLocations
* });
- *
+ *
* @see ShaderCache#getShaderProgram
*/
ShaderCache.prototype.replaceShaderProgram = function(options) {
@@ -103,7 +103,7 @@ define([
var keyword = vertexShaderText + fragmentShaderText + JSON.stringify(attributeLocations);
var cachedShader;
- if (this._shaders[keyword]) {
+ if (defined(this._shaders[keyword])) {
cachedShader = this._shaders[keyword];
// No longer want to release this if it was previously released.
@@ -125,6 +125,7 @@ define([
cache : this,
shaderProgram : shaderProgram,
keyword : keyword,
+ derivedKeywords : [],
count : 0
};
@@ -138,14 +139,86 @@ define([
return cachedShader.shaderProgram;
};
+ ShaderCache.prototype.getDerivedShaderProgram = function(shaderProgram, keyword) {
+ var cachedShader = shaderProgram._cachedShader;
+ var derivedKeyword = keyword + cachedShader.keyword;
+ var cachedDerivedShader = this._shaders[derivedKeyword];
+ if (!defined(cachedDerivedShader)) {
+ return undefined;
+ }
+
+ return cachedDerivedShader.shaderProgram;
+ };
+
+ ShaderCache.prototype.createDerivedShaderProgram = function(shaderProgram, keyword, options) {
+ var cachedShader = shaderProgram._cachedShader;
+ var derivedKeyword = keyword + cachedShader.keyword;
+
+ var vertexShaderSource = options.vertexShaderSource;
+ var fragmentShaderSource = options.fragmentShaderSource;
+ var attributeLocations = options.attributeLocations;
+
+ if (typeof vertexShaderSource === 'string') {
+ vertexShaderSource = new ShaderSource({
+ sources : [vertexShaderSource]
+ });
+ }
+
+ if (typeof fragmentShaderSource === 'string') {
+ fragmentShaderSource = new ShaderSource({
+ sources : [fragmentShaderSource]
+ });
+ }
+
+ var vertexShaderText = vertexShaderSource.createCombinedVertexShader();
+ var fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader();
+
+ var context = this._context;
+ var derivedShaderProgram = new ShaderProgram({
+ gl : context._gl,
+ logShaderCompilation : context.logShaderCompilation,
+ debugShaders : context.debugShaders,
+ vertexShaderSource : vertexShaderSource,
+ vertexShaderText : vertexShaderText,
+ fragmentShaderSource : fragmentShaderSource,
+ fragmentShaderText : fragmentShaderText,
+ attributeLocations : attributeLocations
+ });
+
+ var derivedCachedShader = {
+ cache : this,
+ shaderProgram : derivedShaderProgram,
+ keyword : derivedKeyword,
+ derivedKeywords : [],
+ count : 0
+ };
+
+ cachedShader.derivedKeywords.push(keyword);
+ derivedShaderProgram._cachedShader = derivedCachedShader;
+ this._shaders[derivedKeyword] = derivedCachedShader;
+ return derivedShaderProgram;
+ };
+
+ function destroyShader(cache, cachedShader) {
+ var derivedKeywords = cachedShader.derivedKeywords;
+ var length = derivedKeywords.length;
+ for (var i = 0; i < length; ++i) {
+ var keyword = derivedKeywords[i] + cachedShader.keyword;
+ var derivedCachedShader = cache._shaders[keyword];
+ destroyShader(cache, derivedCachedShader);
+ }
+
+ delete cache._shaders[cachedShader.keyword];
+ cachedShader.shaderProgram.finalDestroy();
+ }
+
ShaderCache.prototype.destroyReleasedShaderPrograms = function() {
var shadersToRelease = this._shadersToRelease;
for ( var keyword in shadersToRelease) {
if (shadersToRelease.hasOwnProperty(keyword)) {
var cachedShader = shadersToRelease[keyword];
- delete this._shaders[cachedShader.keyword];
- cachedShader.shaderProgram.finalDestroy();
+ destroyShader(this, cachedShader);
--this._numberOfShaders;
}
}
@@ -168,13 +241,11 @@ define([
ShaderCache.prototype.destroy = function() {
var shaders = this._shaders;
-
- for ( var keyword in shaders) {
+ for (var keyword in shaders) {
if (shaders.hasOwnProperty(keyword)) {
shaders[keyword].shaderProgram.finalDestroy();
}
}
-
return destroyObject(this);
};
diff --git a/Source/Scene/FrameState.js b/Source/Scene/FrameState.js
index 0d4278dc64a6..1431589182a0 100644
--- a/Source/Scene/FrameState.js
+++ b/Source/Scene/FrameState.js
@@ -117,7 +117,14 @@ define([
* @type {Boolean}
* @default false
*/
- pick : false
+ pick : false,
+
+ /**
+ * true
if the primitive should update for a depth only pass, false
otherwise.
+ * @type {Boolean}
+ * @default false
+ */
+ depth : false
};
/**
diff --git a/Source/Scene/OIT.js b/Source/Scene/OIT.js
index eba923512306..ac43dbcd8238 100644
--- a/Source/Scene/OIT.js
+++ b/Source/Scene/OIT.js
@@ -82,8 +82,6 @@ define([
this._translucentRenderStateCache = {};
this._alphaRenderStateCache = {};
- this._translucentShaderCache = {};
- this._alphaShaderCache = {};
this._compositeCommand = undefined;
this._adjustTranslucentCommand = undefined;
@@ -411,9 +409,8 @@ define([
' float ai = czm_gl_FragColor.a;\n' +
' gl_FragColor = vec4(ai);\n';
- function getTranslucentShaderProgram(context, shaderProgram, cache, source) {
- var id = shaderProgram.id;
- var shader = cache[id];
+ function getTranslucentShaderProgram(context, shaderProgram, keyword, source) {
+ var shader = context.shaderCache.getDerivedShaderProgram(shaderProgram, keyword);
if (!defined(shader)) {
var attributeLocations = shaderProgram._attributeLocations;
@@ -446,29 +443,26 @@ define([
source +
'}\n');
- shader = ShaderProgram.fromCache({
- context : context,
+ shader = context.shaderCache.createDerivedShaderProgram(shaderProgram, keyword, {
vertexShaderSource : shaderProgram.vertexShaderSource,
fragmentShaderSource : fs,
attributeLocations : attributeLocations
});
-
- cache[id] = shader;
}
return shader;
}
- function getTranslucentMRTShaderProgram(oit, context, shaderProgram) {
- return getTranslucentShaderProgram(context, shaderProgram, oit._translucentShaderCache, mrtShaderSource);
+ function getTranslucentMRTShaderProgram(context, shaderProgram) {
+ return getTranslucentShaderProgram(context, shaderProgram, 'translucentMRT', mrtShaderSource);
}
- function getTranslucentColorShaderProgram(oit, context, shaderProgram) {
- return getTranslucentShaderProgram(context, shaderProgram, oit._translucentShaderCache, colorShaderSource);
+ function getTranslucentColorShaderProgram(context, shaderProgram) {
+ return getTranslucentShaderProgram(context, shaderProgram, 'translucentMultipass', colorShaderSource);
}
- function getTranslucentAlphaShaderProgram(oit, context, shaderProgram) {
- return getTranslucentShaderProgram(context, shaderProgram, oit._alphaShaderCache, alphaShaderSource);
+ function getTranslucentAlphaShaderProgram(context, shaderProgram) {
+ return getTranslucentShaderProgram(context, shaderProgram, 'alphaMultipass', alphaShaderSource);
}
OIT.prototype.createDerivedCommands = function(command, context, result) {
@@ -487,7 +481,7 @@ define([
result.translucentCommand = DrawCommand.shallowClone(command, result.translucentCommand);
if (!defined(translucentShader) || result.shaderProgramId !== command.shaderProgram.id) {
- result.translucentCommand.shaderProgram = getTranslucentMRTShaderProgram(this, context, command.shaderProgram);
+ result.translucentCommand.shaderProgram = getTranslucentMRTShaderProgram(context, command.shaderProgram);
result.translucentCommand.renderState = getTranslucentMRTRenderState(this, context, command.renderState);
result.shaderProgramId = command.shaderProgram.id;
} else {
@@ -510,9 +504,9 @@ define([
result.alphaCommand = DrawCommand.shallowClone(command, result.alphaCommand);
if (!defined(colorShader) || result.shaderProgramId !== command.shaderProgram.id) {
- result.translucentCommand.shaderProgram = getTranslucentColorShaderProgram(this, context, command.shaderProgram);
+ result.translucentCommand.shaderProgram = getTranslucentColorShaderProgram(context, command.shaderProgram);
result.translucentCommand.renderState = getTranslucentColorRenderState(this, context, command.renderState);
- result.alphaCommand.shaderProgram = getTranslucentAlphaShaderProgram(this, context, command.shaderProgram);
+ result.alphaCommand.shaderProgram = getTranslucentAlphaShaderProgram(context, command.shaderProgram);
result.alphaCommand.renderState = getTranslucentAlphaRenderState(this, context, command.renderState);
result.shaderProgramId = command.shaderProgram.id;
} else {
@@ -639,23 +633,6 @@ define([
this._adjustAlphaCommand.shaderProgram = this._adjustAlphaCommand.shaderProgram && this._adjustAlphaCommand.shaderProgram.destroy();
}
- var name;
- var cache = this._translucentShaderCache;
- for (name in cache) {
- if (cache.hasOwnProperty(name) && defined(cache[name])) {
- cache[name].destroy();
- }
- }
- this._translucentShaderCache = {};
-
- cache = this._alphaShaderCache;
- for (name in cache) {
- if (cache.hasOwnProperty(name) && defined(cache[name])) {
- cache[name].destroy();
- }
- }
- this._alphaShaderCache = {};
-
return destroyObject(this);
};
diff --git a/Source/Scene/Scene.js b/Source/Scene/Scene.js
index 1aa52b4d734e..e32dcc4afe31 100644
--- a/Source/Scene/Scene.js
+++ b/Source/Scene/Scene.js
@@ -28,6 +28,7 @@ define([
'../Core/Matrix4',
'../Core/mergeSort',
'../Core/Occluder',
+ '../Core/PixelFormat',
'../Core/ShowGeometryInstanceAttribute',
'../Core/Transforms',
'../Renderer/ClearCommand',
@@ -35,10 +36,14 @@ define([
'../Renderer/Context',
'../Renderer/ContextLimits',
'../Renderer/DrawCommand',
+ '../Renderer/Framebuffer',
'../Renderer/Pass',
'../Renderer/PassState',
+ '../Renderer/PixelDatatype',
+ '../Renderer/RenderState',
'../Renderer/ShaderProgram',
'../Renderer/ShaderSource',
+ '../Renderer/Texture',
'./Camera',
'./CreditDisplay',
'./CullingVolume',
@@ -96,6 +101,7 @@ define([
Matrix4,
mergeSort,
Occluder,
+ PixelFormat,
ShowGeometryInstanceAttribute,
Transforms,
ClearCommand,
@@ -103,10 +109,14 @@ define([
Context,
ContextLimits,
DrawCommand,
+ Framebuffer,
Pass,
PassState,
+ PixelDatatype,
+ RenderState,
ShaderProgram,
ShaderSource,
+ Texture,
Camera,
CreditDisplay,
CullingVolume,
@@ -294,6 +304,12 @@ define([
this._pickDepths = [];
this._debugGlobeDepths = [];
+ this._pickDepthPassState = undefined;
+ this._pickDepthFramebuffer = undefined;
+ this._pickDepthFramebufferWidth = undefined;
+ this._pickDepthFramebufferHeight = undefined;
+ this._depthOnlyRenderStateCache = {};
+
this._transitioner = new SceneTransitioner(this);
this._renderError = new Event();
@@ -548,6 +564,18 @@ define([
*/
this.useDepthPicking = true;
+ /**
+ * When true
, enables picking translucent geometry using the depth buffer.
+ * {@link Scene#useDepthPicking} must also be true to enable picking the depth buffer.
+ *
+ * There is a decrease in performance when enabled. There are extra draw calls to write depth for + * translucent geometry. + *
+ * @type {Boolean} + * @default false + */ + this.pickTranslucentDepth = false; + /** * The time in milliseconds to wait before checking if the camera has not moved and fire the cameraMoveEnd event. * @type {Number} @@ -1162,11 +1190,10 @@ define([ shadowsDirty = true; } - if (command.dirty) { + var derivedCommands = command.derivedCommands; + if (command.dirty && defined(derivedCommands)) { command.dirty = false; - var derivedCommands = command.derivedCommands; - if (shadowsEnabled && (command.receiveShadows || command.castShadows)) { derivedCommands.shadows = ShadowMap.createDerivedCommands(shadowMaps, lightShadowMaps, command, shadowsDirty, context, derivedCommands.shadows); } @@ -1180,6 +1207,8 @@ define([ derivedCommands.oit = oit.createDerivedCommands(command, context, derivedCommands.oit); } } + + derivedCommands.depth = createDepthOnlyDerivedCommand(scene, command, context, derivedCommands.depth); } } @@ -1203,6 +1232,7 @@ define([ function clearPasses(passes) { passes.render = false; passes.pick = false; + passes.depth = false; } function updateFrameState(scene, frameNumber, time) { @@ -1577,6 +1607,8 @@ define([ // Some commands, such as OIT derived commands, do not have derived shadow commands themselves // and instead shadowing is built-in. In this case execute the command regularly below. command.derivedCommands.shadows.receiveCommand.execute(context, passState); + } else if (scene.frameState.passes.depth && defined(command.derivedCommands.depth)) { + command.derivedCommands.depth.depthOnlyCommand.execute(context, passState); } else { command.execute(context, passState); } @@ -1704,7 +1736,7 @@ define([ var scratchPerspectiveOffCenterFrustum = new PerspectiveOffCenterFrustum(); var scratchOrthographicFrustum = new OrthographicFrustum(); - function executeCommands(scene, passState, picking) { + function executeCommands(scene, passState) { var camera = scene._camera; var context = scene.context; var us = context.uniformState; @@ -1729,6 +1761,9 @@ define([ us.updatePass(Pass.ENVIRONMENT); var useWebVR = scene._useWebVR && scene.mode !== SceneMode.SCENE2D; + var passes = scene._frameState.passes; + var picking = passes.pick; + var depthOnly = passes.depth; var environmentState = scene._environmentState; // Do not render environment primitives during a pick pass since they do not generate picking commands. @@ -1877,10 +1912,11 @@ define([ commands.length = frustumCommands.indices[Pass.TRANSLUCENT]; executeTranslucentCommands(scene, executeCommand, passState, commands); - if (defined(globeDepth) && environmentState.useGlobeDepthFramebuffer && scene.useDepthPicking) { + if (defined(globeDepth) && (environmentState.useGlobeDepthFramebuffer || depthOnly) && scene.useDepthPicking) { // PERFORMANCE_IDEA: Use MRT to avoid the extra copy. + var depthStencilTexture = depthOnly ? passState.framebuffer.depthStencilTexture : globeDepth.framebuffer.depthStencilTexture; var pickDepth = getPickDepth(scene, index); - pickDepth.update(context, globeDepth.framebuffer.depthStencilTexture); + pickDepth.update(context, depthStencilTexture); pickDepth.executeCopyDepth(context, passState); } } @@ -1999,7 +2035,7 @@ define([ } } - function updateAndExecuteCommands(scene, passState, backgroundColor, picking) { + function updateAndExecuteCommands(scene, passState, backgroundColor) { var context = scene._context; var viewport = passState.viewport; @@ -2007,13 +2043,20 @@ define([ var frameState = scene._frameState; var camera = frameState.camera; var mode = frameState.mode; + var depthOnly = frameState.passes.depth; if (scene._useWebVR && mode !== SceneMode.SCENE2D) { - updatePrimitives(scene); + if (!depthOnly) { + updatePrimitives(scene); + } + createPotentiallyVisibleSet(scene); - updateAndClearFramebuffers(scene, passState, backgroundColor, picking); - executeComputeCommands(scene); - executeShadowMapCastCommands(scene); + updateAndClearFramebuffers(scene, passState, backgroundColor); + + if (!depthOnly) { + executeComputeCommands(scene); + executeShadowMapCastCommands(scene); + } // Based on Calculating Stereo pairs by Paul Bourke // http://paulbourke.net/stereographics/stereorender/ @@ -2037,14 +2080,14 @@ define([ Cartesian3.add(savedCamera.position, eyeTranslation, camera.position); camera.frustum.xOffset = offset; - executeCommands(scene, passState, picking); + executeCommands(scene, passState); viewport.x = passState.viewport.width; Cartesian3.subtract(savedCamera.position, eyeTranslation, camera.position); camera.frustum.xOffset = -offset; - executeCommands(scene, passState, picking); + executeCommands(scene, passState); Camera.clone(savedCamera, camera); } else { @@ -2054,9 +2097,9 @@ define([ viewport.height = context.drawingBufferHeight; if (mode !== SceneMode.SCENE2D || scene._mapMode2D === MapMode2D.ROTATE) { - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); } else { - execute2DViewportCommands(scene, passState, backgroundColor, picking); + execute2DViewportCommands(scene, passState, backgroundColor); } } } @@ -2069,7 +2112,7 @@ define([ var scratch2DViewportEyePoint = new Cartesian3(); var scratch2DViewportWindowCoords = new Cartesian3(); - function execute2DViewportCommands(scene, passState, backgroundColor, picking) { + function execute2DViewportCommands(scene, passState, backgroundColor) { var context = scene.context; var frameState = scene.frameState; var camera = scene.camera; @@ -2100,7 +2143,7 @@ define([ var viewportWidth = viewport.width; if (x === 0.0 || windowCoordinates.x <= 0.0 || windowCoordinates.x >= context.drawingBufferWidth) { - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); } else if (Math.abs(context.drawingBufferWidth * 0.5 - windowCoordinates.x) < 1.0) { viewport.width = windowCoordinates.x; @@ -2111,7 +2154,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); viewport.x = viewport.width; @@ -2123,7 +2166,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(false, scene, passState, backgroundColor, picking); + executeCommandsInViewport(false, scene, passState, backgroundColor); } else if (windowCoordinates.x > context.drawingBufferWidth * 0.5) { viewport.width = windowCoordinates.x; @@ -2133,7 +2176,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); viewport.x += windowCoordinates.x; viewport.width = context.drawingBufferWidth - windowCoordinates.x; @@ -2146,7 +2189,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(false, scene, passState, backgroundColor, picking); + executeCommandsInViewport(false, scene, passState, backgroundColor); } else { viewport.x = windowCoordinates.x; viewport.width = context.drawingBufferWidth - windowCoordinates.x; @@ -2157,7 +2200,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(true, scene, passState, backgroundColor, picking); + executeCommandsInViewport(true, scene, passState, backgroundColor); viewport.x = 0; viewport.width = windowCoordinates.x; @@ -2170,7 +2213,7 @@ define([ frameState.cullingVolume = camera.frustum.computeCullingVolume(camera.positionWC, camera.directionWC, camera.upWC); context.uniformState.update(frameState); - executeCommandsInViewport(false, scene, passState, backgroundColor, picking); + executeCommandsInViewport(false, scene, passState, backgroundColor); } camera._setTransform(transform); @@ -2181,21 +2224,28 @@ define([ viewport.width = viewportWidth; } - function executeCommandsInViewport(firstViewport, scene, passState, backgroundColor, picking) { - if (!firstViewport) { + function executeCommandsInViewport(firstViewport, scene, passState, backgroundColor) { + var depthOnly = scene.frameState.passes.depth; + + if (!firstViewport && !depthOnly) { scene.frameState.commandList.length = 0; } - updatePrimitives(scene); + if (!depthOnly) { + updatePrimitives(scene); + } + createPotentiallyVisibleSet(scene); if (firstViewport) { - updateAndClearFramebuffers(scene, passState, backgroundColor, picking); - executeComputeCommands(scene); - executeShadowMapCastCommands(scene); + updateAndClearFramebuffers(scene, passState, backgroundColor); + if (!depthOnly) { + executeComputeCommands(scene); + executeShadowMapCastCommands(scene); + } } - executeCommands(scene, passState, picking); + executeCommands(scene, passState); } function updateEnvironment(scene) { @@ -2305,10 +2355,12 @@ define([ } } - function updateAndClearFramebuffers(scene, passState, clearColor, picking) { + function updateAndClearFramebuffers(scene, passState, clearColor) { var context = scene._context; var environmentState = scene._environmentState; + var passes = scene._frameState.passes; + var picking = passes.pick; var useWebVR = scene._useWebVR && scene.mode !== SceneMode.SCENE2D; // Preserve the reference to the original framebuffer. @@ -2687,7 +2739,7 @@ define([ var passState = this._pickFramebuffer.begin(scratchRectangle); - updateAndExecuteCommands(this, passState, scratchColorZero, true); + updateAndExecuteCommands(this, passState, scratchColorZero); resolveFramebuffers(this, passState); var object = this._pickFramebuffer.end(scratchRectangle); @@ -2696,6 +2748,149 @@ define([ return object; }; + var fragDepthRegex = /\bgl_FragDepthEXT\b/; + var discardRegex = /\bdiscard\b/; + + function getDepthOnlyShaderProgram(context, shaderProgram) { + var shader = context.shaderCache.getDerivedShaderProgram(shaderProgram, 'depthOnly'); + if (!defined(shader)) { + var attributeLocations = shaderProgram._attributeLocations; + var fs = shaderProgram.fragmentShaderSource; + + var writesDepthOrDiscards = false; + var sources = fs.sources; + var length = sources.length; + for (var i = 0; i < length; ++i) { + if (fragDepthRegex.test(sources[i]) || discardRegex.test(sources[i])) { + writesDepthOrDiscards = true; + break; + } + } + + if (!writesDepthOrDiscards) { + fs = new ShaderSource({ + sources : ['void main() { gl_FragColor = vec4(1.0); }'] + }); + } + + shader = context.shaderCache.createDerivedShaderProgram(shaderProgram, 'depthOnly', { + vertexShaderSource : shaderProgram.vertexShaderSource, + fragmentShaderSource : fs, + attributeLocations : attributeLocations + }); + } + + return shader; + } + + function getDepthOnlyRenderState(scene, renderState) { + var cache = scene._depthOnlyRenderStateCache; + var depthOnlyState = cache[renderState.id]; + if (!defined(depthOnlyState)) { + var rs = RenderState.getState(renderState); + rs.depthMask = true; + rs.colorMask = { + red : false, + green : false, + blue : false, + alpha : false + }; + + depthOnlyState = RenderState.fromCache(rs); + cache[renderState.id] = depthOnlyState; + } + + return depthOnlyState; + } + + function createDepthOnlyDerivedCommand(scene, command, context, result) { + // For a depth only pass, we bind a framebuffer with only a depth attachment (no color attachments), + // do not write color, and write depth. If the fragment shader doesn't modify the fragment depth + // or discard, the driver can replace the fragment shader with a pass-through shader. We're unsure if this + // actually happens so we modify the shader to use a pass-through fragment shader. + + if (!defined(result)) { + result = {}; + } + + var shader; + var renderState; + if (defined(result.depthOnlyCommand)) { + shader = result.depthOnlyCommand.shaderProgram; + renderState = result.depthOnlyCommand.renderState; + } + + result.depthOnlyCommand = DrawCommand.shallowClone(command, result.depthOnlyCommand); + + if (!defined(shader) || result.shaderProgramId !== command.shaderProgram.id) { + result.depthOnlyCommand.shaderProgram = getDepthOnlyShaderProgram(context, command.shaderProgram); + result.depthOnlyCommand.renderState = getDepthOnlyRenderState(scene, command.renderState); + result.shaderProgramId = command.shaderProgram.id; + } else { + result.depthOnlyCommand.shaderProgram = shader; + result.depthOnlyCommand.renderState = renderState; + } + + return result; + } + + function renderTranslucentDepthForPick(scene, drawingBufferPosition) { + // PERFORMANCE_IDEA: render translucent only and merge with the previous frame + var context = scene._context; + var frameState = scene._frameState; + + clearPasses(frameState.passes); + frameState.passes.pick = true; + frameState.passes.depth = true; + frameState.cullingVolume = getPickCullingVolume(scene, drawingBufferPosition, 1, 1); + + var passState = scene._pickDepthPassState; + if (!defined(passState)) { + passState = scene._pickDepthPassState = new PassState(context); + passState.scissorTest = { + enabled : true, + rectangle : new BoundingRectangle() + }; + passState.viewport = new BoundingRectangle(); + } + + var width = context.drawingBufferWidth; + var height = context.drawingBufferHeight; + + var framebuffer = scene._pickDepthFramebuffer; + var pickDepthFBWidth = scene._pickDepthFramebufferWidth; + var pickDepthFBHeight = scene._pickDepthFramebufferHeight; + if (!defined(framebuffer) || pickDepthFBWidth !== width || pickDepthFBHeight !== height) { + scene._pickDepthFramebuffer = scene._pickDepthFramebuffer && scene._pickDepthFramebuffer.destroy(); + framebuffer = scene._pickDepthFramebuffer = new Framebuffer({ + context : context, + depthStencilTexture : new Texture({ + context : context, + width : width, + height : height, + pixelFormat : PixelFormat.DEPTH_STENCIL, + pixelDatatype : PixelDatatype.UNSIGNED_INT_24_8 + }) + }); + + scene._pickDepthFramebufferWidth = width; + scene._pickDepthFramebufferHeight = height; + } + + passState.framebuffer = framebuffer; + passState.viewport.width = width; + passState.viewport.height = height; + passState.scissorTest.rectangle.x = drawingBufferPosition.x; + passState.scissorTest.rectangle.y = height - drawingBufferPosition.y; + passState.scissorTest.rectangle.width = 1; + passState.scissorTest.rectangle.height = 1; + + updateAndExecuteCommands(scene, passState, scratchColorZero); + resolveFramebuffers(scene, passState); + + context.endFrame(); + } + var scratchPackedDepth = new Cartesian4(); var packedDepthScale = new Cartesian4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 16581375.0); @@ -2703,6 +2898,10 @@ define([ * Returns the cartesian position reconstructed from the depth buffer and window position. * The returned position is in world coordinates. Used internally by camera functions to * prevent conversion to projected 2D coordinates and then back. + *
+ * Set {@link Scene#pickTranslucentDepth} to true
to include the depth of
+ * translucent primitives; otherwise, this essentially picks through translucent primitives.
+ *
+ * Set {@link Scene#pickTranslucentDepth} to true
to include the depth of
+ * translucent primitives; otherwise, this essentially picks through translucent primitives.
+ *