GLS.NGDRagdoll.pas 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. //
  2. // The graphics engine GLXEngine. The unit of GLScene for Delphi
  3. //
  4. unit GLS.NGDRagdoll;
  5. (* The Ragdoll extension using Newton Game Dynamics Engine *)
  6. interface
  7. uses
  8. System.Classes,
  9. System.SysUtils,
  10. Stage.VectorGeometry,
  11. Stage.VectorTypes,
  12. GLS.VectorFileObjects,
  13. NGD.Import;
  14. type
  15. TNewtonRagdoll = class
  16. private
  17. FERP, FSlideLimit, FAngleLimit: single;
  18. FEnabled: boolean;
  19. newtonworld: PNewtonWorld;
  20. procedure SetSlideLimit(value: single);
  21. procedure SetAngleLimit(value: single);
  22. procedure SetERP(value: single);
  23. procedure SetEnabled(value: boolean);
  24. procedure Clean;
  25. public
  26. Actor: TGLActor;
  27. Bodies: TList;
  28. Joints: array of PNewtonJoint;
  29. Norm_matrices: array of TGLMatrix;
  30. Envelopes: array of record kind: byte;
  31. Mat: TGLMatrix;
  32. Pt: TVector3f;
  33. W, D, H, Mass: single;
  34. end;
  35. property Enabled: boolean read FEnabled write SetEnabled;
  36. property SlideLimit: single read FSlideLimit write SetSlideLimit;
  37. property AngleLimit: single read FAngleLimit write SetAngleLimit;
  38. property ERP: single read FERP write SetERP;
  39. constructor Create(model: TGLActor; world: PNewtonWorld; min_env_size: single = 0.8;
  40. slide_limit: single = 0.5; erp_: single = 0.8; angle_limit: single = 15; full: boolean = true);
  41. procedure Conform;
  42. destructor Destroy; override;
  43. procedure LoadFromFile(filename: string);
  44. procedure SaveToFile(filename: string);
  45. function TranslatePos(n: integer; add: boolean): TGLVector;
  46. end;
  47. function GetBoneParent(Actor: TGLActor; bone: integer): integer;
  48. // --------------------------------------------
  49. implementation
  50. // --------------------------------------------
  51. function TNewtonRagdoll.TranslatePos;
  52. begin
  53. with Envelopes[n] do
  54. if add then
  55. Result := VectorAdd(Mat.W, VectorAdd(VectorScale(Mat.X, Pt.X),
  56. VectorAdd(VectorScale(Mat.Y, Pt.Y), VectorScale(Mat.Z, Pt.Z))))
  57. else
  58. Result := VectorSubtract(Mat.W, VectorAdd(VectorScale(Mat.X, Pt.X),
  59. VectorAdd(VectorScale(Mat.Y, Pt.Y), VectorScale(Mat.Z, Pt.Z))));
  60. end;
  61. function GetBoneParent;
  62. var
  63. i, j: integer;
  64. begin
  65. Result := 0;
  66. for i := 0 to Actor.Skeleton.BoneCount - 2 do
  67. if Actor.Skeleton.BoneByID(i) <> nil then
  68. for j := 0 to Actor.Skeleton.BoneByID(i).Count - 1 do
  69. if Actor.Skeleton.BoneByID(i).Items[j].BoneID = bone then
  70. begin
  71. Result := i;
  72. Exit;
  73. end;
  74. end;
  75. procedure NewtonApplyForceAndTorqueCallback(const body: PNewtonBody; timestep: single;
  76. threadIndex: integer); cdecl;
  77. var
  78. m: single;
  79. i: TVector3f;
  80. F: TVector3f;
  81. begin
  82. NewtonBodyGetMassMatrix(body, @m, @i.X, @i.Y, @i.Z);
  83. F := AffineVectorMake(0, -9.81 * m, 0);
  84. NewtonBodyAddForce(body, @F.X);
  85. end;
  86. function NewtonJointCallBack(const Universal: PNewtonJoint; desc: PNewtonHingeSliderUpdateDesc)
  87. : cardinal; cdecl;
  88. var
  89. angle: single;
  90. begin
  91. // if Abs(desc.m_accel)>100 then
  92. // desc.m_accel:=desc.m_accel/2;
  93. // desc.m_accel:=NewtonUniversalCalculateStopAlpha1(Universal,desc,0);
  94. (*
  95. angle:=NewtonUniversalGetJointAngle0(Universal);
  96. if angle<-2.6 then desc.m_accel:=NewtonUniversalCalculateStopAlpha0(Universal,desc,-2.6);
  97. if angle>0 then desc.m_accel:=NewtonUniversalCalculateStopAlpha0(Universal,desc,0);
  98. angle:=NewtonUniversalGetJointAngle1(Universal);
  99. if angle<-2.6 then desc.m_accel:=NewtonUniversalCalculateStopAlpha1(Universal,desc,-2.6);
  100. if angle>0 then desc.m_accel:=NewtonUniversalCalculateStopAlpha1(Universal,desc,0);
  101. *)
  102. Result := 0;
  103. end;
  104. constructor TNewtonRagdoll.Create;
  105. var
  106. i, j: integer;
  107. p1, p2: TVector4f;
  108. D: single;
  109. Collision: PNewtonCollision;
  110. CollisionBox, CollisionCylinder, CollisionSphere: PNewtonCollision;
  111. Matrix: TGLMatrix;
  112. CollisionOffsetMatrix: TGLMatrix; // For cone capsule and cylinder
  113. begin
  114. CollisionOffsetMatrix := IdentityHmgMatrix;
  115. D := 0;
  116. if full then
  117. begin
  118. inherited Create;
  119. Actor := model;
  120. newtonworld := world;
  121. end;
  122. FEnabled := false;
  123. Bodies := TList.Create;
  124. SetLength(Envelopes, Actor.Skeleton.BoneCount - 1);
  125. SetLength(Norm_matrices, Actor.Skeleton.BoneCount - 1);
  126. SetLength(Joints, Actor.Skeleton.BoneCount - 1);
  127. for i := 0 to Actor.Skeleton.BoneCount - 2 do
  128. begin
  129. p1 := Actor.Skeleton.BoneByID(i).GlobalMatrix.W;
  130. if Actor.Skeleton.BoneByID(i).BoneCount > 1 then
  131. p2 := Actor.Skeleton.BoneByID(i).Items[0].GlobalMatrix.W
  132. else
  133. p2 := p1;
  134. p1 := VectorTransform(p1, Actor.AbsoluteMatrix);
  135. p2 := VectorTransform(p2, Actor.AbsoluteMatrix);
  136. with Envelopes[i] do
  137. begin
  138. if full then
  139. begin
  140. kind := 1;
  141. Mass := 1;
  142. D := 2 * min_env_size;
  143. H := 2 * min_env_size;
  144. W := 0.8 * VectorLength(VectorSubtract(p2, p1));
  145. if W < 1 then
  146. begin
  147. W := min_env_size;
  148. D := min_env_size;
  149. H := min_env_size;
  150. end;
  151. Pt := AffineVectorMake(W * 0.5 / 0.8, 0, 0);
  152. // p2:=m[0]; m[0]:=m[1]; m[1]:=p2;
  153. end;
  154. Mat := MatrixMultiply(Actor.Skeleton.BoneByID(i).GlobalMatrix, Actor.AbsoluteMatrix);
  155. Mat.W := TranslatePos(i, true);
  156. case kind of
  157. 0, 1:
  158. begin
  159. Collision := NewtonCreateBox(newtonworld, W, H, D, 0, @CollisionOffsetMatrix);
  160. Bodies.add(NewtonCreateBody(world, Collision, @CollisionOffsetMatrix));
  161. NewtonBodySetMassMatrix(Bodies[Bodies.Count - 1], Mass, W, H, D);
  162. end;
  163. 2:
  164. begin
  165. Bodies.add(NewtonCreateBody(world, NewtonCreateCylinder(newtonworld, W, H, 0,
  166. @CollisionOffsetMatrix), @CollisionOffsetMatrix));
  167. NewtonBodySetMassMatrix(Bodies[Bodies.Count - 1], Mass, 2, W, H);
  168. end;
  169. 3:
  170. begin
  171. Bodies.add(NewtonCreateBody(world, NewtonCreateSphere(newtonworld, W, W, W, 0,
  172. @CollisionOffsetMatrix), @CollisionOffsetMatrix));
  173. NewtonBodySetMassMatrix(Bodies[Bodies.Count - 1], Mass, W, W, W);
  174. end;
  175. end;
  176. NewtonBodySetLinearDamping(Bodies[i], 0);
  177. NewtonBodySetAngularDamping(Bodies[i], @D);
  178. NewtonBodySetMatrix(Bodies[i], @Mat);
  179. NewtonBodySetForceAndTorqueCallBack(Bodies[i], NewtonApplyForceAndTorqueCallback);
  180. end;
  181. end;
  182. FERP := erp_;
  183. FSlideLimit := slide_limit;
  184. FAngleLimit := angle_limit;
  185. for i := 0 to Actor.Skeleton.BoneCount - 2 do
  186. begin
  187. j := GetBoneParent(Actor, i);
  188. if i = j then
  189. Continue;
  190. p1 := TranslatePos(i, false);
  191. with Envelopes[i] do
  192. Joints[i] := NewtonConstraintCreateHinge(newtonworld, @p1, @Mat.Y, Bodies[i], Bodies[j]);
  193. NewtonJointSetCollisionState(Joints[i], 1);
  194. NewtonHingeSetUserCallback(Joints[i], NewtonJointCallBack);
  195. end;
  196. end;
  197. procedure TNewtonRagdoll.Conform;
  198. var
  199. i: integer;
  200. begin
  201. if Enabled = false then
  202. Exit;
  203. for i := 0 to Length(Envelopes) - 1 do
  204. with Envelopes[i] do
  205. begin
  206. NewtonBodyGetMatrix(Bodies[i], @Mat);
  207. Mat.W := TranslatePos(i, false);
  208. Actor.Skeleton.BoneByID(i).SetGlobalMatrixForRagDoll(Mat);
  209. end;
  210. Actor.Skeleton.MorphMesh(true);
  211. end;
  212. procedure TNewtonRagdoll.Clean;
  213. var
  214. i: integer;
  215. begin
  216. for i := 0 to Length(Joints) - 1 do
  217. if Joints[i] <> nil then
  218. NewtonDestroyJoint(newtonworld, Joints[i]);
  219. SetLength(Joints, 0);
  220. for i := 0 to Bodies.Count - 1 do
  221. NewtonDestroyBody(newtonworld, Bodies[i]);
  222. Bodies.Clear;
  223. FreeAndNil(Bodies);
  224. end;
  225. destructor TNewtonRagdoll.Destroy;
  226. begin
  227. Clean;
  228. SetLength(Envelopes, 0);
  229. SetLength(Norm_matrices, 0);
  230. inherited Destroy;
  231. end;
  232. procedure TNewtonRagdoll.SetEnabled;
  233. var
  234. i: integer;
  235. a: TGLMatrix;
  236. v: TVector3f;
  237. begin
  238. if FEnabled = value then
  239. Exit;
  240. FEnabled := value;
  241. if value = true then
  242. begin
  243. Actor.Skeleton.StartRagdoll;
  244. for i := 0 to Length(Envelopes) - 1 do
  245. Norm_matrices[i] := Envelopes[i].Mat;
  246. Exit;
  247. end;
  248. Actor.Skeleton.StopRagdoll;
  249. for i := 0 to Length(Envelopes) - 1 do
  250. begin
  251. v := NullVector;
  252. NewtonBodySetVelocity(Bodies[i], @v);
  253. NewtonBodySetOmega(Bodies[i], @v);
  254. NewtonBodySetForce(Bodies[i], @v);
  255. NewtonBodySetTorque(Bodies[i], @v);
  256. Envelopes[i].Mat := Norm_matrices[i];
  257. a := Envelopes[i].Mat;
  258. NewtonBodySetMatrix(Bodies[i], @a);
  259. NewtonBodySetCollision(Bodies[i], nil);
  260. Actor.Skeleton.BoneByID(i).SetGlobalMatrixForRagDoll(a);
  261. end;
  262. Actor.Skeleton.MorphMesh(true);
  263. end;
  264. procedure TNewtonRagdoll.SetSlideLimit;
  265. begin
  266. FSlideLimit := value;
  267. end;
  268. procedure TNewtonRagdoll.SetAngleLimit;
  269. begin
  270. FAngleLimit := value;
  271. end;
  272. procedure TNewtonRagdoll.SetERP;
  273. var
  274. i: integer;
  275. begin
  276. FERP := value;
  277. end;
  278. procedure TNewtonRagdoll.LoadFromFile;
  279. var
  280. i: integer;
  281. s, a, e: single;
  282. F: TFileStream;
  283. begin
  284. F := TFileStream.Create(filename, fmOpenRead);
  285. F.Read(i, SizeOf(i));
  286. SetLength(Envelopes, i);
  287. F.Read(s, SizeOf(s));
  288. F.Read(e, SizeOf(e));
  289. F.Read(a, SizeOf(a));
  290. Clean;
  291. for i := 0 to Length(Envelopes) - 1 do
  292. begin
  293. F.Read(Envelopes[i].kind, SizeOf(Envelopes[i].kind));
  294. F.Read(Envelopes[i].W, SizeOf(Envelopes[i].W));
  295. F.Read(Envelopes[i].H, SizeOf(Envelopes[i].H));
  296. F.Read(Envelopes[i].D, SizeOf(Envelopes[i].D));
  297. F.Read(Envelopes[i].Mass, SizeOf(Envelopes[i].Mass));
  298. F.Read(Envelopes[i].Pt, SizeOf(Envelopes[i].Pt));
  299. end;
  300. /// Create(actor, newtonworld, 0.8, s, e, a, false);
  301. F.Free;
  302. end;
  303. procedure TNewtonRagdoll.SaveToFile;
  304. var
  305. i: integer;
  306. F: TFileStream;
  307. begin
  308. if FileExists(filename) then
  309. F := TFileStream.Create(filename, fmOpenWrite)
  310. else
  311. F := TFileStream.Create(filename, fmCreate);
  312. i := Length(Envelopes);
  313. F.Write(i, SizeOf(i));
  314. F.Write(FSlideLimit, SizeOf(FSlideLimit));
  315. F.Write(FERP, SizeOf(FERP));
  316. F.Write(FAngleLimit, SizeOf(FAngleLimit));
  317. for i := 0 to Length(Envelopes) - 1 do
  318. begin
  319. F.Write(Envelopes[i].kind, SizeOf(Envelopes[i].kind));
  320. F.Write(Envelopes[i].W, SizeOf(Envelopes[i].W));
  321. F.Write(Envelopes[i].H, SizeOf(Envelopes[i].H));
  322. F.Write(Envelopes[i].D, SizeOf(Envelopes[i].D));
  323. F.Write(Envelopes[i].Mass, SizeOf(Envelopes[i].Mass));
  324. F.Write(Envelopes[i].Pt, SizeOf(Envelopes[i].Pt));
  325. end;
  326. F.Free;
  327. end;
  328. end.