Recommended: Use
NSDT scene editor
Quickly build 3D application scenes
Using Box3 and Sphere
三.js has objects representing mathematical volumes and shapes – for 3D AABBs and bounding spheres we can use Box3
and Sphere
object. Once instantiated, they have methods that can be used for intersection testing against other volumes.
Instance box
To create a Box3
instance we need to provide the lower and upper limits of the box. Typically, we want this AABB to be “linked” to an object (such as a character) in our 3D world. In Three.js, instances have the properties and bounds of an object. Remember that in order to define this property you need to call it manually beforehand. GeometryboundingBoxminmaxGeometry.computeBoundingBox
.JS copied to clipboard
const knot = new THREE.Mesh( new THREE.TorusKnotGeometry(0.5, 0.1), new MeshNormalMaterial({}), ); knot.geometry.computeBoundingBox(); const knotBBox = new Box3( knot.geometry.boundingBox.min, knot.geometry.boundingBox.max, );
Note: This property takes itself as a reference, not . Therefore, any transformations (such as scale, position, etc.) applied to will be ignored when calculating the calculation box. boundingBoxGeometryMeshMesh
A simpler alternative to the previous problem is to set these bounds later using , which will calculate the dimensions taking into account theTransformandAny subgrid. Box3.setFromObject
.JS copied to clipboard
const knot = new THREE.Mesh( new THREE.TorusKnotGeometry(0.5, 0.1), new MeshNormalMaterial({}), ); const knotBBox = new Box3(new THREE.Vector3(), new THREE.Vector3()); knotBBox.setFromObject(knot);
Instanced sphere
Instantiating a Sphere
object is similar. We need to provide the center and radius of the sphere, which can be added to the properties available in . boundingSphereGeometry
.JS copied to clipboard
const knot = new THREE.Mesh( new THREE.TorusKnotGeometry(0.5, 0.1), new MeshNormalMaterial({}), ); const knotBSphere = new Sphere( knot.position, knot.geometry.boundingSphere.radius, );
Unfortunately, there is no equivalent Sphere instance. Therefore, if we apply a transformation or change the position, we need to update the bounding sphere manually. For example: Box3.setFromObjectMesh
.JS copied to clipboard
knot.scale.set(2, 2, 2); knotBSphere.radius = knot.geometry.radius * 2;
Cross test
Points and Box3
/ Sphere
Both have a include dot
method to perform this test. Box3Sphere
.JS copied to clipboard
const point = new THREE.Vector3(2, 4, 7); knotBBox.containsPoint(point);
Box3
and Box3
The Box3.intersectsBox
method can be used to perform this test.
.JS copied to clipboard
knotBbox.intersectsBox(otherBox);
Note: This is different from checking whether Box3 completely wraps another. Box3.containsBox
Sphere
and Sphere
Similar to before, there is a Sphere.intersectsSphere
method to perform this test.
.JS copied to clipboard
knotBSphere.intersectsSphere(otherSphere);
Sphere
and Box3
Unfortunately, this test is not implemented in Three.js, but we can patch Sphere to implement the Sphere and AABB intersection algorithm.
.JS copied to clipboard
// expand THREE.js Sphere to support collision tests vs. Box3 // we are creating a vector outside the method scope to // avoid spawning a new instance of Vector3 on every check THREE.Sphere.__closest = new THREE.Vector3(); THREE.Sphere.prototype.intersectsBox = function (box) { // get box closest point to sphere center by clamping THREE.Sphere.__closest.set(this.center.x, this.center.y, this.center.z); THREE.Sphere.__closest.clamp(box.min, box.max); const distance = this.center.distanceToSquared(THREE.Sphere.__closest); return distance <this.radius * this.radius; };
Demo
We have prepared some live demos to demonstrate these techniques and provide source code to examine.
- Points and boxes and spheres
- Box vs. Box and Sphere
- Sphere vs. box and sphere
Use BoxHelper
As an alternative to using raw and object, Three.js has a useful object that makes handling bounding boxeseasier:BoxHelper
(formerly Deprecated). This helper obtains and computes the bounding box volume (including its subgrids) for it. This will generate a new box representing the bounding box, which shows the shape of the bounding box, and can be passed to the method seen previously to make the bounding box the same as .Box3SphereBoundingBoxHelperMeshMeshsetFromObjectMesh
BoxHelper
is the recommended way to handle 3D collision of bounding volumes in Three.js. You’ll miss out on orb testing, but the trade-off is well worth it.
The advantages of using this helper are:
- It has a method that if the linked grid rotates or changes its dimensions, it will resize its bounding box grid and update its position.
update()
- It takes subgrids into account when calculating the size of the bounding box, so the original grid and all itssubgrids are wrapped.
- We can easily debug collisions byrendering the created es. By default, they are created using materials (tri.js materials for drawing wireframe style geometry).
MeshBoxHelperLineBasicMaterial
The main disadvantage is that it only creates a box bounding volume, so if you need a sphere to test with AABB, you need to create your own object. Sphere
To use it, we need to create a new instance and provide the geometry and (optionally) the color that will be used for the wireframe material. We also need to add the newly created object to the scene in order to render it. We assume our scene variable is called. BoxHelperthree.jsscene
.JS copied to clipboard
const knot = new THREE.Mesh( new THREE.TorusKnotGeometry(0.5, 0.1), new THREE.MeshNormalMaterial({}), ); const knotBoxHelper = new THREE.BoxHelper(knot, 0x00ff00); scene.add(knotBoxHelper);
To also have our actual bounding box, we create a new object and give it the shape and position of . Box3Box3BoxHelper
.JS copied to clipboard
const box3 = new THREE.Box3(); box3.setFromObject(knotBoxHelper);
If we change position, rotation, scale, etc., we need to call this method so that the instance matches its link. We also need to call it again to make .Meshupdate()BoxHelperMeshsetFromObjectBox3Mesh
.JS copied to clipboard
knot.position.set(-3, 2, 1); knot.rotation.x = -Math.PI / 4; // update the bounding box so it stills wraps the knot knotBoxHelper.update(); box3.setFromObject(knotBoxHelper);
The way to perform collision testing is the same as explained in the previous section – we use Box3 objects in the same way as above.
.JS copied to clipboard
// box vs. box box3.intersectsBox(otherBox3); // box vs. point box3.containsPoint(point.position);
Demo
You can view both demos on our live demos page. The first shows the use of . The second performs box-to-box testing. BoxHelper
Original link: Boundary volume collision detection using THREE.js (mvrlink.com)