Home | History | Annotate | Download | only in objects
      1 /*
      2  * Copyright (c) 2009-2012 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 package com.jme3.bullet.objects;
     33 
     34 import com.bulletphysics.dynamics.RigidBody;
     35 import com.jme3.bullet.collision.PhysicsCollisionObject;
     36 import com.jme3.bullet.util.Converter;
     37 import com.jme3.export.*;
     38 import com.jme3.math.Quaternion;
     39 import com.jme3.math.Vector3f;
     40 import com.jme3.scene.Spatial;
     41 import java.io.IOException;
     42 
     43 /**
     44  * Stores info about one wheel of a PhysicsVehicle
     45  * @author normenhansen
     46  */
     47 public class VehicleWheel implements Savable {
     48 
     49     protected com.bulletphysics.dynamics.vehicle.WheelInfo wheelInfo;
     50     protected boolean frontWheel;
     51     protected Vector3f location = new Vector3f();
     52     protected Vector3f direction = new Vector3f();
     53     protected Vector3f axle = new Vector3f();
     54     protected float suspensionStiffness = 20.0f;
     55     protected float wheelsDampingRelaxation = 2.3f;
     56     protected float wheelsDampingCompression = 4.4f;
     57     protected float frictionSlip = 10.5f;
     58     protected float rollInfluence = 1.0f;
     59     protected float maxSuspensionTravelCm = 500f;
     60     protected float maxSuspensionForce = 6000f;
     61     protected float radius = 0.5f;
     62     protected float restLength = 1f;
     63     protected Vector3f wheelWorldLocation = new Vector3f();
     64     protected Quaternion wheelWorldRotation = new Quaternion();
     65     protected Spatial wheelSpatial;
     66     protected com.jme3.math.Matrix3f tmp_Matrix = new com.jme3.math.Matrix3f();
     67     protected final Quaternion tmp_inverseWorldRotation = new Quaternion();
     68     private boolean applyLocal = false;
     69 
     70     public VehicleWheel() {
     71     }
     72 
     73     public VehicleWheel(Spatial spat, Vector3f location, Vector3f direction, Vector3f axle,
     74             float restLength, float radius, boolean frontWheel) {
     75         this(location, direction, axle, restLength, radius, frontWheel);
     76         wheelSpatial = spat;
     77     }
     78 
     79     public VehicleWheel(Vector3f location, Vector3f direction, Vector3f axle,
     80             float restLength, float radius, boolean frontWheel) {
     81         this.location.set(location);
     82         this.direction.set(direction);
     83         this.axle.set(axle);
     84         this.frontWheel = frontWheel;
     85         this.restLength = restLength;
     86         this.radius = radius;
     87     }
     88 
     89     public synchronized void updatePhysicsState() {
     90         Converter.convert(wheelInfo.worldTransform.origin, wheelWorldLocation);
     91         Converter.convert(wheelInfo.worldTransform.basis, tmp_Matrix);
     92         wheelWorldRotation.fromRotationMatrix(tmp_Matrix);
     93     }
     94 
     95     public synchronized void applyWheelTransform() {
     96         if (wheelSpatial == null) {
     97             return;
     98         }
     99         Quaternion localRotationQuat = wheelSpatial.getLocalRotation();
    100         Vector3f localLocation = wheelSpatial.getLocalTranslation();
    101         if (!applyLocal && wheelSpatial.getParent() != null) {
    102             localLocation.set(wheelWorldLocation).subtractLocal(wheelSpatial.getParent().getWorldTranslation());
    103             localLocation.divideLocal(wheelSpatial.getParent().getWorldScale());
    104             tmp_inverseWorldRotation.set(wheelSpatial.getParent().getWorldRotation()).inverseLocal().multLocal(localLocation);
    105 
    106             localRotationQuat.set(wheelWorldRotation);
    107             tmp_inverseWorldRotation.set(wheelSpatial.getParent().getWorldRotation()).inverseLocal().mult(localRotationQuat, localRotationQuat);
    108 
    109             wheelSpatial.setLocalTranslation(localLocation);
    110             wheelSpatial.setLocalRotation(localRotationQuat);
    111         } else {
    112             wheelSpatial.setLocalTranslation(wheelWorldLocation);
    113             wheelSpatial.setLocalRotation(wheelWorldRotation);
    114         }
    115     }
    116 
    117     public com.bulletphysics.dynamics.vehicle.WheelInfo getWheelInfo() {
    118         return wheelInfo;
    119     }
    120 
    121     public void setWheelInfo(com.bulletphysics.dynamics.vehicle.WheelInfo wheelInfo) {
    122         this.wheelInfo = wheelInfo;
    123         applyInfo();
    124     }
    125 
    126     public boolean isFrontWheel() {
    127         return frontWheel;
    128     }
    129 
    130     public void setFrontWheel(boolean frontWheel) {
    131         this.frontWheel = frontWheel;
    132         applyInfo();
    133     }
    134 
    135     public Vector3f getLocation() {
    136         return location;
    137     }
    138 
    139     public Vector3f getDirection() {
    140         return direction;
    141     }
    142 
    143     public Vector3f getAxle() {
    144         return axle;
    145     }
    146 
    147     public float getSuspensionStiffness() {
    148         return suspensionStiffness;
    149     }
    150 
    151     /**
    152      * the stiffness constant for the suspension.  10.0 - Offroad buggy, 50.0 - Sports car, 200.0 - F1 Car
    153      * @param suspensionStiffness
    154      */
    155     public void setSuspensionStiffness(float suspensionStiffness) {
    156         this.suspensionStiffness = suspensionStiffness;
    157         applyInfo();
    158     }
    159 
    160     public float getWheelsDampingRelaxation() {
    161         return wheelsDampingRelaxation;
    162     }
    163 
    164     /**
    165      * the damping coefficient for when the suspension is expanding.
    166      * See the comments for setWheelsDampingCompression for how to set k.
    167      * @param wheelsDampingRelaxation
    168      */
    169     public void setWheelsDampingRelaxation(float wheelsDampingRelaxation) {
    170         this.wheelsDampingRelaxation = wheelsDampingRelaxation;
    171         applyInfo();
    172     }
    173 
    174     public float getWheelsDampingCompression() {
    175         return wheelsDampingCompression;
    176     }
    177 
    178     /**
    179      * the damping coefficient for when the suspension is compressed.
    180      * Set to k * 2.0 * FastMath.sqrt(m_suspensionStiffness) so k is proportional to critical damping.<br>
    181      * k = 0.0 undamped & bouncy, k = 1.0 critical damping<br>
    182      * 0.1 to 0.3 are good values
    183      * @param wheelsDampingCompression
    184      */
    185     public void setWheelsDampingCompression(float wheelsDampingCompression) {
    186         this.wheelsDampingCompression = wheelsDampingCompression;
    187         applyInfo();
    188     }
    189 
    190     public float getFrictionSlip() {
    191         return frictionSlip;
    192     }
    193 
    194     /**
    195      * the coefficient of friction between the tyre and the ground.
    196      * Should be about 0.8 for realistic cars, but can increased for better handling.
    197      * Set large (10000.0) for kart racers
    198      * @param frictionSlip
    199      */
    200     public void setFrictionSlip(float frictionSlip) {
    201         this.frictionSlip = frictionSlip;
    202         applyInfo();
    203     }
    204 
    205     public float getRollInfluence() {
    206         return rollInfluence;
    207     }
    208 
    209     /**
    210      * reduces the rolling torque applied from the wheels that cause the vehicle to roll over.
    211      * This is a bit of a hack, but it's quite effective. 0.0 = no roll, 1.0 = physical behaviour.
    212      * If m_frictionSlip is too high, you'll need to reduce this to stop the vehicle rolling over.
    213      * You should also try lowering the vehicle's centre of mass
    214      * @param rollInfluence the rollInfluence to set
    215      */
    216     public void setRollInfluence(float rollInfluence) {
    217         this.rollInfluence = rollInfluence;
    218         applyInfo();
    219     }
    220 
    221     public float getMaxSuspensionTravelCm() {
    222         return maxSuspensionTravelCm;
    223     }
    224 
    225     /**
    226      * the maximum distance the suspension can be compressed (centimetres)
    227      * @param maxSuspensionTravelCm
    228      */
    229     public void setMaxSuspensionTravelCm(float maxSuspensionTravelCm) {
    230         this.maxSuspensionTravelCm = maxSuspensionTravelCm;
    231         applyInfo();
    232     }
    233 
    234     public float getMaxSuspensionForce() {
    235         return maxSuspensionForce;
    236     }
    237 
    238     /**
    239      * The maximum suspension force, raise this above the default 6000 if your suspension cannot
    240      * handle the weight of your vehcile.
    241      * @param maxSuspensionForce
    242      */
    243     public void setMaxSuspensionForce(float maxSuspensionForce) {
    244         this.maxSuspensionForce = maxSuspensionForce;
    245         applyInfo();
    246     }
    247 
    248     private void applyInfo() {
    249         if (wheelInfo == null) {
    250             return;
    251         }
    252         wheelInfo.suspensionStiffness = suspensionStiffness;
    253         wheelInfo.wheelsDampingRelaxation = wheelsDampingRelaxation;
    254         wheelInfo.wheelsDampingCompression = wheelsDampingCompression;
    255         wheelInfo.frictionSlip = frictionSlip;
    256         wheelInfo.rollInfluence = rollInfluence;
    257         wheelInfo.maxSuspensionTravelCm = maxSuspensionTravelCm;
    258         wheelInfo.maxSuspensionForce = maxSuspensionForce;
    259         wheelInfo.wheelsRadius = radius;
    260         wheelInfo.bIsFrontWheel = frontWheel;
    261         wheelInfo.suspensionRestLength1 = restLength;
    262     }
    263 
    264     public float getRadius() {
    265         return radius;
    266     }
    267 
    268     public void setRadius(float radius) {
    269         this.radius = radius;
    270         applyInfo();
    271     }
    272 
    273     public float getRestLength() {
    274         return restLength;
    275     }
    276 
    277     public void setRestLength(float restLength) {
    278         this.restLength = restLength;
    279         applyInfo();
    280     }
    281 
    282     /**
    283      * returns the object this wheel is in contact with or null if no contact
    284      * @return the PhysicsCollisionObject (PhysicsRigidBody, PhysicsGhostObject)
    285      */
    286     public PhysicsCollisionObject getGroundObject() {
    287         if (wheelInfo.raycastInfo.groundObject == null) {
    288             return null;
    289         } else if (wheelInfo.raycastInfo.groundObject instanceof RigidBody) {
    290             System.out.println("RigidBody");
    291             return (PhysicsRigidBody) ((RigidBody) wheelInfo.raycastInfo.groundObject).getUserPointer();
    292         } else {
    293             return null;
    294         }
    295     }
    296 
    297     /**
    298      * returns the location where the wheel collides with the ground (world space)
    299      */
    300     public Vector3f getCollisionLocation(Vector3f vec) {
    301         Converter.convert(wheelInfo.raycastInfo.contactPointWS, vec);
    302         return vec;
    303     }
    304 
    305     /**
    306      * returns the location where the wheel collides with the ground (world space)
    307      */
    308     public Vector3f getCollisionLocation() {
    309         return Converter.convert(wheelInfo.raycastInfo.contactPointWS);
    310     }
    311 
    312     /**
    313      * returns the normal where the wheel collides with the ground (world space)
    314      */
    315     public Vector3f getCollisionNormal(Vector3f vec) {
    316         Converter.convert(wheelInfo.raycastInfo.contactNormalWS, vec);
    317         return vec;
    318     }
    319 
    320     /**
    321      * returns the normal where the wheel collides with the ground (world space)
    322      */
    323     public Vector3f getCollisionNormal() {
    324         return Converter.convert(wheelInfo.raycastInfo.contactNormalWS);
    325     }
    326 
    327     /**
    328      * returns how much the wheel skids on the ground (for skid sounds/smoke etc.)<br>
    329      * 0.0 = wheels are sliding, 1.0 = wheels have traction.
    330      */
    331     public float getSkidInfo() {
    332         return wheelInfo.skidInfo;
    333     }
    334 
    335     /**
    336      * returns how many degrees the wheel has turned since the last physics
    337      * step.
    338      */
    339     public float getDeltaRotation() {
    340         return wheelInfo.deltaRotation;
    341     }
    342 
    343     @Override
    344     public void read(JmeImporter im) throws IOException {
    345         InputCapsule capsule = im.getCapsule(this);
    346         wheelSpatial = (Spatial) capsule.readSavable("wheelSpatial", null);
    347         frontWheel = capsule.readBoolean("frontWheel", false);
    348         location = (Vector3f) capsule.readSavable("wheelLocation", new Vector3f());
    349         direction = (Vector3f) capsule.readSavable("wheelDirection", new Vector3f());
    350         axle = (Vector3f) capsule.readSavable("wheelAxle", new Vector3f());
    351         suspensionStiffness = capsule.readFloat("suspensionStiffness", 20.0f);
    352         wheelsDampingRelaxation = capsule.readFloat("wheelsDampingRelaxation", 2.3f);
    353         wheelsDampingCompression = capsule.readFloat("wheelsDampingCompression", 4.4f);
    354         frictionSlip = capsule.readFloat("frictionSlip", 10.5f);
    355         rollInfluence = capsule.readFloat("rollInfluence", 1.0f);
    356         maxSuspensionTravelCm = capsule.readFloat("maxSuspensionTravelCm", 500f);
    357         maxSuspensionForce = capsule.readFloat("maxSuspensionForce", 6000f);
    358         radius = capsule.readFloat("wheelRadius", 0.5f);
    359         restLength = capsule.readFloat("restLength", 1f);
    360     }
    361 
    362     @Override
    363     public void write(JmeExporter ex) throws IOException {
    364         OutputCapsule capsule = ex.getCapsule(this);
    365         capsule.write(wheelSpatial, "wheelSpatial", null);
    366         capsule.write(frontWheel, "frontWheel", false);
    367         capsule.write(location, "wheelLocation", new Vector3f());
    368         capsule.write(direction, "wheelDirection", new Vector3f());
    369         capsule.write(axle, "wheelAxle", new Vector3f());
    370         capsule.write(suspensionStiffness, "suspensionStiffness", 20.0f);
    371         capsule.write(wheelsDampingRelaxation, "wheelsDampingRelaxation", 2.3f);
    372         capsule.write(wheelsDampingCompression, "wheelsDampingCompression", 4.4f);
    373         capsule.write(frictionSlip, "frictionSlip", 10.5f);
    374         capsule.write(rollInfluence, "rollInfluence", 1.0f);
    375         capsule.write(maxSuspensionTravelCm, "maxSuspensionTravelCm", 500f);
    376         capsule.write(maxSuspensionForce, "maxSuspensionForce", 6000f);
    377         capsule.write(radius, "wheelRadius", 0.5f);
    378         capsule.write(restLength, "restLength", 1f);
    379     }
    380 
    381     /**
    382      * @return the wheelSpatial
    383      */
    384     public Spatial getWheelSpatial() {
    385         return wheelSpatial;
    386     }
    387 
    388     /**
    389      * @param wheelSpatial the wheelSpatial to set
    390      */
    391     public void setWheelSpatial(Spatial wheelSpatial) {
    392         this.wheelSpatial = wheelSpatial;
    393     }
    394 
    395     public boolean isApplyLocal() {
    396         return applyLocal;
    397     }
    398 
    399     public void setApplyLocal(boolean applyLocal) {
    400         this.applyLocal = applyLocal;
    401     }
    402 }
    403