-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pick translucent geometry #4979
Conversation
Source/Scene/Scene.js
Outdated
@@ -2727,6 +2799,9 @@ define([ | |||
var uniformState = context.uniformState; | |||
|
|||
var drawingBufferPosition = SceneTransforms.transformWindowToDrawingBuffer(this, windowPosition, scratchPosition); | |||
if (this.pickTranslucentDepth) { | |||
renderForPickDepth(this, drawingBufferPosition); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps rename to renderTranslucentDepthForPick
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure pickTranslucentDepth
need to be a member of Scene
? It is only checked here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure pickTranslucentDepth need to be a member of Scene?
Yes, unless you have a better suggestion. We call pickPosition
in ScreenSpaceCameraController
for panning, zooming, terrain collision, etc. If we don't have the option on Scene, would we do it by default?
Source/Scene/Scene.js
Outdated
// Update with previous frame's number and time, assuming that render is called before picking. | ||
updateFrameState(scene, frameState.frameNumber, frameState.time); | ||
frameState.cullingVolume = getPickCullingVolume(scene, drawingBufferPosition, 1, 1); | ||
frameState.passes.render = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it better for this to be
frameState.passes.pick = true;
Or to do whatever the shadow map pass does since they only writes depth.
If doc, please add a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thing to consider here is that we do not want a pick to cause 3D Tiles to make new requests or process new tiles (which could happen because the cull volume is different) so this needs to be pick/depth or we need to signal to pause requests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The shadow map pass happens during the render pass. It uses derived commands that disables color writes and enables depth writes. Also, the framebuffer only has a depth attachment.
I could change it to pick, but the depth copies for each frustum only happen during the render pass. Another option is to add a new depth pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the depth copies for each frustum only happen during the render pass
I'm not following. What depth copies?
Another option is to add a new depth pass
Could work, but what about this: could we just derive commands from the previous frame's commands? Instead of calling all the update
functions, we rely on the state of the frustums/commands from the previous frame. We would need to guarantee that WebGL resources pointed to by the commands were not deleted, we could even rename the function to indicate this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What depth copies?
We copy the frustum depth to a texture after each frustum is rendered here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated this in e522ffe. There wasn't a need for derived commands. Everything is updated for the pick and depth pass which essentially queues pick commands for each command that was used in the previous render pass.
Do 3D Tiles work this way or does it select new tiles on pick?
Source/Scene/Scene.js
Outdated
@@ -2696,6 +2706,68 @@ define([ | |||
return object; | |||
}; | |||
|
|||
var scratchPickDepthPassState; | |||
|
|||
function renderForPickDepth(scene, drawingBufferPosition) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps add a PERFORMANCE_IDEA
about rendering translucent only and merging with the previous frame; I still think it could work if it checks the state is in sync.
Source/Scene/Scene.js
Outdated
|
||
var passState = scratchPickDepthPassState; | ||
if (!defined(passState)) { | ||
passState = scratchPickDepthPassState = new PassState(context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the app has more than one context? Should scratchPickDepthPassState
be part of the Scene
?
Source/Scene/Scene.js
Outdated
var width = context.drawingBufferWidth; | ||
var height = context.drawingBufferHeight; | ||
|
||
var framebuffer = scene._pickDepthFramebuffer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_pickDepthFramebuffer
should be declared in the constructor function.
Looks good. I expect performance will be reasonable. |
The performance is OK. The function is still bound by |
@pjcozzi This is ready for another look. |
3D Tiles use the same tiles for picking. |
Source/Scene/Scene.js
Outdated
frameState.passes.pick = true; | ||
frameState.passes.depth = true; | ||
|
||
us.update(frameState); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Offline we discussed using the commands from the previous frame. Why didn't you take that approach? Because some primitives will want to generate different commands here? Which precisely since pick ids won't matter.
If we stick with this approach, let's add a PERFORMANCE_IDEA
about reusing the commands.
I've been thinking about this in three levels of reuse/efficiency:
- The most efficient is what was previously done; reuse the previous frame's depth buffer. This is not possible unless the render pass writes an extra depth buffer with translucent primitives.
- Reuse the previous frame's commands. From a GL perspective, this is no more efficient, but it saves CPU overhead in Cesium.
- Reuse nothing from the previous frame, and explicitly
update
/render
.
var height = context.drawingBufferHeight; | ||
|
||
var framebuffer = scene._pickDepthFramebuffer; | ||
var pickDepthFBWidth = scene._pickDepthFramebufferWidth; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this and height below declared in the constructor function?
@@ -294,6 +302,9 @@ define([ | |||
this._pickDepths = []; | |||
this._debugGlobeDepths = []; | |||
|
|||
this._pickDepthPassState = undefined; | |||
this._pickDepthFramebuffer = undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be destroyed in the Scene's destroy
function?
Tweaked reference doc in be613f9. |
Also merge in master. |
…om executing on depth only pass.
…s enabled, and color writes disabled. Revert PassState depth mask overwrites.
@pjcozzi This is ready for another look. I updated this to use the commands from the previous frame and generate derived commands like we discussed. A simple way to test is to click the 'pick position' button in the picking Sandcastle example and replace the model entity code with: viewer.scene.pickTranslucentDepth = true;
var modelEntity = viewer.entities.add({
name : 'milktruck',
position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706),
model : {
uri : '../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck-kmc.gltf',
color : Cesium.Color.WHITE.withAlpha(0.5),
colorBlendAmount : 0.5,
colorBlendMode : Cesium.ColorBlendMode.MIX
}
}); |
Source/Scene/Scene.js
Outdated
var attributeLocations = shaderProgram._attributeLocations; | ||
var fs = shaderProgram.fragmentShaderSource; | ||
|
||
var writesFragDepth = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps combine this into one: writesDepthOrDiscards
and simplify the logic below?
Source/Scene/Scene.js
Outdated
var fragDepthRegex = /\bgl_FragDepthEXT\b/; | ||
var discardRegex = /\bdiscard\b/; | ||
|
||
function getDepthOnlyShaderProgram(scene, context, shaderProgram) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps add a comment here or somewhere that this is an optimization because we're not sure that drivers will replace the fragment shader when it doesn't discard/write-depth when the color mask is all falses and the framebuffer doesn't have a color attachment.
Who knows in the future, this might not be required.
Source/Scene/Scene.js
Outdated
attributeLocations : attributeLocations | ||
}); | ||
|
||
cache[id] = shader; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it a concern that this cache always grows and never shrinks? Should it be possible for the original shader program to basically own this and free it when the ref count goes to zero? Instead of being an object literal, this could be its own shader program cache instance if useful.
Also, is all this being shared with the shadow map pass code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it a concern that this cache always grows and never shrinks?
Yes, the derived commands for OIT are using a separate cache and has the same problem.
Also, is all this being shared with the shadow map pass code?
No. The shadow map derived commands don't have a cache. The source is generated each time the shader on the command changes. Also, it is never released.
}); | ||
|
||
scene.pickTranslucentDepth = true; | ||
expect(scene).toRenderAndCall(function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this do a second pick and spy on each one or do some other check to make sure the cached derived commands work OK?
This is super close. |
…pth only derived commands.
…es. Updated depth only and OIT derived commands.
@pjcozzi This is ready for another look. |
@@ -138,14 +139,86 @@ define([ | |||
return cachedShader.shaderProgram; | |||
}; | |||
|
|||
ShaderCache.prototype.getDerivedShaderProgram = function(shaderProgram, keyword) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add unit tests for the new stuff here.
Can you merge this into |
I tested in the This should be ready to go. I can merge |
Great! Please merge into |
Adds
Scene.pickTranslucentDepth
which can enable picking the depth of translucent pixels.Decreases performance as the scene has to be rendered again where translucent fragments write depth. It may not be as bad because we use a culling frustum and scissor test for a single pixel.
#4897 #4511 #4678