/** * Check the two triangles of a given grid space for intersection. * * @param gridX grid row * @param gridY grid column * @param pick our pick ray * @param intersection the store variable * @param block the terrain block we are currently testing against. * @return true if a pick was found on these triangles. */ protected boolean checkTriangles( float gridX, float gridY, Ray pick, Vector3f intersection, TerrainBlock block) { if (!getTriangles(gridX, gridY, block)) return false; if (!pick.intersectWhere(_gridTriA, intersection)) { return pick.intersectWhere(_gridTriB, intersection); } else { return true; } }
/** {@inheritDoc} */ public Vector3f getIntersection(Ray ray, Spatial parent, Vector3f store, boolean local) { if (store == null) { store = new Vector3f(); } TrianglePickResults results = new TrianglePickResults(); results.setCheckDistance(true); Vector3f[] vertices = new Vector3f[3]; parent.findPick(ray, results); boolean hit = false; if (results.getNumber() > 0) { PickData data = results.getPickData(0); ArrayList<Integer> triangles = data.getTargetTris(); if (!triangles.isEmpty()) { TriMesh mesh = (TriMesh) data.getTargetMesh(); mesh.getTriangle(triangles.get(0).intValue(), vertices); for (int j = 0; j < vertices.length; j++) { mesh.localToWorld(vertices[j], vertices[j]); } hit = ray.intersectWhere(vertices[0], vertices[1], vertices[2], store); if (hit && local) { parent.worldToLocal(store, store); return store; } else if (hit && !local) { return store; } } } return null; }
/** * Ask for the point of intersection between the given ray and the terrain. * * @param worldPick our pick ray, in world space. * @param store if not null, the results will be stored in this vector and the vector returned. If * store is null, a new vector will be created. * @return null if no pick is found. Otherwise it returns a Vector3f (the store param, if that was * not null) populated with the pick coordinates. */ public Vector3f getTerrainIntersection(final Ray worldPick, final Vector3f store) { if (_root == null || _root.getWorldBound() == null) return null; if (!_root.getWorldBound().intersects(worldPick)) return null; // Set up our working ray _workRay.set(worldPick); // Grab all terrain blocks and do a grid walk on each starting from // closest. _pr.clear(); _root.findPick(_workRay, _pr); for (int i = 0, max = _pr.getNumber(); i < max; i++) { PickData pd = _pr.getPickData(i); if (pd == null) continue; Geometry g = pd.getTargetMesh(); if (g instanceof TerrainBlock) { TerrainBlock block = (TerrainBlock) g; _tracer.getGridSpacing().set(block.getWorldScale()).multLocal(block.getStepScale()); _tracer.setGridOrigin(block.getWorldTranslation()); _workRay .getOrigin() .set(worldPick.getDirection()) .multLocal(pd.getDistance() - .1f) .addLocal(worldPick.getOrigin()); _tracer.startWalk(_workRay); if (_tracer.isRayPerpendicularToGrid()) { // no intersection return null; } final Vector3f intersection = store != null ? store : new Vector3f(); final Vector2f loc = _tracer.getGridLocation(); while (loc.x >= -1 && loc.x <= block.getSize() && loc.y >= -1 && loc.y <= block.getSize()) { // check the triangles of main square for intersection. if (checkTriangles(loc.x, loc.y, _workRay, intersection, block)) { // we found an intersection, so return that! return intersection; } // because of how we get our height coords, we will // sometimes be off be a grid spot, so we check the next // grid space up. int dx = 0, dz = 0; Direction d = _tracer.getLastStepDirection(); switch (d) { case PositiveX: case NegativeX: dx = 0; dz = 1; break; case PositiveZ: case NegativeZ: dx = 1; dz = 0; break; } if (checkTriangles(loc.x + dx, loc.y + dz, _workRay, intersection, block)) { // we found an intersection, so return that! return intersection; } _tracer.next(); } } } return null; }