2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Base abstract ragdoll class. Should be extended to use any physics system.
8
10/11/12 - PW - Added CPP compatibility: changed vector arrays to arrays of records
9
23/08/10 - Yar - Added GLVectorTypes to uses
10
09/11/05 - LucasG - Fixed joint and few small things
11
07/11/05 - LucasG - Fixed bone position and rotation (Align to animation)
12
02/11/05 - LucasG - First version created.
21
GLScene, GLPersistentClasses, GLVectorGeometry, GLVectorFileObjects,
22
GLVectorLists, GLObjects;
26
TGLRagdolBone = class;
28
TGLRagdolJoint = class
31
TGLRagdolBoneList = class (TPersistentObjectList)
34
FRagdoll : TGLRagdoll;
37
function GetRagdollBone(Index: Integer) : TGLRagdolBone;
40
constructor Create(Ragdoll: TGLRagdoll); reintroduce;
41
destructor Destroy; override;
43
procedure WriteToFiler(writer : TVirtualWriter); override;
44
procedure ReadFromFiler(reader : TVirtualReader); override;
46
property Ragdoll : TGLRagdoll read FRagdoll;
47
property Items[Index: Integer] : TGLRagdolBone read GetRagdollBone; default;
50
TGLRagdolBone = class (TGLRagdolBoneList)
53
FOwner : TGLRagdolBoneList;
55
FBoneID : Integer; //Refering to TGLActor Bone
56
FBoundMax: TAffineVector;
57
FBoundMin: TAffineVector;
58
FBoundBoneDelta: TAffineVector; //Stores the diference from the bone.GlobalMatrix to the center of the bone's bounding box
59
FOrigin: TAffineVector;
62
FJoint: TGLRagdolJoint;
63
FOriginalMatrix: TMatrix; //Stores the Bone.GlobalMatrix before the ragdoll start
64
FReferenceMatrix: TMatrix; //Stores the first bone matrix to be used as reference
65
FAnchor: TAffineVector; //The position of the joint
66
procedure CreateBoundingBox;
67
procedure SetAnchor(Anchor: TAffineVector);
68
procedure AlignToSkeleton;
69
procedure CreateBoundsChild;
72
procedure UpdateChild;
76
function GetRagdollBone(Index: Integer) : TGLRagdolBone;
77
procedure Start; virtual; abstract;
78
procedure Align; virtual; abstract;
79
procedure Update; virtual; abstract;
80
procedure Stop; virtual; abstract;
83
constructor CreateOwned(aOwner : TGLRagdolBoneList);
84
constructor Create(Ragdoll: TGLRagdoll);
85
destructor Destroy; override;
87
procedure WriteToFiler(writer : TVirtualWriter); override;
88
procedure ReadFromFiler(reader : TVirtualReader); override;
90
property Owner : TGLRagdolBoneList read FOwner;
91
property Name : String read FName write FName;
92
property BoneID : Integer read FBoneID write FBoneID;
93
property Origin : TAffineVector read FOrigin;
94
property Size : TAffineVector read FSize;
95
property BoneMatrix : TMatrix read FBoneMatrix;
96
property ReferenceMatrix : TMatrix read FReferenceMatrix;
97
property Anchor : TAffineVector read FAnchor;
98
property Joint : TGLRagdolJoint read FJoint write FJoint;
99
property Items[Index: Integer] : TGLRagdolBone read GetRagdollBone; default;
102
TGLRagdoll = class(TPersistentObject)
105
FOwner : TGLBaseMesh;
106
FRootBone : TGLRagdolBone;
113
constructor Create(AOwner : TGLBaseMesh); reintroduce;
114
destructor Destroy; override;
116
procedure WriteToFiler(writer : TVirtualWriter); override;
117
procedure ReadFromFiler(reader : TVirtualReader); override;
119
{ Must be set before build the ragdoll }
120
procedure SetRootBone(RootBone: TGLRagdolBone);
121
{ Create the bounding box and setup the ragdoll do be started later }
122
procedure BuildRagdoll;
128
property Owner : TGLBaseMesh read FOwner;
129
property RootBone : TGLRagdolBone read FRootBone;
130
property Enabled : Boolean read FEnabled;
140
constructor TGLRagdolBoneList.Create(Ragdoll: TGLRagdoll);
146
destructor TGLRagdolBoneList.Destroy;
149
for i:=0 to Count-1 do Items[i].Destroy;
153
function TGLRagdolBoneList.GetRagdollBone(Index: Integer): TGLRagdolBone;
155
Result:=TGLRagdolBone(List^[Index]);
158
procedure TGLRagdolBoneList.ReadFromFiler(reader: TVirtualReader);
164
procedure TGLRagdolBoneList.WriteToFiler(writer: TVirtualWriter);
172
constructor TGLRagdolBone.Create(Ragdoll: TGLRagdoll);
174
inherited Create(Ragdoll);
177
procedure TGLRagdolBone.CreateBoundingBox;
179
bone: TGLSkeletonBone;
181
BoneVertices : TAffineVectorList;
182
BoneVertex, max,min: TAffineVector;
183
invMat, mat: TMatrix;
185
bone := Ragdoll.Owner.Skeleton.BoneByID(FBoneID);
187
//Get all vertices weighted to this bone
188
BoneVertices:=TAffineVectorList.Create;
189
for i:=0 to Ragdoll.Owner.MeshObjects.Count-1 do
190
with TGLSkeletonMeshObject(Ragdoll.Owner.MeshObjects[i]) do
191
for j:=0 to Vertices.Count-1 do
192
if bone.BoneID = VerticesBonesWeights[j][0].BoneID then
193
BoneVertices.FindOrAdd(Vertices[j]);
195
invMat := bone.GlobalMatrix;
196
InvertMatrix(invMat);
198
//For each vertex, get the max and min XYZ (Bounding box)
199
if BoneVertices.Count > 0 then
201
BoneVertex := VectorTransform(BoneVertices[0], invMat);
204
for i:=1 to BoneVertices.Count-1 do begin
205
BoneVertex := VectorTransform(BoneVertices[i], invMat);
206
if (BoneVertex.V[0] > max.V[0]) then max.V[0] := BoneVertex.V[0];
207
if (BoneVertex.V[1] > max.V[1]) then max.V[1] := BoneVertex.V[1];
208
if (BoneVertex.V[2] > max.V[2]) then max.V[2] := BoneVertex.V[2];
210
if (BoneVertex.V[0] < min.V[0]) then min.V[0] := BoneVertex.V[0];
211
if (BoneVertex.V[1] < min.V[1]) then min.V[1] := BoneVertex.V[1];
212
if (BoneVertex.V[2] < min.V[2]) then min.V[2] := BoneVertex.V[2];
217
//Get the origin and subtract from the bone matrix
218
FBoundBoneDelta := VectorScale(VectorAdd(FBoundMax, FBoundMin), 0.5);
220
FBoundMax := NullVector;
221
FBoundMin := NullVector;
225
FReferenceMatrix := FBoneMatrix;
226
mat := MatrixMultiply(bone.GlobalMatrix,FRagdoll.Owner.AbsoluteMatrix);
228
SetAnchor(AffineVectorMake(mat.V[3]));
230
BoneVertices.Free; // NEW1
233
constructor TGLRagdolBone.CreateOwned(aOwner: TGLRagdolBoneList);
235
Create(aOwner.Ragdoll);
240
destructor TGLRagdolBone.Destroy;
245
procedure TGLRagdolBone.AlignToSkeleton;
248
bone: TGLSkeletonBone;
249
mat, posMat: TMatrix;
252
bone := Ragdoll.Owner.Skeleton.BoneByID(FBoneID);
253
noBounds := VectorIsNull(FBoundMax) and VectorIsNull(FBoundMin);
254
//Get the bone matrix relative to the Actor matrix
255
mat := MatrixMultiply(bone.GlobalMatrix,FRagdoll.Owner.AbsoluteMatrix);
258
NormalizeMatrix(FBoneMatrix);
262
FOrigin := AffineVectorMake(mat.V[3]);
263
FSize := AffineVectorMake(0.1,0.1,0.1);
267
posMat.V[3] := NullHmgVector;
268
o := VectorTransform(FBoundBoneDelta, posMat);
269
FOrigin := VectorAdd(AffineVectorMake(mat.V[3]), o);
271
FSize := VectorScale(VectorSubtract(FBoundMax, FBoundMin),0.9);
272
FSize.V[0] := FSize.V[0]*VectorLength(mat.V[0]);
273
FSize.V[1] := FSize.V[1]*VectorLength(mat.V[1]);
274
FSize.V[2] := FSize.V[2]*VectorLength(mat.V[2]);
276
//Put the origin in the BoneMatrix
277
FBoneMatrix.V[3] := VectorMake(FOrigin,1);
280
function TGLRagdolBone.GetRagdollBone(Index: Integer): TGLRagdolBone;
282
Result:=TGLRagdolBone(List^[Index]);
285
procedure TGLRagdolBone.ReadFromFiler(reader: TVirtualReader);
291
procedure TGLRagdolBone.StartChild;
294
FOriginalMatrix := Ragdoll.Owner.Skeleton.BoneByID(FBoneID).GlobalMatrix;
297
for i := 0 to Count-1 do items[i].StartChild;
300
procedure TGLRagdolBone.UpdateChild;
304
for i := 0 to Count-1 do items[i].UpdateChild;
307
procedure TGLRagdolBone.WriteToFiler(writer: TVirtualWriter);
313
procedure TGLRagdolBone.StopChild;
317
Ragdoll.Owner.Skeleton.BoneByID(FBoneID).SetGlobalMatrix(FOriginalMatrix);
318
for i := 0 to Count-1 do items[i].StopChild;
321
procedure TGLRagdolBone.CreateBoundsChild;
325
for i := 0 to Count-1 do items[i].CreateBoundsChild;
328
procedure TGLRagdolBone.SetAnchor(Anchor: TAffineVector);
333
procedure TGLRagdolBone.AlignChild;
338
for i := 0 to Count-1 do items[i].AlignChild;
343
constructor TGLRagdoll.Create(AOwner : TGLBaseMesh);
350
destructor TGLRagdoll.Destroy;
352
if FEnabled then Stop;
356
procedure TGLRagdoll.ReadFromFiler(reader: TVirtualReader);
361
procedure TGLRagdoll.SetRootBone(RootBone: TGLRagdolBone);
363
FRootBone := RootBone;
366
procedure TGLRagdoll.Start;
368
Assert(FBuilt, 'First you need to build the ragdoll. BuildRagdoll;');
369
if (FEnabled) then Exit;
371
//First start the ragdoll in the reference position
373
//Now align it to the animation
375
//Now it recalculate the vertices to use as reference
376
FOwner.Skeleton.StartRagDoll;
379
procedure TGLRagdoll.Update;
383
RootBone.UpdateChild;
384
FOwner.Skeleton.MorphMesh(true);
388
procedure TGLRagdoll.Stop;
390
if not FEnabled then Exit;
393
//Restore the old information
394
FOwner.Skeleton.StopRagDoll;
395
FOwner.Skeleton.MorphMesh(true);
398
procedure TGLRagdoll.WriteToFiler(writer: TVirtualWriter);
404
procedure TGLRagdoll.BuildRagdoll;
406
Assert(RootBone <> nil, 'First you need to set the root bone. SetRootBone();');
407
RootBone.CreateBoundsChild;