|
@@ -67,31 +67,41 @@ public class BresenhamTerrainPicker implements TerrainPicker {
|
|
|
private final TerrainQuad root;
|
|
|
private final BresenhamYUpGridTracer tracer = new BresenhamYUpGridTracer();
|
|
|
|
|
|
+ private boolean multipleCollisions = true;
|
|
|
+
|
|
|
|
|
|
public BresenhamTerrainPicker(TerrainQuad root) {
|
|
|
this.root = root;
|
|
|
}
|
|
|
|
|
|
- public Vector3f getTerrainIntersection(Ray worldPick, CollisionResults results) {
|
|
|
+ public void setSupportMultipleCollisions(boolean multipleCollisions) {
|
|
|
+ this.multipleCollisions = multipleCollisions;
|
|
|
+ }
|
|
|
|
|
|
+ public boolean isSupportingMultipleCollisions() {
|
|
|
+ return multipleCollisions;
|
|
|
+ }
|
|
|
+
|
|
|
+ public int getTerrainIntersection(Ray worldPick, CollisionResults results) {
|
|
|
+ int numCollisions = 0;
|
|
|
worldPickRay.set(worldPick);
|
|
|
- List<TerrainPickData> pickData = new ArrayList<TerrainPickData>();
|
|
|
+ List<TerrainPickData> pickData = new ArrayList<>();
|
|
|
root.findPick(worldPick.clone(), pickData);
|
|
|
Collections.sort(pickData);
|
|
|
|
|
|
- if (pickData.isEmpty())
|
|
|
- return null;
|
|
|
+ if (pickData.isEmpty()) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
workRay.set(worldPick);
|
|
|
|
|
|
for (TerrainPickData pd : pickData) {
|
|
|
TerrainPatch patch = pd.targetPatch;
|
|
|
|
|
|
-
|
|
|
tracer.getGridSpacing().set(patch.getWorldScale());
|
|
|
tracer.setGridOrigin(patch.getWorldTranslation());
|
|
|
|
|
|
- workRay.getOrigin().set(worldPick.getDirection()).multLocal(pd.cr.getDistance()-.1f).addLocal(worldPick.getOrigin());
|
|
|
+ workRay.getOrigin().set(worldPick.getDirection()).multLocal(pd.cr.getDistance() - .1f).addLocal(worldPick.getOrigin());
|
|
|
|
|
|
tracer.startWalk(workRay);
|
|
|
|
|
@@ -99,67 +109,141 @@ public class BresenhamTerrainPicker implements TerrainPicker {
|
|
|
final Vector2f loc = tracer.getGridLocation();
|
|
|
|
|
|
if (tracer.isRayPerpendicularToGrid()) {
|
|
|
- Triangle hit = new Triangle();
|
|
|
- checkTriangles(loc.x, loc.y, workRay, intersection, patch, hit);
|
|
|
- float distance = worldPickRay.origin.distance(intersection);
|
|
|
- CollisionResult cr = new CollisionResult(intersection, distance);
|
|
|
- cr.setGeometry(patch);
|
|
|
- cr.setContactNormal(hit.getNormal());
|
|
|
- results.addCollision(cr);
|
|
|
- return intersection;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- while (loc.x >= -1 && loc.x <= patch.getSize() &&
|
|
|
- loc.y >= -1 && loc.y <= patch.getSize()) {
|
|
|
-
|
|
|
- //System.out.print(loc.x+","+loc.y+" : ");
|
|
|
- // check the triangles of main square for intersection.
|
|
|
Triangle hit = new Triangle();
|
|
|
if (checkTriangles(loc.x, loc.y, workRay, intersection, patch, hit)) {
|
|
|
- // we found an intersection, so return that!
|
|
|
float distance = worldPickRay.origin.distance(intersection);
|
|
|
- CollisionResult cr = new CollisionResult(intersection, distance);
|
|
|
- cr.setGeometry(patch);
|
|
|
- results.addCollision(cr);
|
|
|
- cr.setContactNormal(hit.getNormal());
|
|
|
- return intersection;
|
|
|
- }
|
|
|
|
|
|
- // because of how we get our height coords, we will
|
|
|
- // sometimes be off by 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;
|
|
|
+ //@TODO: Verify if it's even possible to have a ray hit multiple "PickData"s when being perpendicular at all.
|
|
|
+ // because otherwise, we could always return 1 here.
|
|
|
+ if (worldPick.getLimit() < Float.POSITIVE_INFINITY) {
|
|
|
+ if (distance <= worldPick.getLimit()) {
|
|
|
+ if (addCollision(results, patch, intersection, hit, distance)) {
|
|
|
+ if (!multipleCollisions) {
|
|
|
+ return 1;
|
|
|
+ } else {
|
|
|
+ numCollisions++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } // else return 0; // < this is the old behavior, since the code checked for the range afterwards.
|
|
|
+ } else { // unlimited range
|
|
|
+ if (addCollision(results, patch, intersection, hit, distance)) {
|
|
|
+ if (!multipleCollisions) {
|
|
|
+ return 1;
|
|
|
+ } else {
|
|
|
+ numCollisions++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } // else no collision
|
|
|
+ } else { // If the ray is perpendicular, tracer.next() would never advance loc, leading to an infinite loop.
|
|
|
+ while (loc.x >= -1 && loc.x <= patch.getSize() &&
|
|
|
+ loc.y >= -1 && loc.y <= patch.getSize()) {
|
|
|
+
|
|
|
+ //System.out.print(loc.x + "," + loc.y + " : ");
|
|
|
+ // check the triangles of main square for intersection.
|
|
|
+ Triangle hit = new Triangle();
|
|
|
+ if (checkTriangles(loc.x, loc.y, workRay, intersection, patch, hit)) {
|
|
|
+ // we found an intersection, so return that!
|
|
|
+ float distance = worldPickRay.origin.distance(intersection);
|
|
|
+
|
|
|
+ if (worldPick.getLimit() < Float.POSITIVE_INFINITY) {
|
|
|
+ if (distance <= worldPick.getLimit()) {
|
|
|
+ if (addCollision(results, patch, intersection, hit, distance)) {
|
|
|
+ if (!multipleCollisions) {
|
|
|
+ return 1;
|
|
|
+ } else {
|
|
|
+ numCollisions++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }// else return 0; // < this is the old behavior, since the code checked for the range afterwards.
|
|
|
+ } else { // unlimited range
|
|
|
+ if (addCollision(results, patch, intersection, hit, distance)) {
|
|
|
+ if (!multipleCollisions) {
|
|
|
+ return 1;
|
|
|
+ } else {
|
|
|
+ numCollisions++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // because of how we get our height coords, we will
|
|
|
+ // sometimes be off by 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, patch, hit)) {
|
|
|
+ // we found an intersection, so return that!
|
|
|
+ float distance = worldPickRay.origin.distance(intersection);
|
|
|
+
|
|
|
+ if (worldPick.getLimit() < Float.POSITIVE_INFINITY) {
|
|
|
+ if (distance <= worldPick.getLimit()) {
|
|
|
+ if (addCollision(results, patch, intersection, hit, distance)) {
|
|
|
+ if (!multipleCollisions) {
|
|
|
+ return 1;
|
|
|
+ } else {
|
|
|
+ numCollisions++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } // else return null; // < this is the old behavior, since the code checked for the range afterwards.
|
|
|
+ } else { // unlimited range
|
|
|
+ if (addCollision(results, patch, intersection, hit, distance)) {
|
|
|
+ if (!multipleCollisions) {
|
|
|
+ return 1;
|
|
|
+ } else {
|
|
|
+ numCollisions++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ tracer.next();
|
|
|
}
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (checkTriangles(loc.x + dx, loc.y + dz, workRay, intersection, patch, hit)) {
|
|
|
- // we found an intersection, so return that!
|
|
|
- float distance = worldPickRay.origin.distance(intersection);
|
|
|
- CollisionResult cr = new CollisionResult(intersection, distance);
|
|
|
- results.addCollision(cr);
|
|
|
- cr.setGeometry(patch);
|
|
|
- cr.setContactNormal(hit.getNormal());
|
|
|
- return intersection;
|
|
|
- }
|
|
|
+ return numCollisions;
|
|
|
+ }
|
|
|
|
|
|
- tracer.next();
|
|
|
+ /**
|
|
|
+ * This method adds the found Collision to an existing collisionResult.
|
|
|
+ * @param results The results to add this collision to
|
|
|
+ * @param patch The TerrainPatch which collided
|
|
|
+ * @param intersection The actual intersection position
|
|
|
+ * @param hit The hit triangle
|
|
|
+ * @param distance The distance at which the hit occurred
|
|
|
+ * @return Whether the collision was accepted to the list or whether it has been deduplicated
|
|
|
+ */
|
|
|
+ private boolean addCollision(CollisionResults results, TerrainPatch patch, Vector3f intersection, Triangle hit, float distance) {
|
|
|
+ CollisionResult cr = new CollisionResult(intersection.clone(), distance);
|
|
|
+ cr.setGeometry(patch);
|
|
|
+ cr.setContactNormal(hit.getNormal());
|
|
|
+ cr.setTriangleIndex(hit.getIndex()); // this will probably always be 0
|
|
|
+
|
|
|
+ for (int i = 0; i < results.size(); i++) {
|
|
|
+ CollisionResult compare = results.getCollision(i);
|
|
|
+ if (compare.getDistance() == cr.getDistance() && compare.getGeometry() == cr.getGeometry() &&
|
|
|
+ compare.getContactPoint().equals(cr.getContactPoint()) &&
|
|
|
+ compare.getContactNormal().equals(cr.getContactNormal())) {
|
|
|
+ return false; // Collision already available, deduplicate.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return null;
|
|
|
+ results.addCollision(cr);
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
protected boolean checkTriangles(float gridX, float gridY, Ray pick, Vector3f intersection, TerrainPatch patch, Triangle store) {
|