rigidbody.cpp
上传用户:qccn516
上传日期:2013-05-02
资源大小:3382k
文件大小:10k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /* RigidBody dynamics
  2.  *
  3.  * Copyright (C) 2003-2004, Alexander Zaprjagaev <frustum@frustum.org>
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  */
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include "collide.h"
  22. #include "physic.h"
  23. #include "joint.h"
  24. #include "object.h"
  25. #include "collide.h"
  26. #include "engine.h"
  27. #include "rigidbody.h"
  28. RigidBody::RigidBody(Object *object,float mass,float restitution,float friction,int flag) :
  29. object(object), mass(mass), restitution(restitution), friction(friction),
  30. frozen(0), frozen_time(0.0), frozen_num_objects(0), num_joints(0), simulated(0), immovable(0) {
  31. if(flag & COLLIDE_MESH) collide_type = COLLIDE_MESH;
  32. else if(flag & COLLIDE_SPHERE) collide_type = COLLIDE_SPHERE;
  33. collide = new Collide();
  34. if(flag && BODY_BOX) {
  35. vec3 min = object->getMin();
  36. vec3 max = object->getMax();
  37. vec3 v = (max - min) / 2.0;
  38. mat3 inertiaTensor;
  39. inertiaTensor[0] = 1.0f / 12.0f * mass * (v.y * v.y + v.z * v.z);
  40. inertiaTensor[4] = 1.0f / 12.0f * mass * (v.x * v.x + v.z * v.z);
  41. inertiaTensor[8] = 1.0f / 12.0f * mass * (v.x * v.x + v.y * v.y);
  42. iBodyInertiaTensor = inertiaTensor.inverse();
  43. }
  44. else if(flag && BODY_SPHERE) {
  45. float radius = object->getRadius();
  46. mat3 inertiaTensor;
  47. inertiaTensor[0] = 2.0f / 5.0f * mass * radius * radius;
  48. inertiaTensor[4] = 2.0f / 5.0f * mass * radius * radius;
  49. inertiaTensor[8] = 2.0f / 5.0f * mass * radius * radius;
  50. iBodyInertiaTensor = inertiaTensor.inverse();
  51. }
  52. else if(flag && BODY_CYLINDER) {
  53. vec3 min = object->getMin();
  54. vec3 max = object->getMax();
  55. float radius = max.x - min.x;
  56. float height = max.z - min.z;
  57. mat3 inertiaTensor;
  58. inertiaTensor[0] = 1.0f / 12.0f * mass * height * height;
  59. inertiaTensor[4] = 1.0f / 12.0f * mass * height * height;
  60. inertiaTensor[8] = 1.0f / 2.0f * mass * radius * radius;
  61. iBodyInertiaTensor = inertiaTensor.inverse();
  62. }
  63. set(object->transform);
  64. RigidBody **rb = new RigidBody*[++Physic::all_rigidbodies];
  65. memcpy(rb,Physic::rigidbodies,sizeof(RigidBody*) * (Physic::all_rigidbodies - 1));
  66. if(Physic::rigidbodies) delete Physic::rigidbodies;
  67. Physic::rigidbodies = rb;
  68. }
  69. RigidBody::~RigidBody() {
  70. delete collide;
  71. if(num_joints) delete joints[0];
  72. if(Physic::all_rigidbodies) Physic::all_rigidbodies--;
  73. else {
  74. delete Physic::rigidbodies;
  75. Physic::rigidbodies = NULL;
  76. }
  77. }
  78. /*
  79.  */
  80. void RigidBody::set(const vec3 &p) {
  81. mat4 m;
  82. m.translate(p);
  83. set(m);
  84. }
  85. /*
  86.  */
  87. void RigidBody::set(const mat4 &m) {
  88. vec3 old_pos = pos;
  89. pos = m * vec3(0,0,0);
  90. orienation = mat3(m);
  91. mat4 old_transform = transform;
  92. transform = m;
  93. itransform = transform.inverse();
  94. //velocity = (pos - old_pos) * Engine::ifps * 100.0f;
  95. velocity = vec3(0,0,0);
  96. angularVelocity = vec3(0,0,0);
  97. angularMomentum = vec3(0,0,0);
  98. iWorldInertiaTensor.identity();
  99. frozen = 0;
  100. frozen_time = 0.0f;
  101. immovable = 1;
  102. }
  103. /*
  104.  */
  105. void RigidBody::simulate() {
  106. if(simulated) return;
  107. simulated = 1;
  108. Physic::rigidbodies[Physic::num_rigidbodies++] = this;
  109. for(int i = 0; i < num_joints; i++) { // add all joined rigid bodies
  110. RigidBody *rb = joined_rigidbodies[i];
  111. if(rb->simulated == 0) {
  112. Physic::joints[Physic::num_joints++] = joints[i];
  113. rb->simulate();
  114. }
  115. }
  116. }
  117. /*
  118.  */
  119. void RigidBody::addImpulse(const vec3 &point,const vec3 &impulse) {
  120. velocity += impulse / mass;
  121. angularMomentum += cross(point - pos,impulse);
  122. angularVelocity = iWorldInertiaTensor * angularMomentum;
  123. }
  124. /*****************************************************************************/
  125. /*                                                                           */
  126. /*                                                                           */
  127. /*                                                                           */
  128. /*****************************************************************************/
  129. /*
  130.  */
  131. void RigidBody::calcForce(float ifps) {
  132. force = vec3(0,0,0);
  133. torque = vec3(0,0,0);
  134. if(!frozen) force.z += Physic::gravitation * mass;
  135. force -= velocity * 0.1f;
  136. }
  137. /*
  138.  */
  139. void RigidBody::findContacts(float ifps) {
  140. static vec3 old_velicity;
  141. static vec3 old_angularMomentum;
  142. static vec3 old_angularVelocity;
  143. static Position old_pos;
  144. static mat3 old_orientation;
  145. static mat3 old_iWorldInertiaTensor;
  146. old_velicity = velocity;
  147. old_angularMomentum = angularMomentum;
  148. old_angularVelocity = angularVelocity;
  149. old_pos = pos;
  150. old_orientation = orienation;
  151. old_iWorldInertiaTensor = iWorldInertiaTensor;
  152. // predicted new position
  153. integrateVelocity(ifps);
  154. integratePos(ifps);
  155. // find conact points
  156. if(collide_type == COLLIDE_MESH) collide->collide(object);
  157. else if(collide_type == COLLIDE_SPHERE) collide->collide(object,object->pos,object->getRadius());
  158. velocity = old_velicity; // restore old values
  159. angularMomentum = old_angularMomentum;
  160. angularVelocity = old_angularVelocity;
  161. pos = old_pos;
  162. orienation = old_orientation;
  163. iWorldInertiaTensor = old_iWorldInertiaTensor;
  164. }
  165. /*
  166.  */
  167. void RigidBody::integrateVelocity(float ifps) {
  168. velocity += force * ifps / mass;
  169. float vel = velocity.length();
  170. if(vel > Physic::velocity_max) velocity *= Physic::velocity_max / vel;
  171. angularMomentum += torque * ifps;
  172. angularVelocity = iWorldInertiaTensor * angularMomentum;
  173. }
  174. /*
  175.  */
  176. void RigidBody::integratePos(float ifps) {
  177. pos += velocity * ifps;
  178. mat3 m;
  179. m[0] = 0.0; m[3] = -angularVelocity[2]; m[6] = angularVelocity[1];
  180. m[1] = angularVelocity[2]; m[4] = 0.0; m[7] = -angularVelocity[0];
  181. m[2] = -angularVelocity[1]; m[5] = angularVelocity[0]; m[8] = 0.0;
  182. orienation += (m * orienation) * ifps;
  183. orienation.orthonormalize();
  184. iWorldInertiaTensor = orienation * iBodyInertiaTensor * orienation.transpose();
  185. transform = mat4(orienation);
  186. transform[12] = pos.x;
  187. transform[13] = pos.y;
  188. transform[14] = pos.z;
  189. itransform = transform.inverse();
  190. object->transform = transform;
  191. object->itransform = itransform;
  192. object->updatePos(pos);
  193. }
  194. /*
  195.  */
  196. int RigidBody::contactsResponse(float ifps,int zero_restitution) {
  197. int done = 1;
  198. for(int i = 0; i < collide->num_contacts; i++) {
  199. Collide::Contact *c = &collide->contacts[i];
  200. if(c->object->rigidbody) { // rigidbody - rigidbody contact
  201. RigidBody *rb = c->object->rigidbody;
  202. vec3 r0 = c->point - pos;
  203. vec3 r1 = c->point - rb->pos;
  204. vec3 vel = (cross(angularVelocity,r0) + velocity) - (cross(rb->angularVelocity,r1) + rb->velocity);
  205. float normal_vel = c->normal * vel;
  206. if(normal_vel > -EPSILON) continue;
  207. float impulse_numerator;
  208. if(!zero_restitution) impulse_numerator = -(1.0f + restitution) * normal_vel;
  209. else impulse_numerator = -normal_vel + c->depth * Physic::penetration_speed / ifps;
  210. if(impulse_numerator < EPSILON) continue;
  211. vec3 tangent = -(vel - c->normal * normal_vel);
  212. done = 0;
  213. float impulse_denominator = 1.0f / mass + 1.0f / rb->mass
  214. + c->normal * cross(iWorldInertiaTensor * cross(r0,c->normal),r0)
  215. + c->normal * cross(rb->iWorldInertiaTensor * cross(r1,c->normal),r1);
  216. vec3 impulse = c->normal * impulse_numerator / impulse_denominator;
  217. if(frozen == 0 && immovable == 0) {
  218. velocity += impulse / mass;
  219. angularMomentum += cross(r0,impulse);
  220. angularVelocity = iWorldInertiaTensor * angularMomentum;
  221. }
  222. if(rb->frozen == 0 && rb->immovable == 0) {
  223. rb->velocity -= impulse / rb->mass;
  224. rb->angularMomentum -= cross(r1,impulse);
  225. rb->angularVelocity = rb->iWorldInertiaTensor * rb->angularMomentum;
  226. }
  227. // friction
  228. if(tangent.normalize() < EPSILON) continue;
  229. vel = (cross(angularVelocity,r0) + velocity) - (cross(rb->angularVelocity,r1) + rb->velocity);
  230. float tangent_vel = tangent * vel;
  231. if(tangent_vel > -EPSILON) continue;
  232. float friction_numerator = -tangent_vel * friction;
  233. float friction_denominator = 1.0f / mass + 1.0f / rb->mass +
  234. tangent * cross(iWorldInertiaTensor * cross(r0,tangent),r0) +
  235. tangent * cross(rb->iWorldInertiaTensor * cross(r1,tangent),r1);
  236. impulse = tangent * friction_numerator / friction_denominator;
  237. if(!frozen) {
  238. velocity += impulse / mass;
  239. angularMomentum += cross(r0,impulse);
  240. angularVelocity = iWorldInertiaTensor * angularMomentum;
  241. }
  242. if(!rb->frozen) {
  243. rb->velocity -= impulse / rb->mass;
  244. rb->angularMomentum -= cross(r1,impulse);
  245. rb->angularVelocity = rb->iWorldInertiaTensor * rb->angularMomentum;
  246. }
  247. } else { // rigidbody - scene contact
  248. if(frozen) continue;
  249. vec3 r = c->point - pos;
  250. vec3 vel = cross(angularVelocity,r) + velocity;
  251. float normal_vel = c->normal * vel;
  252. if(normal_vel > -EPSILON) continue;
  253. float impulse_numerator;
  254. if(!zero_restitution) impulse_numerator = -(1.0f + restitution) * normal_vel;
  255. else impulse_numerator = -normal_vel + c->depth * Physic::penetration_speed / ifps;
  256. if(impulse_numerator < EPSILON) continue;
  257. vec3 tangent = -(vel - c->normal * normal_vel);
  258. done = 0;
  259. float impulse_denominator = 1.0f / mass + c->normal * cross(iWorldInertiaTensor * cross(r,c->normal),r);
  260. vec3 impulse = c->normal * impulse_numerator / impulse_denominator;
  261. velocity += impulse / mass;
  262. angularMomentum += cross(r,impulse);
  263. angularVelocity = iWorldInertiaTensor * angularMomentum;
  264. // friction
  265. if(tangent.normalize() < EPSILON) continue;
  266. vel = cross(angularVelocity,r) + velocity;
  267. float tangent_vel = tangent * vel;
  268. if(tangent_vel > -EPSILON) continue;
  269. float friction_numerator = -tangent_vel * friction;
  270. float friction_denominator = 1.0f / mass + tangent * cross(iWorldInertiaTensor * cross(r,tangent),r);
  271. impulse = tangent * friction_numerator / friction_denominator;
  272. velocity += impulse / mass;
  273. angularMomentum += cross(r,impulse);
  274. angularVelocity = iWorldInertiaTensor * angularMomentum;
  275. }
  276. }
  277. return done;
  278. }