GLS.NGDRagdoll.pas 9.4 KB

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