/** * This will cause all normals for this terrain quad to be recalculated */ protected void setNeedToRecalculateNormals() { affectedAreaBBox = new BoundingBox(getWorldTranslation(), Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE); }
/** * Computes the bounds of multiple bounding volumes * * @param bv * @return */ public static BoundingBox computeUnionBound(List<BoundingVolume> bv) { BoundingBox bbox = new BoundingBox(); for (int i = 0; i < bv.size(); i++) { BoundingVolume vol = bv.get(i); bbox.mergeLocal(vol); } return bbox; }
@Override public void updateModelBound() { if (boundingBox == null) { boundingBox = new BoundingBox(); } Vector3f min = new Vector3f(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE); Vector3f max = new Vector3f(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE); for (Vector3f v : vertices) { min.set(Math.min(min.x, v.x), Math.min(min.y, v.y), Math.min(min.z, v.z)); max.set(Math.max(max.x, v.x), Math.max(max.y, v.y), Math.max(max.z, v.z)); } boundingBox.setMinMax(min, max); }
/** * Forces the recalculation of all normals on the terrain. */ public void recalculateAllNormals() { affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), totalSize*2, Float.MAX_VALUE, totalSize*2); }
/** * Signal if the normal vectors for the terrain need to be recalculated. * Does this by looking at the affectedAreaBBox bounding box. If the bbox * exists already, then it will grow the box to fit the new changedPoint. * If the affectedAreaBBox is null, then it will create one of unit size. * * @param needToRecalculateNormals if null, will cause needToRecalculateNormals() to return false */ protected void setNormalRecalcNeeded(Vector2f changedPoint) { if (changedPoint == null) { // set needToRecalculateNormals() to false affectedAreaBBox = null; return; } if (affectedAreaBBox == null) { affectedAreaBBox = new BoundingBox(new Vector3f(changedPoint.x, 0, changedPoint.y), 1f, Float.MAX_VALUE, 1f); // unit length } else { // adjust size of box to be larger affectedAreaBBox.mergeLocal(new BoundingBox(new Vector3f(changedPoint.x, 0, changedPoint.y), 1f, Float.MAX_VALUE, 1f)); } }
protected boolean needToRecalculateNormals() { if (affectedAreaBBox != null) return true; if (!lastScale.equals(getWorldScale())) { affectedAreaBBox = new BoundingBox(getWorldTranslation(), Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE); lastScale = getWorldScale(); return true; } return false; }
public static void main(String[] args){ Ray r = new Ray(Vector3f.ZERO, Vector3f.UNIT_X); BoundingBox bbox = new BoundingBox(new Vector3f(5, 0, 0), 1, 1, 1); CollisionResults res = new CollisionResults(); bbox.collideWith(r, res); System.out.println("Bounding:" +bbox); System.out.println("Ray: "+r); System.out.println("Num collisions: "+res.size()); for (int i = 0; i < res.size(); i++){ System.out.println("--- Collision #"+i+" ---"); float dist = res.getCollision(i).getDistance(); Vector3f pt = res.getCollision(i).getContactPoint(); System.out.println("distance: "+dist); System.out.println("point: "+pt); } }
private int collideWithBoundingVolume(BoundingVolume bv, Matrix4f worldMatrix, CollisionResults results) { BoundingBox bbox; if (bv instanceof BoundingSphere) { BoundingSphere sphere = (BoundingSphere) bv; bbox = new BoundingBox(bv.getCenter().clone(), sphere.getRadius(), sphere.getRadius(), sphere.getRadius()); } else if (bv instanceof BoundingBox) { bbox = new BoundingBox((BoundingBox) bv); } else { throw new UnsupportedCollisionException("BoundingVolume:" + bv); } bbox.transform(worldMatrix.invert(), bbox); return root.intersectWhere(bv, bbox, worldMatrix, this, results); }
/** * Compute bounds of a geomList * @param list * @param transform * @return */ public static BoundingBox computeUnionBound(GeometryList list, Transform transform) { BoundingBox bbox = new BoundingBox(); TempVars tempv = TempVars.get(); for (int i = 0; i < list.size(); i++) { BoundingVolume vol = list.get(i).getWorldBound(); BoundingVolume newVol = vol.transform(transform, tempv.bbox); //Nehon : prevent NaN and infinity values to screw the final bounding box if (!Float.isNaN(newVol.getCenter().x) && !Float.isInfinite(newVol.getCenter().x)) { bbox.mergeLocal(newVol); } } tempv.release(); return bbox; }
/** * Compute bounds of a geomList * @param list * @param mat * @return */ public static BoundingBox computeUnionBound(GeometryList list, Matrix4f mat) { BoundingBox bbox = new BoundingBox(); TempVars tempv = TempVars.get(); for (int i = 0; i < list.size(); i++) { BoundingVolume vol = list.get(i).getWorldBound(); BoundingVolume store = vol.transform(mat, tempv.bbox); //Nehon : prevent NaN and infinity values to screw the final bounding box if (!Float.isNaN(store.getCenter().x) && !Float.isInfinite(store.getCenter().x)) { bbox.mergeLocal(store); } } tempv.release(); return bbox; }
private int collideWithBoundingVolume(BoundingVolume boundingVolume, CollisionResults results) { if (boundingVolume instanceof BoundingBox) return collideWithBoundingBox((BoundingBox)boundingVolume, results); else if(boundingVolume instanceof BoundingSphere) { BoundingSphere sphere = (BoundingSphere) boundingVolume; BoundingBox bbox = new BoundingBox(boundingVolume.getCenter().clone(), sphere.getRadius(), sphere.getRadius(), sphere.getRadius()); return collideWithBoundingBox(bbox, results); } return 0; }
public TerrainGrid(String name, int patchSize, int maxVisibleSize, Vector3f scale, TerrainGridTileLoader terrainQuadGrid, Vector2f offset, float offsetAmount) { this.name = name; this.patchSize = patchSize; this.size = maxVisibleSize; this.stepScale = scale; this.offset = offset; this.offsetAmount = offsetAmount; initData(); this.gridTileLoader = terrainQuadGrid; terrainQuadGrid.setPatchSize(this.patchSize); terrainQuadGrid.setQuadSize(this.quadSize); addControl(new UpdateControl()); fixNormalEdges(new BoundingBox(new Vector3f(0,0,0), size*2, Float.MAX_VALUE, size*2)); addControl(new NormalRecalcControl(this)); }
private BoundingBox createBox(int l, int r) { TempVars vars = TempVars.get(); Vector3f min = vars.vect1.set(new Vector3f(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)); Vector3f max = vars.vect2.set(new Vector3f(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY)); Vector3f v1 = vars.vect3, v2 = vars.vect4, v3 = vars.vect5; for (int i = l; i <= r; i++) { getTriangle(i, v1, v2, v3); BoundingBox.checkMinMax(min, max, v1); BoundingBox.checkMinMax(min, max, v2); BoundingBox.checkMinMax(min, max, v3); } BoundingBox bbox = new BoundingBox(min, max); vars.release(); return bbox; }
/** * Compute bounds from an array of points * * @param pts * @param transform * @return */ public static BoundingBox computeBoundForPoints(Vector3f[] pts, Transform transform) { Vector3f min = new Vector3f(Vector3f.POSITIVE_INFINITY); Vector3f max = new Vector3f(Vector3f.NEGATIVE_INFINITY); Vector3f temp = new Vector3f(); for (int i = 0; i < pts.length; i++) { transform.transformVector(pts[i], temp); min.minLocal(temp); max.maxLocal(temp); } Vector3f center = min.add(max).multLocal(0.5f); Vector3f extent = max.subtract(min).multLocal(0.5f); return new BoundingBox(center, extent.x, extent.y, extent.z); }
@Override public void read(JmeImporter e) throws IOException { super.read(e); InputCapsule c = e.getCapsule(this); size = c.readInt("size", 0); stepScale = (Vector3f) c.readSavable("stepScale", null); offset = (Vector2f) c.readSavable("offset", new Vector2f(0,0)); offsetAmount = c.readFloat("offsetAmount", 0); quadrant = c.readInt("quadrant", 0); totalSize = c.readInt("totalSize", 0); //lodCalculator = (LodCalculator) c.readSavable("lodCalculator", createDefaultLodCalculator()); //lodCalculatorFactory = (LodCalculatorFactory) c.readSavable("lodCalculatorFactory", null); if ( !(getParent() instanceof TerrainQuad) ) { BoundingBox all = new BoundingBox(getWorldTranslation(), totalSize, totalSize, totalSize); affectedAreaBBox = all; updateNormals(); } }
@Test public void testBoxBoxCollision() { BoundingBox box1 = new BoundingBox(Vector3f.ZERO, 1, 1, 1); BoundingBox box2 = new BoundingBox(Vector3f.ZERO, 1, 1, 1); checkCollision(box1, box2, 1); // Put it at the very edge - should still intersect. box2.setCenter(new Vector3f(2f, 0f, 0f)); checkCollision(box1, box2, 1); // Put it a wee bit farther - no intersection expected box2.setCenter(new Vector3f(2f + FastMath.ZERO_TOLERANCE, 0, 0)); checkCollision(box1, box2, 0); // Check the corners. box2.setCenter(new Vector3f(2f, 2f, 2f)); checkCollision(box1, box2, 1); box2.setCenter(new Vector3f(2f, 2f, 2f + FastMath.ZERO_TOLERANCE)); checkCollision(box1, box2, 0); }
@Override public void simpleInitApp() { Mesh mesh = new Mesh(); mesh.setBuffer(VertexBuffer.Type.Index, 1, BufferUtils.createIntBuffer(new int[]{1})); mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(new float[]{0, 0, 0})); mesh.setMode(Mesh.Mode.Points); mesh.setBound(new BoundingBox(new Vector3f(0, 0, 0), 10, 10, 10)); mesh.updateCounts(); Geometry geometry = new Geometry("Test", mesh); geometry.updateGeometricState(); geometry.setMaterial(new Material(assetManager, "Materials/Geom/SimpleGeom.j3md")); //geometry.getMaterial().getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off); //geometry.setMaterial(assetManager.loadMaterial("Materials/Geom/SimpleTess.j3md")); rootNode.attachChild(geometry); Geometry geometry1 = new Geometry("T1", new Sphere(10, 10, 1)); geometry1.setMaterial(new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md")); rootNode.attachChild(geometry1); }
@Test public void testBoxSphereCollision() { BoundingBox box1 = new BoundingBox(Vector3f.ZERO, 1, 1, 1); BoundingSphere sphere2 = new BoundingSphere(1, Vector3f.ZERO); checkCollision(box1, sphere2, 1); // Put it at the very edge - for sphere vs. box, it will not intersect sphere2.setCenter(new Vector3f(2f, 0f, 0f)); checkCollision(box1, sphere2, 0); // Put it a wee bit closer - should intersect. sphere2.setCenter(new Vector3f(2f - FastMath.ZERO_TOLERANCE, 0, 0)); checkCollision(box1, sphere2, 1); // Test if the algorithm converts the sphere // to a box before testing the collision (incorrect) float sqrt3 = FastMath.sqrt(3); sphere2.setCenter(Vector3f.UNIT_XYZ.mult(2)); sphere2.setRadius(sqrt3); checkCollision(box1, sphere2, 0); // Make it a wee bit larger. sphere2.setRadius(sqrt3 + FastMath.ZERO_TOLERANCE); checkCollision(box1, sphere2, 1); }
@Test public void testBoxRayCollision() { BoundingBox box = new BoundingBox(Vector3f.ZERO, 1, 1, 1); Ray ray = new Ray(Vector3f.ZERO, Vector3f.UNIT_Z); // XXX: seems incorrect, ray inside box should only generate // one result... checkCollision(box, ray, 2); ray.setOrigin(new Vector3f(0, 0, -5)); checkCollision(box, ray, 2); // XXX: is this right? the ray origin is on the box's side.. ray.setOrigin(new Vector3f(0, 0, 2f)); checkCollision(box, ray, 0); ray.setOrigin(new Vector3f(0, 0, -2f)); checkCollision(box, ray, 2); // parallel to the edge, touching the side ray.setOrigin(new Vector3f(0, 1f, -2f)); checkCollision(box, ray, 2); // still parallel, but not touching the side ray.setOrigin(new Vector3f(0, 1f + FastMath.ZERO_TOLERANCE, -2f)); checkCollision(box, ray, 0); }
@Test public void testBoxTriangleCollision() { BoundingBox box = new BoundingBox(Vector3f.ZERO, 1, 1, 1); Geometry geom = new Geometry("geom", new Quad(1, 1)); checkCollision(box, geom, 2); // Both triangles intersect // The box touches the edges of the triangles. box.setCenter(new Vector3f(-1f, 0, 0)); checkCollision(box, geom, 2); // Move it slightly farther.. box.setCenter(new Vector3f(-1f - FastMath.ZERO_TOLERANCE, 0, 0)); checkCollision(box, geom, 0); // Parallel triangle / box side, touching box.setCenter(new Vector3f(0, 0, -1f)); checkCollision(box, geom, 2); // Not touching box.setCenter(new Vector3f(0, 0, -1f - FastMath.ZERO_TOLERANCE)); checkCollision(box, geom, 0); // Test collisions only against one of the triangles box.setCenter(new Vector3f(-1f, 1.5f, 0f)); checkCollision(box, geom, 1); box.setCenter(new Vector3f(1.5f, -1f, 0f)); checkCollision(box, geom, 1); }