Пример #1
0
  protected void splitMesh(
      final Mesh mesh, final int sectionStart, final int sectionEnd, final boolean doSort) {
    _mesh = makeRef(mesh);

    // Split range in half
    final int rangeSize = sectionEnd - sectionStart;
    final int halfRange = rangeSize / 2; // odd number will give +1 to right.

    // left half:
    // if half size == 1, create as regular CollisionTree
    if (halfRange == 1) {
      // compute section
      final int section = sectionStart;

      // create the left child
      _left = new CollisionTree(_type);

      _left._primitiveIndices = new int[mesh.getMeshData().getPrimitiveCount(section)];
      for (int i = 0; i < _left._primitiveIndices.length; i++) {
        _left._primitiveIndices[i] = i;
      }
      _left._mesh = _mesh;
      _left.createTree(section, 0, _left._primitiveIndices.length, doSort);
    } else {
      // otherwise, make an empty collision tree and call split with new range
      _left = new CollisionTree(_type);
      _left.splitMesh(mesh, sectionStart, sectionStart + halfRange, doSort);
    }

    // right half:
    // if rangeSize - half size == 1, create as regular CollisionTree
    if (rangeSize - halfRange == 1) {
      // compute section
      final int section = sectionStart + 1;

      // create the left child
      _right = new CollisionTree(_type);

      _right._primitiveIndices = new int[mesh.getMeshData().getPrimitiveCount(section)];
      for (int i = 0; i < _right._primitiveIndices.length; i++) {
        _right._primitiveIndices[i] = i;
      }
      _right._mesh = _mesh;
      _right.createTree(section, 0, _right._primitiveIndices.length, doSort);
    } else {
      // otherwise, make an empty collision tree and call split with new range
      _right = new CollisionTree(_type);
      _right.splitMesh(mesh, sectionStart + halfRange, sectionEnd, doSort);
    }

    // Ok, now since we technically have no primitives, we need our bounds to be the merging of our
    // children bounds
    // instead:
    _bounds = _left._bounds.clone(_bounds);
    _bounds.mergeLocal(_right._bounds);
    _worldBounds = _bounds.clone(_worldBounds);
  }
Пример #2
0
 /**
  * Tests if the world bounds of the node at this level intersects a provided bounding volume. If
  * an intersection occurs, true is returned, otherwise false is returned. If the provided volume
  * is invalid, false is returned.
  *
  * @param volume the volume to intersect with.
  * @return true if there is an intersect, false otherwise.
  */
 public boolean intersectsBounding(final BoundingVolume volume) {
   switch (volume.getType()) {
     case AABB:
       return _worldBounds.intersectsBoundingBox((BoundingBox) volume);
     case OBB:
       return _worldBounds.intersectsOrientedBoundingBox((OrientedBoundingBox) volume);
     case Sphere:
       return _worldBounds.intersectsSphere((BoundingSphere) volume);
     default:
       return false;
   }
 }
Пример #3
0
  /**
   * <code>mergeLocal</code> combines this sphere with a second bounding sphere locally. Altering
   * this sphere to contain both the original and the additional sphere volumes;
   *
   * @param volume the sphere to combine with this sphere.
   * @return this
   */
  @Override
  public BoundingVolume mergeLocal(final BoundingVolume volume) {
    if (volume == null) {
      return this;
    }

    switch (volume.getType()) {
      case Sphere:
        {
          final BoundingSphere sphere = (BoundingSphere) volume;
          final double temp_radius = sphere.getRadius();
          final ReadOnlyVector3 temp_center = sphere.getCenter();
          return merge(temp_radius, temp_center, this);
        }

      case AABB:
        {
          final BoundingBox box = (BoundingBox) volume;
          final Vector3 temp_center = box._center;
          _compVect1.set(box.getXExtent(), box.getYExtent(), box.getZExtent());
          final double radius = _compVect1.length();
          return merge(radius, temp_center, this);
        }

      case OBB:
        {
          return mergeLocalOBB((OrientedBoundingBox) volume);
        }

      default:
        return null;
    }
  }
Пример #4
0
  @Override
  public boolean intersects(final BoundingVolume bv) {
    if (bv == null) {
      return false;
    }

    return bv.intersectsSphere(this);
  }
Пример #5
0
 @Override
 public void read(final InputCapsule capsule) throws IOException {
   super.read(capsule);
   try {
     setRadius(capsule.readDouble("radius", 0));
   } catch (final IOException ex) {
     logger.logp(
         Level.SEVERE, this.getClass().toString(), "read(Ardor3DImporter)", "Exception", ex);
   }
 }
Пример #6
0
 @Override
 public void write(final OutputCapsule capsule) throws IOException {
   super.write(capsule);
   try {
     capsule.write(getRadius(), "radius", 0);
   } catch (final IOException ex) {
     logger.logp(
         Level.SEVERE, this.getClass().toString(), "write(Ardor3DExporter)", "Exception", ex);
   }
 }
Пример #7
0
  /**
   * <code>clone</code> creates a new BoundingSphere object containing the same data as this one.
   *
   * @param store where to store the cloned information. if null or wrong class, a new store is
   *     created.
   * @return the new BoundingSphere
   */
  @Override
  public BoundingVolume clone(final BoundingVolume store) {
    if (store != null && store.getType() == Type.Sphere) {
      final BoundingSphere rVal = (BoundingSphere) store;
      rVal._center.set(_center);
      rVal.setRadius(_radius);
      rVal._checkPlane = _checkPlane;
      return rVal;
    }

    return new BoundingSphere(getRadius(), _center);
  }
Пример #8
0
  /**
   * Creates a Collision Tree by recursively creating children nodes, splitting the primitives this
   * node is responsible for in half until the desired primitive count is reached.
   *
   * @param start The start index of the primitivesArray, inclusive.
   * @param end The end index of the primitivesArray, exclusive.
   * @param doSort True if the primitives should be sorted at each level, false otherwise.
   */
  public void createTree(final int section, final int start, final int end, final boolean doSort) {
    _section = section;
    _start = start;
    _end = end;

    if (_primitiveIndices == null) {
      return;
    }

    createBounds();

    // the bounds at this level should contain all the primitives this level is responsible for.
    _bounds.computeFromPrimitives(
        getMesh().getMeshData(), _section, _primitiveIndices, _start, _end);

    // check to see if we are a leaf, if the number of primitives we reference is less than or equal
    // to the maximum
    // defined by the CollisionTreeManager we are done.
    if (_end - _start + 1 <= CollisionTreeManager.getInstance().getMaxPrimitivesPerLeaf()) {
      return;
    }

    // if doSort is set we need to attempt to optimize the referenced primitives. optimizing the
    // sorting of the
    // primitives will help group them spatially in the left/right children better.
    if (doSort) {
      sortPrimitives();
    }

    // create the left child
    if (_left == null) {
      _left = new CollisionTree(_type);
    }

    _left._primitiveIndices = _primitiveIndices;
    _left._mesh = _mesh;
    _left.createTree(_section, _start, (_start + _end) / 2, doSort);

    // create the right child
    if (_right == null) {
      _right = new CollisionTree(_type);
    }
    _right._primitiveIndices = _primitiveIndices;
    _right._mesh = _mesh;
    _right.createTree(_section, (_start + _end) / 2, _end, doSort);
  }
Пример #9
0
  /**
   * intersect checks for collisions between this collision tree and a provided Ray. Any collisions
   * are stored in a provided list as primitive index values. The ray is assumed to have a
   * normalized direction for accurate calculations.
   *
   * @param ray the ray to test for intersections.
   * @param store a list to fill with the index values of the primitive hit. if null, a new List is
   *     created.
   * @return the list.
   */
  public List<PrimitiveKey> intersect(final Ray3 ray, final List<PrimitiveKey> store) {
    List<PrimitiveKey> result = store;
    if (result == null) {
      result = new ArrayList<PrimitiveKey>();
    }

    // if our ray doesn't hit the bounds, then it must not hit a primitive.
    if (!_worldBounds.intersects(ray)) {
      return result;
    }

    // This is not a leaf node, therefore, check each child (left/right) for intersection with the
    // ray.
    if (_left != null) {
      _left._worldBounds =
          _left._bounds.transform(getMesh().getWorldTransform(), _left._worldBounds);
      _left.intersect(ray, result);
    }

    if (_right != null) {
      _right._worldBounds =
          _right._bounds.transform(getMesh().getWorldTransform(), _right._worldBounds);
      _right.intersect(ray, result);
    } else if (_left == null) {
      // This is a leaf node. We can therefore check each primitive this node contains. If an
      // intersection occurs,
      // place it in the list.

      final MeshData data = getMesh().getMeshData();
      final ReadOnlyTransform transform = getMesh().getWorldTransform();

      Vector3[] points = null;
      for (int i = _start; i < _end; i++) {
        points = data.getPrimitiveVertices(_primitiveIndices[i], _section, points);
        for (int t = 0; t < points.length; t++) {
          transform.applyForward(points[t]);
        }
        if (ray.intersects(points, null)) {
          result.add(new PrimitiveKey(_primitiveIndices[i], _section));
        }
      }
    }
    return result;
  }
Пример #10
0
  @Override
  public BoundingVolume transform(final ReadOnlyTransform transform, final BoundingVolume store) {
    BoundingSphere sphere;
    if (store == null || store.getType() != BoundingVolume.Type.Sphere) {
      sphere = new BoundingSphere(1, new Vector3(0, 0, 0));
    } else {
      sphere = (BoundingSphere) store;
    }

    transform.applyForward(_center, sphere._center);

    if (!transform.isRotationMatrix()) {
      final Vector3 scale = new Vector3(1, 1, 1);
      transform.applyForwardVector(scale);
      sphere.setRadius(Math.abs(maxAxis(scale) * getRadius()) + radiusEpsilon - 1);
    } else {
      final ReadOnlyVector3 scale = transform.getScale();
      sphere.setRadius(Math.abs(maxAxis(scale) * getRadius()) + radiusEpsilon - 1);
    }

    return sphere;
  }
Пример #11
0
  /**
   * <code>merge</code> combines this sphere with a second bounding sphere. This new sphere contains
   * both bounding spheres and is returned.
   *
   * @param volume the sphere to combine with this sphere.
   * @return a new sphere
   */
  @Override
  public BoundingVolume merge(final BoundingVolume volume) {
    if (volume == null) {
      return this;
    }

    switch (volume.getType()) {
      case Sphere:
        {
          final BoundingSphere sphere = (BoundingSphere) volume;
          final double temp_radius = sphere.getRadius();
          final ReadOnlyVector3 tempCenter = sphere.getCenter();
          final BoundingSphere rVal = new BoundingSphere();
          return merge(temp_radius, tempCenter, rVal);
        }

      case AABB:
        {
          final BoundingBox box = (BoundingBox) volume;
          final Vector3 radVect = new Vector3(box.getXExtent(), box.getYExtent(), box.getZExtent());
          final Vector3 tempCenter = box._center;
          final BoundingSphere rVal = new BoundingSphere();
          return merge(radVect.length(), tempCenter, rVal);
        }

      case OBB:
        {
          final OrientedBoundingBox box = (OrientedBoundingBox) volume;
          final BoundingSphere rVal = (BoundingSphere) this.clone(null);
          return rVal.mergeLocalOBB(box);
        }

      default:
        return null;
    }
  }
Пример #12
0
 /** Get the point and distance to seek to */
 @Override
 public double getSeekPointAndDistance(Vector3 point) {
   BoundingVolume bv = getWorldBound();
   point.set(bv.getCenter());
   return (getRadius() * 1.5);
 }