Hide obj when camera is behind

Hey, I found this SO thread which describes the same issue I have: A 3d room with seperated wall. I want them to be hidden when the camera is orbiting behind the wall and reappear when the front is visible again. Demo jsFiddle here

I tried to implement the solution found in the thread using the onBeforeRender and onAfterRender functions, but I cant get it to work. Its never firing the return onBeforeRender function

    // Container
    this.obj = new THREE.Object3D()
    this.obj.name = 'wall.obj3D'
    // Wall cuboid
    this.geometry3D = new THREE.BoxGeometry(this.ctrl.w, this.ctrl.h, this.ctrl.d)
    // Alter pivot
    this.geometry3D.applyMatrix(new THREE.Matrix4().makeTranslation(+(this.ctrl.w / 2), -(this.ctrl.h / 2), -(this.ctrl.d / 2)))

    this.mesh = new THREE.Mesh( this.geometry3D , Color.wallMaterial(this.color))
    this.mesh.name = 'wall'
    this.obj.add(this.mesh)

    let onBeforeRender = () => {

        let v = new THREE.Vector3()
    
        return function ( renderer, scene, camera, geometry, material, group ) {
            
            if ( v.subVectors( camera.position, this.parent.position ).dot( this.parent.position.clone().normalize() ) > 0 ) {
    
                geometry.setDrawRange( 0, 0 ) 
            }
        }
    }
    
    let onAfterRender = ( renderer, scene, camera, geometry, material, group ) => {
    
        geometry.setDrawRange( 0, Infinity )
    }

    this.mesh.onBeforeRender = onBeforeRender
    this.mesh.onAfterRender = onAfterRender

Any other approach is welcomed as well
Thanks a lot!

Um, the fiddle seems to work quite well. onBeforeRender() is actually called.

Oh sorry, the fiddle is just a demo of what I want. I try to copy this solution from the fiddle. Going to make a fiddle of my version too.

Instead of

let onBeforeRender = () => {

    let v = new THREE.Vector3()

    return function ( renderer, scene, camera, geometry, material, group ) {
        
        if ( v.subVectors( camera.position, this.parent.position ).dot( this.parent.position.clone().normalize() ) > 0 ) {

            geometry.setDrawRange( 0, 0 ) 
        }
    }
}

I had to do

let onBeforeRender = ( renderer, scene, camera, geometry, material, group ) => {

   let v = new THREE.Vector3()

   if ( v.subVectors( camera.position, this.obj.position ).dot( this.obj.position.clone().normalize() ) > 0 ) {

       geometry.setDrawRange( 0, 0 ) 
   }
}

You can wrap your first function in

const foo = ( 
  ()=> function(){} 
)()

And it will work as well, this isn’t at all three.js or onbeforerender related. Do you understand what your first function does, and what the second?

You’re right. Im just not that good with js syntax. The first function is anonymous and stored in a variable. The vector is made and then its returning the actual onBeforeFunction also anonym.
Whats the benefit using return?

You do not want to create the vector v on each invocation of onBeforeRender(). By using a closure (or IIFE), it’s created just once and then reused in the inner code. Object creation and the respective GC overhead are expensive operations in JavaScript. The idea is to avoid object creation in your rendering loop and dependent code as much as possible.

1 Like

Good point ^

I didn’t even look at the logic inside, just why it wasn’t firing. Before, three would invoke the callback, and you’d just create a new vector and a new function every time. I’m not sure but i think that this would eventually leak.

This is a common pattern with three.js:

function distanceBetweenTwoVectors( a, b){
  //return a.sub(b).length() //not good because you mutated a
  return new Vector3().subVectors(a,b).length() //not good because you create a new vector each time you do the operation
}

Three solves it:

function distanceBetweenTwoVectors(){
  const cachedVector = new THREE.Vector3()
  return function(a,b){
    return cachedVector //<-- only available in this scope
      .subVectors(a,b).length()
  }
}

const myFunction = distanceBetweenTwoVectors() //this actually creates the function (and caches that inside vector ONCE)
myFunction(myA, myB) //returns length between a and b

Yes but thats not all that is happening. It’s an IIFE or an immediately invoked function expression meaning that with that extra set of parenthesis you call and evaluate it right then and there. You get he inside function that the anonymous one returns, and you lose the scope in the closure.

1 Like

Ah nice, so basicly you’re making an instance of your function, which invokes and holds the vector3 and then reuse its return function for calculation/setting the vector.

I know the IIFE, but why do I need it here? Is mesh.onBeforeRender = ()=> { ... } not going to set the function and mesh has something like if( onBeforeRender ) onBeforeRender() ?

1 Like

I think that this is not technically an instance, you could create several instances with a function that returns a function. But this is rather philosophical for me :slight_smile:

I didn’t understand the last question.

I just asked why it has to be immediately invoked? I thought its a Function variable that is called instead of being self executed, before each draw, like if( onBeforeRender ) onBeforeRender().

The function you return inside the closure is called each time. Not the closure itself. I suggest you debug this to better understand the related processes.

1 Like

Ah now I get it! Thanks

Try putting a debugger statement right below where you make your vector, and one inside the function being returned. Trust me, do this :slight_smile: it will become obvious what is going on.