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.collision.dispatch.CollisionFlags; 35 import com.bulletphysics.dynamics.RigidBody; 36 import com.bulletphysics.dynamics.RigidBodyConstructionInfo; 37 import com.bulletphysics.linearmath.Transform; 38 import com.jme3.bullet.PhysicsSpace; 39 import com.jme3.bullet.collision.PhysicsCollisionObject; 40 import com.jme3.bullet.collision.shapes.CollisionShape; 41 import com.jme3.bullet.collision.shapes.MeshCollisionShape; 42 import com.jme3.bullet.joints.PhysicsJoint; 43 import com.jme3.bullet.objects.infos.RigidBodyMotionState; 44 import com.jme3.bullet.util.Converter; 45 import com.jme3.export.InputCapsule; 46 import com.jme3.export.JmeExporter; 47 import com.jme3.export.JmeImporter; 48 import com.jme3.export.OutputCapsule; 49 import com.jme3.math.Matrix3f; 50 import com.jme3.math.Quaternion; 51 import com.jme3.math.Vector3f; 52 import com.jme3.scene.Geometry; 53 import com.jme3.scene.Node; 54 import com.jme3.scene.Spatial; 55 import com.jme3.scene.debug.Arrow; 56 import java.io.IOException; 57 import java.util.ArrayList; 58 import java.util.Iterator; 59 import java.util.List; 60 61 /** 62 * <p>PhysicsRigidBody - Basic physics object</p> 63 * @author normenhansen 64 */ 65 public class PhysicsRigidBody extends PhysicsCollisionObject { 66 67 protected RigidBodyConstructionInfo constructionInfo; 68 protected RigidBody rBody; 69 protected RigidBodyMotionState motionState = new RigidBodyMotionState(); 70 protected float mass = 1.0f; 71 protected boolean kinematic = false; 72 protected javax.vecmath.Vector3f tempVec = new javax.vecmath.Vector3f(); 73 protected javax.vecmath.Vector3f tempVec2 = new javax.vecmath.Vector3f(); 74 protected Transform tempTrans = new Transform(new javax.vecmath.Matrix3f()); 75 protected javax.vecmath.Matrix3f tempMatrix = new javax.vecmath.Matrix3f(); 76 //TEMP VARIABLES 77 protected javax.vecmath.Vector3f localInertia = new javax.vecmath.Vector3f(); 78 protected ArrayList<PhysicsJoint> joints = new ArrayList<PhysicsJoint>(); 79 80 public PhysicsRigidBody() { 81 } 82 83 /** 84 * Creates a new PhysicsRigidBody with the supplied collision shape 85 * @param shape 86 */ 87 public PhysicsRigidBody(CollisionShape shape) { 88 collisionShape = shape; 89 rebuildRigidBody(); 90 } 91 92 public PhysicsRigidBody(CollisionShape shape, float mass) { 93 collisionShape = shape; 94 this.mass = mass; 95 rebuildRigidBody(); 96 } 97 98 /** 99 * Builds/rebuilds the phyiscs body when parameters have changed 100 */ 101 protected void rebuildRigidBody() { 102 boolean removed = false; 103 if(collisionShape instanceof MeshCollisionShape && mass != 0){ 104 throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!"); 105 } 106 if (rBody != null) { 107 if (rBody.isInWorld()) { 108 PhysicsSpace.getPhysicsSpace().remove(this); 109 removed = true; 110 } 111 rBody.destroy(); 112 } 113 preRebuild(); 114 rBody = new RigidBody(constructionInfo); 115 postRebuild(); 116 if (removed) { 117 PhysicsSpace.getPhysicsSpace().add(this); 118 } 119 } 120 121 protected void preRebuild() { 122 collisionShape.calculateLocalInertia(mass, localInertia); 123 if (constructionInfo == null) { 124 constructionInfo = new RigidBodyConstructionInfo(mass, motionState, collisionShape.getCShape(), localInertia); 125 } else { 126 constructionInfo.mass = mass; 127 constructionInfo.collisionShape = collisionShape.getCShape(); 128 constructionInfo.motionState = motionState; 129 } 130 } 131 132 protected void postRebuild() { 133 rBody.setUserPointer(this); 134 if (mass == 0.0f) { 135 rBody.setCollisionFlags(rBody.getCollisionFlags() | CollisionFlags.STATIC_OBJECT); 136 } else { 137 rBody.setCollisionFlags(rBody.getCollisionFlags() & ~CollisionFlags.STATIC_OBJECT); 138 } 139 } 140 141 /** 142 * @return the motionState 143 */ 144 public RigidBodyMotionState getMotionState() { 145 return motionState; 146 } 147 148 /** 149 * Sets the physics object location 150 * @param location the location of the actual physics object 151 */ 152 public void setPhysicsLocation(Vector3f location) { 153 rBody.getCenterOfMassTransform(tempTrans); 154 Converter.convert(location, tempTrans.origin); 155 rBody.setCenterOfMassTransform(tempTrans); 156 motionState.setWorldTransform(tempTrans); 157 } 158 159 /** 160 * Sets the physics object rotation 161 * @param rotation the rotation of the actual physics object 162 */ 163 public void setPhysicsRotation(Matrix3f rotation) { 164 rBody.getCenterOfMassTransform(tempTrans); 165 Converter.convert(rotation, tempTrans.basis); 166 rBody.setCenterOfMassTransform(tempTrans); 167 motionState.setWorldTransform(tempTrans); 168 } 169 170 /** 171 * Sets the physics object rotation 172 * @param rotation the rotation of the actual physics object 173 */ 174 public void setPhysicsRotation(Quaternion rotation) { 175 rBody.getCenterOfMassTransform(tempTrans); 176 Converter.convert(rotation, tempTrans.basis); 177 rBody.setCenterOfMassTransform(tempTrans); 178 motionState.setWorldTransform(tempTrans); 179 } 180 181 /** 182 * Gets the physics object location, instantiates a new Vector3f object 183 */ 184 public Vector3f getPhysicsLocation() { 185 return getPhysicsLocation(null); 186 } 187 188 /** 189 * Gets the physics object rotation 190 */ 191 public Matrix3f getPhysicsRotationMatrix() { 192 return getPhysicsRotationMatrix(null); 193 } 194 195 /** 196 * Gets the physics object location, no object instantiation 197 * @param location the location of the actual physics object is stored in this Vector3f 198 */ 199 public Vector3f getPhysicsLocation(Vector3f location) { 200 if (location == null) { 201 location = new Vector3f(); 202 } 203 rBody.getCenterOfMassTransform(tempTrans); 204 return Converter.convert(tempTrans.origin, location); 205 } 206 207 /** 208 * Gets the physics object rotation as a matrix, no conversions and no object instantiation 209 * @param rotation the rotation of the actual physics object is stored in this Matrix3f 210 */ 211 public Matrix3f getPhysicsRotationMatrix(Matrix3f rotation) { 212 if (rotation == null) { 213 rotation = new Matrix3f(); 214 } 215 rBody.getCenterOfMassTransform(tempTrans); 216 return Converter.convert(tempTrans.basis, rotation); 217 } 218 219 /** 220 * Gets the physics object rotation as a quaternion, converts the bullet Matrix3f value, 221 * instantiates new object 222 */ 223 public Quaternion getPhysicsRotation(){ 224 return getPhysicsRotation(null); 225 } 226 227 /** 228 * Gets the physics object rotation as a quaternion, converts the bullet Matrix3f value 229 * @param rotation the rotation of the actual physics object is stored in this Quaternion 230 */ 231 public Quaternion getPhysicsRotation(Quaternion rotation){ 232 if (rotation == null) { 233 rotation = new Quaternion(); 234 } 235 rBody.getCenterOfMassTransform(tempTrans); 236 return Converter.convert(tempTrans.basis, rotation); 237 } 238 239 /** 240 * Gets the physics object location 241 * @param location the location of the actual physics object is stored in this Vector3f 242 */ 243 public Vector3f getInterpolatedPhysicsLocation(Vector3f location) { 244 if (location == null) { 245 location = new Vector3f(); 246 } 247 rBody.getInterpolationWorldTransform(tempTrans); 248 return Converter.convert(tempTrans.origin, location); 249 } 250 251 /** 252 * Gets the physics object rotation 253 * @param rotation the rotation of the actual physics object is stored in this Matrix3f 254 */ 255 public Matrix3f getInterpolatedPhysicsRotation(Matrix3f rotation) { 256 if (rotation == null) { 257 rotation = new Matrix3f(); 258 } 259 rBody.getInterpolationWorldTransform(tempTrans); 260 return Converter.convert(tempTrans.basis, rotation); 261 } 262 263 /** 264 * Sets the node to kinematic mode. in this mode the node is not affected by physics 265 * but affects other physics objects. Its kinetic force is calculated by the amount 266 * of movement it is exposed to and its weight. 267 * @param kinematic 268 */ 269 public void setKinematic(boolean kinematic) { 270 this.kinematic = kinematic; 271 if (kinematic) { 272 rBody.setCollisionFlags(rBody.getCollisionFlags() | CollisionFlags.KINEMATIC_OBJECT); 273 rBody.setActivationState(com.bulletphysics.collision.dispatch.CollisionObject.DISABLE_DEACTIVATION); 274 } else { 275 rBody.setCollisionFlags(rBody.getCollisionFlags() & ~CollisionFlags.KINEMATIC_OBJECT); 276 rBody.setActivationState(com.bulletphysics.collision.dispatch.CollisionObject.ACTIVE_TAG); 277 } 278 } 279 280 public boolean isKinematic() { 281 return kinematic; 282 } 283 284 public void setCcdSweptSphereRadius(float radius) { 285 rBody.setCcdSweptSphereRadius(radius); 286 } 287 288 /** 289 * Sets the amount of motion that has to happen in one physics tick to trigger the continuous motion detection<br/> 290 * This avoids the problem of fast objects moving through other objects, set to zero to disable (default) 291 * @param threshold 292 */ 293 public void setCcdMotionThreshold(float threshold) { 294 rBody.setCcdMotionThreshold(threshold); 295 } 296 297 public float getCcdSweptSphereRadius() { 298 return rBody.getCcdSweptSphereRadius(); 299 } 300 301 public float getCcdMotionThreshold() { 302 return rBody.getCcdMotionThreshold(); 303 } 304 305 public float getCcdSquareMotionThreshold() { 306 return rBody.getCcdSquareMotionThreshold(); 307 } 308 309 public float getMass() { 310 return mass; 311 } 312 313 /** 314 * Sets the mass of this PhysicsRigidBody, objects with mass=0 are static. 315 * @param mass 316 */ 317 public void setMass(float mass) { 318 this.mass = mass; 319 if(collisionShape instanceof MeshCollisionShape && mass != 0){ 320 throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!"); 321 } 322 if (collisionShape != null) { 323 collisionShape.calculateLocalInertia(mass, localInertia); 324 } 325 if (rBody != null) { 326 rBody.setMassProps(mass, localInertia); 327 if (mass == 0.0f) { 328 rBody.setCollisionFlags(rBody.getCollisionFlags() | CollisionFlags.STATIC_OBJECT); 329 } else { 330 rBody.setCollisionFlags(rBody.getCollisionFlags() & ~CollisionFlags.STATIC_OBJECT); 331 } 332 } 333 } 334 335 public Vector3f getGravity() { 336 return getGravity(null); 337 } 338 339 public Vector3f getGravity(Vector3f gravity) { 340 if (gravity == null) { 341 gravity = new Vector3f(); 342 } 343 rBody.getGravity(tempVec); 344 return Converter.convert(tempVec, gravity); 345 } 346 347 /** 348 * Set the local gravity of this PhysicsRigidBody<br/> 349 * Set this after adding the node to the PhysicsSpace, 350 * the PhysicsSpace assigns its current gravity to the physics node when its added. 351 * @param gravity the gravity vector to set 352 */ 353 public void setGravity(Vector3f gravity) { 354 rBody.setGravity(Converter.convert(gravity, tempVec)); 355 } 356 357 public float getFriction() { 358 return rBody.getFriction(); 359 } 360 361 /** 362 * Sets the friction of this physics object 363 * @param friction the friction of this physics object 364 */ 365 public void setFriction(float friction) { 366 constructionInfo.friction = friction; 367 rBody.setFriction(friction); 368 } 369 370 public void setDamping(float linearDamping, float angularDamping) { 371 constructionInfo.linearDamping = linearDamping; 372 constructionInfo.angularDamping = angularDamping; 373 rBody.setDamping(linearDamping, angularDamping); 374 } 375 376 public void setLinearDamping(float linearDamping) { 377 constructionInfo.linearDamping = linearDamping; 378 rBody.setDamping(linearDamping, constructionInfo.angularDamping); 379 } 380 381 public void setAngularDamping(float angularDamping) { 382 constructionInfo.angularDamping = angularDamping; 383 rBody.setDamping(constructionInfo.linearDamping, angularDamping); 384 } 385 386 public float getLinearDamping() { 387 return constructionInfo.linearDamping; 388 } 389 390 public float getAngularDamping() { 391 return constructionInfo.angularDamping; 392 } 393 394 public float getRestitution() { 395 return rBody.getRestitution(); 396 } 397 398 /** 399 * The "bouncyness" of the PhysicsRigidBody, best performance if restitution=0 400 * @param restitution 401 */ 402 public void setRestitution(float restitution) { 403 constructionInfo.restitution = restitution; 404 rBody.setRestitution(restitution); 405 } 406 407 /** 408 * Get the current angular velocity of this PhysicsRigidBody 409 * @return the current linear velocity 410 */ 411 public Vector3f getAngularVelocity() { 412 return Converter.convert(rBody.getAngularVelocity(tempVec)); 413 } 414 415 /** 416 * Get the current angular velocity of this PhysicsRigidBody 417 * @param vec the vector to store the velocity in 418 */ 419 public void getAngularVelocity(Vector3f vec) { 420 Converter.convert(rBody.getAngularVelocity(tempVec), vec); 421 } 422 423 /** 424 * Sets the angular velocity of this PhysicsRigidBody 425 * @param vec the angular velocity of this PhysicsRigidBody 426 */ 427 public void setAngularVelocity(Vector3f vec) { 428 rBody.setAngularVelocity(Converter.convert(vec, tempVec)); 429 rBody.activate(); 430 } 431 432 /** 433 * Get the current linear velocity of this PhysicsRigidBody 434 * @return the current linear velocity 435 */ 436 public Vector3f getLinearVelocity() { 437 return Converter.convert(rBody.getLinearVelocity(tempVec)); 438 } 439 440 /** 441 * Get the current linear velocity of this PhysicsRigidBody 442 * @param vec the vector to store the velocity in 443 */ 444 public void getLinearVelocity(Vector3f vec) { 445 Converter.convert(rBody.getLinearVelocity(tempVec), vec); 446 } 447 448 /** 449 * Sets the linear velocity of this PhysicsRigidBody 450 * @param vec the linear velocity of this PhysicsRigidBody 451 */ 452 public void setLinearVelocity(Vector3f vec) { 453 rBody.setLinearVelocity(Converter.convert(vec, tempVec)); 454 rBody.activate(); 455 } 456 457 /** 458 * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call 459 * updates the physics space.<br> 460 * To apply an impulse, use applyImpulse, use applyContinuousForce to apply continuous force. 461 * @param force the force 462 * @param location the location of the force 463 */ 464 public void applyForce(final Vector3f force, final Vector3f location) { 465 rBody.applyForce(Converter.convert(force, tempVec), Converter.convert(location, tempVec2)); 466 rBody.activate(); 467 } 468 469 /** 470 * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call 471 * updates the physics space.<br> 472 * To apply an impulse, use applyImpulse. 473 * 474 * @param force the force 475 */ 476 public void applyCentralForce(final Vector3f force) { 477 rBody.applyCentralForce(Converter.convert(force, tempVec)); 478 rBody.activate(); 479 } 480 481 /** 482 * Apply a force to the PhysicsRigidBody, only applies force if the next physics update call 483 * updates the physics space.<br> 484 * To apply an impulse, use applyImpulse. 485 * 486 * @param torque the torque 487 */ 488 public void applyTorque(final Vector3f torque) { 489 rBody.applyTorque(Converter.convert(torque, tempVec)); 490 rBody.activate(); 491 } 492 493 /** 494 * Apply an impulse to the PhysicsRigidBody in the next physics update. 495 * @param impulse applied impulse 496 * @param rel_pos location relative to object 497 */ 498 public void applyImpulse(final Vector3f impulse, final Vector3f rel_pos) { 499 rBody.applyImpulse(Converter.convert(impulse, tempVec), Converter.convert(rel_pos, tempVec2)); 500 rBody.activate(); 501 } 502 503 /** 504 * Apply a torque impulse to the PhysicsRigidBody in the next physics update. 505 * @param vec 506 */ 507 public void applyTorqueImpulse(final Vector3f vec) { 508 rBody.applyTorqueImpulse(Converter.convert(vec, tempVec)); 509 rBody.activate(); 510 } 511 512 /** 513 * Clear all forces from the PhysicsRigidBody 514 * 515 */ 516 public void clearForces() { 517 rBody.clearForces(); 518 } 519 520 public void setCollisionShape(CollisionShape collisionShape) { 521 super.setCollisionShape(collisionShape); 522 if(collisionShape instanceof MeshCollisionShape && mass!=0){ 523 throw new IllegalStateException("Dynamic rigidbody can not have mesh collision shape!"); 524 } 525 if (rBody == null) { 526 rebuildRigidBody(); 527 } else { 528 collisionShape.calculateLocalInertia(mass, localInertia); 529 constructionInfo.collisionShape = collisionShape.getCShape(); 530 rBody.setCollisionShape(collisionShape.getCShape()); 531 } 532 } 533 534 /** 535 * reactivates this PhysicsRigidBody when it has been deactivated because it was not moving 536 */ 537 public void activate() { 538 rBody.activate(); 539 } 540 541 public boolean isActive() { 542 return rBody.isActive(); 543 } 544 545 /** 546 * sets the sleeping thresholds, these define when the object gets deactivated 547 * to save ressources. Low values keep the object active when it barely moves 548 * @param linear the linear sleeping threshold 549 * @param angular the angular sleeping threshold 550 */ 551 public void setSleepingThresholds(float linear, float angular) { 552 constructionInfo.linearSleepingThreshold = linear; 553 constructionInfo.angularSleepingThreshold = angular; 554 rBody.setSleepingThresholds(linear, angular); 555 } 556 557 public void setLinearSleepingThreshold(float linearSleepingThreshold) { 558 constructionInfo.linearSleepingThreshold = linearSleepingThreshold; 559 rBody.setSleepingThresholds(linearSleepingThreshold, constructionInfo.angularSleepingThreshold); 560 } 561 562 public void setAngularSleepingThreshold(float angularSleepingThreshold) { 563 constructionInfo.angularSleepingThreshold = angularSleepingThreshold; 564 rBody.setSleepingThresholds(constructionInfo.linearSleepingThreshold, angularSleepingThreshold); 565 } 566 567 public float getLinearSleepingThreshold() { 568 return constructionInfo.linearSleepingThreshold; 569 } 570 571 public float getAngularSleepingThreshold() { 572 return constructionInfo.angularSleepingThreshold; 573 } 574 575 public float getAngularFactor() { 576 return rBody.getAngularFactor(); 577 } 578 579 public void setAngularFactor(float factor) { 580 rBody.setAngularFactor(factor); 581 } 582 583 /** 584 * do not use manually, joints are added automatically 585 */ 586 public void addJoint(PhysicsJoint joint) { 587 if (!joints.contains(joint)) { 588 joints.add(joint); 589 } 590 updateDebugShape(); 591 } 592 593 /** 594 * 595 */ 596 public void removeJoint(PhysicsJoint joint) { 597 joints.remove(joint); 598 } 599 600 /** 601 * Returns a list of connected joints. This list is only filled when 602 * the PhysicsRigidBody is actually added to the physics space or loaded from disk. 603 * @return list of active joints connected to this PhysicsRigidBody 604 */ 605 public List<PhysicsJoint> getJoints() { 606 return joints; 607 } 608 609 /** 610 * used internally 611 */ 612 public RigidBody getObjectId() { 613 return rBody; 614 } 615 616 /** 617 * destroys this PhysicsRigidBody and removes it from memory 618 */ 619 public void destroy() { 620 rBody.destroy(); 621 } 622 623 @Override 624 protected Spatial getDebugShape() { 625 //add joints 626 Spatial shape = super.getDebugShape(); 627 Node node = null; 628 if (shape instanceof Node) { 629 node = (Node) shape; 630 } else { 631 node = new Node("DebugShapeNode"); 632 node.attachChild(shape); 633 } 634 int i = 0; 635 for (Iterator<PhysicsJoint> it = joints.iterator(); it.hasNext();) { 636 PhysicsJoint physicsJoint = it.next(); 637 Vector3f pivot = null; 638 if (physicsJoint.getBodyA() == this) { 639 pivot = physicsJoint.getPivotA(); 640 } else { 641 pivot = physicsJoint.getPivotB(); 642 } 643 Arrow arrow = new Arrow(pivot); 644 Geometry geom = new Geometry("DebugBone" + i, arrow); 645 geom.setMaterial(debugMaterialGreen); 646 node.attachChild(geom); 647 i++; 648 } 649 return node; 650 } 651 652 @Override 653 public void write(JmeExporter e) throws IOException { 654 super.write(e); 655 OutputCapsule capsule = e.getCapsule(this); 656 657 capsule.write(getMass(), "mass", 1.0f); 658 659 capsule.write(getGravity(), "gravity", Vector3f.ZERO); 660 capsule.write(getFriction(), "friction", 0.5f); 661 capsule.write(getRestitution(), "restitution", 0); 662 capsule.write(getAngularFactor(), "angularFactor", 1); 663 capsule.write(kinematic, "kinematic", false); 664 665 capsule.write(constructionInfo.linearDamping, "linearDamping", 0); 666 capsule.write(constructionInfo.angularDamping, "angularDamping", 0); 667 capsule.write(constructionInfo.linearSleepingThreshold, "linearSleepingThreshold", 0.8f); 668 capsule.write(constructionInfo.angularSleepingThreshold, "angularSleepingThreshold", 1.0f); 669 670 capsule.write(getCcdMotionThreshold(), "ccdMotionThreshold", 0); 671 capsule.write(getCcdSweptSphereRadius(), "ccdSweptSphereRadius", 0); 672 673 capsule.write(getPhysicsLocation(new Vector3f()), "physicsLocation", new Vector3f()); 674 capsule.write(getPhysicsRotationMatrix(new Matrix3f()), "physicsRotation", new Matrix3f()); 675 676 capsule.writeSavableArrayList(joints, "joints", null); 677 } 678 679 @Override 680 public void read(JmeImporter e) throws IOException { 681 super.read(e); 682 683 InputCapsule capsule = e.getCapsule(this); 684 float mass = capsule.readFloat("mass", 1.0f); 685 this.mass = mass; 686 rebuildRigidBody(); 687 setGravity((Vector3f) capsule.readSavable("gravity", Vector3f.ZERO.clone())); 688 setFriction(capsule.readFloat("friction", 0.5f)); 689 setKinematic(capsule.readBoolean("kinematic", false)); 690 691 setRestitution(capsule.readFloat("restitution", 0)); 692 setAngularFactor(capsule.readFloat("angularFactor", 1)); 693 setDamping(capsule.readFloat("linearDamping", 0), capsule.readFloat("angularDamping", 0)); 694 setSleepingThresholds(capsule.readFloat("linearSleepingThreshold", 0.8f), capsule.readFloat("angularSleepingThreshold", 1.0f)); 695 setCcdMotionThreshold(capsule.readFloat("ccdMotionThreshold", 0)); 696 setCcdSweptSphereRadius(capsule.readFloat("ccdSweptSphereRadius", 0)); 697 698 setPhysicsLocation((Vector3f) capsule.readSavable("physicsLocation", new Vector3f())); 699 setPhysicsRotation((Matrix3f) capsule.readSavable("physicsRotation", new Matrix3f())); 700 701 joints = capsule.readSavableArrayList("joints", null); 702 } 703 } 704