collisionPairs method

  1. @override
void collisionPairs(
  1. World world,
  2. List<Body> pairs1,
  3. List<Body> pairs2
)
override

Get all the collision pairs in the physics world

Implementation

@override
void collisionPairs(World world, List<Body> pairs1, List<Body> pairs2) {
  final N = world.bodies.length;
  final bodies = world.bodies;
  final max = aabbMax;
  final min = aabbMin;
  final nx = this.nx;
  final ny = this.ny;
  final nz = this.nz;

  final xstep = ny * nz;
  final ystep = nz;
  const zstep = 1;

  final xmax = max.x;
  final ymax = max.y;
  final zmax = max.z;
  final xmin = min.x;
  final ymin = min.y;
  final zmin = min.z;
  final xmult = nx / (xmax - xmin);
  final ymult = ny / (ymax - ymin);
  final zmult = nz / (zmax - zmin);
  final binsizeX = (xmax - xmin) / nx;
  final binsizeY = (ymax - ymin) / ny;
  final binsizeZ = (zmax - zmin) / nz;

  final binRadius = math.sqrt(binsizeX * binsizeX + binsizeY * binsizeY + binsizeZ * binsizeZ) * 0.5;
  final bins = this.bins;
  final binLengths = this.binLengths;
  final nBins = this.bins.length;

  // Reset bins
  for (int i = 0; i != nBins; i++) {
    binLengths[i] = 0;
  }

  void addBoxToBins(double x0, double y0,double z0,double x1,double y1,double z1,Body bi) {
    int xoff0 = ((x0 - xmin) * xmult).floor();
    int yoff0 = ((y0 - ymin) * ymult).floor();
    int zoff0 = ((z0 - zmin) * zmult).floor();
    int xoff1 = ((x1 - xmin) * xmult).ceil();
    int yoff1 = ((y1 - ymin) * ymult).ceil();
    int zoff1 = ((z1 - zmin) * zmult).ceil();

    if (xoff0 < 0) {
      xoff0 = 0;
    } else if (xoff0 >= nx) {
      xoff0 = nx - 1;
    }
    if (yoff0 < 0) {
      yoff0 = 0;
    } else if (yoff0 >= ny) {
      yoff0 = ny - 1;
    }
    if (zoff0 < 0) {
      zoff0 = 0;
    } else if (zoff0 >= nz) {
      zoff0 = nz - 1;
    }
    if (xoff1 < 0) {
      xoff1 = 0;
    } else if (xoff1 >= nx) {
      xoff1 = nx - 1;
    }
    if (yoff1 < 0) {
      yoff1 = 0;
    } else if (yoff1 >= ny) {
      yoff1 = ny - 1;
    }
    if (zoff1 < 0) {
      zoff1 = 0;
    } else if (zoff1 >= nz) {
      zoff1 = nz - 1;
    }

    xoff0 *= xstep;
    yoff0 *= ystep;
    zoff0 *= zstep;
    xoff1 *= xstep;
    yoff1 *= ystep;
    zoff1 *= zstep;

    for (int xoff = xoff0; xoff <= xoff1; xoff += xstep) {
      for (int yoff = yoff0; yoff <= yoff1; yoff += ystep) {
        for (int zoff = zoff0; zoff <= zoff1; zoff += zstep) {
          final idx = xoff + yoff + zoff;
          bins[idx][binLengths[idx]++] = bi;
        }
      }
    }
  }

  // Put all bodies into the bins
  for (int i = 0; i != N; i++) {
    final bi = bodies[i];
    final si = bi.shapes[0];

    switch (si.type) {
      case ShapeType.sphere: {
        final shape = si as Sphere;
        // Put in bin
        // check if overlap with other bins
        final x = bi.position.x;
        final y = bi.position.y;
        final z = bi.position.z;
        final r = shape.radius;

        addBoxToBins(x - r, y - r, z - r, x + r, y + r, z + r, bi);
        break;
      }
      case ShapeType.plane: {
        final shape = si as Plane;

        if (shape.worldNormalNeedsUpdate) {
          shape.computeWorldNormal(bi.quaternion);
        }
        final planeNormal = shape.worldNormal;

        //Relative position from origin of plane object to the first bin
        //Incremented as we iterate through the bins
        final xreset = xmin + binsizeX * 0.5 - bi.position.x;

        final yreset = ymin + binsizeY * 0.5 - bi.position.y;
        final zreset = zmin + binsizeZ * 0.5 - bi.position.z;

        final d = _gridBroadphaseCollisionPairsD;
        d.set(xreset, yreset, zreset);

        for (int xi = 0, xoff = 0; xi != nx; xi++, xoff += xstep, d.y = yreset, d.x += binsizeX) {
          for (int yi = 0, yoff = 0; yi != ny; yi++, yoff += ystep, d.z = zreset, d.y += binsizeY) {
            for (int zi = 0, zoff = 0; zi != nz; zi++, zoff += zstep, d.z += binsizeZ) {
              if (d.dot(planeNormal) < binRadius) {
                final idx = xoff + yoff + zoff;
                bins[idx][binLengths[idx]++] = bi;
              }
            }
          }
        }
        break;
      }
      default: {
        if (bi.aabbNeedsUpdate) {
          bi.updateAABB();
        }

        addBoxToBins(
          bi.aabb.lowerBound.x,
          bi.aabb.lowerBound.y,
          bi.aabb.lowerBound.z,
          bi.aabb.upperBound.x,
          bi.aabb.upperBound.y,
          bi.aabb.upperBound.z,
          bi
        );
        break;
      }
    }
  }

  // Check each bin
  for (int i = 0; i != nBins; i++) {
    final binLength = binLengths[i];
    //Skip bins with no potential collisions
    if (binLength > 1) {
      final bin = bins[i];

      // Do N^2 broadphase inside
      for (int xi = 0; xi != binLength; xi++) {
        final bi = bin[xi];
        for (int yi = 0; yi != xi; yi++) {
          final bj = bin[yi];
          if (needBroadphaseCollision(bi, bj)) {
            intersectionTest(bi, bj, pairs1, pairs2);
          }
        }
      }
    }
  }

  makePairsUnique(pairs1, pairs2);
}