How to Check if Mesh Ancestor is Visible in Canvas?

So what I am trying to achieve is :
let’s say we have a hierarchy structure as show below,

Here I have show only two level to simplify this, but it could be more.

So Now let say, via code I traverse and hide the Main Group (The Red Dot),
so in its data visible is set to false and in canvas all objects are hidden.

Now using the Raycaster from THREE.Js If I click in canvas it will return Mesh1 or Mesh2 (Depends upon on which Item I tried to click).

But what I want is to ignore the mesh if it’s hidden in the canvas. But since mesh data says that, visible= true.

So I can’t use that to ignore it (Oh I forgot I have a recursive function which go through the list of Items raycaster hits and ignore based on such conditions).

Yes, one solution would be to set all child’s, to false for its visible when we are doing to parent via traversing. But there is a certain use case I have the way it works now … So I can’t do that either.

Is there any parameter which allows me to know its current visibility, or how would you implement this.

Thank you
SeeOn

Do you mean to have the raycaster not intersect certain objects set to visible = false? Why not setup an array where you push and remove the objects you need / do not need and raycast against the said array, instead of raycasting all objects? The intersects array can be dynamic…

No, basically ignore its child. Let’s say in above Main group is set its Visible to false … so it will hide it’s all children visually in canvas as well … but those children will still have visible to true in their data. Even thought they are not visible in canvas.

I am using the method you suggested, not for this purpose. I do have mesh names like shadow,glass and so in array which I use with raycaster to ignore.

I am not using this with method for all because … there are lots for import of external model at different requirement and all have levels for hierarchy so if I would add new mesh to this dynamic Array (coz also need to track what I imported with their children names) It would be tedious to remove later when I completely delete this Item from scene.

So I was thinking there would be some other approach.

So other thought which came in mind is whenever I click in canvas if lets say mesh1 got selected
so I can traverse upward to its parent and till I find a parent whose visible set to false.

If I found one I will Ignore this mesh 1.

But issue is it will work for any click I do and traverse till root node if no parent is hidden. Which look totally unnecessary.

try using intersecObject with recursive flag set to false, look here.
to your latest question, yes you can use traverseAncestors which traverses the objects parents upwards…

a cheap way to know if a mesh is visible is to check onBeforeRender, which is only called when the object is actually being rendered out. this applies to both the “visible” prop on the object itself or any ancestor, as well if the object is within the cameras frustum or not (three occludes it if it isn’t).

this is pseudo-code:

function renderloop() {
  const isVisible = false
  mesh.onBeforeRender = () => (isVisible = true)
  gl.render(scene, camera)
  if (isVisible) console.log("mesh was visible")

a while ago i made this into a re-usable with an onChange callback if visibility changes. i use it for all sorts of things to test visibility without expense or having to calculate frustum every frame.

i tried if it would also work for your use case it seems to do ok: awesome-faraday-wp2h3h - CodeSandbox

change line 43 <group visible={false}> to true and the objects below will start to catch events again. the code is react, and i wouldn’t know how to even approach that in vanilla but perhaps it gives you an idea. in my opinion climbing up the entire ancestor tree on every event doesn’t seem like a good solution, it would only create overhead that grows with the scale of the app.

2 Likes

@drcmda this tip seems very usefull, thanks for sharing!

it worked exactly the way I wanted :heart_eyes:… had to play around with promises with setTimeout due to delay in updating the value.

Thank you so much @drcmda