Is it possible to flatten an object in the depth buffer?

Is it possible to manipulate the depth buffer to make a 3D object behave the same way as a flat plane?

For example, if you had a mesh and something in front of it, make it so that it was possible to position them in roughly the same z position in the scene but not have the mesh behind push through the object in front?

This can be done by clearing the depth buffer but clearing the buffer applies to the entire scene. To keep the effect isolated to a couple of objects, would it be possible to set a constant depth buffer value for an object or compress its depth buffer range?

It looks like the depth values are calculated in depth_frag-glsl.js:

How would I pass a material property into that shader to tell it how to render the object’s depth values, for example, material.depthScale = 0.01 and then in the shader, it would check if depthScale was set and if it was, compress the depth values to 0.01x the scale or even use a constant value like the object’s scene z-position and ignore the vertex/fragment positions.

Yes, you can do this inside the vertex shader.

Maybe you can use Object3D.renderOrder here?

Do you know where the renderOrder overrides the depth buffer in ThreeJS? It renders opaque objects first then transparent and it sorts those lists by different parameters. So setting renderOrder should push an object forward in the sorted lists but where does the renderOrder property on an opaque object render it in front of a transparent one?

if ( opaqueObjects.length ) renderObjects( opaqueObjects, scene, camera );
// transparent pass (back-to-front order)
if ( transparentObjects.length ) renderObjects( transparentObjects, scene, camera );

If transparent objects are always rendered after opaque and a transparent object is further forward, how does an opaque object with a higher renderOrder get rendered in front?

It seems if you have a transparent object in front of an opaque one e.g red cube behind transparent plane and disable depthWrite on the front object, the renderOrder doesn’t have any effect as they are sorted in separate lists:

var materialt = new THREE.MeshStandardMaterial({color:0xFF0000});
var geometryt = new THREE.BoxBufferGeometry(100, 100, 100);
var object = new THREE.Mesh(geometryt, materialt);
object.renderOrder = 1;

var materialp = new THREE.MeshStandardMaterial({transparent:true, opacity:0.5, depthWrite:false});
var geometryp = new THREE.PlaneBufferGeometry(200, 200, 1);
var object2 = new THREE.Mesh(geometryp, materialp);
object2.position.z = 100;

If you set the transparent:true property on the opaque object, the renderOrder property works ok.

If I had the plane in the middle of the cube (z-position = 0) and wanted to render that on top, setting object2.renderOrder = 1 doesn’t render it on top unless I set depthWrite:false on the cube but that causes some rendering issues with other objects.

As mentioned in the documentation, you can’t do this with Object3D.renderOrder:

This value allows the default rendering order of scene graph objects to be overridden although opaque and transparent objects remain sorted independently.

2 Likes

Do you know which vertex shader renders into the depth buffer? I tried depth_vert.glsl.js but changing this doesn’t seem to have any effect.

What I’d like to do is modify the vertices of an object when it gets rendered into the depth buffer.

1 you probably need to add gl_Position.z = …const; right before }

2 not in depth_vert.glsl.js but in your material.onBeforeCompile = function (tsk) {
// here
tsk.vertexShader = …

@adevart

Writing a custom shader is a bit more pain that you seem to think, it’s fun too. There are a bunch of tutorials on that, I would recommend checking out the bookshelf

1 Like