aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core/com/jme3/collision/SweepSphere.java
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/core/com/jme3/collision/SweepSphere.java')
-rw-r--r--engine/src/core/com/jme3/collision/SweepSphere.java440
1 files changed, 440 insertions, 0 deletions
diff --git a/engine/src/core/com/jme3/collision/SweepSphere.java b/engine/src/core/com/jme3/collision/SweepSphere.java
new file mode 100644
index 0000000..9d43f89
--- /dev/null
+++ b/engine/src/core/com/jme3/collision/SweepSphere.java
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.collision;
+
+import com.jme3.math.*;
+
+/**
+ * No longer public ..
+ *
+ * @author Kirill Vainer
+ */
+@Deprecated
+class SweepSphere implements Collidable {
+
+ private Vector3f velocity = new Vector3f();
+ private Vector3f center = new Vector3f();
+ private Vector3f dimension = new Vector3f();
+ private Vector3f invDim = new Vector3f();
+
+ private final Triangle scaledTri = new Triangle();
+ private final Plane triPlane = new Plane();
+ private final Vector3f temp1 = new Vector3f(),
+ temp2 = new Vector3f(),
+ temp3 = new Vector3f();
+ private final Vector3f sVelocity = new Vector3f(),
+ sCenter = new Vector3f();
+
+ public Vector3f getCenter() {
+ return center;
+ }
+
+ public void setCenter(Vector3f center) {
+ this.center.set(center);
+ }
+
+ public Vector3f getDimension() {
+ return dimension;
+ }
+
+ public void setDimension(Vector3f dimension) {
+ this.dimension.set(dimension);
+ this.invDim.set(1,1,1).divideLocal(dimension);
+ }
+
+ public void setDimension(float x, float y, float z){
+ this.dimension.set(x,y,z);
+ this.invDim.set(1,1,1).divideLocal(dimension);
+ }
+
+ public void setDimension(float dim){
+ this.dimension.set(dim, dim, dim);
+ this.invDim.set(1,1,1).divideLocal(dimension);
+ }
+
+ public Vector3f getVelocity() {
+ return velocity;
+ }
+
+ public void setVelocity(Vector3f velocity) {
+ this.velocity.set(velocity);
+ }
+
+ private boolean pointsOnSameSide(Vector3f p1, Vector3f p2, Vector3f line1, Vector3f line2) {
+ // V1 = (line2 - line1) x (p1 - line1)
+ // V2 = (p2 - line1) x (line2 - line1)
+
+ temp1.set(line2).subtractLocal(line1);
+ temp3.set(temp1);
+ temp2.set(p1).subtractLocal(line1);
+ temp1.crossLocal(temp2);
+
+ temp2.set(p2).subtractLocal(line1);
+ temp3.crossLocal(temp2);
+
+ // V1 . V2 >= 0
+ return temp1.dot(temp3) >= 0;
+ }
+
+ private boolean isPointInTriangle(Vector3f point, AbstractTriangle tri) {
+ if (pointsOnSameSide(point, tri.get1(), tri.get2(), tri.get3())
+ && pointsOnSameSide(point, tri.get2(), tri.get1(), tri.get3())
+ && pointsOnSameSide(point, tri.get3(), tri.get1(), tri.get2()))
+ return true;
+ return false;
+ }
+
+ private static float getLowestRoot(float a, float b, float c, float maxR) {
+ float determinant = b * b - 4f * a * c;
+ if (determinant < 0){
+ return Float.NaN;
+ }
+
+ float sqrtd = FastMath.sqrt(determinant);
+ float r1 = (-b - sqrtd) / (2f * a);
+ float r2 = (-b + sqrtd) / (2f * a);
+
+ if (r1 > r2){
+ float temp = r2;
+ r2 = r1;
+ r1 = temp;
+ }
+
+ if (r1 > 0 && r1 < maxR){
+ return r1;
+ }
+
+ if (r2 > 0 && r2 < maxR){
+ return r2;
+ }
+
+ return Float.NaN;
+ }
+
+ private float collideWithVertex(Vector3f sCenter, Vector3f sVelocity,
+ float velocitySquared, Vector3f vertex, float t) {
+ // A = velocity * velocity
+ // B = 2 * (velocity . (center - vertex));
+ // C = ||vertex - center||^2 - 1f;
+
+ temp1.set(sCenter).subtractLocal(vertex);
+ float a = velocitySquared;
+ float b = 2f * sVelocity.dot(temp1);
+ float c = temp1.negateLocal().lengthSquared() - 1f;
+ float newT = getLowestRoot(a, b, c, t);
+
+// float A = velocitySquared;
+// float B = sCenter.subtract(vertex).dot(sVelocity) * 2f;
+// float C = vertex.subtract(sCenter).lengthSquared() - 1f;
+//
+// float newT = getLowestRoot(A, B, C, Float.MAX_VALUE);
+// if (newT > 1.0f)
+// newT = Float.NaN;
+
+ return newT;
+ }
+
+ private float collideWithSegment(Vector3f sCenter,
+ Vector3f sVelocity,
+ float velocitySquared,
+ Vector3f l1,
+ Vector3f l2,
+ float t,
+ Vector3f store) {
+ Vector3f edge = temp1.set(l2).subtractLocal(l1);
+ Vector3f base = temp2.set(l1).subtractLocal(sCenter);
+
+ float edgeSquared = edge.lengthSquared();
+ float baseSquared = base.lengthSquared();
+
+ float EdotV = edge.dot(sVelocity);
+ float EdotB = edge.dot(base);
+
+ float a = (edgeSquared * -velocitySquared) + EdotV * EdotV;
+ float b = (edgeSquared * 2f * sVelocity.dot(base))
+ - (2f * EdotV * EdotB);
+ float c = (edgeSquared * (1f - baseSquared)) + EdotB * EdotB;
+ float newT = getLowestRoot(a, b, c, t);
+ if (!Float.isNaN(newT)){
+ float f = (EdotV * newT - EdotB) / edgeSquared;
+ if (f >= 0f && f < 1f){
+ store.scaleAdd(f, edge, l1);
+ return newT;
+ }
+ }
+ return Float.NaN;
+ }
+
+ private CollisionResult collideWithTriangle(AbstractTriangle tri){
+ // scale scaledTriangle based on dimension
+ scaledTri.get1().set(tri.get1()).multLocal(invDim);
+ scaledTri.get2().set(tri.get2()).multLocal(invDim);
+ scaledTri.get3().set(tri.get3()).multLocal(invDim);
+// Vector3f sVelocity = velocity.mult(invDim);
+// Vector3f sCenter = center.mult(invDim);
+ velocity.mult(invDim, sVelocity);
+ center.mult(invDim, sCenter);
+
+ triPlane.setPlanePoints(scaledTri);
+
+ float normalDotVelocity = triPlane.getNormal().dot(sVelocity);
+ // XXX: sVelocity.normalize() needed?
+ // back facing scaledTriangles not considered
+ if (normalDotVelocity > 0f)
+ return null;
+
+ float t0, t1;
+ boolean embedded = false;
+
+ float signedDistanceToPlane = triPlane.pseudoDistance(sCenter);
+ if (normalDotVelocity == 0.0f){
+ // we are travelling exactly parrallel to the plane
+ if (FastMath.abs(signedDistanceToPlane) >= 1.0f){
+ // no collision possible
+ return null;
+ }else{
+ // we are embedded
+ t0 = 0;
+ t1 = 1;
+ embedded = true;
+ System.out.println("EMBEDDED");
+ return null;
+ }
+ }else{
+ t0 = (-1f - signedDistanceToPlane) / normalDotVelocity;
+ t1 = ( 1f - signedDistanceToPlane) / normalDotVelocity;
+
+ if (t0 > t1){
+ float tf = t1;
+ t1 = t0;
+ t0 = tf;
+ }
+
+ if (t0 > 1.0f || t1 < 0.0f){
+ // collision is out of this sVelocity range
+ return null;
+ }
+
+ // clamp the interval to [0, 1]
+ t0 = Math.max(t0, 0.0f);
+ t1 = Math.min(t1, 1.0f);
+ }
+
+ boolean foundCollision = false;
+ float minT = 1f;
+
+ Vector3f contactPoint = new Vector3f();
+ Vector3f contactNormal = new Vector3f();
+
+// if (!embedded){
+ // check against the inside of the scaledTriangle
+ // contactPoint = sCenter - p.normal + t0 * sVelocity
+ contactPoint.set(sVelocity);
+ contactPoint.multLocal(t0);
+ contactPoint.addLocal(sCenter);
+ contactPoint.subtractLocal(triPlane.getNormal());
+
+ // test to see if the collision is on a scaledTriangle interior
+ if (isPointInTriangle(contactPoint, scaledTri) && !embedded){
+ foundCollision = true;
+
+ minT = t0;
+
+ // scale collision point back into R3
+ contactPoint.multLocal(dimension);
+ contactNormal.set(velocity).multLocal(t0);
+ contactNormal.addLocal(center);
+ contactNormal.subtractLocal(contactPoint).normalizeLocal();
+
+// contactNormal.set(triPlane.getNormal());
+
+ CollisionResult result = new CollisionResult();
+ result.setContactPoint(contactPoint);
+ result.setContactNormal(contactNormal);
+ result.setDistance(minT * velocity.length());
+ return result;
+ }
+// }
+
+ float velocitySquared = sVelocity.lengthSquared();
+
+ Vector3f v1 = scaledTri.get1();
+ Vector3f v2 = scaledTri.get2();
+ Vector3f v3 = scaledTri.get3();
+
+ // vertex 1
+ float newT;
+ newT = collideWithVertex(sCenter, sVelocity, velocitySquared, v1, minT);
+ if (!Float.isNaN(newT)){
+ minT = newT;
+ contactPoint.set(v1);
+ foundCollision = true;
+ }
+
+ // vertex 2
+ newT = collideWithVertex(sCenter, sVelocity, velocitySquared, v2, minT);
+ if (!Float.isNaN(newT)){
+ minT = newT;
+ contactPoint.set(v2);
+ foundCollision = true;
+ }
+
+ // vertex 3
+ newT = collideWithVertex(sCenter, sVelocity, velocitySquared, v3, minT);
+ if (!Float.isNaN(newT)){
+ minT = newT;
+ contactPoint.set(v3);
+ foundCollision = true;
+ }
+
+ // edge 1-2
+ newT = collideWithSegment(sCenter, sVelocity, velocitySquared, v1, v2, minT, contactPoint);
+ if (!Float.isNaN(newT)){
+ minT = newT;
+ foundCollision = true;
+ }
+
+ // edge 2-3
+ newT = collideWithSegment(sCenter, sVelocity, velocitySquared, v2, v3, minT, contactPoint);
+ if (!Float.isNaN(newT)){
+ minT = newT;
+ foundCollision = true;
+ }
+
+ // edge 3-1
+ newT = collideWithSegment(sCenter, sVelocity, velocitySquared, v3, v1, minT, contactPoint);
+ if (!Float.isNaN(newT)){
+ minT = newT;
+ foundCollision = true;
+ }
+
+ if (foundCollision){
+ // compute contact normal based on minimum t
+ contactPoint.multLocal(dimension);
+ contactNormal.set(velocity).multLocal(t0);
+ contactNormal.addLocal(center);
+ contactNormal.subtractLocal(contactPoint).normalizeLocal();
+
+ CollisionResult result = new CollisionResult();
+ result.setContactPoint(contactPoint);
+ result.setContactNormal(contactNormal);
+ result.setDistance(minT * velocity.length());
+
+ return result;
+ }else{
+ return null;
+ }
+ }
+
+ public CollisionResult collideWithSweepSphere(SweepSphere other){
+ temp1.set(velocity).subtractLocal(other.velocity);
+ temp2.set(center).subtractLocal(other.center);
+ temp3.set(dimension).addLocal(other.dimension);
+ // delta V
+ // delta C
+ // Rsum
+
+ float a = temp1.lengthSquared();
+ float b = 2f * temp1.dot(temp2);
+ float c = temp2.lengthSquared() - temp3.getX() * temp3.getX();
+ float t = getLowestRoot(a, b, c, 1);
+
+ // no collision
+ if (Float.isNaN(t))
+ return null;
+
+ CollisionResult result = new CollisionResult();
+ result.setDistance(velocity.length() * t);
+
+ temp1.set(velocity).multLocal(t).addLocal(center);
+ temp2.set(other.velocity).multLocal(t).addLocal(other.center);
+ temp3.set(temp2).subtractLocal(temp1);
+ // temp3 contains center to other.center vector
+
+ // normalize it to get normal
+ temp2.set(temp3).normalizeLocal();
+ result.setContactNormal(new Vector3f(temp2));
+
+ // temp3 is contact point
+ temp3.set(temp2).multLocal(dimension).addLocal(temp1);
+ result.setContactPoint(new Vector3f(temp3));
+
+ return result;
+ }
+
+ public static void main(String[] args){
+ SweepSphere ss = new SweepSphere();
+ ss.setCenter(Vector3f.ZERO);
+ ss.setDimension(1);
+ ss.setVelocity(new Vector3f(10, 10, 10));
+
+ SweepSphere ss2 = new SweepSphere();
+ ss2.setCenter(new Vector3f(5, 5, 5));
+ ss2.setDimension(1);
+ ss2.setVelocity(new Vector3f(-10, -10, -10));
+
+ CollisionResults cr = new CollisionResults();
+ ss.collideWith(ss2, cr);
+ if (cr.size() > 0){
+ CollisionResult c = cr.getClosestCollision();
+ System.out.println("D = "+c.getDistance());
+ System.out.println("P = "+c.getContactPoint());
+ System.out.println("N = "+c.getContactNormal());
+ }
+ }
+
+ public int collideWith(Collidable other, CollisionResults results)
+ throws UnsupportedCollisionException {
+ if (other instanceof AbstractTriangle){
+ AbstractTriangle tri = (AbstractTriangle) other;
+ CollisionResult result = collideWithTriangle(tri);
+ if (result != null){
+ results.addCollision(result);
+ return 1;
+ }
+ return 0;
+ }else if (other instanceof SweepSphere){
+ SweepSphere sph = (SweepSphere) other;
+
+ CollisionResult result = collideWithSweepSphere(sph);
+ if (result != null){
+ results.addCollision(result);
+ return 1;
+ }
+ return 0;
+ }else{
+ throw new UnsupportedCollisionException();
+ }
+ }
+
+}