123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.Ragdoll;
- (* Base abstract ragdoll class. Should be extended to use any physics system *)
- interface
- uses
- Stage.VectorTypes,
- GXS.PersistentClasses,
- Stage.VectorGeometry,
- GXS.VectorLists,
- GXS.Scene,
- GXS.Objects,
- GXS.VectorFileObjects;
- type
- TgxRagdoll = class;
- TgxRagdolBone = class;
- TgxRagdolJoint = class
- end;
- TgxRagdolBoneList = class (TgxPersistentObjectList)
- private
- FRagdoll : TgxRagdoll;
- protected
- function GetRagdollBone(Index: Integer) : TgxRagdolBone;
- public
- constructor Create(Ragdoll: TgxRagdoll); reintroduce;
- destructor Destroy; override;
- procedure WriteToFiler(writer : TgxVirtualWriter); override;
- procedure ReadFromFiler(reader : TgxVirtualReader); override;
- property Ragdoll : TgxRagdoll read FRagdoll;
- property Items[Index: Integer] : TgxRagdolBone read GetRagdollBone; default;
- end;
- TgxRagdolBone = class (TgxRagdolBoneList)
- private
- FOwner : TgxRagdolBoneList;
- FName : String;
- FBoneID : Integer; //Refering to TgxActor Bone
- FBoundMax: TAffineVector;
- FBoundMin: TAffineVector;
- FBoundBoneDelta: TAffineVector; //Stores the diference from the bone.GlobalMatrix to the center of the bone's bounding box
- FOrigin: TAffineVector;
- FSize: TAffineVector;
- FBoneMatrix: TMatrix4f;
- FJoint: TgxRagdolJoint;
- FOriginalMatrix: TMatrix4f; //Stores the Bone.GlobalMatrix before the ragdoll start
- FReferenceMatrix: TMatrix4f; //Stores the first bone matrix to be used as reference
- FAnchor: TAffineVector; //The position of the joint
- procedure CreateBoundingBox;
- procedure SetAnchor(Anchor: TAffineVector);
- procedure AlignToSkeleton;
- procedure CreateBoundsChild;
- procedure StartChild;
- procedure AlignChild;
- procedure UpdateChild;
- procedure StopChild;
- protected
- function GetRagdollBone(Index: Integer) : TgxRagdolBone;
- procedure Start; virtual; abstract;
- procedure Align; virtual; abstract;
- procedure Update; virtual; abstract;
- procedure Stop; virtual; abstract;
- public
- constructor CreateOwned(aOwner : TgxRagdolBoneList);
- constructor Create(Ragdoll: TgxRagdoll);
- destructor Destroy; override;
- procedure WriteToFiler(writer : TgxVirtualWriter); override;
- procedure ReadFromFiler(reader : TgxVirtualReader); override;
- property Owner : TgxRagdolBoneList read FOwner;
- property Name : String read FName write FName;
- property BoneID : Integer read FBoneID write FBoneID;
- property Origin : TAffineVector read FOrigin;
- property Size : TAffineVector read FSize;
- property BoneMatrix : TMatrix4f read FBoneMatrix;
- property ReferenceMatrix : TMatrix4f read FReferenceMatrix;
- property Anchor : TAffineVector read FAnchor;
- property Joint : TgxRagdolJoint read FJoint write FJoint;
- property Items[Index: Integer] : TgxRagdolBone read GetRagdollBone; default;
- end;
- TgxRagdoll = class(TgxPersistentObject)
- private
- FOwner : TgxBaseMesh;
- FRootBone : TgxRagdolBone;
- FEnabled: Boolean;
- FBuilt: Boolean;
- public
- constructor Create(AOwner : TgxBaseMesh); reintroduce;
- destructor Destroy; override;
- procedure WriteToFiler(writer : TgxVirtualWriter); override;
- procedure ReadFromFiler(reader : TgxVirtualReader); override;
- // Must be set before build the ragdoll
- procedure SetRootBone(RootBone: TgxRagdolBone);
- // Create the bounding box and setup the ragdoll do be started later
- procedure BuildRagdoll;
- procedure Start;
- procedure Update;
- procedure Stop;
- property Owner : TgxBaseMesh read FOwner;
- property RootBone : TgxRagdolBone read FRootBone;
- property Enabled : Boolean read FEnabled;
- end;
- implementation //-------------------------------------------------------------
- //--------------------------------
- // TgxRagdolBoneList
- //--------------------------------
- constructor TgxRagdolBoneList.Create(Ragdoll: TgxRagdoll);
- begin
- inherited Create;
- FRagdoll := Ragdoll;
- end;
- destructor TgxRagdolBoneList.Destroy;
- var i: integer;
- begin
- for i:=0 to Count-1 do Items[i].Destroy;
- inherited;
- end;
- function TgxRagdolBoneList.GetRagdollBone(Index: Integer): TgxRagdolBone;
- begin
- Result:=TgxRagdolBone(List^[Index]);
- end;
- procedure TgxRagdolBoneList.ReadFromFiler(reader: TgxVirtualReader);
- begin
- inherited;
- //Not implemented
- end;
- procedure TgxRagdolBoneList.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited;
- //Not implemented
- end;
- { TgxRagdolBone }
- constructor TgxRagdolBone.Create(Ragdoll: TgxRagdoll);
- begin
- inherited Create(Ragdoll);
- end;
- procedure TgxRagdolBone.CreateBoundingBox;
- var
- bone: TgxSkeletonBone;
- i, j: integer;
- BoneVertices : TgxAffineVectorList;
- BoneVertex, max,min: TAffineVector;
- invMat, mat: TMatrix4f;
- begin
- bone := Ragdoll.Owner.Skeleton.BoneByID(FBoneID);
- //Get all vertices weighted to this bone
- BoneVertices:=TgxAffineVectorList.Create;
- for i:=0 to Ragdoll.Owner.MeshObjects.Count-1 do
- with TgxSkeletonMeshObject(Ragdoll.Owner.MeshObjects[i]) do
- for j:=0 to Vertices.Count-1 do
- if bone.BoneID = VerticesBonesWeights[j][0].BoneID then
- BoneVertices.FindOrAdd(Vertices[j]);
- invMat := bone.GlobalMatrix;
- InvertMatrix(invMat);
- //For each vertex, get the max and min XYZ (Bounding box)
- if BoneVertices.Count > 0 then
- begin
- BoneVertex := VectorTransform(BoneVertices[0], invMat);
- max := BoneVertex;
- min := BoneVertex;
- for i:=1 to BoneVertices.Count-1 do begin
- BoneVertex := VectorTransform(BoneVertices[i], invMat);
- if (BoneVertex.X > max.X) then max.X := BoneVertex.X;
- if (BoneVertex.Y > max.Y) then max.Y := BoneVertex.Y;
- if (BoneVertex.Z > max.Z) then max.Z := BoneVertex.Z;
- if (BoneVertex.X < min.X) then min.X := BoneVertex.X;
- if (BoneVertex.Y < min.Y) then min.Y := BoneVertex.Y;
- if (BoneVertex.Z < min.Z) then min.Z := BoneVertex.Z;
- end;
- FBoundMax := max;
- FBoundMin := min;
- //Get the origin and subtract from the bone matrix
- FBoundBoneDelta := VectorScale(VectorAdd(FBoundMax, FBoundMin), 0.5);
- end else begin
- FBoundMax := NullVector;
- FBoundMin := NullVector;
- end;
- AlignToSkeleton;
- FReferenceMatrix := FBoneMatrix;
- mat := MatrixMultiply(bone.GlobalMatrix,FRagdoll.Owner.AbsoluteMatrix);
- //Set Joint position
- SetAnchor(AffineVectorMake(mat.W));
- BoneVertices.Free; // NEW1
- end;
- constructor TgxRagdolBone.CreateOwned(aOwner: TgxRagdolBoneList);
- begin
- Create(aOwner.Ragdoll);
- FOwner:=aOwner;
- aOwner.Add(Self);
- end;
- destructor TgxRagdolBone.Destroy;
- begin
- inherited;
- end;
- procedure TgxRagdolBone.AlignToSkeleton;
- var
- o: TAffineVector;
- bone: TgxSkeletonBone;
- mat, posMat: TMatrix4f;
- noBounds: Boolean;
- begin
- bone := Ragdoll.Owner.Skeleton.BoneByID(FBoneID);
- noBounds := VectorIsNull(FBoundMax) and VectorIsNull(FBoundMin);
- //Get the bone matrix relative to the Actor matrix
- mat := MatrixMultiply(bone.GlobalMatrix,FRagdoll.Owner.AbsoluteMatrix);
- //Set Rotation
- FBoneMatrix := mat;
- NormalizeMatrix(FBoneMatrix);
- if (noBounds) then
- begin
- FOrigin := AffineVectorMake(mat.W);
- FSize := AffineVectorMake(0.1,0.1,0.1);
- end else begin
- //Set Origin
- posMat := mat;
- posMat.W := NullHmgVector;
- o := VectorTransform(FBoundBoneDelta, posMat);
- FOrigin := VectorAdd(AffineVectorMake(mat.W), o);
- //Set Size
- FSize := VectorScale(VectorSubtract(FBoundMax, FBoundMin),0.9);
- FSize.X := FSize.X*VectorLength(mat.X);
- FSize.Y := FSize.Y*VectorLength(mat.Y);
- FSize.Z := FSize.Z*VectorLength(mat.Z);
- end;
- //Put the origin in the BoneMatrix
- FBoneMatrix.W := VectorMake(FOrigin,1);
- end;
- function TgxRagdolBone.GetRagdollBone(Index: Integer): TgxRagdolBone;
- begin
- Result:=TgxRagdolBone(List^[Index]);
- end;
- procedure TgxRagdolBone.ReadFromFiler(reader: TgxVirtualReader);
- begin
- inherited;
- end;
- procedure TgxRagdolBone.StartChild;
- var i: integer;
- begin
- FOriginalMatrix := Ragdoll.Owner.Skeleton.BoneByID(FBoneID).GlobalMatrix;
- AlignToSkeleton;
- Start;
- for i := 0 to Count-1 do items[i].StartChild;
- end;
- procedure TgxRagdolBone.UpdateChild;
- var i: integer;
- begin
- Update;
- for i := 0 to Count-1 do items[i].UpdateChild;
- end;
- procedure TgxRagdolBone.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited;
- end;
- procedure TgxRagdolBone.StopChild;
- var i: integer;
- begin
- Stop;
- Ragdoll.Owner.Skeleton.BoneByID(FBoneID).SetGlobalMatrix(FOriginalMatrix);
- for i := 0 to Count-1 do items[i].StopChild;
- end;
- procedure TgxRagdolBone.CreateBoundsChild;
- var i: integer;
- begin
- CreateBoundingBox;
- for i := 0 to Count-1 do items[i].CreateBoundsChild;
- end;
- procedure TgxRagdolBone.SetAnchor(Anchor: TAffineVector);
- begin
- FAnchor := Anchor;
- end;
- procedure TgxRagdolBone.AlignChild;
- var i: integer;
- begin
- Align;
- Update;
- for i := 0 to Count-1 do items[i].AlignChild;
- end;
- { TgxRagdoll }
- constructor TgxRagdoll.Create(AOwner : TgxBaseMesh);
- begin
- FOwner := AOwner;
- FEnabled := False;
- FBuilt := False;
- end;
- destructor TgxRagdoll.Destroy;
- begin
- if FEnabled then Stop;
- inherited Destroy;
- end;
- procedure TgxRagdoll.ReadFromFiler(reader: TgxVirtualReader);
- begin
- inherited;
- end;
- procedure TgxRagdoll.SetRootBone(RootBone: TgxRagdolBone);
- begin
- FRootBone := RootBone;
- end;
- procedure TgxRagdoll.Start;
- begin
- Assert(FBuilt, 'First you need to build the ragdoll. BuildRagdoll;');
- if (FEnabled) then Exit;
- FEnabled:= True;
- //First start the ragdoll in the reference position
- RootBone.StartChild;
- //Now align it to the animation
- RootBone.AlignChild;
- //Now it recalculate the vertices to use as reference
- FOwner.Skeleton.StartRagDoll;
- end;
- procedure TgxRagdoll.Update;
- begin
- if FEnabled then
- begin
- RootBone.UpdateChild;
- FOwner.Skeleton.MorphMesh(true);
- end;
- end;
- procedure TgxRagdoll.Stop;
- begin
- if not FEnabled then Exit;
- FEnabled := False;
- RootBone.StopChild;
- //Restore the old information
- FOwner.Skeleton.StopRagDoll;
- FOwner.Skeleton.MorphMesh(true);
- end;
- procedure TgxRagdoll.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited;
- end;
- procedure TgxRagdoll.BuildRagdoll;
- begin
- Assert(RootBone <> nil, 'First you need to set the root bone. SetRootBone();');
- RootBone.CreateBoundsChild;
- FBuilt := True;
- end;
- //-----------------------------------------------------------------------
- end.
|