GLRagdoll.pas 10 KB

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