Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions jme3-core/src/main/java/com/jme3/collision/CollisionResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
package com.jme3.collision;

import com.jme3.math.Triangle;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
Expand All @@ -50,6 +51,7 @@ public class CollisionResult implements Comparable<CollisionResult> {
private Vector3f contactNormal;
private float distance;
private int triangleIndex;
private Vector2f contactBaryCoords;

public CollisionResult(Geometry geometry, Vector3f contactPoint, float distance, int triangleIndex) {
this.geometry = geometry;
Expand Down Expand Up @@ -86,6 +88,10 @@ public void setTriangleIndex(int index) {
this.triangleIndex = index;
}

public void setContactBaryCoords(Vector2f baryCoords) {
this.contactBaryCoords = baryCoords;
}

public Triangle getTriangle(Triangle store) {
if (store == null)
store = new Triangle();
Expand Down Expand Up @@ -135,13 +141,28 @@ public int getTriangleIndex() {
return triangleIndex;
}

/**
* Returns the barycentric coordinates of the contact point within the
* hit triangle, or null if barycentric coordinates are not available.
*
* <p>The returned vector stores (u, v) where u is the weight of the
* second triangle vertex, v is the weight of the third triangle vertex,
* and the weight of the first triangle vertex is (1 - u - v).
*
* @return the barycentric (u, v) coordinates, or null
*/
public Vector2f getContactBaryCoords() {
return contactBaryCoords;
}

@Override
public String toString() {
return "CollisionResult[geometry=" + geometry
+ ", contactPoint=" + contactPoint
+ ", contactNormal=" + contactNormal
+ ", distance=" + distance
+ ", triangleIndex=" + triangleIndex
+ ", contactBaryCoords=" + contactBaryCoords
+ "]";
}
}
32 changes: 32 additions & 0 deletions jme3-core/src/main/java/com/jme3/collision/CollisionResults.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,38 @@ public class CollisionResults implements Iterable<CollisionResult> {

private ArrayList<CollisionResult> results = null;
private boolean sorted = true;
private boolean requiresBaryCoords = false;

/**
* Returns whether collision queries against this instance will compute and
* store barycentric coordinates in each {@link CollisionResult}.
*
* <p>Barycentric coordinate computation is disabled by default.
* Enable it when you need the (u, v) weights for texture-coordinate
* interpolation or other per-hit surface lookups.
*
* @return true if barycentric coordinates will be computed
* @see #setRequiresBaryCoords(boolean)
*/
public boolean isRequiresBaryCoords() {
return requiresBaryCoords;
}

/**
* Controls whether collision queries against this instance should compute
* and store barycentric coordinates in each {@link CollisionResult}.
*
* <p>Barycentric coordinate computation is disabled by default.
* Enable it when you need the (u, v) weights for texture-coordinate
* interpolation or other per-hit surface lookups.
*
* @param requiresBaryCoords true to enable barycentric coordinate
* computation, false (the default) to skip it
* @see #isRequiresBaryCoords()
*/
public void setRequiresBaryCoords(boolean requiresBaryCoords) {
this.requiresBaryCoords = requiresBaryCoords;
}

/**
* Clears all collision results added to this list
Expand Down
9 changes: 7 additions & 2 deletions jme3-core/src/main/java/com/jme3/collision/bih/BIHNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.jme3.math.Matrix4f;
import com.jme3.math.Ray;
import com.jme3.math.Triangle;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.util.TempVars;
import java.io.IOException;
Expand Down Expand Up @@ -401,13 +402,14 @@ public final int intersectWhere(Ray r,
for (int i = node.leftIndex; i <= node.rightIndex; i++) {
tree.getTriangle(i, v1, v2, v3);

float t = r.intersects(v1, v2, v3);
Vector2f baryCoords = results.isRequiresBaryCoords() ? new Vector2f() : null;
float t = r.intersects(v1, v2, v3, baryCoords);
if (!Float.isInfinite(t)) {
if (worldMatrix != null) {
worldMatrix.mult(v1, v1);
worldMatrix.mult(v2, v2);
worldMatrix.mult(v3, v3);
float t_world = new Ray(o, d).intersects(v1, v2, v3);
float t_world = new Ray(o, d).intersects(v1, v2, v3, baryCoords);
t = t_world;
}

Expand All @@ -422,6 +424,9 @@ public final int intersectWhere(Ray r,
CollisionResult cr = new CollisionResult(contactPoint, worldSpaceDist);
cr.setContactNormal(contactNormal);
cr.setTriangleIndex(tree.getTriangleIndex(i));
if (baryCoords != null) {
cr.setContactBaryCoords(baryCoords);
}
results.addCollision(cr);
cols++;
}
Expand Down
93 changes: 91 additions & 2 deletions jme3-core/src/main/java/com/jme3/math/Ray.java
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,90 @@ public float intersects(Vector3f v0, Vector3f v1, Vector3f v2) {
return Float.POSITIVE_INFINITY;
}

/**
* Test for an intersection between the ray and the given triangle and,
* if an intersection exists, store the barycentric coordinates of the
* contact point in <code>baryCoords</code>.
*
* <p>The stored (u, v) barycentric coordinates mean: u is the weight
* of <code>v1</code>, v is the weight of <code>v2</code>, and
* (1&nbsp;-&nbsp;u&nbsp;-&nbsp;v) is the weight of <code>v0</code>.
*
* @param v0 first vertex of the triangle (not null, unaffected)
* @param v1 second vertex of the triangle (not null, unaffected)
* @param v2 third vertex of the triangle (not null, unaffected)
* @param baryCoords storage for the barycentric (u, v) coordinates of the
* contact point (modified on hit, may be null)
* @return the distance along the ray to the intersection, or
* {@link Float#POSITIVE_INFINITY} if there is no intersection
*/
public float intersects(Vector3f v0, Vector3f v1, Vector3f v2, Vector2f baryCoords) {
float edge1X = v1.x - v0.x;
float edge1Y = v1.y - v0.y;
float edge1Z = v1.z - v0.z;

float edge2X = v2.x - v0.x;
float edge2Y = v2.y - v0.y;
float edge2Z = v2.z - v0.z;

float normX = ((edge1Y * edge2Z) - (edge1Z * edge2Y));
float normY = ((edge1Z * edge2X) - (edge1X * edge2Z));
float normZ = ((edge1X * edge2Y) - (edge1Y * edge2X));

float dirDotNorm = direction.x * normX + direction.y * normY + direction.z * normZ;

float diffX = origin.x - v0.x;
float diffY = origin.y - v0.y;
float diffZ = origin.z - v0.z;

float sign;
if (dirDotNorm > FastMath.FLT_EPSILON) {
sign = 1;
} else if (dirDotNorm < -FastMath.FLT_EPSILON) {
sign = -1f;
dirDotNorm = -dirDotNorm;
} else {
// ray and triangle/quad are parallel
return Float.POSITIVE_INFINITY;
}

float diffEdge2X = ((diffY * edge2Z) - (diffZ * edge2Y));
float diffEdge2Y = ((diffZ * edge2X) - (diffX * edge2Z));
float diffEdge2Z = ((diffX * edge2Y) - (diffY * edge2X));

float dirDotDiffxEdge2 = sign * (direction.x * diffEdge2X
+ direction.y * diffEdge2Y
+ direction.z * diffEdge2Z);

if (dirDotDiffxEdge2 >= 0.0f) {
diffEdge2X = ((edge1Y * diffZ) - (edge1Z * diffY));
diffEdge2Y = ((edge1Z * diffX) - (edge1X * diffZ));
diffEdge2Z = ((edge1X * diffY) - (edge1Y * diffX));

float dirDotEdge1xDiff = sign * (direction.x * diffEdge2X
+ direction.y * diffEdge2Y
+ direction.z * diffEdge2Z);

if (dirDotEdge1xDiff >= 0.0f) {
if (dirDotDiffxEdge2 + dirDotEdge1xDiff <= dirDotNorm) {
float diffDotNorm = -sign * (diffX * normX + diffY * normY + diffZ * normZ);
if (diffDotNorm >= 0.0f) {
// ray intersects triangle
float inv = 1f / dirDotNorm;
float t = diffDotNorm * inv;
if (baryCoords != null) {
baryCoords.set(dirDotDiffxEdge2 * inv,
dirDotEdge1xDiff * inv);
}
return t;
}
}
}
}

return Float.POSITIVE_INFINITY;
}

/**
* <code>intersectWherePlanar</code> determines if the Ray intersects a
* quad defined by the specified points and if so it stores the point of
Expand Down Expand Up @@ -393,13 +477,18 @@ public int collideWith(Collidable other, CollisionResults results) {
return bv.collideWith(this, results);
} else if (other instanceof AbstractTriangle) {
AbstractTriangle tri = (AbstractTriangle) other;
float d = intersects(tri.get1(), tri.get2(), tri.get3());
Vector2f baryCoords = results.isRequiresBaryCoords() ? new Vector2f() : null;
float d = intersects(tri.get1(), tri.get2(), tri.get3(), baryCoords);
if (Float.isInfinite(d) || Float.isNaN(d)) {
return 0;
}

Vector3f point = new Vector3f(direction).multLocal(d).addLocal(origin);
results.addCollision(new CollisionResult(point, d));
CollisionResult cr = new CollisionResult(point, d);
if (baryCoords != null) {
cr.setContactBaryCoords(baryCoords);
}
results.addCollision(cr);
return 1;
} else {
throw new UnsupportedCollisionException();
Expand Down
Loading
Loading