• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
VehicleWheel()70     public VehicleWheel() {
71     }
72 
VehicleWheel(Spatial spat, Vector3f location, Vector3f direction, Vector3f axle, float restLength, float radius, boolean frontWheel)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 
VehicleWheel(Vector3f location, Vector3f direction, Vector3f axle, float restLength, float radius, boolean frontWheel)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 
updatePhysicsState()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 
applyWheelTransform()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 
getWheelInfo()117     public com.bulletphysics.dynamics.vehicle.WheelInfo getWheelInfo() {
118         return wheelInfo;
119     }
120 
setWheelInfo(com.bulletphysics.dynamics.vehicle.WheelInfo wheelInfo)121     public void setWheelInfo(com.bulletphysics.dynamics.vehicle.WheelInfo wheelInfo) {
122         this.wheelInfo = wheelInfo;
123         applyInfo();
124     }
125 
isFrontWheel()126     public boolean isFrontWheel() {
127         return frontWheel;
128     }
129 
setFrontWheel(boolean frontWheel)130     public void setFrontWheel(boolean frontWheel) {
131         this.frontWheel = frontWheel;
132         applyInfo();
133     }
134 
getLocation()135     public Vector3f getLocation() {
136         return location;
137     }
138 
getDirection()139     public Vector3f getDirection() {
140         return direction;
141     }
142 
getAxle()143     public Vector3f getAxle() {
144         return axle;
145     }
146 
getSuspensionStiffness()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      */
setSuspensionStiffness(float suspensionStiffness)155     public void setSuspensionStiffness(float suspensionStiffness) {
156         this.suspensionStiffness = suspensionStiffness;
157         applyInfo();
158     }
159 
getWheelsDampingRelaxation()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      */
setWheelsDampingRelaxation(float wheelsDampingRelaxation)169     public void setWheelsDampingRelaxation(float wheelsDampingRelaxation) {
170         this.wheelsDampingRelaxation = wheelsDampingRelaxation;
171         applyInfo();
172     }
173 
getWheelsDampingCompression()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      */
setWheelsDampingCompression(float wheelsDampingCompression)185     public void setWheelsDampingCompression(float wheelsDampingCompression) {
186         this.wheelsDampingCompression = wheelsDampingCompression;
187         applyInfo();
188     }
189 
getFrictionSlip()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      */
setFrictionSlip(float frictionSlip)200     public void setFrictionSlip(float frictionSlip) {
201         this.frictionSlip = frictionSlip;
202         applyInfo();
203     }
204 
getRollInfluence()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      */
setRollInfluence(float rollInfluence)216     public void setRollInfluence(float rollInfluence) {
217         this.rollInfluence = rollInfluence;
218         applyInfo();
219     }
220 
getMaxSuspensionTravelCm()221     public float getMaxSuspensionTravelCm() {
222         return maxSuspensionTravelCm;
223     }
224 
225     /**
226      * the maximum distance the suspension can be compressed (centimetres)
227      * @param maxSuspensionTravelCm
228      */
setMaxSuspensionTravelCm(float maxSuspensionTravelCm)229     public void setMaxSuspensionTravelCm(float maxSuspensionTravelCm) {
230         this.maxSuspensionTravelCm = maxSuspensionTravelCm;
231         applyInfo();
232     }
233 
getMaxSuspensionForce()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      */
setMaxSuspensionForce(float maxSuspensionForce)243     public void setMaxSuspensionForce(float maxSuspensionForce) {
244         this.maxSuspensionForce = maxSuspensionForce;
245         applyInfo();
246     }
247 
applyInfo()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 
getRadius()264     public float getRadius() {
265         return radius;
266     }
267 
setRadius(float radius)268     public void setRadius(float radius) {
269         this.radius = radius;
270         applyInfo();
271     }
272 
getRestLength()273     public float getRestLength() {
274         return restLength;
275     }
276 
setRestLength(float restLength)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      */
getGroundObject()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      */
getCollisionLocation(Vector3f vec)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      */
getCollisionLocation()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      */
getCollisionNormal(Vector3f vec)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      */
getCollisionNormal()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      */
getSkidInfo()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      */
getDeltaRotation()339     public float getDeltaRotation() {
340         return wheelInfo.deltaRotation;
341     }
342 
343     @Override
read(JmeImporter im)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
write(JmeExporter ex)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      */
getWheelSpatial()384     public Spatial getWheelSpatial() {
385         return wheelSpatial;
386     }
387 
388     /**
389      * @param wheelSpatial the wheelSpatial to set
390      */
setWheelSpatial(Spatial wheelSpatial)391     public void setWheelSpatial(Spatial wheelSpatial) {
392         this.wheelSpatial = wheelSpatial;
393     }
394 
isApplyLocal()395     public boolean isApplyLocal() {
396         return applyLocal;
397     }
398 
setApplyLocal(boolean applyLocal)399     public void setApplyLocal(boolean applyLocal) {
400         this.applyLocal = applyLocal;
401     }
402 }
403