Always render an custom mesh on top?

Greetings,

I have been searching for this issue for quite a long time. I am looking for a way to always set my GLTF mesh on top of everything. I am familiar with quite a few tactics

  • depthWrite, depthTest
  • custom layers, one for model and one for scene
  • using an invisible box, setting render to 999, then adding mesh and setting render to 999 (must tap into onBeforeRender hooks)

All of these solutions are not really ideal. depthWrite renders the mesh out of order. The layers and invisible box have different challenges. I couldn’t utilize layers for my mesh because I needed my mesh to use an environmentMap, which was providing some additional challenges due to the unique ways I had it set up. The final solution almost works, but it involves transparent objects always rendering on top, and any sprites I strike at an intersection also end up being on top of everything.

Is there a way I could implement a mesh always on top based through GLSL? I would love to understand how this would work if possible.

const material = new THREE.ShaderMaterial({
  uniforms: {},
  vertexShader: `
    void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    void main() {
      gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    }
  `,
});

I understand this would not work but I believe gl_Position could be changed ever so slightly to make this work correctly. However, I’m also thinking it might be outside of the scope of what is provided by three to us in GLSL (local space, world space, etc). I am also open to any other possibilities of always rendering a mesh on top.

Feel free to let me know your thoughts.

Render the scene without that special object. Clear the depth buffer. Render only the object. This is pure Three.js, no custom shaders involved.

1 Like

Something like this? It isn’t working right off the bat but I will try eliminating some of my settings to ensure bare bones this works/doesn’t work.

    renderer.render(gun, camera);
    renderer.renderer.clearDepth();
    renderer.render(scene, camera);

If I do the scene first then gun object, I get a black screen.

renderer.autoClear=false;


function animate(){
requestAnimationFrame(animate);
renderer.clear();
renderer.render(scene, camera);
renderer.clearDepth();
renderer.render(gun, camera);
}

You want to display gun top because he goes through walls?

2 Likes

It’s because by default autoClear is true (so render will clear the buffers before rendering). Set it to false as in @Chaser_Code’s code.

Yes. I like this solution, but it does take away all lighting from the object, meaning I would have to give it it’s own lighting. Is there a way I could somehow do this effect while still using the same lighting from the scene?

edit: Also takes away from any transparency I’m using on said object

First solution - raycast from gun to screen center. If intersection then rotate gun down.
Second solution - decrease weapon scale and hands and move close to camera to make it no small looking its uses in triple A games too.

2 Likes

Amazing solution on making the hands smaller. I just implemented this and it worked much better than I had anticipated. I have been looking for the most streamlined solutions that will be easiest for three js to render. This way I am avoiding layers, adding additional lighting or using raycasting. Deeply appreciated.

1 Like