GXS.ODERagdoll.pas 11 KB

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