Skip to content
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

added WebGLDepthPrepass #8676

Closed
wants to merge 1 commit into from
Closed

added WebGLDepthPrepass #8676

wants to merge 1 commit into from

Conversation

mlknz
Copy link
Contributor

@mlknz mlknz commented Apr 19, 2016

THREE.WebGLDepthPrepass renders opaque objects depth before main render pass.

It could speed up rendering in certain scenarios ( complex per-fragment computations in a scene, where effective objects sorting couldn't be performed ). Here is a simple example scene to demonstrate speed-up: https://jsfiddle.net/mlkn/fd6mg4kr ( might have to resize a canvas until FPS drops ).

Currently interface is: renderer.depthPrepass.enable() / renderer.depthPrepass.disable() .

Notes: object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ) is performed twice (in depth pass and in main pass).
renderer.info now just doubles its values with DepthPrepass enabled. If this feature is going to be merged, I suppose it makes sense to extend renderer.info.

@mrdoob
Copy link
Owner

mrdoob commented Apr 19, 2016

Hmm... I'm not sure this should be part of the renderer. Currently this can be done at the app level, right?

@mlknz
Copy link
Contributor Author

mlknz commented Apr 19, 2016

As far as I understand if the one decides to try it from app level using renderer.render() he has to do the following before depth pass:

  • delete all sprites and lensFlares from scene or set their opacity to 0.0 (second will still cause extra gl calls currently)
  • delete lights from scene so setupLights() won't get called
  • renderer.shadowMap.enabled = false
  • set renderTarget to null
  • determine which objects are opaque, set depth materials for them (with colorWrite = false) and cache their usual materials somewhere (or use scene.overrideMaterial, which is not going to work with instanced geometry, for example. If there is scene.overrideMaterial already, set it to null)
  • set renderer.autoclear, renderer.sortObjects, scene.autoUpdate to true

and the following before main pass:

  • restore sprites / flares / lights state
  • restore renderTarget / shadowMap.enabled state
  • set renderer.autoclear, renderer.sortObjects, scene.autoUpdate to false
  • change materials to usual materials (first time you do set their depthWrite to false and cache their initial depthWrite so you could change it back)

After doing that you still get potentially major overhead from updating camera matrix and doing frustum culling twice. I've noticed there is an object.frustumCulled property but couldn't find an obvious way to set it only for objects, culled in a first pass.

From my perspective doing this from app is not user friendly (even if there were no overheads). Having complex scene the one could want to check if depth prepass would give him performance boost without spending time in renderer code. And it is probably not worth trying due to extra frustum culling cost.

Sorry if I missed something.

@mlknz mlknz closed this Jan 14, 2017
@mrdoob
Copy link
Owner

mrdoob commented Jan 18, 2017

Hmm, I think I didn't understood exactly how this works.

As far as I understand, you're pre-rendering the opaque objects using the depth material (similar code to WebGLShadowMap).

How does this improve performance?

@mlknz
Copy link
Contributor Author

mlknz commented Jan 19, 2017

Right, it was something like that.

Now I'm not sure that this optimization should be in core since it complicates code base and is very situational, that is why I closed PR. If someone needs this optimization he indeed could tinker it in renderer or at app level (with some overhead).

However, performance boost from depth prepass comes in case of "complex per-fragment computations in a scene, where effective objects sorting couldn't be performed". It makes sure that unneeded computations in fragment shader wouldn't be performed for opaque objects (like with early z-test, which is not guaranteed) at cost of extra render pass with depth materials.

@bhouston
Copy link
Contributor

@WestLangley @mrdoob This was actually a really good idea. Depth-prepasses are used by all modern games, such as Doom, Metal Gear Solid V, etc.

@mrdoob
Copy link
Owner

mrdoob commented May 17, 2018

I think we just need more context. What would be a use case for a core material to use this?

@bhouston
Copy link
Contributor

The idea is that before you render your opaque beauty pass (which is costly on a per-pixel basis) , you render the depth pre-pass, which is a fast to run material and it just fills the z-buffer.

Then when you run the opaque beauty pass, no pixels that are hidden are every written because you have pre-populated the z-buffer. You need to render the beauty pass with EQUAL rather than LESS THAN, but given you are just re-rendering the same faces with the same values, it will not produce artifacts/z-fighting.

This is useful when there is lots of complex geometry that leads to costly overdraw. If you just have a single sphere, this doesn't help. But if you have lots of complex large shapes that hide each other (think indoors with walls, etc), this can save between 30% to 50% of beauty pixel computations.

@bhouston
Copy link
Contributor

I think this can be implemented as a DepthPrePass in the composer maybe. Rather than the way it was in this specific PR.

@mrdoob
Copy link
Owner

mrdoob commented May 17, 2018

Ah, I see. Yeah, for objects with a lot of "self overdraw".

I think this can be implemented as a DepthPrePass in the composer maybe. Rather than the way it was in this specific PR.

Indeed. It seems simple enough though. I think it's more of a matter of repurposing the ShadowMap code instead of duplicating.

@mrdoob mrdoob reopened this May 17, 2018
@mrdoob mrdoob added this to the rXX milestone May 17, 2018
@WestLangley
Copy link
Collaborator

Related #13858

@gkjohnson
Copy link
Collaborator

There was a post on the forum related to selectively performing a depth prepass for helping to alleviate transparent object artifacts here which would be nice to support with a material flag:

https://discourse.threejs.org/t/does-anyone-know-how-the-depth-pre-pass-option-of-babylonjs-is-implemented/20623

It also occurred to me that a simple version of a scene depth prepass could be achieved by rendering all opaque objects beforehand with colorWrite set to false which I would expect to cause the GPU to skip the fragment shader in most cases. It might not be able to do so if discard is used or the depth is set in the fragment shader -- perhaps it can still optimize something in those cases but it would probably be good enough for a first pass here either way.

Basically this would boil down to reusing the vertex shader that's already on the object material so even custom user shaders that manipulate a materials vertices would work with it. It would be possible to create more optimal prepass materials that don't calculate things like normals in the vertex shader but I believe depth prepass is most useful for fragment-bound cases anyway?

@LeviPesin
Copy link
Contributor

@mlknz Can you please update this PR?

@mlknz
Copy link
Contributor Author

mlknz commented Apr 8, 2022

@LeviPesin I think with also these years passed it should be easier to write new PR from scratch.
I haven't looked intro three.js for years and lifting weights at my day job so I'm pretty sure I'm not ready to look into this soon, sorry.

@mrdoob
Copy link
Owner

mrdoob commented Apr 8, 2022

Seems like #20673 is a good working alternative.

@mrdoob mrdoob closed this Apr 8, 2022
@mrdoob mrdoob removed this from the r??? milestone Apr 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants