Three.js: InstancedMesh and computeBoundingBox

Created on 8 Jan 2020  路  11Comments  路  Source: mrdoob/three.js

Geometry bounding box gives a somewhat misleading result when used in an InstancedMesh.

    var count = 10000;

    var mesh = new THREE.InstancedMesh( geometry, material, count );

    var dummy = new THREE.Object3D();

    for ( var i = 0; i < count; i ++ ) {

        dummy.position.set(
        Math.random() * 20 - 10,
        Math.random() * 20 - 10,
        Math.random() * 20 - 10
    );

    dummy.updateMatrix();

    mesh.setMatrixAt( i, dummy.matrix );

    }

Using new Box3().setFromObject(mesh) only gives you the Box3 for the single geometry, and not for the whole instance.

Enhancement

Most helpful comment

SkinnedMesh case is a less visible glitch.
But yes, we should solve this at some point.

All 11 comments

With "whole instance" you mean an AABB that encloses all instances of InstancedMesh, right?

@Mugen87 Yes.

Similar to the conversation in https://github.com/mrdoob/three.js/pull/8953 about SkinnedMesh, I've been getting multiple issues reported on my viewer (https://github.com/donmccurdy/three-gltf-viewer/issues/147) because the viewport (determined with Box3().setFromObject(...)) does not factor in skinning deformations. Those deformations can be 100x for anything converted from FBX.

I'm not sure that geometry.boundingBox should be any different than it is now, but maybe either Box3 or the Mesh subclasses like InstancedMesh and SkinnedMesh should have some method to provide a better bounding box?

I think we have a design problem in the library since bounding volumes not only depend on pure geometry data. Classes like InstancedMesh or SkinnedMesh needs to be considered in order to compute proper AABBs and bounding spheres.

What bothers me is the fact that BufferGeometry.boundingBox and BufferGeometry.boundingSphere currently represent more or less useless bounding volumes in certain use cases right now. It would be great to find a solution that avoids this situation. Introducing bounding volumes on object level (and keeping the ones on geometry level) seems a bit of a workaround to me. Although it would be a pragmatic approach.

Classes like InstancedMesh or SkinnedMesh needs to be considered in order to compute proper AABBs and bounding spheres.

I agree -- there are cases even with just a mesh where being able to specify the bounding volume per-object rather than per-geometry would be beneficial. Materials can change the apparent bounds of geometry, as well, with custom vertex shaders, instancing, and displacement maps (which I also think don't work correctly at the moment).

I still think it's valuable to store the bounding volume on the geometry, though, to share the volume instances. Maybe the responsibility of checking for frustum intersection should shift to the objects? Should the Mesh class define an intersectsFrustum function that can be implemented by derivative classes? I think this would help with the problems mentioned here. Here's a simple example:

Mesh.prototype.intersectsFrustum = function ( frustum ) {

  var geometry = this.geometry;
  var box = this.boundingBox || geometry.boundingBox;
  return frustum.intersectsBox( box );

}

This would allow a bounding box to optionally be set on the Mesh to account for cases where the material changes the visual bounds of the shape. Of course raycasting would also have to be updated to support custom intersections if desired but that's already override-able.

I'm not sure about the best design right now. This needs some experimenting and studying. I think it's also worth to check how other engines solve this issue.

Actually,I do some tries about InstancedMesh's boudingBox and boundingSpere. In my program,I make two bounding that one represents geometry data and other represents the mesh's real volume. I use mesh's real volume to render sort ,which make transparent rendering isn鈥榯 right in some cases. I think maybe the method of sorting return Z should also be encapsulated under the subclass of mesh, such as instancedmesh, to make correct calculation and sorting according to different situations. These are just some of my thoughts,I hope useful.

@Mugen87

I'm not sure about the best design right now. This needs some experimenting and studying. I think it's also worth to check how other engines solve this issue.

I can appreciate that. I do think it's worth noting that the design pattern chosen for raycast affords the type of flexibility we're talking about here, though. Because it's defined on Object3D rather than Ray the object has control over how to perform the raycasting and handle dependencies on material, shader, and render primitive. We'd be running into a similar situation if instead of Object3D.raycast we used Ray.intersectObject, I think. The Frustum.intersectsObject API feels a little inconsistent at the moment.

_Edit:_ Box3.setFromObject likely suffers from similar issues.

As a (temporary?) workaround I changed frustumCulled to false by default. https://github.com/mrdoob/three.js/pull/18464

As a (temporary?) workaround I changed frustumCulled to false by default. #18464

Should the same temporary fix be done for SkinnedMesh, as well? It suffers from the same problem.

Also I do hope this is just temporary and that we can come up with a better solution for frustum culling and raycasting in these cases.

SkinnedMesh case is a less visible glitch.
But yes, we should solve this at some point.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zsitro picture zsitro  路  3Comments

filharvey picture filharvey  路  3Comments

danieljack picture danieljack  路  3Comments

scrubs picture scrubs  路  3Comments

makc picture makc  路  3Comments