123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.ODERagdoll;
- (* Ragdoll extended using Open Dynamics Engine (ODE) *)
- interface
- uses
- Stage.VectorTypes,
- Stage.VectorGeometry,
- GXS.Ragdoll,
- GXS.Scene,
- GXS.Objects,
- GXS.Texture,
- GXS.VectorFileObjects,
- ODE.Import,
- GXS.ODEUtils;
- const
- cMaxContacts = 4;
- type
- TgxODERagdoll = class;
- TgxODERagdollBone = class;
- TgxODERagdollCube = class(TgxCube)
- public
- Bone: TgxODERagdollBone; // Useful in Oncollision Event
- Ragdoll: TgxODERagdoll; // Useful in Oncollision Event
- end;
- TgxODERagdollWorld = class
- private
- FSpace: PdxSpace;
- FWorld: PdxWorld;
- FContactGroup: TdJointGroupID;
- FRagdoll: TgxODERagdoll;
- isWorldCreated: Boolean; // NEW1
- public
- constructor Create;
- // Create the world from any existing ODE world
- constructor CreateFrom(World: PdxWorld; Space: PdxSpace;
- ContactGroup: TdJointGroupID);
- destructor Destroy; override;
- procedure WorldUpdate;
- property World: PdxWorld read FWorld;
- property Space: PdxSpace read FSpace;
- property ContactGroup: TdJointGroupID read FContactGroup;
- property Ragdoll: TgxODERagdoll read FRagdoll;
- end;
- TgxODERagdollDummyJoint = class(TgxRagdolJoint)
- end;
- TgxODERagdollHingeJoint = class(TgxRagdolJoint)
- private
- FParamHiStop: Single;
- FParamLoStop: Single;
- FAxis: TAffineVector;
- public
- constructor Create(Axis: TAffineVector; ParamLoStop: Single;
- ParamHiStop: Single);
- property Axis: TAffineVector read FAxis;
- property ParamLoStop: Single read FParamLoStop write FParamLoStop;
- property ParamHiStop: Single read FParamHiStop write FParamHiStop;
- end;
- TgxODERagdollUniversalJoint = class(TgxODERagdollHingeJoint)
- private
- FParamHiStop2: Single;
- FParamLoStop2: Single;
- FAxis2: TAffineVector;
- public
- constructor Create(Axis: TAffineVector; ParamLoStop: Single;
- ParamHiStop: Single; Axis2: TAffineVector; ParamLoStop2: Single;
- ParamHiStop2: Single);
- property Axis2: TAffineVector read FAxis2;
- property ParamLoStop2: Single read FParamLoStop2 write FParamLoStop2;
- property ParamHiStop2: Single read FParamHiStop2 write FParamHiStop2;
- end;
- TgxODERagdollBone = class(TgxRagdolBone)
- private
- FOwner: TgxODERagdollBone;
- FRagdoll: TgxODERagdoll;
- FBody: PdxBody;
- FGeom: PdxGeom;
- FJointId: TdJointID;
- procedure AlignBodyToMatrix(Mat: TMatrix4f);
- protected
- procedure Start; override;
- procedure Align; override;
- procedure Update; override;
- procedure Stop; override;
- public
- constructor CreateOwned(aOwner: TgxODERagdollBone);
- constructor Create(Ragdoll: TgxODERagdoll);
- property Body: PdxBody read FBody;
- property Geom: PdxGeom read FGeom;
- end;
- TgxODERagdoll = class(TgxRagdoll)
- private
- FODEWorld: TgxODERagdollWorld;
- FGLXceneRoot: TgxBaseSceneObject;
- FShowBoundingBoxes: Boolean;
- public
- constructor Create(aOwner: TgxBaseMesh);
- property ODEWorld: TgxODERagdollWorld read FODEWorld write FODEWorld;
- property GLXceneRoot: TgxBaseSceneObject read FGLXceneRoot
- write FGLXceneRoot;
- property ShowBoundingBoxes: Boolean read FShowBoundingBoxes
- write FShowBoundingBoxes;
- end;
- var
- vODERagdoll_cDensity: Single;
- vODERagdoll_cMass: Single;
- // ------------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------------
- procedure ODERagdollCallback(data: pointer; o1, o2: PdxGeom); cdecl;
- var
- i, n: integer;
- b1, b2: PdxBody;
- c: TdJointID;
- contact: Array [0 .. cMaxContacts - 1] of TdContact;
- begin
- b1 := dGeomGetBody(o1);
- b2 := dGeomGetBody(o2);
- if (assigned(b1) and assigned(b2) and (dAreConnected(b1, b2) <> 0)) then
- exit;
- n := dCollide(o1, o2, cMaxContacts, contact[0].Geom, sizeof(TdContact));
- if (n > 0) then
- begin
- for i := 0 to n - 1 do
- begin
- contact[i].surface.mode := ord(dContactBounce) or ord(dContactSoftCFM) or
- ord(dContactSlip1) or ord(dContactSlip2);
- contact[i].surface.mu := 10E9;
- contact[i].surface.mu2 := 0;
- contact[i].surface.soft_cfm := 0.001;
- contact[i].surface.bounce := 0.15;
- contact[i].surface.bounce_vel := 0.2;
- contact[i].surface.slip1 := 0.1;
- contact[i].surface.slip2 := 0.1;
- c := dJointCreateContact(TgxODERagdollWorld(data).World,
- TgxODERagdollWorld(data).ContactGroup, @contact[i]);
- dJointAttach(c, dGeomGetBody(contact[i].Geom.g1),
- dGeomGetBody(contact[i].Geom.g2));
- end;
- end;
- end;
- // ------------------------------------------
- // TgxODERagdollWorld
- // ------------------------------------------
- constructor TgxODERagdollWorld.Create;
- begin
- // Create default physics
- FWorld := dWorldCreate();
- dWorldSetQuickStepNumIterations(FWorld, 8);
- FSpace := dHashSpaceCreate(nil);
- FContactGroup := dJointGroupCreate(0);
- dWorldSetGravity(FWorld, 0, 0, -0.81);
- dWorldSetCFM(FWorld, 1E-5);
- isWorldCreated := True; // NEW1
- end;
- constructor TgxODERagdollWorld.CreateFrom(World: PdxWorld; Space: PdxSpace;
- ContactGroup: TdJointGroupID);
- begin
- FWorld := World;
- FSpace := Space;
- FContactGroup := ContactGroup;
- isWorldCreated := False; // NEW1
- end;
- destructor TgxODERagdollWorld.Destroy;
- begin
- if isWorldCreated then
- begin
- dJointGroupDestroy(FContactGroup);
- dSpaceDestroy(FSpace);
- dWorldDestroy(FWorld);
- end;
- inherited;
- end;
- procedure TgxODERagdollWorld.WorldUpdate;
- const
- cDeltaTime = 1 / 50;
- begin
- // Update the physic
- dSpaceCollide(FSpace, Self, ODERagdollCallback);
- dWorldQuickStep(FWorld, cDeltaTime);
- // remove all contact joints
- dJointGroupEmpty(FContactGroup);
- end;
- //------------------------------------
- // TgxODERagdollHingeJoint
- //------------------------------------
- constructor TgxODERagdollHingeJoint.Create(Axis: TAffineVector;
- ParamLoStop, ParamHiStop: Single);
- begin
- inherited Create;
- FAxis := Axis;
- FParamLoStop := ParamLoStop;
- FParamHiStop := ParamHiStop;
- end;
- //------------------------------------
- // TgxODERagdollUniversalJoint
- //------------------------------------
- constructor TgxODERagdollUniversalJoint.Create(Axis: TAffineVector;
- ParamLoStop, ParamHiStop: Single; Axis2: TAffineVector;
- ParamLoStop2, ParamHiStop2: Single);
- begin
- inherited Create(Axis, ParamLoStop, ParamHiStop);
- FAxis2 := Axis2;
- FParamLoStop := ParamLoStop;
- FParamHiStop := ParamHiStop;
- FParamLoStop2 := ParamLoStop2;
- FParamHiStop2 := ParamHiStop2;
- end;
- //------------------------------------
- // TgxODERagdollBone
- //------------------------------------
- constructor TgxODERagdollBone.Create(Ragdoll: TgxODERagdoll);
- begin
- inherited Create(Ragdoll);
- FRagdoll := Ragdoll;
- end;
- constructor TgxODERagdollBone.CreateOwned(aOwner: TgxODERagdollBone);
- begin
- inherited CreateOwned(aOwner);
- FOwner := aOwner;
- FRagdoll := aOwner.FRagdoll;
- end;
- procedure TgxODERagdollBone.AlignBodyToMatrix(Mat: TMatrix4f); // By Stuart Gooding
- var
- R: TdMatrix3;
- begin
- if not assigned(FBody) then
- exit;
- R[0] := Mat.X.X;
- R[1] := Mat.Y.X;
- R[2] := Mat.Z.X;
- R[3] := 0;
- R[4] := Mat.X.Y;
- R[5] := Mat.Y.Y;
- R[6] := Mat.Z.Y;
- R[7] := 0;
- R[8] := Mat.X.Z;
- R[9] := Mat.Y.Z;
- R[10] := Mat.Z.Z;
- R[11] := 0;
- dBodySetRotation(FBody, R);
- dBodySetPosition(FBody, Mat.W.X, Mat.W.Y, Mat.W.Z);
- end;
- procedure TgxODERagdollBone.Start;
- var
- mass: TdMass;
- boneSize, vAxis, vAxis2: TAffineVector;
- n: integer;
- function RotateAxis(Axis: TAffineVector): TAffineVector;
- var
- absMat: TMatrix4f;
- begin
- absMat := ReferenceMatrix;
- absMat.W := NullHmgVector;
- Result := VectorNormalize(VectorTransform(Axis, absMat));
- end;
- begin
- FBody := dBodyCreate(FRagdoll.ODEWorld.World);
- boneSize.X := Size.X * VectorLength(BoneMatrix.X);
- boneSize.Y := Size.Y * VectorLength(BoneMatrix.Y);
- boneSize.Z := Size.Z * VectorLength(BoneMatrix.Z);
- // prevent ODE 0.9 "bNormalizationResult failed" error:
- for n := 0 to 2 do
- if (boneSize.V[n] = 0) then
- boneSize.V[n] := 0.000001;
- dMassSetBox(mass, vODERagdoll_cDensity, boneSize.X, boneSize.Y, boneSize.Z);
- dMassAdjust(mass, vODERagdoll_cMass);
- dBodySetMass(FBody, @mass);
- AlignBodyToMatrix(ReferenceMatrix);
- FGeom := dCreateBox(FRagdoll.ODEWorld.Space, boneSize.X, boneSize.Y, boneSize.Z);
- FGeom.data := FRagdoll.GLXceneRoot.AddNewChild(TgxODERagdollCube);
- if (Joint is TgxODERagdollDummyJoint) then
- dGeomSetBody(FGeom, FOwner.Body)
- else
- dGeomSetBody(FGeom, FBody);
- if (Owner <> nil) then
- begin
- if (Joint is TgxODERagdollHingeJoint) then
- with (Joint as TgxODERagdollHingeJoint) do
- begin
- vAxis := RotateAxis(Axis);
- FJointId := dJointCreateHinge(FRagdoll.ODEWorld.World, nil);
- dJointAttach(FJointId, TgxODERagdollBone(Owner).Body, FBody);
- dJointSetHingeAnchor(FJointId, Anchor.X, Anchor.Y, Anchor.Z);
- dJointSetHingeAxis(FJointId, vAxis.X, vAxis.Y, vAxis.Z);
- dJointSetHingeParam(FJointId, dParamLoStop, ParamLoStop);
- dJointSetHingeParam(FJointId, dParamHiStop, ParamHiStop);
- end;
- if (Joint is TgxODERagdollUniversalJoint) then
- with (Joint as TgxODERagdollUniversalJoint) do
- begin
- vAxis := RotateAxis(Axis);
- vAxis2 := RotateAxis(Axis2);
- FJointId := dJointCreateUniversal(FRagdoll.ODEWorld.World, nil);
- dJointAttach(FJointId, TgxODERagdollBone(Owner).Body, FBody);
- dJointSetUniversalAnchor(FJointId, Anchor.X, Anchor.Y, Anchor.Z);
- dJointSetUniversalAxis1(FJointId, vAxis.X, vAxis.Y, vAxis.Z);
- dJointSetUniversalAxis2(FJointId, vAxis2.X, vAxis2.Y, vAxis2.Z);
- dJointSetUniversalParam(FJointId, dParamLoStop, ParamLoStop);
- dJointSetUniversalParam(FJointId, dParamHiStop, ParamHiStop);
- dJointSetUniversalParam(FJointId, dParamLoStop2, ParamLoStop2);
- dJointSetUniversalParam(FJointId, dParamHiStop2, ParamHiStop2);
- end;
- end;
- with TgxODERagdollCube(FGeom.data) do
- begin
- Visible := FRagdoll.ShowBoundingBoxes;
- Material.FrontProperties.Diffuse.SetColor(1, 0, 0, 0.4);
- CubeWidth := boneSize.X;
- CubeHeight := boneSize.Y;
- CubeDepth := boneSize.Z;
- Bone := Self;
- Ragdoll := Self.FRagdoll;
- end;
- end;
- procedure TgxODERagdollBone.Stop;
- var
- o: TgxBaseSceneObject;
- begin
- inherited;
- dBodyDestroy(FBody);
- if assigned(FGeom.data) then
- begin
- o := TgxBaseSceneObject(FGeom.data);
- FRagdoll.GLXceneRoot.Remove(o, False);
- o.free;
- end;
- if FJointId <> nil then
- dJointDestroy(FJointId);
- dGeomDestroy(FGeom);
- end;
- procedure TgxODERagdollBone.Update;
- begin
- PositionSceneObject(TgxBaseSceneObject(PdxGeom(FGeom.data)), FGeom);
- Ragdoll.Owner.Skeleton.BoneByID(BoneID).SetGlobalMatrixForRagDoll
- (TgxBaseSceneObject(PdxGeom(FGeom.data)).AbsoluteMatrix);
- end;
- procedure TgxODERagdollBone.Align;
- begin
- inherited;
- AlignBodyToMatrix(BoneMatrix);
- end;
- //------------------------------------
- // TgxODERagdoll
- //------------------------------------
- constructor TgxODERagdoll.Create(aOwner: TgxBaseMesh);
- begin
- inherited Create(aOwner);
- FShowBoundingBoxes := False;
- end;
- //------------------------------------
- initialization
- //------------------------------------
- vODERagdoll_cDensity := 20;
- vODERagdoll_cMass := 1;
- end.
|