GLS.ODERagdoll.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.ODERagdoll;
  5. (* The extension of TGLRagdoll by using Open Dynamics Engine (ODE) *)
  6. interface
  7. uses
  8. Stage.VectorTypes,
  9. Stage.VectorGeometry,
  10. GLS.Ragdoll,
  11. GLS.Scene,
  12. GLS.Objects,
  13. GLS.Texture,
  14. GLS.VectorFileObjects,
  15. ODE.Import,
  16. GLS.ODEUtils;
  17. const
  18. cMaxContacts = 4;
  19. type
  20. TGLODERagdoll = class;
  21. TGLODERagdollBone = class;
  22. TGLODERagdollCube = class(TGLCube)
  23. public
  24. Bone: TGLODERagdollBone; // Useful in Oncollision Event
  25. Ragdoll: TGLODERagdoll; // Useful in Oncollision Event
  26. end;
  27. TGLODERagdollWorld = class
  28. private
  29. FSpace: PdxSpace;
  30. FWorld: PdxWorld;
  31. FContactGroup: TdJointGroupID;
  32. FRagdoll: TGLODERagdoll;
  33. isWorldCreated: Boolean; // NEW1
  34. public
  35. constructor Create;
  36. // Create the world from any existing ODE world
  37. constructor CreateFrom(World: PdxWorld; Space: PdxSpace;
  38. ContactGroup: TdJointGroupID);
  39. destructor Destroy; override;
  40. procedure WorldUpdate;
  41. property World: PdxWorld read FWorld;
  42. property Space: PdxSpace read FSpace;
  43. property ContactGroup: TdJointGroupID read FContactGroup;
  44. property Ragdoll: TGLODERagdoll read FRagdoll;
  45. end;
  46. TGLODERagdollDummyJoint = class(TGLRagdolJoint)
  47. end;
  48. TGLODERagdollHingeJoint = class(TGLRagdolJoint)
  49. private
  50. FParamHiStop: Single;
  51. FParamLoStop: Single;
  52. FAxis: TAffineVector;
  53. public
  54. constructor Create(Axis: TAffineVector; ParamLoStop: Single;
  55. ParamHiStop: Single);
  56. property Axis: TAffineVector read FAxis;
  57. property ParamLoStop: Single read FParamLoStop write FParamLoStop;
  58. property ParamHiStop: Single read FParamHiStop write FParamHiStop;
  59. end;
  60. TGLODERagdollUniversalJoint = class(TGLODERagdollHingeJoint)
  61. private
  62. FParamHiStop2: Single;
  63. FParamLoStop2: Single;
  64. FAxis2: TAffineVector;
  65. public
  66. constructor Create(Axis: TAffineVector; ParamLoStop: Single;
  67. ParamHiStop: Single; Axis2: TAffineVector; ParamLoStop2: Single;
  68. ParamHiStop2: Single);
  69. property Axis2: TAffineVector read FAxis2;
  70. property ParamLoStop2: Single read FParamLoStop2 write FParamLoStop2;
  71. property ParamHiStop2: Single read FParamHiStop2 write FParamHiStop2;
  72. end;
  73. TGLODERagdollBone = class(TGLRagdolBone)
  74. private
  75. FOwner: TGLODERagdollBone;
  76. FRagdoll: TGLODERagdoll;
  77. FBody: PdxBody;
  78. FGeom: PdxGeom;
  79. FJointId: TdJointID;
  80. procedure AlignBodyToMatrix(Mat: TGLMatrix);
  81. protected
  82. procedure Start; override;
  83. procedure Align; override;
  84. procedure Update; override;
  85. procedure Stop; override;
  86. public
  87. constructor CreateOwned(aOwner: TGLODERagdollBone);
  88. constructor Create(Ragdoll: TGLODERagdoll);
  89. property Body: PdxBody read FBody;
  90. property Geom: PdxGeom read FGeom;
  91. end;
  92. TGLODERagdoll = class(TGLRagdoll)
  93. private
  94. FODEWorld: TGLODERagdollWorld;
  95. FGLSceneRoot: TGLBaseSceneObject;
  96. FShowBoundingBoxes: Boolean;
  97. FEnabled: Boolean;
  98. public
  99. constructor Create(aOwner: TGLBaseMesh);
  100. property ODEWorld: TGLODERagdollWorld read FODEWorld write FODEWorld;
  101. property GLSceneRoot: TGLBaseSceneObject read FGLSceneRoot
  102. write FGLSceneRoot;
  103. property ShowBoundingBoxes: Boolean read FShowBoundingBoxes
  104. write FShowBoundingBoxes;
  105. property Enabled: Boolean read FEnabled write FEnabled;
  106. end;
  107. var
  108. vODERagdoll_cDensity: Single;
  109. vODERagdoll_cMass: Single;
  110. // ----------------------------------------
  111. implementation
  112. //-------------------------------------
  113. // TGLODERagdollWorld
  114. // ----------------------------------------
  115. constructor TGLODERagdollWorld.Create;
  116. begin
  117. // Create default physics
  118. FWorld := dWorldCreate();
  119. dWorldSetQuickStepNumIterations(FWorld, 8);
  120. FSpace := dHashSpaceCreate(nil);
  121. FContactGroup := dJointGroupCreate(0);
  122. dWorldSetGravity(FWorld, 0, 0, -0.81);
  123. dWorldSetCFM(FWorld, 1E-5);
  124. isWorldCreated := True; // NEW1
  125. end;
  126. constructor TGLODERagdollWorld.CreateFrom(World: PdxWorld; Space: PdxSpace;
  127. ContactGroup: TdJointGroupID);
  128. begin
  129. FWorld := World;
  130. FSpace := Space;
  131. FContactGroup := ContactGroup;
  132. isWorldCreated := False; // NEW1
  133. end;
  134. destructor TGLODERagdollWorld.Destroy;
  135. begin
  136. if isWorldCreated then
  137. begin
  138. dJointGroupDestroy(FContactGroup);
  139. dSpaceDestroy(FSpace);
  140. dWorldDestroy(FWorld);
  141. end;
  142. inherited;
  143. end;
  144. procedure ODERagdollCallback(data: pointer; o1, o2: PdxGeom); cdecl;
  145. var
  146. i, n: integer;
  147. b1, b2: PdxBody;
  148. c: TdJointID;
  149. contact: Array [0 .. cMaxContacts - 1] of TdContact;
  150. begin
  151. b1 := dGeomGetBody(o1);
  152. b2 := dGeomGetBody(o2);
  153. if (assigned(b1) and assigned(b2) and (dAreConnected(b1, b2) <> 0)) then
  154. exit;
  155. n := dCollide(o1, o2, cMaxContacts, contact[0].Geom, sizeof(TdContact));
  156. if (n > 0) then
  157. begin
  158. for i := 0 to n - 1 do
  159. begin
  160. contact[i].surface.mode := ord(dContactBounce) or ord(dContactSoftCFM) or
  161. ord(dContactSlip1) or ord(dContactSlip2);
  162. contact[i].surface.mu := 10E9;
  163. contact[i].surface.mu2 := 0;
  164. contact[i].surface.soft_cfm := 0.001;
  165. contact[i].surface.bounce := 0.15;
  166. contact[i].surface.bounce_vel := 0.2;
  167. contact[i].surface.slip1 := 0.1;
  168. contact[i].surface.slip2 := 0.1;
  169. c := dJointCreateContact(TGLODERagdollWorld(data).World,
  170. TGLODERagdollWorld(data).ContactGroup, @contact[i]);
  171. dJointAttach(c, dGeomGetBody(contact[i].Geom.g1),
  172. dGeomGetBody(contact[i].Geom.g2));
  173. end;
  174. end;
  175. end;
  176. procedure TGLODERagdollWorld.WorldUpdate;
  177. const
  178. cDeltaTime = 1 / 50;
  179. begin
  180. // Update the physic
  181. dSpaceCollide(FSpace, Self, ODERagdollCallback);
  182. dWorldQuickStep(FWorld, cDeltaTime);
  183. // remove all contact joints
  184. dJointGroupEmpty(FContactGroup);
  185. end;
  186. //
  187. // TGLODERagdollHingeJoint
  188. //
  189. constructor TGLODERagdollHingeJoint.Create(Axis: TAffineVector;
  190. ParamLoStop, ParamHiStop: Single);
  191. begin
  192. inherited Create;
  193. FAxis := Axis;
  194. FParamLoStop := ParamLoStop;
  195. FParamHiStop := ParamHiStop;
  196. end;
  197. //
  198. // TGLODERagdollUniversalJoint
  199. //
  200. constructor TGLODERagdollUniversalJoint.Create(Axis: TAffineVector;
  201. ParamLoStop, ParamHiStop: Single; Axis2: TAffineVector;
  202. ParamLoStop2, ParamHiStop2: Single);
  203. begin
  204. inherited Create(Axis, ParamLoStop, ParamHiStop);
  205. FAxis2 := Axis2;
  206. FParamLoStop := ParamLoStop;
  207. FParamHiStop := ParamHiStop;
  208. FParamLoStop2 := ParamLoStop2;
  209. FParamHiStop2 := ParamHiStop2;
  210. end;
  211. //
  212. // TGLODERagdollBone
  213. //
  214. constructor TGLODERagdollBone.Create(Ragdoll: TGLODERagdoll);
  215. begin
  216. inherited Create(Ragdoll);
  217. FRagdoll := Ragdoll;
  218. end;
  219. constructor TGLODERagdollBone.CreateOwned(aOwner: TGLODERagdollBone);
  220. begin
  221. inherited CreateOwned(aOwner);
  222. FOwner := aOwner;
  223. FRagdoll := aOwner.FRagdoll;
  224. end;
  225. procedure TGLODERagdollBone.AlignBodyToMatrix(Mat: TGLMatrix);
  226. var
  227. R: TdMatrix3;
  228. begin
  229. if not assigned(FBody) then
  230. exit;
  231. R[0] := Mat.X.X;
  232. R[1] := Mat.Y.X;
  233. R[2] := Mat.Z.X;
  234. R[3] := 0;
  235. R[4] := Mat.X.Y;
  236. R[5] := Mat.Y.Y;
  237. R[6] := Mat.Z.Y;
  238. R[7] := 0;
  239. R[8] := Mat.X.Z;
  240. R[9] := Mat.Y.Z;
  241. R[10] := Mat.Z.Z;
  242. R[11] := 0;
  243. dBodySetRotation(FBody, R);
  244. dBodySetPosition(FBody, Mat.W.X, Mat.W.Y, Mat.W.Z);
  245. end;
  246. procedure TGLODERagdollBone.Start;
  247. var
  248. mass: TdMass;
  249. boneSize, vAxis, vAxis2: TAffineVector;
  250. n: integer;
  251. function RotateAxis(Axis: TAffineVector): TAffineVector;
  252. var
  253. absMat: TGLMatrix;
  254. begin
  255. absMat := ReferenceMatrix;
  256. absMat.W := NullHmgVector;
  257. Result := VectorNormalize(VectorTransform(Axis, absMat));
  258. end;
  259. begin
  260. FBody := dBodyCreate(FRagdoll.ODEWorld.World);
  261. boneSize.X := Size.X * VectorLength(BoneMatrix.X);
  262. boneSize.Y := Size.Y * VectorLength(BoneMatrix.Y);
  263. boneSize.Z := Size.Z * VectorLength(BoneMatrix.Z);
  264. // prevent ODE 0.9 "bNormalizationResult failed" error:
  265. for n := 0 to 2 do
  266. if (boneSize.V[n] = 0) then
  267. boneSize.V[n] := 0.000001;
  268. dMassSetBox(mass, vODERagdoll_cDensity, boneSize.X, boneSize.Y, boneSize.Z);
  269. dMassAdjust(mass, vODERagdoll_cMass);
  270. dBodySetMass(FBody, @mass);
  271. AlignBodyToMatrix(ReferenceMatrix);
  272. FGeom := dCreateBox(FRagdoll.ODEWorld.Space, boneSize.X, boneSize.Y,
  273. boneSize.Z);
  274. FGeom.data := FRagdoll.GLSceneRoot.AddNewChild(TGLODERagdollCube);
  275. if (Joint is TGLODERagdollDummyJoint) then
  276. dGeomSetBody(FGeom, FOwner.Body)
  277. else
  278. dGeomSetBody(FGeom, FBody);
  279. if (Owner <> nil) then
  280. begin
  281. if (Joint is TGLODERagdollHingeJoint) then
  282. with (Joint as TGLODERagdollHingeJoint) do
  283. begin
  284. vAxis := RotateAxis(Axis);
  285. FJointId := dJointCreateHinge(FRagdoll.ODEWorld.World, nil);
  286. dJointAttach(FJointId, TGLODERagdollBone(Owner).Body, FBody);
  287. dJointSetHingeAnchor(FJointId, Anchor.X, Anchor.Y, Anchor.Z);
  288. dJointSetHingeAxis(FJointId, vAxis.X, vAxis.Y, vAxis.Z);
  289. dJointSetHingeParam(FJointId, dParamLoStop, ParamLoStop);
  290. dJointSetHingeParam(FJointId, dParamHiStop, ParamHiStop);
  291. end;
  292. if (Joint is TGLODERagdollUniversalJoint) then
  293. with (Joint as TGLODERagdollUniversalJoint) do
  294. begin
  295. vAxis := RotateAxis(Axis);
  296. vAxis2 := RotateAxis(Axis2);
  297. FJointId := dJointCreateUniversal(FRagdoll.ODEWorld.World, nil);
  298. dJointAttach(FJointId, TGLODERagdollBone(Owner).Body, FBody);
  299. dJointSetUniversalAnchor(FJointId, Anchor.X, Anchor.Y, Anchor.Z);
  300. dJointSetUniversalAxis1(FJointId, vAxis.X, vAxis.Y, vAxis.Z);
  301. dJointSetUniversalAxis2(FJointId, vAxis2.X, vAxis2.Y, vAxis2.Z);
  302. dJointSetUniversalParam(FJointId, dParamLoStop, ParamLoStop);
  303. dJointSetUniversalParam(FJointId, dParamHiStop, ParamHiStop);
  304. dJointSetUniversalParam(FJointId, dParamLoStop2, ParamLoStop2);
  305. dJointSetUniversalParam(FJointId, dParamHiStop2, ParamHiStop2);
  306. end;
  307. end;
  308. with TGLODERagdollCube(FGeom.data) do
  309. begin
  310. Visible := FRagdoll.ShowBoundingBoxes;
  311. Material.FrontProperties.Diffuse.SetColor(1, 0, 0, 0.4);
  312. CubeWidth := boneSize.X;
  313. CubeHeight := boneSize.Y;
  314. CubeDepth := boneSize.Z;
  315. Bone := Self;
  316. Ragdoll := Self.FRagdoll;
  317. end;
  318. end;
  319. procedure TGLODERagdollBone.Stop;
  320. var
  321. o: TGLBaseSceneObject;
  322. begin
  323. inherited;
  324. dBodyDestroy(FBody);
  325. if assigned(FGeom.data) then
  326. begin
  327. o := TGLBaseSceneObject(FGeom.data);
  328. FRagdoll.GLSceneRoot.Remove(o, False);
  329. o.free;
  330. end;
  331. if FJointId <> nil then
  332. dJointDestroy(FJointId);
  333. dGeomDestroy(FGeom);
  334. end;
  335. procedure TGLODERagdollBone.Update;
  336. begin
  337. PositionSceneObject(TGLBaseSceneObject(PdxGeom(FGeom.data)), FGeom);
  338. Ragdoll.Owner.Skeleton.BoneByID(BoneID).SetGlobalMatrixForRagDoll
  339. (TGLBaseSceneObject(PdxGeom(FGeom.data)).AbsoluteMatrix);
  340. end;
  341. procedure TGLODERagdollBone.Align;
  342. begin
  343. inherited;
  344. AlignBodyToMatrix(BoneMatrix);
  345. end;
  346. //
  347. // TGLODERagdoll
  348. //
  349. constructor TGLODERagdoll.Create(aOwner: TGLBaseMesh);
  350. begin
  351. inherited Create(aOwner);
  352. FShowBoundingBoxes := False;
  353. end;
  354. // -------------------------------------------------
  355. initialization
  356. // -------------------------------------------------
  357. vODERagdoll_cDensity := 20;
  358. vODERagdoll_cMass := 1;
  359. end.