From 350a482b32512191596daad55104beec98af9981 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Wed, 16 Feb 2011 08:12:56 +0000 Subject: Added alden's code, moved his objects into the object class and made them extend physical object. Fixed a node selection problem in TesseractUI. --- src/alden/CollidableObject.java | 62 +++++++---- src/alden/CollisionDetector.java | 204 ++++++++++++++++++++++++++++++------ src/alden/CollisionInfo.java | 13 ++- src/alden/Sphere.java | 35 ------- src/tesseract/TesseractUI.java | 20 +++- src/tesseract/objects/Box.java | 36 +++++++ src/tesseract/objects/Circle.java | 55 ++++++++++ src/tesseract/objects/Particle.java | 2 +- src/tesseract/objects/Polygon.java | 43 ++++++++ src/tesseract/objects/Sphere.java | 35 +++++++ 10 files changed, 411 insertions(+), 94 deletions(-) delete mode 100644 src/alden/Sphere.java create mode 100644 src/tesseract/objects/Box.java create mode 100644 src/tesseract/objects/Circle.java create mode 100644 src/tesseract/objects/Polygon.java create mode 100644 src/tesseract/objects/Sphere.java diff --git a/src/alden/CollidableObject.java b/src/alden/CollidableObject.java index f3e1ed9..eb3ff6a 100644 --- a/src/alden/CollidableObject.java +++ b/src/alden/CollidableObject.java @@ -45,7 +45,7 @@ public abstract class CollidableObject { angularVelocity = new Vector3f(); torqueAccumulator = new Vector3f(); inverseInertiaTensor = new Matrix3f(); - coefficientOfRestitution = 0.65f; + coefficientOfRestitution = 0.75f; penetrationCorrection = 1.05f; dynamicFriction = 0.02f; TG = new TransformGroup(); @@ -58,7 +58,7 @@ public abstract class CollidableObject { protected void setShape(Node node) { this.node = node; TG.addChild(node); - //TG.addChild(CollisionDetector.createShape(CollisionDetector.triangularize(node))); +// TG.addChild(CollisionDetector.createShape(CollisionDetector.triangularize(node))); } public Group getGroup() { @@ -79,6 +79,7 @@ public abstract class CollidableObject { velocity.scaleAdd(duration, forceAccumulator, velocity); // The force vector is cleared. forceAccumulator.set(0, 0, 0); + angularVelocity.scaleAdd(duration, torqueAccumulator, angularVelocity); torqueAccumulator.set(0, 0, 0); UnQuat4f tmp = new UnQuat4f(angularVelocity.x, angularVelocity.y, angularVelocity.z, 0); @@ -89,10 +90,16 @@ public abstract class CollidableObject { } protected void updateTransformGroup() { + Vector3f com = new Vector3f(-centerOfMass.x, -centerOfMass.y, -centerOfMass.z); Transform3D tmp = new Transform3D(); - tmp.setRotation(orientation); - tmp.setTranslation(position); - TG.setTransform(tmp); + tmp.setTranslation(com); + Transform3D tmp2 = new Transform3D(); + tmp2.setRotation(orientation); + com.negate(); + com.add(position); + tmp2.setTranslation(com); + tmp2.mul(tmp); + TG.setTransform(tmp2); clearCaches(); } @@ -122,12 +129,15 @@ public abstract class CollidableObject { if (inverseInertiaTensorCache == null) { inverseInertiaTensorCache = new Matrix3f(); inverseInertiaTensorCache.set(orientation); - inverseInertiaTensorCache.invert(); - inverseInertiaTensorCache.mul(inverseInertiaTensor); + Matrix3f tmp = new Matrix3f(inverseInertiaTensor); + Matrix3f tmp2 = new Matrix3f(inverseInertiaTensorCache); + tmp2.invert(); + tmp.mul(tmp2); + inverseInertiaTensorCache.mul(tmp); } return inverseInertiaTensorCache; } - + protected void clearCaches() { vertexCache = null; triangleCache = null; @@ -144,7 +154,6 @@ public abstract class CollidableObject { float max = Float.NEGATIVE_INFINITY; int count = 0; for (CollisionInfo collision : collisions) { -// float speed = collision.contactNormal.dot(previousVelocity) - collision.contactNormal.dot(other.previousVelocity); Vector3f thisRelativeContactPosition = new Vector3f(); thisRelativeContactPosition.scaleAdd(-1, position, collision.contactPoint); thisRelativeContactPosition.scaleAdd(-1, centerOfMass, thisRelativeContactPosition); @@ -203,34 +212,47 @@ public abstract class CollidableObject { if (totalInverseMass == 0) return; + Vector3f thisMovementUnit = new Vector3f(); + thisMovementUnit.cross(thisRelativeContactPosition, ci.contactNormal); + getInverseInertiaTensor().transform(thisMovementUnit); Vector3f thisAngularVelocityUnit = new Vector3f(); - thisAngularVelocityUnit.cross(thisRelativeContactPosition, ci.contactNormal); - getInverseInertiaTensor().transform(thisAngularVelocityUnit); - thisAngularVelocityUnit.cross(thisAngularVelocityUnit, thisRelativeContactPosition); + thisAngularVelocityUnit.cross(thisMovementUnit, thisRelativeContactPosition); totalInverseMass += thisAngularVelocityUnit.dot(ci.contactNormal); + Vector3f otherMovementUnit = new Vector3f(); + otherMovementUnit.cross(otherRelativeContactPosition, ci.contactNormal); + other.getInverseInertiaTensor().transform(otherMovementUnit); Vector3f otherAngularVelocityUnit = new Vector3f(); - otherAngularVelocityUnit.cross(otherRelativeContactPosition, ci.contactNormal); - other.getInverseInertiaTensor().transform(otherAngularVelocityUnit); - otherAngularVelocityUnit.cross(otherAngularVelocityUnit, otherRelativeContactPosition); + otherAngularVelocityUnit.cross(otherMovementUnit, otherRelativeContactPosition); totalInverseMass += otherAngularVelocityUnit.dot(ci.contactNormal); - + Vector3f impulse = new Vector3f(ci.contactNormal); impulse.scale(deltaClosingSpeed / totalInverseMass); + velocity.scaleAdd(inverseMass, impulse, velocity); Vector3f tmp = new Vector3f(); tmp.cross(thisRelativeContactPosition, impulse); - tmp.scale(thisAngularVelocityUnit.dot(ci.contactNormal)); getInverseInertiaTensor().transform(tmp); angularVelocity.add(tmp); - position.scaleAdd(-ci.penetration * penetrationCorrection * inverseMass / (inverseMass + other.inverseMass), ci.contactNormal, position); + position.scaleAdd(-ci.penetration * penetrationCorrection * inverseMass / totalInverseMass, ci.contactNormal, position); + thisMovementUnit.scale(-ci.penetration * penetrationCorrection / totalInverseMass); + UnQuat4f tmp2 = new UnQuat4f(thisMovementUnit.x, thisMovementUnit.y, thisMovementUnit.z, 0); + tmp2.scale(0.5f); + tmp2.mul(orientation); + orientation.add(tmp2); + orientation.normalize(); impulse.negate(); other.velocity.scaleAdd(other.inverseMass, impulse, other.velocity); tmp.cross(otherRelativeContactPosition, impulse); - tmp.scale(otherAngularVelocityUnit.dot(ci.contactNormal)); other.getInverseInertiaTensor().transform(tmp); other.angularVelocity.add(tmp); - other.position.scaleAdd(ci.penetration * penetrationCorrection * other.inverseMass / (inverseMass + other.inverseMass), ci.contactNormal, other.position); + other.position.scaleAdd(ci.penetration * penetrationCorrection * other.inverseMass / totalInverseMass, ci.contactNormal, other.position); + otherMovementUnit.scale(ci.penetration * penetrationCorrection / totalInverseMass); + tmp2.set(otherMovementUnit.x, otherMovementUnit.y, otherMovementUnit.z, 0); + tmp2.scale(0.5f); + tmp2.mul(other.orientation); + other.orientation.add(tmp2); + other.orientation.normalize(); } } diff --git a/src/alden/CollisionDetector.java b/src/alden/CollisionDetector.java index bb7817c..84682b8 100644 --- a/src/alden/CollisionDetector.java +++ b/src/alden/CollisionDetector.java @@ -1,4 +1,5 @@ package alden; + import java.util.ArrayList; import javax.media.j3d.Appearance; @@ -15,11 +16,15 @@ import javax.media.j3d.Transform3D; import javax.media.j3d.TriangleArray; import javax.media.j3d.TriangleFanArray; import javax.media.j3d.TriangleStripArray; +import javax.vecmath.Matrix3f; import javax.vecmath.Point3f; import javax.vecmath.Tuple3f; import javax.vecmath.Vector3f; import tesseract.objects.HalfSpace; +import tesseract.objects.Particle; +import tesseract.objects.Polygon; +import tesseract.objects.Sphere; import com.sun.j3d.utils.geometry.Primitive; @@ -228,21 +233,6 @@ public class CollisionDetector { } return region; } - - public boolean isAdjacent(Triangle other) { - if (a.equals(other.a)) { - if (b.equals(other.b) || b.equals(other.c) || c.equals(other.b) || c.equals(other.c)) - return true; - } else if (a.equals(other.b)) { - if (b.equals(other.a) || b.equals(other.c) || c.equals(other.a) || c.equals(other.c)) - return true; - } else if (a.equals(other.c)) { - if (b.equals(other.a) || b.equals(other.b) || c.equals(other.a) || c.equals(other.b)) - return true; - } else if ((b.equals(other.b) || b.equals(other.c)) && (c.equals(other.b) || c.equals(other.c))) - return true; - return false; - } } public static ArrayList calculateCollisions(CollidableObject a, CollidableObject b) { @@ -251,28 +241,72 @@ public class CollisionDetector { if (a instanceof HalfSpace) { if (b instanceof HalfSpace) return EMPTY_COLLISION_LIST; + if (b instanceof Particle) + return calculateCollisions((HalfSpace)a, (Particle)b); if (b instanceof Sphere) return calculateCollisions((HalfSpace)a, (Sphere)b); return calculateCollisions((HalfSpace)a, b.getVertices()); } - if (!a.getBounds().intersect(b.getBounds())) - return EMPTY_COLLISION_LIST; + if (b instanceof HalfSpace) { + if (a instanceof Particle) + return flipContactNormals(calculateCollisions((HalfSpace)b, (Particle)a)); + if (a instanceof Sphere) + return flipContactNormals(calculateCollisions((HalfSpace)b, (Sphere)a)); + return flipContactNormals(calculateCollisions((HalfSpace)b, a.getVertices())); + } + if (a instanceof Particle) { + if (b instanceof Particle) + return EMPTY_COLLISION_LIST; + if (b instanceof Sphere) + return calculateCollisions((Particle)a, (Sphere)b); + if (b instanceof Polygon) + return calculateCollisions((Particle)a, (Polygon)b); + } + if (b instanceof Particle) { + if (a instanceof Sphere) + return flipContactNormals(calculateCollisions((Particle)b, (Sphere)a)); + if (a instanceof Polygon) + return flipContactNormals(calculateCollisions((Particle)b, (Polygon)a)); + } if (a instanceof Sphere && b instanceof Sphere) return calculateCollisions((Sphere)a, (Sphere)b); + + if (!a.getBounds().intersect(b.getBounds())) + return EMPTY_COLLISION_LIST; + + if (a instanceof Particle) + return calculateCollisions((Particle)a, b); + if (b instanceof Particle) + return flipContactNormals(calculateCollisions((Particle)b, a)); + if (a instanceof Polygon) + return calculateCollisions((Polygon)a, b); + if (b instanceof Polygon) + return calculateCollisions((Polygon)b, a); return CollisionDetector.calculateCollisions(a.getCollisionTriangles(), b.getCollisionTriangles()); } + private static ArrayList calculateCollisions(HalfSpace a, Particle b) { + float penetration = a.intercept - a.normal.dot(b.position); + if (penetration < 0) + return EMPTY_COLLISION_LIST; + Vector3f contactPoint = new Vector3f(); + contactPoint.scaleAdd(penetration, a.normal, b.position); + assert(Math.abs(a.normal.dot(contactPoint) - a.intercept) < 0.01); + ArrayList collisions = new ArrayList(); + collisions.add(new CollisionInfo(contactPoint, new Vector3f(a.normal), penetration)); + return collisions; + } + private static ArrayList calculateCollisions(HalfSpace a, Sphere b) { float penetration = b.radius - (a.normal.dot(b.position) - a.intercept); - if (penetration >= 0) { - Vector3f contactPoint = new Vector3f(); - contactPoint.scaleAdd(-(b.radius - penetration), a.normal, b.position); - assert(Math.abs(a.normal.dot(contactPoint) - a.intercept) < 0.01); - ArrayList collisions = new ArrayList(); - collisions.add(new CollisionInfo(contactPoint, a.normal, penetration)); - return collisions; - } - return EMPTY_COLLISION_LIST; + if (penetration < 0) + return EMPTY_COLLISION_LIST; + Vector3f contactPoint = new Vector3f(); + contactPoint.scaleAdd(-(b.radius - penetration), a.normal, b.position); + assert(Math.abs(a.normal.dot(contactPoint) - a.intercept) < 0.01); + ArrayList collisions = new ArrayList(); + collisions.add(new CollisionInfo(contactPoint, new Vector3f(a.normal), penetration)); + return collisions; } private static ArrayList calculateCollisions(HalfSpace a, ArrayList setB) { @@ -283,24 +317,124 @@ public class CollisionDetector { Vector3f contactPoint = new Vector3f(); contactPoint.scaleAdd(penetration, a.normal, vertex); assert(Math.abs(a.normal.dot(contactPoint) - a.intercept) < 0.01); - collisions.add(new CollisionInfo(contactPoint, a.normal, penetration)); + collisions.add(new CollisionInfo(contactPoint, new Vector3f(a.normal), penetration)); } } return collisions; } + private static ArrayList calculateCollisions(Particle a, Sphere b) { + Vector3f delta = new Vector3f(); + delta.scaleAdd(-1, a.position, b.position); + float penetration = b.radius - delta.length(); + if (penetration < 0) + return EMPTY_COLLISION_LIST; + + ArrayList collisions = new ArrayList(); + delta.normalize(); + Vector3f contactPoint = new Vector3f(); + contactPoint.scaleAdd(-(b.radius - 0.5f * penetration), delta, b.position); + collisions.add(new CollisionInfo(contactPoint, delta, penetration)); + return collisions; + } + + private static ArrayList calculateCollisions(Particle a, Polygon b) { + float penetration = b.intercept - b.normal.dot(a.position); + float previousPenetration = b.intercept - b.normal.dot(a.previousPosition); + if (Math.signum(penetration) == Math.signum(previousPenetration)) + return EMPTY_COLLISION_LIST; + + for (Triangle triangle : b.getCollisionTriangles()) { + Matrix3f tmp = new Matrix3f(a.previousPosition.x - a.position.x, triangle.b.x - triangle.a.x, triangle.c.x - triangle.a.x, + a.previousPosition.y - a.position.y, triangle.b.y - triangle.a.y, triangle.c.y - triangle.a.y, + a.previousPosition.z - a.position.z, triangle.b.z - triangle.a.z, triangle.c.z - triangle.a.z); + tmp.invert(); + Vector3f intercept = new Vector3f(); + intercept.scaleAdd(-1, triangle.a, a.previousPosition); + tmp.transform(intercept); + + assert(intercept.x >= 0 && intercept.x <= 1); + + if (intercept.y >= 0 && intercept.y <= 1 && intercept.z >= 0 && intercept.z <= 1 && (intercept.y + intercept.z) <= 1) { + Vector3f contactPoint = new Vector3f(); + contactPoint.scaleAdd(-1, a.previousPosition, a.position); + contactPoint.scale(intercept.x); + contactPoint.add(a.previousPosition); + assert(Math.abs(b.normal.dot(contactPoint) - b.intercept) < 0.01); + Vector3f contactNormal = new Vector3f(b.normal); + if (penetration - previousPenetration > 0) + contactNormal.negate(); + else + penetration = -penetration; + ArrayList collisions = new ArrayList(); + collisions.add(new CollisionInfo(contactPoint, contactNormal, penetration)); + return collisions; + } + } + return EMPTY_COLLISION_LIST; + } + + private static ArrayList calculateCollisions(Particle a, CollidableObject b) { + ArrayList collisions = new ArrayList(); + for (Triangle triangle : b.getCollisionTriangles()) { + float penetration = triangle.intercept - triangle.normal.dot(a.position); + if (penetration < 0 || (!collisions.isEmpty() && penetration <= collisions.get(0).penetration)) + continue; + float previousPenetration = triangle.intercept - triangle.normal.dot(a.previousPosition); + if (Math.signum(penetration) == Math.signum(previousPenetration)) + continue; + + Matrix3f tmp = new Matrix3f(a.previousPosition.x - a.position.x, triangle.b.x - triangle.a.x, triangle.c.x - triangle.a.x, + a.previousPosition.y - a.position.y, triangle.b.y - triangle.a.y, triangle.c.y - triangle.a.y, + a.previousPosition.z - a.position.z, triangle.b.z - triangle.a.z, triangle.c.z - triangle.a.z); + tmp.invert(); + Vector3f intercept = new Vector3f(); + intercept.scaleAdd(-1, triangle.a, a.previousPosition); + tmp.transform(intercept); + + assert(intercept.x >= 0 && intercept.x <= 1); + + if (intercept.y >= 0 && intercept.y <= 1 && intercept.z >= 0 && intercept.z <= 1 && (intercept.y + intercept.z) <= 1) { + Vector3f contactPoint = new Vector3f(); + contactPoint.scaleAdd(-1, a.previousPosition, a.position); + contactPoint.scale(intercept.x); + contactPoint.add(a.previousPosition); + assert(Math.abs(triangle.normal.dot(contactPoint) - triangle.intercept) < 0.01); + Vector3f contactNormal = new Vector3f(triangle.normal); + if (penetration - previousPenetration > 0) + contactNormal.negate(); + else + penetration = -penetration; + collisions.clear(); + collisions.add(new CollisionInfo(contactPoint, contactNormal, penetration)); + } + } + return collisions; + } + private static ArrayList calculateCollisions(Sphere a, Sphere b) { Vector3f delta = new Vector3f(); delta.scaleAdd(-1, a.position, b.position); - float penetration = delta.length() - a.radius - b.radius; - if (penetration > 0) + float penetration = a.radius + b.radius - delta.length(); + if (penetration < 0) return EMPTY_COLLISION_LIST; ArrayList collisions = new ArrayList(); delta.normalize(); Vector3f contactPoint = new Vector3f(); - contactPoint.scaleAdd(a.radius + 0.5f * penetration, delta, a.position); - collisions.add(new CollisionInfo(contactPoint, delta, -penetration)); + contactPoint.scaleAdd(a.radius - 0.5f * penetration, delta, a.position); + collisions.add(new CollisionInfo(contactPoint, delta, penetration)); + return collisions; + } + + private static ArrayList calculateCollisions(Polygon a, CollidableObject b) { + ArrayList collisions = calculateCollisions(a.getCollisionTriangles(), b.getCollisionTriangles()); + int size = collisions.size(); + collisions.ensureCapacity(2 * size); + for (int i = 0; i < size; i++) { + collisions.add(collisions.get(i).clone()); + collisions.get(collisions.size() - 1).contactNormal.negate(); + } return collisions; } @@ -315,6 +449,12 @@ public class CollisionDetector { return collisions; } + private static ArrayList flipContactNormals(ArrayList collisions) { + for (CollisionInfo collision : collisions) + collision.contactNormal.negate(); + return collisions; + } + public static ArrayList extractVertices(Node node) { ArrayList vertices = new ArrayList(); extractVertices(node, vertices); @@ -343,7 +483,7 @@ public class CollisionDetector { for (int i = 0; i < group.numChildren(); i++) extractVertices(group.getChild(i), vertices); } else - throw new IllegalArgumentException("Illegal node type for vertex extraction "); + throw new IllegalArgumentException("Illegal node type for vertex extraction"); } private static void extractVertices(Geometry geometry, Transform3D transform, ArrayList vertices) { diff --git a/src/alden/CollisionInfo.java b/src/alden/CollisionInfo.java index 9cefcd0..dad74a5 100644 --- a/src/alden/CollisionInfo.java +++ b/src/alden/CollisionInfo.java @@ -2,7 +2,7 @@ package alden; import javax.vecmath.*; @SuppressWarnings("restriction") -public class CollisionInfo { +public class CollisionInfo implements Cloneable { public Vector3f contactPoint; public Vector3f contactNormal; public float penetration; @@ -12,4 +12,15 @@ public class CollisionInfo { this.contactNormal = contactNormal; this.penetration = penetration; } + + public CollisionInfo clone() { + try { + CollisionInfo copy = (CollisionInfo)super.clone(); + copy.contactPoint = new Vector3f(contactPoint); + copy.contactNormal = new Vector3f(contactNormal); + return copy; + } catch (CloneNotSupportedException e) { + return null; + } + } } \ No newline at end of file diff --git a/src/alden/Sphere.java b/src/alden/Sphere.java deleted file mode 100644 index ddbaff4..0000000 --- a/src/alden/Sphere.java +++ /dev/null @@ -1,35 +0,0 @@ -package alden; - -import javax.media.j3d.*; -import javax.vecmath.*; - -@SuppressWarnings("restriction") -public class Sphere extends CollidableObject { - protected float radius; - - public Sphere(float radius, Vector3f position) { - this(1, radius, position); - } - - public Sphere(float mass, float radius, Vector3f position) { - super(mass); - setShape(createShape(radius, 22)); - this.radius = radius; - this.position.set(position); - if (inverseMass != 0) { - inverseInertiaTensor.m00 = 2f / 5 / inverseMass * radius * radius; - inverseInertiaTensor.m11 = inverseInertiaTensor.m00; - inverseInertiaTensor.m22 = inverseInertiaTensor.m00; - inverseInertiaTensor.invert(); - } - updateTransformGroup(); - } - - protected Node createShape(float radius, int divisions) { - Appearance appearance = new Appearance(); - Material material = new Material(); - material.setDiffuseColor(0.7f, 0.7f, 1); - appearance.setMaterial(material); - return new com.sun.j3d.utils.geometry.Sphere(radius, com.sun.j3d.utils.geometry.Sphere.GENERATE_NORMALS, divisions, appearance); - } -} diff --git a/src/tesseract/TesseractUI.java b/src/tesseract/TesseractUI.java index 1e8ff9c..ca882e2 100644 --- a/src/tesseract/TesseractUI.java +++ b/src/tesseract/TesseractUI.java @@ -12,6 +12,7 @@ import java.awt.event.MouseWheelListener; import javax.media.j3d.BoundingBox; import javax.media.j3d.Canvas3D; +import javax.media.j3d.Node; import javax.media.j3d.Transform3D; import javax.media.j3d.TransformGroup; import javax.swing.JCheckBoxMenuItem; @@ -39,6 +40,7 @@ import tesseract.menuitems.IcosahedronMenuItem; import tesseract.menuitems.ParticleEmitterMenuItem; import tesseract.menuitems.ParticleMenuItem; import tesseract.menuitems.PlanarPolygonMenuItem; +import tesseract.objects.Box; import tesseract.objects.ChainLink2; import tesseract.objects.PhysicalObject; @@ -149,6 +151,7 @@ public class TesseractUI extends JFrame { ChainLink2 o = new ChainLink2(new Vector3f(), 1); o.setRotation(); myWorld.addObject(o); + myWorld.addObject(new Box(0.20f, 0.09f, 0.10f, new Vector3f(0, 0.25f, 0))); } /** @@ -342,11 +345,18 @@ public class TesseractUI extends JFrame { pc.setShapeLocation(e); PickResult r = pc.pickClosest(); - if (r != null && r.getObject().getUserData() instanceof PhysicalObject) { - myCurrentObject = - (PhysicalObject) r.getObject().getUserData(); - - myCurrentObject.selected(true); + if (r != null) { + for (int i = r.getSceneGraphPath().nodeCount() - 1; + i > 0; i--) { + Node n = r.getSceneGraphPath().getNode(i); + if (n.getUserData() instanceof PhysicalObject) { + myCurrentObject = + (PhysicalObject) n.getUserData(); + myCurrentObject.selected(true); + + break; + } + } } } diff --git a/src/tesseract/objects/Box.java b/src/tesseract/objects/Box.java new file mode 100644 index 0000000..fb3dc42 --- /dev/null +++ b/src/tesseract/objects/Box.java @@ -0,0 +1,36 @@ +package tesseract.objects; +import javax.media.j3d.Appearance; +import javax.media.j3d.Geometry; +import javax.media.j3d.Material; +import javax.media.j3d.Node; +import javax.vecmath.Vector3f; + +import com.sun.j3d.utils.geometry.Primitive; + +public class Box extends PhysicalObject { + public Box(float width, float height, float depth, Vector3f position) { + this(1, width, height, depth, position); + } + + public Box(float mass, float width, float height, float depth, Vector3f position) { + super(position, mass); + setShape(createShape(width, height, depth)); + + previousPosition.set(position); + if (inverseMass != 0) { + inverseInertiaTensor.m00 = 1f / 12 / inverseMass * (height * height + depth * depth); + inverseInertiaTensor.m11 = 1f / 12 / inverseMass * (width * width + depth * depth); + inverseInertiaTensor.m22 = 1f / 12 / inverseMass * (width * width + height * height); + inverseInertiaTensor.invert(); + } + updateTransformGroup(); + } + + protected Node createShape(float width, float height, float depth) { + Appearance appearance = new Appearance(); + Material material = new Material(); + material.setDiffuseColor(0.7f, 1, 0.7f); + appearance.setMaterial(material); + return new com.sun.j3d.utils.geometry.Box(width / 2, height / 2, depth / 2, appearance); + } +} diff --git a/src/tesseract/objects/Circle.java b/src/tesseract/objects/Circle.java new file mode 100644 index 0000000..3019a2b --- /dev/null +++ b/src/tesseract/objects/Circle.java @@ -0,0 +1,55 @@ +package tesseract.objects; +import com.sun.j3d.utils.image.*; +import javax.media.j3d.*; +import javax.vecmath.*; + +public class Circle extends Polygon { + public Circle(float radius, Vector3f position, Vector3f normal) { + this(1, radius, position, normal); + } + + public Circle(float mass, float radius, Vector3f position, Vector3f normal) { + super(mass, position, normal); + setShape(createShape(radius, 22)); + if (inverseMass != 0) { + inverseInertiaTensor.m00 = 1f / 4 / inverseMass * radius * radius; + inverseInertiaTensor.m11 = 2 * inverseInertiaTensor.m00; + inverseInertiaTensor.m22 = inverseInertiaTensor.m00; + inverseInertiaTensor.invert(); + } + updateTransformGroup(); + } + + protected Node createShape(float radius, int divisions) { + TriangleFanArray geometry = new TriangleFanArray(divisions, TriangleFanArray.COORDINATES | TriangleFanArray.TEXTURE_COORDINATE_2, new int[] {divisions}); + for (int i = 0; i < divisions; i++) { + float baseX = (float)Math.cos(2 * Math.PI * i / divisions); + float baseZ = -(float)Math.sin(2 * Math.PI * i / divisions); + geometry.setCoordinate(i, new Point3f(radius * baseX, 0, radius * baseZ)); + geometry.setTextureCoordinate(0, i, new TexCoord2f((baseX + 1) / 2, (-baseZ + 1) / 2)); + } + + TextureLoader tl = new TextureLoader("wood.jpg", null); + ImageComponent2D image = tl.getImage(); + int width = image.getWidth(); + int height = image.getHeight(); + Texture2D texture = new Texture2D(Texture.MULTI_LEVEL_MIPMAP, Texture.RGB, width, height); + + int imageLevel = 0; + texture.setImage(imageLevel, image); + while (width > 1 || height > 1) { + imageLevel++; + if (width > 1) width /= 2; + if (height > 1) height /= 2; + texture.setImage(imageLevel, tl.getScaledImage(width, height)); + } + texture.setMagFilter(Texture2D.NICEST); + texture.setMinFilter(Texture2D.NICEST); + + Appearance appearance = new Appearance(); + appearance.setTexture(texture); + PolygonAttributes polyAttr = new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0); + appearance.setPolygonAttributes(polyAttr); + return new Shape3D(geometry, appearance); + } +} diff --git a/src/tesseract/objects/Particle.java b/src/tesseract/objects/Particle.java index 6dcc864..b3b6274 100644 --- a/src/tesseract/objects/Particle.java +++ b/src/tesseract/objects/Particle.java @@ -75,7 +75,7 @@ public class Particle extends PhysicalObject { cAttr = new ColoringAttributes(color, ColoringAttributes.FASTEST); Appearance appearance = new Appearance(); appearance.setColoringAttributes(cAttr); - Sphere sphere = new Sphere(RADIUS, Sphere.ENABLE_GEOMETRY_PICKING | Sphere.GEOMETRY_NOT_SHARED, + Sphere sphere = new Sphere(RADIUS, Sphere.ENABLE_GEOMETRY_PICKING, DIVISIONS, appearance); TransformGroup tg = new TransformGroup(); tg.addChild(sphere); diff --git a/src/tesseract/objects/Polygon.java b/src/tesseract/objects/Polygon.java new file mode 100644 index 0000000..c8fcf53 --- /dev/null +++ b/src/tesseract/objects/Polygon.java @@ -0,0 +1,43 @@ +package tesseract.objects; +import javax.media.j3d.Transform3D; +import javax.vecmath.*; + +import alden.CollidableObject; + +public abstract class Polygon extends PhysicalObject { + public Vector3f normal; + // Right-hand side of the plane equation: Ax + By + Cz = D + public float intercept; + + public Polygon(Vector3f position, Vector3f normal) { + this(1, position, normal); + } + + public Polygon(float mass, Vector3f position, Vector3f normal) { + super(position, mass); + + this.normal = new Vector3f(normal); + this.normal.normalize(); + intercept = this.normal.dot(position); + Vector3f newX = new Vector3f(1, 0, 0); + if (Math.abs(newX.dot(this.normal)) == 1) + newX = new Vector3f(0, -1, 0); + newX.scaleAdd(-newX.dot(this.normal), this.normal, newX); + newX.normalize(); + Vector3f newZ = new Vector3f(); + newZ.cross(newX, this.normal); + new Matrix4f(new Matrix3f(newX.x, this.normal.x, newZ.x, newX.y, this.normal.y, newZ.y, newX.z, this.normal.z, newZ.z), position, 1).get(orientation); + } + + protected void updateTransformGroup() { + super.updateTransformGroup(); + Transform3D tmp = new Transform3D(); + TG.getTransform(tmp); + Matrix3f rot = new Matrix3f(); + tmp.get(rot); + normal.x = rot.m01; + normal.y = rot.m11; + normal.z = rot.m21; + intercept = normal.dot(position); + } +} diff --git a/src/tesseract/objects/Sphere.java b/src/tesseract/objects/Sphere.java new file mode 100644 index 0000000..4ec4aaa --- /dev/null +++ b/src/tesseract/objects/Sphere.java @@ -0,0 +1,35 @@ +package tesseract.objects; +import javax.media.j3d.*; +import javax.vecmath.*; + +import alden.CollidableObject; + +public class Sphere extends PhysicalObject { + public float radius; + + public Sphere(float radius, Vector3f position) { + this(1, radius, position); + } + + public Sphere(float mass, float radius, Vector3f position) { + super(position, mass); + setShape(createShape(radius, 22)); + this.radius = radius; + + if (inverseMass != 0) { + inverseInertiaTensor.m00 = 2f / 5 / inverseMass * radius * radius; + inverseInertiaTensor.m11 = inverseInertiaTensor.m00; + inverseInertiaTensor.m22 = inverseInertiaTensor.m00; + inverseInertiaTensor.invert(); + } + updateTransformGroup(); + } + + protected Node createShape(float radius, int divisions) { + Appearance appearance = new Appearance(); + Material material = new Material(); + material.setDiffuseColor(0.7f, 0.7f, 1); + appearance.setMaterial(material); + return new com.sun.j3d.utils.geometry.Sphere(radius, com.sun.j3d.utils.geometry.Sphere.GENERATE_NORMALS, divisions, appearance); + } +} -- cgit v1.2.3