Is Three.js 'cheating' with depth_test?

I took a look at the implementation of @mattdesl’s awesome wireframe showcase:
https://mattdesl.github.io/webgl-wireframes/app/

I’m wondering how Three.js always makes the back side of the meshes visible. Since it rotates, at some point (at least by a rotation of 180°), the solid edges that sit deeper should be discarded by the depth test.

I briefly reviewed the codebase and initially found nothing relevant.

I would appreciate any insights. Thanks a lot for any hints.

here

1 Like

It’s cull face part. (WebGLRenderingContext: cullFace() method - Web APIs | MDN) As far as i know, it has nothing to do with Depth Test. Accordingly to webgl spec, if depth test is enabled, things that are further, gets overwriten in framebuffer with what is comming upfront(so they all are visible) or completely discard it if they follow in rendering order the things that already rendered upfront (so only upfront fragments are visible).
Here, with rotating mesh, backside comes as second in rendering order at latest after roraring by 180 grad. So it has to be discraded.

It looks like Three.js is doing some magic to overcome this.

good catch, then you need to expand that knowledge :smiley: check 3js version used there, depending on the version you might find the code like this in 3js. although I think they went back to single pass later.

What exactly is the question here?

At a basic level you can do.

const front = new Mesh( geom, new Material({side:FrontSide})
const back = new Mesh( geom, new Material({side:BackSide})

...
renderer.render(front.parent, camera)
renderer.render(back.parent, camera)

and get back over the front. Elaborating from here, what do you need?

I see now, this is one draw call, and it has depth test enabled, weird.

Yeah this is a nice little brain tease. My conclusion is that there is some kind of geometry manipulation happening. This sphere seems to be 240 triangles, yet looks fairly low res. I would create two geometries, designating the first one as inner i guess (back facing), flip it’s triangles, and then merge the second one on top of it. I believe this would yield the single draw call and proper sorting, along with no depth issues.

edit

240 vertices, so 80 triangles, which still seems a bit high-ish

I’m not following closely the discussion, but if the issue is how to draw front and back faces with different colors within a single draw call, the trick might be here:

gl_FrontFacing indicates for every fragment whether it is on a front-facing or back-facing triangle.

The question (i believe is) how is that “inside” triangle (the opposite facing of what you would normally expect) even rendering. If the sphere turns 180 from some arbitrary point where it is rendering, then it shouldn’t. Even the threejs docs render 2 draw calls it seems, this demo draws just one. I can’t figure it out.

The expectation is (i think) for the “inside” lines to randomly disappear in some “outside” triangles, as the sphere rotates.

1 Like

Then, you might be looking for the alpha coverage here:

If it is not enabled, then “transparency” breaks down on some view points. Here is how some of the triangles are not transparent any more (left image with enabled SAMPLE_ALPHA_TO_COVERAGE, right image with disabled SAMPLE_ALPHA_TO_COVERAGE):

4 Likes

Damn thanks, i missed this, especially since it was called on the context itself. I was looking for alphaTest and discard in the shader, i didn’t know it can be done like this. Phew, i was starting to panic.

1 Like

Relevant github link:

2 Likes

indeed that did a trick! tnx guys for taking time. i also completely oversaw this part in @mattdesl repo and just wondered how is it even possible to do it in one draw pass.

1 Like

I wasn’t even aware of this. Have to read up a bit on it, it basically does OIT under… specific, hardware dependent circumstances? Still, rendering with two meshes, merged into one, inside followed by outside, could be applied to this particular example. At a minimum on a sphere :smiley: