GXS.NGDRagdoll.pas 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.NGDRagdoll;
  5. interface
  6. uses
  7. System.Classes,
  8. System.SysUtils,
  9. Stage.VectorGeometry,
  10. Stage.VectorTypes,
  11. GXS.VectorFileObjects,
  12. NGD.Import;
  13. type
  14. TNewtonRagdoll = class
  15. private
  16. FERP, FSlideLimit, FAngleLimit: single;
  17. FEnabled: boolean;
  18. newtonworld: PNewtonWorld;
  19. procedure SetSlideLimit(value: single);
  20. procedure SetAngleLimit(value: single);
  21. procedure SetERP(value: single);
  22. procedure SetEnabled(value: boolean);
  23. procedure Clean;
  24. public
  25. Actor: TgxActor;
  26. Bodies: TList;
  27. Joints: array of PNewtonJoint;
  28. Norm_matrices: array of TMatrix4f;
  29. Envelopes: array of record kind: byte;
  30. Mat: TMatrix4f;
  31. Pt: TVector3f;
  32. W, D, H, Mass: single;
  33. end;
  34. property Enabled: boolean read FEnabled write SetEnabled;
  35. property SlideLimit: single read FSlideLimit write SetSlideLimit;
  36. property AngleLimit: single read FAngleLimit write SetAngleLimit;
  37. property ERP: single read FERP write SetERP;
  38. constructor Create(model: TgxActor; world: PNewtonWorld;
  39. min_env_size: single = 0.8; slide_limit: single = 0.5; erp_: single = 0.8;
  40. 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): TVector4f;
  46. end;
  47. function GetBoneParent(actor: TgxActor; 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;
  76. timestep: single; 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;
  87. desc: PNewtonHingeSliderUpdateDesc): 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: TMatrix4f;
  112. CollisionOffsetMatrix: TMatrix4f; // 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,
  155. Actor.AbsoluteMatrix);
  156. Mat.w := TranslatePos(i, true);
  157. case kind of
  158. 0, 1:
  159. begin
  160. Collision := NewtonCreateBox(NewtonWorld, w, h, d, 0, @CollisionOffsetMatrix);
  161. Bodies.Add(NewtonCreateBody(World, Collision, @CollisionOffsetMatrix));
  162. NewtonBodySetMassMatrix(bodies[bodies.Count - 1], mass, w, h, d);
  163. end;
  164. 2:
  165. begin
  166. Bodies.Add(NewtonCreateBody(World, NewtonCreateCylinder(newtonworld,
  167. w, h, 0, @CollisionOffsetMatrix), @CollisionOffsetMatrix));
  168. NewtonBodySetMassMatrix(bodies[bodies.Count - 1], mass, 2, w, h);
  169. end;
  170. 3:
  171. begin
  172. Bodies.Add(NewtonCreateBody(world, NewtonCreateSphere(newtonworld,
  173. w, w, w, 0, @CollisionOffsetMatrix), @CollisionOffsetMatrix));
  174. NewtonBodySetMassMatrix(bodies[bodies.Count - 1], mass, w, w, w);
  175. end;
  176. end;
  177. NewtonBodySetLinearDamping(bodies[i], 0);
  178. NewtonBodySetAngularDamping(bodies[i], @d);
  179. NewtonBodySetMatrix(bodies[i], @Mat);
  180. NewtonBodySetForceAndTorqueCallBack(bodies[i],
  181. NewtonApplyForceAndTorqueCallback);
  182. end;
  183. end;
  184. FERP := erp_;
  185. FSlideLimit := slide_limit;
  186. FAngleLimit := angle_limit;
  187. for i := 0 to actor.Skeleton.BoneCount - 2 do
  188. begin
  189. j := GetBoneParent(actor, i);
  190. if i = j then
  191. Continue;
  192. p1 := TranslatePos(i, false);
  193. with envelopes[i] do
  194. joints[i] := NewtonConstraintCreateHinge(newtonworld, @p1, @Mat.Y,
  195. bodies[i], bodies[j]);
  196. NewtonJointSetCollisionState(joints[i], 1);
  197. NewtonHingeSetUserCallback(joints[i], NewtonJointCallBack);
  198. end;
  199. end;
  200. procedure TNewtonRagdoll.Conform;
  201. var
  202. i: integer;
  203. begin
  204. if Enabled = false then
  205. Exit;
  206. for i := 0 to Length(envelopes) - 1 do
  207. with envelopes[i] do
  208. begin
  209. NewtonBodyGetMatrix(Bodies[i], @Mat);
  210. Mat.w := TranslatePos(i, false);
  211. Actor.Skeleton.BoneByID(i).SetGlobalMatrixForRagDoll(Mat);
  212. end;
  213. actor.Skeleton.MorphMesh(true);
  214. end;
  215. procedure TNewtonRagdoll.Clean;
  216. var
  217. i: integer;
  218. begin
  219. for i := 0 to Length(joints) - 1 do
  220. if joints[i] <> nil then
  221. NewtonDestroyJoint(newtonworld, joints[i]);
  222. SetLength(joints, 0);
  223. for i := 0 to bodies.Count - 1 do
  224. NewtonDestroyBody(newtonworld, bodies[i]);
  225. bodies.Clear;
  226. FreeAndNil(bodies);
  227. end;
  228. destructor TNewtonRagdoll.Destroy;
  229. begin
  230. Clean;
  231. SetLength(envelopes, 0);
  232. SetLength(norm_matrices, 0);
  233. inherited Destroy;
  234. end;
  235. procedure TNewtonRagdoll.SetEnabled;
  236. var
  237. i: integer;
  238. a: TMatrix4f;
  239. v: TVector3f;
  240. begin
  241. if FEnabled = value then
  242. Exit;
  243. FEnabled := value;
  244. if value = true then
  245. begin
  246. actor.Skeleton.StartRagdoll;
  247. for i := 0 to Length(envelopes) - 1 do
  248. norm_matrices[i] := envelopes[i].Mat;
  249. Exit;
  250. end;
  251. actor.Skeleton.StopRagdoll;
  252. for i := 0 to Length(envelopes) - 1 do
  253. begin
  254. v := NullVector;
  255. NewtonBodySetVelocity(bodies[i], @v);
  256. NewtonBodySetOmega(bodies[i], @v);
  257. NewtonBodySetForce(bodies[i], @v);
  258. NewtonBodySetTorque(bodies[i], @v);
  259. envelopes[i].Mat := norm_matrices[i];
  260. a := envelopes[i].Mat;
  261. NewtonBodySetMatrix(bodies[i], @a);
  262. NewtonBodySetCollision(bodies[i], nil);
  263. actor.Skeleton.BoneByID(i).SetGlobalMatrixForRagDoll(a);
  264. end;
  265. actor.Skeleton.MorphMesh(true);
  266. end;
  267. procedure TNewtonRagdoll.SetSlideLimit;
  268. begin
  269. FSlideLimit := value;
  270. end;
  271. procedure TNewtonRagdoll.SetAngleLimit;
  272. begin
  273. FAngleLimit := value;
  274. end;
  275. procedure TNewtonRagdoll.SetERP;
  276. var
  277. i: integer;
  278. begin
  279. FERP := value;
  280. end;
  281. procedure TNewtonRagdoll.LoadFromFile;
  282. var
  283. i: integer;
  284. s, a, e: single;
  285. F: TFileStream;
  286. begin
  287. F := TFileStream.Create(filename, fmOpenRead);
  288. F.Read(i, SizeOf(i));
  289. SetLength(envelopes, i);
  290. F.Read(s, SizeOf(s));
  291. F.Read(e, SizeOf(e));
  292. F.Read(a, SizeOf(a));
  293. Clean;
  294. for i := 0 to Length(envelopes) - 1 do
  295. begin
  296. F.Read(envelopes[i].kind, SizeOf(envelopes[i].kind));
  297. F.Read(envelopes[i].w, SizeOf(envelopes[i].w));
  298. F.Read(envelopes[i].h, SizeOf(envelopes[i].h));
  299. F.Read(envelopes[i].d, SizeOf(envelopes[i].d));
  300. F.Read(envelopes[i].mass, SizeOf(envelopes[i].mass));
  301. F.Read(envelopes[i].pt, SizeOf(envelopes[i].pt));
  302. end;
  303. /// Create(actor, newtonworld, 0.8, s, e, a, false);
  304. F.Free;
  305. end;
  306. procedure TNewtonRagdoll.SaveToFile;
  307. var
  308. i: integer;
  309. F: TFileStream;
  310. begin
  311. if FileExists(filename) then
  312. F := TFileStream.Create(filename, fmOpenWrite)
  313. else
  314. F := TFileStream.Create(filename, fmCreate);
  315. i := Length(envelopes);
  316. F.Write(i, SizeOf(i));
  317. F.Write(FSlideLimit, SizeOf(FSlideLimit));
  318. F.Write(FERP, SizeOf(FERP));
  319. F.Write(FAngleLimit, SizeOf(FAngleLimit));
  320. for i := 0 to Length(envelopes) - 1 do
  321. begin
  322. F.Write(envelopes[i].kind, SizeOf(envelopes[i].kind));
  323. F.Write(envelopes[i].w, SizeOf(envelopes[i].w));
  324. F.Write(envelopes[i].h, SizeOf(envelopes[i].h));
  325. F.Write(envelopes[i].d, SizeOf(envelopes[i].d));
  326. F.Write(envelopes[i].mass, SizeOf(envelopes[i].mass));
  327. F.Write(envelopes[i].pt, SizeOf(envelopes[i].pt));
  328. end;
  329. F.Free;
  330. end;
  331. end.