public static void findTrianglePick( final Mesh mesh, final Ray3 toTest, final List<PrimitiveKey> results) { if (mesh.getWorldBound() == null || !mesh.getSceneHints().isPickingHintEnabled(PickingHint.Pickable)) { return; } if (mesh.getWorldBound().intersects(toTest)) { final CollisionTree ct = CollisionTreeManager.getInstance().getCollisionTree(mesh); if (ct != null) { ct.getBounds().transform(mesh.getWorldTransform(), ct.getWorldBounds()); ct.intersect(toTest, results); } } }
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); }
/** * This function checks for intersection between this mesh and the given one. On the first * intersection, true is returned. * * @param toCheck The intersection testing mesh. * @return True if they intersect. */ public static boolean hasTriangleCollision(final Mesh testMesh, final Mesh toCheck) { if (!testMesh.getSceneHints().isPickingHintEnabled(PickingHint.Collidable) || !toCheck.getSceneHints().isPickingHintEnabled(PickingHint.Collidable)) { return false; } final CollisionTree thisCT = CollisionTreeManager.getInstance().getCollisionTree(testMesh); final CollisionTree checkCT = CollisionTreeManager.getInstance().getCollisionTree(toCheck); if (thisCT == null || checkCT == null) { return false; } final ReadOnlyTransform worldTransform = testMesh.getWorldTransform(); thisCT.getBounds().transform(worldTransform, thisCT.getWorldBounds()); return thisCT.intersect(checkCT); }
/** * 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; }
/** * This function finds all intersections between this mesh and the checking one. The intersections * are stored as Integer objects of Triangle indexes in each of the parameters. * * @param toCheck The Mesh to check. * @param testIndex The array of triangle indexes intersecting in this mesh. * @param otherIndex The array of triangle indexes intersecting in the given mesh. */ public static void findPrimitiveCollision( final Mesh testMesh, final Mesh toCheck, final List<PrimitiveKey> testIndex, final List<PrimitiveKey> otherIndex) { if (!testMesh.getSceneHints().isPickingHintEnabled(PickingHint.Collidable) || !toCheck.getSceneHints().isPickingHintEnabled(PickingHint.Collidable)) { return; } final CollisionTree myTree = CollisionTreeManager.getInstance().getCollisionTree(testMesh); final CollisionTree otherTree = CollisionTreeManager.getInstance().getCollisionTree(toCheck); if (myTree == null || otherTree == null) { return; } myTree.getBounds().transform(testMesh.getWorldTransform(), myTree.getWorldBounds()); myTree.intersect(otherTree, testIndex, otherIndex); }
/** * 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); }
/** * Determines if this Collision Tree intersects the given CollisionTree. If a collision occurs, * true is returned, otherwise false is returned. If the provided collisionTree is invalid, false * is returned. All collisions that occur are stored in lists as an integer index into the mesh's * triangle buffer. where aList is the primitives for this mesh and bList is the primitives for * the test tree. * * @param collisionTree The Tree to test. * @param aList a list to contain the colliding primitives of this mesh. * @param bList a list to contain the colliding primitives of the testing mesh. * @return True if they intersect, false otherwise. */ public boolean intersect( final CollisionTree collisionTree, final List<PrimitiveKey> aList, final List<PrimitiveKey> bList) { if (collisionTree == null) { return false; } collisionTree._worldBounds = collisionTree._bounds.transform( collisionTree.getMesh().getWorldTransform(), collisionTree._worldBounds); // our two collision bounds do not intersect, therefore, our primitives // must not intersect. Return false. if (!intersectsBounding(collisionTree._worldBounds)) { return false; } // if our node is not a leaf send the children (both left and right) to // the test tree. if (_left != null) { // This is not a leaf boolean test = collisionTree.intersect(_left, bList, aList); test = collisionTree.intersect(_right, bList, aList) || test; return test; } // This node is a leaf, but the testing tree node is not. Therefore, // continue processing the testing tree until we find its leaves. if (collisionTree._left != null) { boolean test = intersect(collisionTree._left, aList, bList); test = intersect(collisionTree._right, aList, bList) || test; return test; } // both this node and the testing node are leaves. Therefore, we can // switch to checking the contained primitives with each other. Any // that are found to intersect are placed in the appropriate list. final ReadOnlyTransform transformA = getMesh().getWorldTransform(); final ReadOnlyTransform transformB = collisionTree.getMesh().getWorldTransform(); final MeshData dataA = getMesh().getMeshData(); final MeshData dataB = collisionTree.getMesh().getMeshData(); Vector3[] storeA = null; Vector3[] storeB = null; boolean test = false; for (int i = _start; i < _end; i++) { storeA = dataA.getPrimitiveVertices(_primitiveIndices[i], _section, storeA); // to world space for (int t = 0; t < storeA.length; t++) { transformA.applyForward(storeA[t]); } for (int j = collisionTree._start; j < collisionTree._end; j++) { storeB = dataB.getPrimitiveVertices( collisionTree._primitiveIndices[j], collisionTree._section, storeB); // to world space for (int t = 0; t < storeB.length; t++) { transformB.applyForward(storeB[t]); } if (Intersection.intersection(storeA, storeB)) { test = true; aList.add(new PrimitiveKey(_primitiveIndices[i], _section)); bList.add(new PrimitiveKey(collisionTree._primitiveIndices[j], collisionTree._section)); } } } return test; }
/** * Determines if this Collision Tree intersects the given CollisionTree. If a collision occurs, * true is returned, otherwise false is returned. If the provided collisionTree is invalid, false * is returned. * * @param collisionTree The Tree to test. * @return True if they intersect, false otherwise. */ public boolean intersect(final CollisionTree collisionTree) { if (collisionTree == null) { return false; } collisionTree._worldBounds = collisionTree._bounds.transform( collisionTree.getMesh().getWorldTransform(), collisionTree._worldBounds); // our two collision bounds do not intersect, therefore, our primitives // must not intersect. Return false. if (!intersectsBounding(collisionTree._worldBounds)) { return false; } // check children if (_left != null) { // This is not a leaf if (collisionTree.intersect(_left)) { return true; } if (collisionTree.intersect(_right)) { return true; } return false; } // This is a leaf if (collisionTree._left != null) { // but collision isn't if (intersect(collisionTree._left)) { return true; } if (intersect(collisionTree._right)) { return true; } return false; } // both are leaves final ReadOnlyTransform transformA = getMesh().getWorldTransform(); final ReadOnlyTransform transformB = collisionTree.getMesh().getWorldTransform(); final MeshData dataA = getMesh().getMeshData(); final MeshData dataB = collisionTree.getMesh().getMeshData(); Vector3[] storeA = null; Vector3[] storeB = null; // for every primitive to compare, put them into world space and check for intersections for (int i = _start; i < _end; i++) { storeA = dataA.getPrimitiveVertices(_primitiveIndices[i], _section, storeA); // to world space for (int t = 0; t < storeA.length; t++) { transformA.applyForward(storeA[t]); } for (int j = collisionTree._start; j < collisionTree._end; j++) { storeB = dataB.getPrimitiveVertices( collisionTree._primitiveIndices[j], collisionTree._section, storeB); // to world space for (int t = 0; t < storeB.length; t++) { transformB.applyForward(storeB[t]); } if (Intersection.intersection(storeA, storeB)) { return true; } } } return false; }