Add single mesh to octree

Hello, I am trying to individually add meshes to octrees and I seem to be reaching an error:

If I run scene.createOrUpdateSelectionOctree() I can easily add all meshes to the octree, but I would rather have a custom octree, not necessarily tied to all meshes in a scene but rather specific ones for my collision detection that I am making.

1 Like

addMesh is used here:

2 Likes

If you want to create a Octree by hand, you need to:

  • pass a valid “onCreate” function to the Octree constructor
  • call octree.update to create the octree partition

For eg:

3 Likes

That is really awesome. I appreciate you taking the time to explain that. I tried creating a collision without the use of a ray, and my plan was to use .intersects with meshes. However, upon further look it appears .intersects only works specifically with spheres. And not just any type of sphere, but one must provide a sphereCenter and sphereRadius. Do you know what exactly one would use this functionality for?

I come from Three JS where I was using their built in Octree system. In their octree system, we can just pass in the capsule or sphere without further details. It appears with three JS, one can access the center and radius of a sphere by simply using sphere.center and sphere.radius. I assumed I could do the same with a sphere in babylon js, so I checked all properties on sphere and saw no prototype or property that could be used to access center and radius. While I could find a way to calculate these values, but I am now wondering if I am going about the intersects functionality correctly.

Do you know how I could detect this sphere with the custom octree we just built? Thank you

EDIT: I think I see the issue, I may need to work with a new BoundingSphere. I’m looking into this still.

Apologies for double post, but I am a bit confused with my findings.

I ended up getting the radius and center of a sphere with getBoundingInfo(), so I went ahead and put it into intersects property of octree and received something completely unexpected, the same thing I got above when I implemented it incorrectly:

I ensured my ground was part of the octree, but my sphere is not. I ran the intersects command:
const intersectionTest = octree.intersects(sphereDetails.center, sphereDetails.radius, true);

and swapped out true/false for the third parameter to see if anything would change. However, my return is always this:
image
The response is always a different id, but length and data is always empty/0. I assumed maybe the length is 0 because the circle is already intersecting with mesh, so I increased y position and it was still returning the same results. I even tried to run the octree.update command after importing ground to octree to see if that would help, but nothing. Any advice?

Actually, my first example was a bit misleading because the creation callback you pass to the Octree constructor must populate the block.entries array if the mesh intersects the block!

The easiest way to do it is to simply reuse the existing implementation from Octree: Octree.CreationFuncForMeshes

Your corrected PG:

2 Likes

That is very helpful, thank you. I see with collisions we are passed back a “length” property that specifies how many meshes we will receive in the data category. Depending on the collision type, sometime we receive 4 (slight collision) and sometime 8 (colliding at middle of sphere). If no collision it’s always 0.

However, I added a new item to the octree and things have started to change:

image

As you can see, I have a sphere in-between two planes. My length is 0 and my data is also 0. This was expected because my sphere is not colliding with either plane. However, look what happens when I collide with top plane:

image

My length and data is empty/0. I was actually expecting the length and data to contain properties pertaining to intersected mesh in octree (top plane). Now watch what happens when the sphere collides with the bottom plane:

image

My data and length goes to 16. When we go through the data array, we can see a mix of “box” and “ground” values. I’m interpreting this as the octree believes the intersection took place between both box and ground. If I set the true parameter to false, we can avoid all the repetitive duplicates. But this leads me to more questions.

Why is the last playground returning data for intersections pertaining to both top and bottom plane?
What exactly are the duplicate items for?

Assuming I’m doing something incorrectly, I was ultimately hoping to use octree intersections for grabbing the intersection coordinates, normals at the point of intersection, and distance from where it took place. I was hoping to use these values for a better collision detection system that would potentially work with custom meshes. Is there something I’m missing?

I appreciate all responses.

There’s a misunderstanding here, octree.intersects returns an array of objects that (may) collide with the bounding sphere passed in parameter (center + radius). That is, it finds the blocks of the octree that collide with the sphere and it returns the meshes that are in these blocks. So, length is simply the length of the mesh array, not a measure of the “collisionness”.

You should probably not pass true for the 3rd parameter of octree.intersects, as doing so will duplicate several times the same mesh in the result array, as a mesh can intersect multiple blocks of an octree.

Also, 0.1 is not valid for the maxDepth parameter of the octree constructor, as it is a maximum recursive depth: it should be an integer number. Passing 0.1 means that the octree will never be subdivided and will always have only 8 blocks, which defeats the purpose of using an octree.

Another important thing is that octree.update(worldExtends.min, worldExtends.max, []); should be called with an up-to-date worldExtends object, i.e. some extends that encompasses all the objects of the scene you want to put in the octree. So, you should do it after you create the meshes in the scene, not before.

Lastly, a block of the octree is subdivided into 8 smaller blocks only if the number of entries (meshes in your case) is greater than the max capacity value you passed at construction time.

You have a 0 length because you computed worldExtends before adding the ground and the box to the scene, so they are not in the octree extends. If you fix the code, then the result array is not empty anymore:

Again, there’s a misunderstanding of what the Octree structure will do. It won’t tell you if a mesh intersects with another mesh, it will tell you which meshes are contained in the block(s) of the octree structure that intersect a given bounding sphere, given the sphere center and radius.

It’s an acceleration structure that helps finding meshes which are located around an area in space (defined by a bounding sphere). Note that’s not because a mesh is returned by the intersects method that it really intersects the bounding sphere you passed to intersects! The blocks in the octree are cube blocks, so it’s possible that a bounding sphere intersects a cube without intersecting one or multiple meshes that are contained in this block.

The octree described above will not allow you to do this, as I hope the previous comments have helped you understand.

There’s also the possibility to use an octree for collision and picking detection, as explained in the doc: Optimizing With Octrees | Babylon.js Documentation

It is applicable to a single mesh and should be used only if your mesh is really complex, to avoid checking every faces when looking for an intersection, and instead relying on the octree to eliminate faces that are too far from the testing point to collide. But I’m not sure it is your use case.

You should look for this forum if you want some pointers on how to optimize collisions, there have been a number of threads on the subject I think.

I hope this clarifies things a bit.

1 Like