GXS.Ragdoll.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.Ragdoll;
  5. (* Base abstract ragdoll class. Should be extended to use any physics system *)
  6. interface
  7. uses
  8. Stage.VectorTypes,
  9. GXS.PersistentClasses,
  10. Stage.VectorGeometry,
  11. GXS.VectorLists,
  12. GXS.Scene,
  13. GXS.Objects,
  14. GXS.VectorFileObjects;
  15. type
  16. TgxRagdoll = class;
  17. TgxRagdolBone = class;
  18. TgxRagdolJoint = class
  19. end;
  20. TgxRagdolBoneList = class (TgxPersistentObjectList)
  21. private
  22. FRagdoll : TgxRagdoll;
  23. protected
  24. function GetRagdollBone(Index: Integer) : TgxRagdolBone;
  25. public
  26. constructor Create(Ragdoll: TgxRagdoll); reintroduce;
  27. destructor Destroy; override;
  28. procedure WriteToFiler(writer : TgxVirtualWriter); override;
  29. procedure ReadFromFiler(reader : TgxVirtualReader); override;
  30. property Ragdoll : TgxRagdoll read FRagdoll;
  31. property Items[Index: Integer] : TgxRagdolBone read GetRagdollBone; default;
  32. end;
  33. TgxRagdolBone = class (TgxRagdolBoneList)
  34. private
  35. FOwner : TgxRagdolBoneList;
  36. FName : String;
  37. FBoneID : Integer; //Refering to TgxActor Bone
  38. FBoundMax: TAffineVector;
  39. FBoundMin: TAffineVector;
  40. FBoundBoneDelta: TAffineVector; //Stores the diference from the bone.GlobalMatrix to the center of the bone's bounding box
  41. FOrigin: TAffineVector;
  42. FSize: TAffineVector;
  43. FBoneMatrix: TMatrix4f;
  44. FJoint: TgxRagdolJoint;
  45. FOriginalMatrix: TMatrix4f; //Stores the Bone.GlobalMatrix before the ragdoll start
  46. FReferenceMatrix: TMatrix4f; //Stores the first bone matrix to be used as reference
  47. FAnchor: TAffineVector; //The position of the joint
  48. procedure CreateBoundingBox;
  49. procedure SetAnchor(Anchor: TAffineVector);
  50. procedure AlignToSkeleton;
  51. procedure CreateBoundsChild;
  52. procedure StartChild;
  53. procedure AlignChild;
  54. procedure UpdateChild;
  55. procedure StopChild;
  56. protected
  57. function GetRagdollBone(Index: Integer) : TgxRagdolBone;
  58. procedure Start; virtual; abstract;
  59. procedure Align; virtual; abstract;
  60. procedure Update; virtual; abstract;
  61. procedure Stop; virtual; abstract;
  62. public
  63. constructor CreateOwned(aOwner : TgxRagdolBoneList);
  64. constructor Create(Ragdoll: TgxRagdoll);
  65. destructor Destroy; override;
  66. procedure WriteToFiler(writer : TgxVirtualWriter); override;
  67. procedure ReadFromFiler(reader : TgxVirtualReader); override;
  68. property Owner : TgxRagdolBoneList read FOwner;
  69. property Name : String read FName write FName;
  70. property BoneID : Integer read FBoneID write FBoneID;
  71. property Origin : TAffineVector read FOrigin;
  72. property Size : TAffineVector read FSize;
  73. property BoneMatrix : TMatrix4f read FBoneMatrix;
  74. property ReferenceMatrix : TMatrix4f read FReferenceMatrix;
  75. property Anchor : TAffineVector read FAnchor;
  76. property Joint : TgxRagdolJoint read FJoint write FJoint;
  77. property Items[Index: Integer] : TgxRagdolBone read GetRagdollBone; default;
  78. end;
  79. TgxRagdoll = class(TgxPersistentObject)
  80. private
  81. FOwner : TgxBaseMesh;
  82. FRootBone : TgxRagdolBone;
  83. FEnabled: Boolean;
  84. FBuilt: Boolean;
  85. public
  86. constructor Create(AOwner : TgxBaseMesh); reintroduce;
  87. destructor Destroy; override;
  88. procedure WriteToFiler(writer : TgxVirtualWriter); override;
  89. procedure ReadFromFiler(reader : TgxVirtualReader); override;
  90. // Must be set before build the ragdoll
  91. procedure SetRootBone(RootBone: TgxRagdolBone);
  92. // Create the bounding box and setup the ragdoll do be started later
  93. procedure BuildRagdoll;
  94. procedure Start;
  95. procedure Update;
  96. procedure Stop;
  97. property Owner : TgxBaseMesh read FOwner;
  98. property RootBone : TgxRagdolBone read FRootBone;
  99. property Enabled : Boolean read FEnabled;
  100. end;
  101. implementation //-------------------------------------------------------------
  102. //--------------------------------
  103. // TgxRagdolBoneList
  104. //--------------------------------
  105. constructor TgxRagdolBoneList.Create(Ragdoll: TgxRagdoll);
  106. begin
  107. inherited Create;
  108. FRagdoll := Ragdoll;
  109. end;
  110. destructor TgxRagdolBoneList.Destroy;
  111. var i: integer;
  112. begin
  113. for i:=0 to Count-1 do Items[i].Destroy;
  114. inherited;
  115. end;
  116. function TgxRagdolBoneList.GetRagdollBone(Index: Integer): TgxRagdolBone;
  117. begin
  118. Result:=TgxRagdolBone(List^[Index]);
  119. end;
  120. procedure TgxRagdolBoneList.ReadFromFiler(reader: TgxVirtualReader);
  121. begin
  122. inherited;
  123. //Not implemented
  124. end;
  125. procedure TgxRagdolBoneList.WriteToFiler(writer: TgxVirtualWriter);
  126. begin
  127. inherited;
  128. //Not implemented
  129. end;
  130. { TgxRagdolBone }
  131. constructor TgxRagdolBone.Create(Ragdoll: TgxRagdoll);
  132. begin
  133. inherited Create(Ragdoll);
  134. end;
  135. procedure TgxRagdolBone.CreateBoundingBox;
  136. var
  137. bone: TgxSkeletonBone;
  138. i, j: integer;
  139. BoneVertices : TgxAffineVectorList;
  140. BoneVertex, max,min: TAffineVector;
  141. invMat, mat: TMatrix4f;
  142. begin
  143. bone := Ragdoll.Owner.Skeleton.BoneByID(FBoneID);
  144. //Get all vertices weighted to this bone
  145. BoneVertices:=TgxAffineVectorList.Create;
  146. for i:=0 to Ragdoll.Owner.MeshObjects.Count-1 do
  147. with TgxSkeletonMeshObject(Ragdoll.Owner.MeshObjects[i]) do
  148. for j:=0 to Vertices.Count-1 do
  149. if bone.BoneID = VerticesBonesWeights[j][0].BoneID then
  150. BoneVertices.FindOrAdd(Vertices[j]);
  151. invMat := bone.GlobalMatrix;
  152. InvertMatrix(invMat);
  153. //For each vertex, get the max and min XYZ (Bounding box)
  154. if BoneVertices.Count > 0 then
  155. begin
  156. BoneVertex := VectorTransform(BoneVertices[0], invMat);
  157. max := BoneVertex;
  158. min := BoneVertex;
  159. for i:=1 to BoneVertices.Count-1 do begin
  160. BoneVertex := VectorTransform(BoneVertices[i], invMat);
  161. if (BoneVertex.X > max.X) then max.X := BoneVertex.X;
  162. if (BoneVertex.Y > max.Y) then max.Y := BoneVertex.Y;
  163. if (BoneVertex.Z > max.Z) then max.Z := BoneVertex.Z;
  164. if (BoneVertex.X < min.X) then min.X := BoneVertex.X;
  165. if (BoneVertex.Y < min.Y) then min.Y := BoneVertex.Y;
  166. if (BoneVertex.Z < min.Z) then min.Z := BoneVertex.Z;
  167. end;
  168. FBoundMax := max;
  169. FBoundMin := min;
  170. //Get the origin and subtract from the bone matrix
  171. FBoundBoneDelta := VectorScale(VectorAdd(FBoundMax, FBoundMin), 0.5);
  172. end else begin
  173. FBoundMax := NullVector;
  174. FBoundMin := NullVector;
  175. end;
  176. AlignToSkeleton;
  177. FReferenceMatrix := FBoneMatrix;
  178. mat := MatrixMultiply(bone.GlobalMatrix,FRagdoll.Owner.AbsoluteMatrix);
  179. //Set Joint position
  180. SetAnchor(AffineVectorMake(mat.W));
  181. BoneVertices.Free; // NEW1
  182. end;
  183. constructor TgxRagdolBone.CreateOwned(aOwner: TgxRagdolBoneList);
  184. begin
  185. Create(aOwner.Ragdoll);
  186. FOwner:=aOwner;
  187. aOwner.Add(Self);
  188. end;
  189. destructor TgxRagdolBone.Destroy;
  190. begin
  191. inherited;
  192. end;
  193. procedure TgxRagdolBone.AlignToSkeleton;
  194. var
  195. o: TAffineVector;
  196. bone: TgxSkeletonBone;
  197. mat, posMat: TMatrix4f;
  198. noBounds: Boolean;
  199. begin
  200. bone := Ragdoll.Owner.Skeleton.BoneByID(FBoneID);
  201. noBounds := VectorIsNull(FBoundMax) and VectorIsNull(FBoundMin);
  202. //Get the bone matrix relative to the Actor matrix
  203. mat := MatrixMultiply(bone.GlobalMatrix,FRagdoll.Owner.AbsoluteMatrix);
  204. //Set Rotation
  205. FBoneMatrix := mat;
  206. NormalizeMatrix(FBoneMatrix);
  207. if (noBounds) then
  208. begin
  209. FOrigin := AffineVectorMake(mat.W);
  210. FSize := AffineVectorMake(0.1,0.1,0.1);
  211. end else begin
  212. //Set Origin
  213. posMat := mat;
  214. posMat.W := NullHmgVector;
  215. o := VectorTransform(FBoundBoneDelta, posMat);
  216. FOrigin := VectorAdd(AffineVectorMake(mat.W), o);
  217. //Set Size
  218. FSize := VectorScale(VectorSubtract(FBoundMax, FBoundMin),0.9);
  219. FSize.X := FSize.X*VectorLength(mat.X);
  220. FSize.Y := FSize.Y*VectorLength(mat.Y);
  221. FSize.Z := FSize.Z*VectorLength(mat.Z);
  222. end;
  223. //Put the origin in the BoneMatrix
  224. FBoneMatrix.W := VectorMake(FOrigin,1);
  225. end;
  226. function TgxRagdolBone.GetRagdollBone(Index: Integer): TgxRagdolBone;
  227. begin
  228. Result:=TgxRagdolBone(List^[Index]);
  229. end;
  230. procedure TgxRagdolBone.ReadFromFiler(reader: TgxVirtualReader);
  231. begin
  232. inherited;
  233. end;
  234. procedure TgxRagdolBone.StartChild;
  235. var i: integer;
  236. begin
  237. FOriginalMatrix := Ragdoll.Owner.Skeleton.BoneByID(FBoneID).GlobalMatrix;
  238. AlignToSkeleton;
  239. Start;
  240. for i := 0 to Count-1 do items[i].StartChild;
  241. end;
  242. procedure TgxRagdolBone.UpdateChild;
  243. var i: integer;
  244. begin
  245. Update;
  246. for i := 0 to Count-1 do items[i].UpdateChild;
  247. end;
  248. procedure TgxRagdolBone.WriteToFiler(writer: TgxVirtualWriter);
  249. begin
  250. inherited;
  251. end;
  252. procedure TgxRagdolBone.StopChild;
  253. var i: integer;
  254. begin
  255. Stop;
  256. Ragdoll.Owner.Skeleton.BoneByID(FBoneID).SetGlobalMatrix(FOriginalMatrix);
  257. for i := 0 to Count-1 do items[i].StopChild;
  258. end;
  259. procedure TgxRagdolBone.CreateBoundsChild;
  260. var i: integer;
  261. begin
  262. CreateBoundingBox;
  263. for i := 0 to Count-1 do items[i].CreateBoundsChild;
  264. end;
  265. procedure TgxRagdolBone.SetAnchor(Anchor: TAffineVector);
  266. begin
  267. FAnchor := Anchor;
  268. end;
  269. procedure TgxRagdolBone.AlignChild;
  270. var i: integer;
  271. begin
  272. Align;
  273. Update;
  274. for i := 0 to Count-1 do items[i].AlignChild;
  275. end;
  276. { TgxRagdoll }
  277. constructor TgxRagdoll.Create(AOwner : TgxBaseMesh);
  278. begin
  279. FOwner := AOwner;
  280. FEnabled := False;
  281. FBuilt := False;
  282. end;
  283. destructor TgxRagdoll.Destroy;
  284. begin
  285. if FEnabled then Stop;
  286. inherited Destroy;
  287. end;
  288. procedure TgxRagdoll.ReadFromFiler(reader: TgxVirtualReader);
  289. begin
  290. inherited;
  291. end;
  292. procedure TgxRagdoll.SetRootBone(RootBone: TgxRagdolBone);
  293. begin
  294. FRootBone := RootBone;
  295. end;
  296. procedure TgxRagdoll.Start;
  297. begin
  298. Assert(FBuilt, 'First you need to build the ragdoll. BuildRagdoll;');
  299. if (FEnabled) then Exit;
  300. FEnabled:= True;
  301. //First start the ragdoll in the reference position
  302. RootBone.StartChild;
  303. //Now align it to the animation
  304. RootBone.AlignChild;
  305. //Now it recalculate the vertices to use as reference
  306. FOwner.Skeleton.StartRagDoll;
  307. end;
  308. procedure TgxRagdoll.Update;
  309. begin
  310. if FEnabled then
  311. begin
  312. RootBone.UpdateChild;
  313. FOwner.Skeleton.MorphMesh(true);
  314. end;
  315. end;
  316. procedure TgxRagdoll.Stop;
  317. begin
  318. if not FEnabled then Exit;
  319. FEnabled := False;
  320. RootBone.StopChild;
  321. //Restore the old information
  322. FOwner.Skeleton.StopRagDoll;
  323. FOwner.Skeleton.MorphMesh(true);
  324. end;
  325. procedure TgxRagdoll.WriteToFiler(writer: TgxVirtualWriter);
  326. begin
  327. inherited;
  328. end;
  329. procedure TgxRagdoll.BuildRagdoll;
  330. begin
  331. Assert(RootBone <> nil, 'First you need to set the root bone. SetRootBone();');
  332. RootBone.CreateBoundsChild;
  333. FBuilt := True;
  334. end;
  335. //-----------------------------------------------------------------------
  336. end.