LZScene

Форк
0
/
GLRagdoll.pas 
411 строк · 10.8 Кб
1
//
2
// This unit is part of the GLScene Engine https://github.com/glscene
3
//
4
{
5
    Base abstract ragdoll class. Should be extended to use any physics system. 
6

7
	 History : 
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.
13
   
14
}
15

16
unit GLRagdoll;
17

18
interface
19

20
uses
21
  GLScene, GLPersistentClasses, GLVectorGeometry, GLVectorFileObjects,
22
  GLVectorLists, GLObjects;
23

24
type
25
  TGLRagdoll = class;
26
  TGLRagdolBone = class;
27

28
  TGLRagdolJoint = class
29
  end;
30

31
  TGLRagdolBoneList = class (TPersistentObjectList)
32
  private
33
     
34
     FRagdoll : TGLRagdoll;
35
  protected
36
     
37
    function GetRagdollBone(Index: Integer) : TGLRagdolBone;
38
  public
39
     
40
    constructor Create(Ragdoll: TGLRagdoll); reintroduce;
41
    destructor Destroy; override;
42

43
    procedure WriteToFiler(writer : TVirtualWriter); override;
44
    procedure ReadFromFiler(reader : TVirtualReader); override;
45

46
    property Ragdoll : TGLRagdoll read FRagdoll;
47
    property Items[Index: Integer] : TGLRagdolBone read GetRagdollBone; default;
48
	end;
49

50
	TGLRagdolBone = class (TGLRagdolBoneList)
51
  private
52
     
53
    FOwner : TGLRagdolBoneList;
54
    FName : String;
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;
60
    FSize: TAffineVector;
61
    FBoneMatrix: TMatrix;
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;
70
    procedure StartChild;
71
    procedure AlignChild;
72
    procedure UpdateChild;
73
    procedure StopChild;
74
  protected
75
     
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;
81
  public
82
     
83
    constructor CreateOwned(aOwner : TGLRagdolBoneList);
84
    constructor Create(Ragdoll: TGLRagdoll);
85
    destructor Destroy; override;
86

87
    procedure WriteToFiler(writer : TVirtualWriter); override;
88
    procedure ReadFromFiler(reader : TVirtualReader); override;
89

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;
100
	end;
101

102
  TGLRagdoll = class(TPersistentObject)
103
	private
104
     
105
    FOwner : TGLBaseMesh;
106
    FRootBone : TGLRagdolBone;
107
    FEnabled: Boolean;
108
    FBuilt: Boolean;
109
  protected
110
     
111
  public
112
     
113
    constructor Create(AOwner : TGLBaseMesh); reintroduce;
114
    destructor Destroy; override;
115

116
    procedure WriteToFiler(writer : TVirtualWriter); override;
117
    procedure ReadFromFiler(reader : TVirtualReader); override;
118

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;
123

124
    procedure Start;
125
    procedure Update;
126
    procedure Stop;
127

128
    property Owner : TGLBaseMesh read FOwner;
129
    property RootBone : TGLRagdolBone read FRootBone;
130
    property Enabled : Boolean read FEnabled;
131
	end;
132

133
implementation
134

135
uses
136
  GLVectorTypes;
137

138
{ TGLRagdolBoneList }
139

140
constructor TGLRagdolBoneList.Create(Ragdoll: TGLRagdoll);
141
begin
142
  inherited Create;
143
  FRagdoll := Ragdoll;
144
end;
145

146
destructor TGLRagdolBoneList.Destroy;
147
var i: integer;
148
begin
149
  for i:=0 to Count-1 do Items[i].Destroy;
150
  inherited;
151
end;
152

153
function TGLRagdolBoneList.GetRagdollBone(Index: Integer): TGLRagdolBone;
154
begin
155
  Result:=TGLRagdolBone(List^[Index]);
156
end;
157

158
procedure TGLRagdolBoneList.ReadFromFiler(reader: TVirtualReader);
159
begin
160
  inherited;
161
  //Not implemented
162
end;
163

164
procedure TGLRagdolBoneList.WriteToFiler(writer: TVirtualWriter);
165
begin
166
  inherited;
167
  //Not implemented
168
end;
169

170
{ TGLRagdolBone }
171

172
constructor TGLRagdolBone.Create(Ragdoll: TGLRagdoll);
173
begin
174
  inherited Create(Ragdoll);
175
end;
176

177
procedure TGLRagdolBone.CreateBoundingBox;
178
var
179
  bone: TGLSkeletonBone;
180
  i, j: integer;
181
  BoneVertices : TAffineVectorList;
182
  BoneVertex, max,min: TAffineVector;
183
  invMat, mat: TMatrix;
184
begin
185
  bone := Ragdoll.Owner.Skeleton.BoneByID(FBoneID);
186

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]);
194

195
  invMat := bone.GlobalMatrix;
196
  InvertMatrix(invMat);
197

198
  //For each vertex, get the max and min XYZ (Bounding box)
199
  if BoneVertices.Count > 0 then
200
  begin
201
    BoneVertex := VectorTransform(BoneVertices[0], invMat);
202
    max := BoneVertex;
203
    min := BoneVertex;
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];
209

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];
213
    end;
214

215
    FBoundMax := max;
216
    FBoundMin := min;
217
    //Get the origin and subtract from the bone matrix
218
    FBoundBoneDelta := VectorScale(VectorAdd(FBoundMax, FBoundMin), 0.5);
219
  end else begin
220
    FBoundMax := NullVector;
221
    FBoundMin := NullVector;
222
  end;
223

224
  AlignToSkeleton;
225
  FReferenceMatrix := FBoneMatrix;
226
  mat := MatrixMultiply(bone.GlobalMatrix,FRagdoll.Owner.AbsoluteMatrix);
227
  //Set Joint position
228
  SetAnchor(AffineVectorMake(mat.V[3]));
229

230
  BoneVertices.Free; // NEW1
231
end;
232

233
constructor TGLRagdolBone.CreateOwned(aOwner: TGLRagdolBoneList);
234
begin
235
	Create(aOwner.Ragdoll);
236
  FOwner:=aOwner;
237
  aOwner.Add(Self);
238
end;
239

240
destructor TGLRagdolBone.Destroy;
241
begin
242
  inherited;
243
end;
244

245
procedure TGLRagdolBone.AlignToSkeleton;
246
var
247
  o: TAffineVector;
248
  bone: TGLSkeletonBone;
249
  mat, posMat: TMatrix;
250
  noBounds: Boolean;
251
begin
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);
256
  //Set Rotation
257
  FBoneMatrix := mat;
258
  NormalizeMatrix(FBoneMatrix);
259

260
  if (noBounds) then
261
  begin
262
    FOrigin := AffineVectorMake(mat.V[3]);
263
    FSize := AffineVectorMake(0.1,0.1,0.1);
264
  end else begin
265
    //Set Origin
266
    posMat := mat;
267
    posMat.V[3] := NullHmgVector;
268
    o := VectorTransform(FBoundBoneDelta, posMat);
269
    FOrigin := VectorAdd(AffineVectorMake(mat.V[3]), o);
270
    //Set Size
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]);
275
  end;
276
  //Put the origin in the BoneMatrix
277
  FBoneMatrix.V[3] := VectorMake(FOrigin,1);
278
end;
279

280
function TGLRagdolBone.GetRagdollBone(Index: Integer): TGLRagdolBone;
281
begin
282
  Result:=TGLRagdolBone(List^[Index]);
283
end;
284

285
procedure TGLRagdolBone.ReadFromFiler(reader: TVirtualReader);
286
begin
287
  inherited;
288

289
end;
290

291
procedure TGLRagdolBone.StartChild;
292
var i: integer;
293
begin
294
  FOriginalMatrix := Ragdoll.Owner.Skeleton.BoneByID(FBoneID).GlobalMatrix;
295
  AlignToSkeleton;
296
  Start;
297
  for i := 0 to Count-1 do items[i].StartChild;
298
end;
299

300
procedure TGLRagdolBone.UpdateChild;
301
var i: integer;
302
begin
303
  Update;
304
  for i := 0 to Count-1 do items[i].UpdateChild;
305
end;
306

307
procedure TGLRagdolBone.WriteToFiler(writer: TVirtualWriter);
308
begin
309
  inherited;
310

311
end;
312

313
procedure TGLRagdolBone.StopChild;
314
var i: integer;
315
begin
316
  Stop;
317
  Ragdoll.Owner.Skeleton.BoneByID(FBoneID).SetGlobalMatrix(FOriginalMatrix);
318
  for i := 0 to Count-1 do items[i].StopChild;
319
end;
320

321
procedure TGLRagdolBone.CreateBoundsChild;
322
var i: integer;
323
begin
324
  CreateBoundingBox;
325
  for i := 0 to Count-1 do items[i].CreateBoundsChild;
326
end;
327

328
procedure TGLRagdolBone.SetAnchor(Anchor: TAffineVector);
329
begin
330
  FAnchor := Anchor;
331
end;
332

333
procedure TGLRagdolBone.AlignChild;
334
var i: integer;
335
begin
336
  Align;
337
  Update;
338
  for i := 0 to Count-1 do items[i].AlignChild;
339
end;
340

341
{ TGLRagdoll }
342

343
constructor TGLRagdoll.Create(AOwner : TGLBaseMesh);
344
begin
345
  FOwner := AOwner;
346
  FEnabled := False;
347
  FBuilt := False;
348
end;
349

350
destructor TGLRagdoll.Destroy;
351
begin
352
  if FEnabled then Stop;
353
  inherited Destroy;
354
end;
355

356
procedure TGLRagdoll.ReadFromFiler(reader: TVirtualReader);
357
begin
358
  inherited;
359
end;
360

361
procedure TGLRagdoll.SetRootBone(RootBone: TGLRagdolBone);
362
begin
363
  FRootBone := RootBone;
364
end;
365

366
procedure TGLRagdoll.Start;
367
begin
368
  Assert(FBuilt, 'First you need to build the ragdoll. BuildRagdoll;');
369
  if (FEnabled) then Exit;
370
  FEnabled:= True;
371
  //First start the ragdoll in the reference position
372
  RootBone.StartChild;
373
  //Now align it to the animation
374
  RootBone.AlignChild;
375
  //Now it recalculate the vertices to use as reference
376
  FOwner.Skeleton.StartRagDoll;
377
end;
378

379
procedure TGLRagdoll.Update;
380
begin
381
  if FEnabled then
382
  begin
383
    RootBone.UpdateChild;
384
    FOwner.Skeleton.MorphMesh(true);
385
  end;
386
end;
387

388
procedure TGLRagdoll.Stop;
389
begin
390
  if not FEnabled then Exit;
391
  FEnabled := False;
392
  RootBone.StopChild;
393
  //Restore the old information
394
  FOwner.Skeleton.StopRagDoll;
395
  FOwner.Skeleton.MorphMesh(true);
396
end;
397

398
procedure TGLRagdoll.WriteToFiler(writer: TVirtualWriter);
399
begin
400
  inherited;
401

402
end;
403

404
procedure TGLRagdoll.BuildRagdoll;
405
begin
406
  Assert(RootBone <> nil, 'First you need to set the root bone. SetRootBone();');
407
  RootBone.CreateBoundsChild;
408
  FBuilt := True;
409
end;
410

411
end.
412

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.