3D Collision Detection

Recommendation: Use the NSDT scene editor to quickly build a 3D application scene

axis-aligned bounding box

Like 2D collision detection, Axis Aligned Bounding Box  (AABB) is the fastest algorithm for determining whether two game entities overlap. This involves wrapping the game entity in a non-rotated (and thus axis-aligned) box, and checking the position of those boxes in 3D coordinate space to see if they overlap.

Two 3-D non-rectangular objects floating in space, surrounded by a virtual rectangular box.

There are axis alignment constraints for performance reasons . The overlapping area between two non-rotated boxes can be checked only by logical comparison, while rotated boxes require additional trigonometric operations, which are computationally slow. If you have entities that will be rotated, you can either modify the dimensions of the bounding box so that it still wraps around the object, or choose to use a different bounding geometry type, such as a sphere (invariant to rotation). The animated GIF below shows an example of a graphic of an AABB resizing to fit a rotating entity. The box is constantly changing dimensions to fit snugly to the entities contained within.

Animated rotation nodes showing a virtual rectangular box that shrinks and grows as the node within it rotates.  The box does not rotate.

Note: Check out  the article Bounding volume collision detection with THREE.js  for a practical implementation of this technique.

Point vs. AABB

Checking whether a point is within the AABB is very simple - we just need to check if the point's coordinates are within the AABB; consider each axis separately. If we assume that P  x , P  y  and  P z  are the coordinates of the points, and B minX–B  maxX , B minY–B  maxY  and B  minZB  maxZ  are the ranges for each axis of the AABB, we can calculate the difference between the two using Whether there is a collision between:

or in JavaScript:

.JS copied to clipboard

function isPointInsideAABB(point, box) {
  return (
    point.x >= box.minX &&
    point.x <= box.maxX &&
    point.y >= box.minY &&
    point.y <= box.maxY &&
    point.z >= box.minZ &&
    point.z <= box.maxZ
  );
}

AABB vs. AABB

Checking whether one AABB intersects another AABB is similar to a point test. We only need to do one test per axis using the bounds of the box. The image below shows the test we will perform on the X axis - basically, do the ranges A minX–A maxX and B  minX–B  maxX  overlap?

Hand drawing of two rectangles showing the upper right corner of A overlapping the bottom left corner of B, as A's largest x coordinate is greater than B's smallest x coordinate.

Mathematically, this looks like this:

In JavaScript, we would use this:

.JS copied to clipboard

function intersect(a, b) {
  return (
    a.minX <= b.maxX &&
    a.maxX >= b.minX &&
    a.minY <= b.maxY &&
    a.maxY >= b.minY &&
    a.minZ <= b.maxZ &&
    a.maxZ >= b.minZ
  );
}

bounding sphere

Using a bounding sphere to detect collisions is slightly more complicated than AABB's, but still fairly quick to test. The main advantage of spheres is that they are invariant to rotation, so if the wrapped entity is rotated, the bounding sphere will still be the same. Their main downside is that unless the entity they're wrapping is actually spherical, wrapping is usually not a good fit (i.e. wrapping a person with a bounding sphere would result in a lot of false positives, whereas AABB would be a better match) .

point and sphere

To check if a sphere contains a point, we need to calculate the distance between the point and the center of the sphere. If this distance is less than or equal to the radius of the sphere, the point is inside the sphere.

Freehand 2D projections of spheres and points in a Cartesian coordinate system.  The point is in the lower right corner of the circle.  The distance is represented by a dashed line, labeled D, from the center of the circle to the point.  The lighter line shows the radius from the center of the circle to the circle boundary, labeled R.

Considering   the Euclidean distance between two points A  and  B is

Our point to sphere collision detection formula will look like this:

or in JavaScript:

.JS copied to clipboard

function isPointInsideSphere(point, sphere) {
  // we are using multiplications because is faster than calling Math.pow
  const distance = Math.sqrt(
    (point.x - sphere.x) * (point.x - sphere.x) +
      (point.y - sphere.y) * (point.y - sphere.y) +
      (point.z - sphere.z) * (point.z - sphere.z),
  );
  return distance < sphere.radius;
}

NOTE: The code above has square roots which can be expensive to compute. A simple optimization to avoid this involves comparing the squared distance to the squared radius, so the optimization equation would involve .distanceSqr < sphere.radius * sphere.radius

Sphere vs. Sphere

The Sphere vs. Sphere test is similar to the Point vs. Sphere test. What we need to test here is that the distance between the centers of the spheres is less than or equal to the sum of their radii.

Freehand drawing of two partially overlapping circles.  Each circle (different sizes) has a light radius line from its center to its border, labeled R.  The distance is represented by a dashed line, labeled D, connecting the center points of the two circles.

Mathematically, this looks like:

or in JavaScript:

.JS copied to clipboard

function intersect(sphere, other) {
  // we are using multiplications because it's faster than calling Math.pow
  const distance = Math.sqrt(
    (sphere.x - other.x) * (sphere.x - other.x) +
      (sphere.y - other.y) * (sphere.y - other.y) +
      (sphere.z - other.z) * (sphere.z - other.z),
  );
  return distance < sphere.radius + other.radius;
}

Sphere vs. AABB

Testing whether a sphere and an AABB collide is slightly more complicated, but still quick and easy. A logical approach would be to examine each vertex of the AABB, doing a point versus sphere test for each vertex. However, this is overkill - testing all vertices is unnecessary, since we just need to calculate the distance between the closest point of the AABB (not necessarily a vertex) and the center of the sphere to see if it is less than or equal to the radius of the sphere. We can get this value by clamping the center of the sphere to the limits of the AABB.

Draw a square by hand, partially overlapping the top of the circle.  The radius is represented by a light line labeled R.  Distance line from the center of the circle to the closest point of the square.

In JavaScript, we would do this test like this:

.JS copied to clipboard

function intersect(sphere, box) {
  // get box closest point to sphere center by clamping
  const x = Math.max(box.minX, Math.min(sphere.x, box.maxX));
  const y = Math.max(box.minY, Math.min(sphere.y, box.maxY));
  const z = Math.max(box.minZ, Math.min(sphere.z, box.maxZ));

  // this is the same as isPointInsideSphere
  const distance = Math.sqrt(
    (x - sphere.x) * (x - sphere.x) +
      (y - sphere.y) * (y - sphere.y) +
      (z - sphere.z) * (z - sphere.z),
  );

  return distance < sphere.radius;
}

use physics engine

3D physics engines provide collision detection algorithms, most of which are also based on bounding volumes. The way a physics engine works is to create a physical body , usually attached to its visual representation. This body has properties such as velocity, position, rotation, torque, etc., as well as a physical shape . This shape is what is considered in collision detection calculations.

Original Link: 3D Collision Detection (mvrlink.com)

Guess you like

Origin blog.csdn.net/ygtu2018/article/details/132584224