diff --git a/src/java/com/threerings/jme/sprite/BallisticPath.java b/src/java/com/threerings/jme/sprite/BallisticPath.java index 996afdf2d..51ad7b83a 100644 --- a/src/java/com/threerings/jme/sprite/BallisticPath.java +++ b/src/java/com/threerings/jme/sprite/BallisticPath.java @@ -29,6 +29,9 @@ import com.jme.math.Vector3f; */ public class BallisticPath extends Path { + /** Gravity: it's the law. */ + public static final float G = -9.8f; + /** * Moves the supplied sprite from the starting coordinate (which will * be modified) using the starting velocity, under the specified diff --git a/src/java/com/threerings/jme/sprite/OrientingBallisticPath.java b/src/java/com/threerings/jme/sprite/OrientingBallisticPath.java index a5eeb1cde..da5d6526b 100644 --- a/src/java/com/threerings/jme/sprite/OrientingBallisticPath.java +++ b/src/java/com/threerings/jme/sprite/OrientingBallisticPath.java @@ -21,8 +21,6 @@ package com.threerings.jme.sprite; -import com.jme.math.FastMath; -import com.jme.math.Matrix3f; import com.jme.math.Quaternion; import com.jme.math.Vector3f; @@ -45,42 +43,41 @@ public class OrientingBallisticPath extends BallisticPath { super(sprite, start, velocity, accel, duration); - // rotate the sprite to start - rotate(orient, velocity); + // TODO: handle orient that is not (1, 0, 0) + _orient = orient; + + // compute the up vector (opposite of acceleration) + _up = accel.negate(); + _up.normalizeLocal(); + + computeRotation(velocity); + _sprite.getLocalRotation().set(_rotate); } // documentation inherited public void update (float time) { - // keep track of the old velocity before we update - _ovelocity.set(_velocity); - // do the normal update super.update(time); - // rotate the sprite accordingly - rotate(_ovelocity, _velocity); + computeRotation(_velocity); + _sprite.getLocalRotation().set(_rotate); } - protected void rotate (Vector3f oorient, Vector3f norient) + protected void computeRotation (Vector3f velocity) { - // compute the cross product to get the normal to the plane - // defined by the velocity vectors - oorient.cross(norient, _normal); - - // compute the angle between the two vectors - float angle = FastMath.acos( - oorient.dot(norient) / (norient.length() * oorient.length())); - - // now use that to compute a rotation matrix from the old to the - // new vector - _rotate.fromAngleAxis(angle, _normal); - - // finally rotate the sprite accordingly - _sprite.getLocalRotation().multLocal(_rotate); + _axes[0].set(velocity); + _axes[0].normalizeLocal(); + _axes[0].cross(_up, _axes[1]); + _axes[1].normalizeLocal(); + _axes[1].cross(_axes[0], _axes[2]); + _axes[2].cross(_axes[0], _axes[1]); + _rotate.fromAxes(_axes); } - protected Vector3f _ovelocity = new Vector3f(); - protected Vector3f _normal = new Vector3f(); + protected Vector3f _orient; + protected Vector3f _up; + protected Vector3f[] _axes = { + new Vector3f(), new Vector3f(), new Vector3f() }; protected Quaternion _rotate = new Quaternion(); } diff --git a/tests/src/java/com/threerings/jme/sprite/PathTest.java b/tests/src/java/com/threerings/jme/sprite/PathTest.java index 62ca3296c..ecb320012 100644 --- a/tests/src/java/com/threerings/jme/sprite/PathTest.java +++ b/tests/src/java/com/threerings/jme/sprite/PathTest.java @@ -9,9 +9,12 @@ import com.jme.math.FastMath; import com.jme.math.Matrix3f; import com.jme.math.Quaternion; import com.jme.math.Vector3f; -import com.jme.util.LoggingSystem; +import com.jme.renderer.ColorRGBA; import com.jme.scene.shape.Box; +import com.jme.scene.shape.Quad; import com.jme.scene.shape.Sphere; +import com.jme.scene.state.LightState; +import com.jme.util.LoggingSystem; import com.threerings.jme.JmeApp; @@ -24,25 +27,37 @@ public class PathTest extends JmeApp { super.initRoot(); - float range = 56, muzvel = 24; + float dist = 10; // set up the camera - Vector3f loc = new Vector3f(range/2, -range*2, 0); + Vector3f loc = new Vector3f(0, -dist, 10); _camera.setLocation(loc); Matrix3f rotm = new Matrix3f(); - rotm.fromAngleAxis(-FastMath.PI/2, _camera.getLeft()); + rotm.fromAngleAxis(-FastMath.PI/4, _camera.getLeft()); rotm.multLocal(_camera.getDirection()); rotm.multLocal(_camera.getUp()); rotm.multLocal(_camera.getLeft()); _camera.update(); - Box box = new Box("box", new Vector3f(-1, -1, -1), - new Vector3f(1, 1, 1)); + for (int yy = -1; yy < 1; yy++) { + for (int xx = -1; xx < 1; xx++) { + Quad quad = new Quad("ground", 10, 10); + quad.setLightCombineMode(LightState.OFF); + int index = (yy+1)*2 + (xx+1); + quad.setSolidColor(COLORS[index]); + quad.setLocalTranslation( + new Vector3f(xx * 10 + 5, yy * 10 + 5, -1)); + _geom.attachChild(quad); + } + } + + Box box = new Box("box", new Vector3f(-1, -0.5f, -0.25f), + new Vector3f(1, 0.5f, 0.25f)); _geom.attachChild(box); - Box box2 = new Box("box2", new Vector3f(-1, -1, -1), - new Vector3f(1, 1, 1)); - box2.setLocalTranslation(new Vector3f(range, 0, 0)); + Box box2 = new Box("box2", new Vector3f(-.1f, -.1f, -.1f), + new Vector3f(.1f, .1f, .1f)); + box2.setLocalTranslation(new Vector3f(dist, dist, 0)); _geom.attachChild(box2); Sprite shot = new Sprite(); @@ -52,15 +67,22 @@ public class PathTest extends JmeApp Vector3f start = new Vector3f(0, 0, 0); // start with the "cannon" pointed along the x axis - Vector3f vel = new Vector3f(1, 0, 0); + Vector3f diff = box2.getLocalTranslation().subtract( + box.getLocalTranslation()); + Vector3f vel = diff.normalize(); + float range = diff.length(), angle = -FastMath.PI/4; + + Vector3f axis = UP.cross(vel); + axis.normalizeLocal(); // rotate it up (around the y axis) the necessary elevation Quaternion rot = new Quaternion(); - float angle = BallisticPath.computeElevation(range, muzvel, -9.8f); - rot.fromAngleAxis(angle, new Vector3f(0, 1, 0)); + rot.fromAngleAxis(angle, axis); rot.multLocal(vel); // give the cannon its muzzle velocity + float muzvel = FastMath.sqrt(range * BallisticPath.G / + FastMath.sin(2*angle)); vel.multLocal(muzvel); float time = BallisticPath.computeFlightTime(range, muzvel, angle); @@ -69,6 +91,7 @@ public class PathTest extends JmeApp System.out.println("Range: " + range); System.out.println("Muzzle velocity: " + muzvel); + System.out.println("Rotation axis: " + axis); System.out.println("Angle: " + angle + " (" + (angle * 180 / FastMath.PI) + ")"); System.out.println("Flight time: " + time); @@ -86,4 +109,7 @@ public class PathTest extends JmeApp } protected static final Vector3f GRAVITY = new Vector3f(0, 0, -9.8f); + protected static final Vector3f UP = new Vector3f(0, 0, 1); + protected static final ColorRGBA[] COLORS = { + ColorRGBA.red, ColorRGBA.green, ColorRGBA.blue, ColorRGBA.gray }; }