# Is Three.js 'cheating' with depth\_test?

**URL:** <https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026>\
**Category:** Questions\
**Tags:** materials, shaders\
**Created:** [August 16, 2023, 1:01pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026 "2023-08-16T13:01:58Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![zavalit](https://avatars.discourse-cdn.com/v4/letter/z/90ced4/32.png) [@zavalit](https://discourse.threejs.org/u/zavalit)\
**Post date:** [August 16, 2023, 1:01pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/1 "2023-08-16T13:01:58Z")

</div>

I took a look at the implementation of @mattdesl’s awesome wireframe showcase:  
[https://mattdesl.github.io/webgl-wireframes/app/](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.

---

<div class="post-metadata">

**Author:** ![makc3d](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/makc3d/32/10452_2.png) [@makc3d](https://discourse.threejs.org/u/makc3d)\
**Post date:** [August 16, 2023, 3:39pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/2 "2023-08-16T15:39:26Z")

</div>

> [@zavalit](#):
>
> I briefly reviewed the codebase and initially found nothing relevant.

[here](https://github.com/mattdesl/webgl-wireframes/blob/bf073f8f18215dec87cb910f6da3775f1e8bfb6f/lib/index.js#L60)

---

<div class="post-metadata">

**Author:** ![zavalit](https://avatars.discourse-cdn.com/v4/letter/z/90ced4/32.png) [@zavalit](https://discourse.threejs.org/u/zavalit)\
**Post date:** [August 16, 2023, 4:13pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/3 "2023-08-16T16:13:15Z")

</div>

It’s cull face part. ([WebGLRenderingContext: cullFace() method - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/cullFace)) 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.

---

<div class="post-metadata">

**Author:** ![makc3d](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/makc3d/32/10452_2.png) [@makc3d](https://discourse.threejs.org/u/makc3d)\
**Post date:** [August 16, 2023, 4:36pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/4 "2023-08-16T16:36:41Z")

</div>

> [@zavalit](#):
>
> As far as i know

good catch, then you need to expand that knowledge 😃 check 3js version used there, depending on the version you might find the code [like this](https://github.com/mrdoob/three.js/blob/d081c5a3501d272d19375fab1b01fedf9df29b22/src/renderers/WebGLRenderer.js#L1334-L1342) in 3js. although I think they went back to single pass later.

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [August 16, 2023, 7:00pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/5 "2023-08-16T19:00:42Z")

</div>

What exactly is the question here?

At a basic level you can do.

```javascript
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?

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [August 16, 2023, 7:04pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/6 "2023-08-16T19:04:35Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [August 16, 2023, 7:14pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/7 "2023-08-16T19:14:30Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [August 16, 2023, 7:26pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/8 "2023-08-16T19:26:27Z")

</div>

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:

> <https://github.com/mattdesl/webgl-wireframes/blob/bf073f8f18215dec87cb910f6da3775f1e8bfb6f/lib/wire.frag#L96-L100>

[`gl_FrontFacing`](https://registry.khronos.org/OpenGL-Refpages/gl4/html/gl_FrontFacing.xhtml) indicates for every fragment whether it is on a front-facing or back-facing triangle.

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [August 16, 2023, 7:28pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/9 "2023-08-16T19:28:47Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![PavelBoytchev](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/pavelboytchev/32/38639_2.png) [@PavelBoytchev](https://discourse.threejs.org/u/PavelBoytchev)\
**Post date:** [August 16, 2023, 7:45pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/10 "2023-08-16T19:45:56Z")

</div>

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

> <https://github.com/mattdesl/webgl-wireframes/blob/bf073f8f18215dec87cb910f6da3775f1e8bfb6f/lib/index.js#L38-L40>

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`):

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/c/e/ce64e5499dcdd68e3b0ae193be08e15ef16f53c5.png) ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/6/9/691be995c2ce1d231fcfcf1d4f67acea92273f5f.png)

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [August 16, 2023, 7:53pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/11 "2023-08-16T19:53:56Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [August 16, 2023, 7:55pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/12 "2023-08-16T19:55:05Z")

</div>

Relevant github link:

> <https://github.com/mrdoob/three.js/issues/12438>
>
> \##### Feature: Support Alpha To Coverage
> 
> It would be nice to support a flag f…or \[Alpha to Coverage\](https://medium.com/@bgolus/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f). This feature has existed in WebGL contexts for a while, however, it seems hardly used in practice.
> 
> It can be used to create really crisp alpha cutouts with MSAA-enabled contexts. 
> 
> When enabled, you no longer need to specify alphaTest or perform a \`discard\` in the fragment shader, you simply output the frag alpha and the GL context will handle cutouts. You can read more about it \[here\](https://medium.com/@bgolus/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f), including some tricks to make things even smoother.
> 
> \`\`\`js
> // enable alpha to coverage with current ThreeJS renderer
> const gl = renderer.getContext();
> gl.enable(gl.SAMPLE\_ALPHA\_TO\_COVERAGE);
> \`\`\`
> 
> This feature assumes MSAA is enabled and supported (i.e. may not work in external monitors).
> 
> Here is an example wireframe shader using alpha to coverage:
> https://mattdesl.github.io/webgl-wireframes/app/
> !\[screenshot 64\](https://user-images.githubusercontent.com/1383811/31785155-4396df8a-b4d2-11e7-895e-3056fcd2e8a1.png)
> 
> 
> \##### Browser
> 
> \- \[x\] All of them
> \- \[\] Chrome
> \- \[\] Firefox
> \- \[\] Internet Explorer
> 
> \##### OS
> 
> \- \[x\] All of them
> \- \[\] Windows
> \- \[\] macOS
> \- \[\] Linux
> \- \[\] Android
> \- \[\] iOS

---

<div class="post-metadata">

**Author:** ![zavalit](https://avatars.discourse-cdn.com/v4/letter/z/90ced4/32.png) [@zavalit](https://discourse.threejs.org/u/zavalit)\
**Post date:** [August 17, 2023, 11:23am UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/13 "2023-08-17T11:23:22Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![dubois](https://avatars.discourse-cdn.com/v4/letter/d/e9c0ed/32.png) [@dubois](https://discourse.threejs.org/u/dubois)\
**Post date:** [August 17, 2023, 7:37pm UTC](https://discourse.threejs.org/t/is-three-js-cheating-with-depth-test/55026/14 "2023-08-17T19:37:10Z")

</div>

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 😃
