NewtonCustomJoints.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:50k
源码类别:

2D图形编程

开发平台:

Delphi

  1. {*******************************************************************************}
  2. {                                                                               }
  3. {      Newton Game Dynamics Custom Joints Delphi-Headertranslation              }
  4. {       Current SDK version 1.53                                                }
  5. {                                                                               }
  6. {      Copyright (c) 2005,06 Sascha Willems                                     }
  7. {                            Jon Walton                                         }
  8. {                                                                               }
  9. {*******************************************************************************}
  10. {                                                                               }
  11. { License :                                                                     }
  12. {                                                                               }
  13. {  The contents of this file are used with permission, subject to               }
  14. {  the Mozilla Public License Version 1.1 (the "License"); you may              }
  15. {  not use this file except in compliance with the License. You may             }
  16. {  obtain a copy of the License at                                              }
  17. {  http://www.mozilla.org/MPL/MPL-1.1.html                                      }
  18. {                                                                               }
  19. {  Software distributed under the License is distributed on an                  }
  20. {  "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or               }
  21. {  implied. See the License for the specific language governing                 }
  22. {  rights and limitations under the License.                                    }
  23. {                                                                               }
  24. {*******************************************************************************}
  25. {  Custom Joints in SDK :             Implemented :                             }
  26. {   - BallAndSocket                     Yes                                     }
  27. {   - LimitedBallAndSocket              Yes                                     }
  28. {   - CorkScrew                         Yes                                     }
  29. {   - DryRollingFriction                Yes                                     }
  30. {   - Gear                              Yes                                     }
  31. {   - Hinge                             Yes                                     }
  32. {   - Pulley                            Yes                                     }
  33. {   - Slider                            Yes                                     }
  34. {   - Universal                         Yes                                     }
  35. {   - UpVector                          Yes                                     }
  36. {   - WormGear                          Yes                                     }
  37. {*******************************************************************************}
  38. unit NewtonCustomJoints;
  39. interface
  40. uses
  41.   Math,
  42.   SysUtils,
  43.   NewtonImport,
  44.   NewtonCustomJoints_Math;
  45.   
  46. {$I delphinewton.inc}
  47. {$IFDEF FPC}
  48.  {$MODE DELPHI}
  49.  {$APPTYPE GUI}
  50. {$ENDIF}
  51. type
  52.  // TNewtonCustomBaseJoint =====================================================
  53.  TNewtonCustomBaseJoint = Class(TObject)
  54.   private
  55.    FMaxDOF : Integer;
  56.    FBody0  : PNewtonBody;
  57.    FBody1  : PNewtonBody;
  58.    FJoint  : PNewtonJoint;
  59.    FWorld  : PNewtonWorld;
  60.   public
  61.    constructor Create(aMaxDOF : Integer; aBody0, aBody1 : PNewtonBody);
  62.    destructor Destroy; override;
  63.    procedure CalculateGlobalMatrix(const aLocalMatrix0, aLocalMatrix1 : TMatrix4f; out aMatrix0, aMatrix1 : TMatrix4f);
  64.    procedure CalculateLocalMatrix(const aPivot, aDir : TVector3f; out aLocalMatrix0, aLocalMatrix1 : TMatrix4f);
  65.    property Joint : PNewtonJoint read FJoint;
  66.   protected
  67.    procedure SubmitConstraint; virtual; abstract;
  68.   end;                                 
  69.  // TNewtonCustomJointUpVector =================================================
  70.  TNewtonCustomJointUpVector = Class(TNewtonCustomBaseJoint)
  71.   private
  72.    FLocalMatrix0 : TMatrix4f;
  73.    FLocalMatrix1 : TMatrix4f;
  74.   public
  75.    constructor Create(aPin: TVector3f; aBody : PNewtonBody);
  76.    procedure SetPinDir(const aDir : TVector3f);
  77.   protected
  78.    procedure SubmitConstraint; override;
  79.   end;
  80.  // TNewtonCustomJointBallAndSocket ============================================
  81.  TNewtonCustomJointBallAndSocket = Class(TNewtonCustomBaseJoint)
  82.   private
  83.    FLocalMatrix0 : TMatrix4f;
  84.    FLocalMatrix1 : TMatrix4f;
  85.   public
  86.    constructor Create(aPivot : TVector3f; aChild, aParent : PNewtonBody);
  87.   protected
  88.    procedure SubmitConstraint; override;
  89.   end;
  90.  // TNewtonCustomJointLimitedBallAndSocket =====================================
  91.  TNewtonCustomJointLimitedBallAndSocket = Class(TNewtonCustomJointBallAndSocket)
  92.   private
  93.    FConeAngle    : Single;
  94.    FTwistAngle   : Single;
  95.    FCosConeAngle : Single;
  96.   public
  97.     constructor Create(aPivot, aConeDir : TVector3f; aConeAngle, aTwistAngle : Single; aChild, aParent : PNewtonBody);
  98.   protected
  99.     procedure SubmitConstraint; override;
  100.   end;
  101.  // TNewtonCustomJointCorkScrew ================================================
  102.  TNewtonCustomJointCorkScrew = Class(TNewtonCustomBaseJoint)
  103.   private
  104.    FLocalMatrix0   : TMatrix4f;
  105.    FLocalMatrix1   : TMatrix4f;
  106.    FLimitsOn       : Boolean;
  107.    FMinDist        : Single;
  108.    FMaxDist        : Single;
  109.    FAngularMotorOn : Boolean;
  110.    FAngularDamp    : Single;
  111.    FAngularAccel   : Single;
  112.   public
  113.    constructor Create(aPivot, aPin : TVector3f; aChild, aParent : PNewtonBody);
  114.    procedure EnableLimits(aEnabled : Boolean);
  115.    procedure SetLimits(aMinDist, aMaxDist : Single);
  116.   protected
  117.     procedure SubmitConstraint; override;
  118.   end;
  119.  // TNewtonCustomJointSlider =============================================
  120.  TNewtonCustomJointSlider = Class(TNewtonCustomBaseJoint)
  121.   private
  122.    FLocalMatrix0 : TMatrix4f;
  123.    FLocalMatrix1 : TMatrix4f;
  124.    FLimitsOn     : Boolean;
  125.    FMinDist      : Single;
  126.    FMaxDist      : Single;
  127.   public
  128.    constructor Create(aPivot, aPin : TVector3f; aChild, aParent : PNewtonBody);
  129.    procedure EnableLimits(aEnabled : Boolean);
  130.    procedure SetLimits(aMinDist, aMaxDist : Single);
  131.   protected
  132.    procedure SubmitConstraint; override;
  133.   end;
  134.   // TNewtonCustomJointHinge ===================================================
  135.   TNewtonCustomJointHinge = Class(TNewtonCustomBaseJoint)
  136.    private
  137.     FLocalMatrix0   : TMatrix4f;
  138.     FLocalMatrix1   : TMatrix4f;
  139.     FLimitsOn       : Boolean;
  140.     FMinAngle       : Single;
  141.     FMaxAngle       : Single;
  142.    public
  143.     constructor Create(aPivot, aPin : TVector3f; aChild, aParent : PNewtonBody);
  144.     procedure EnableLimits(aEnabled : Boolean);
  145.     procedure SetLimits(aMinAngle, aMaxAngle : Single);
  146.   protected
  147.     procedure SubmitConstraint; override;
  148.   end;
  149.  // TNewtonCustomJointDryRollingFriction =======================================
  150.  // This joint is usefull to simulate the rolling friction of a rolling ball over
  151.  // a flat surface.
  152.  // Normally this is not important for non spherical objects, but for games like
  153.  // pool, pinball, bowling, golf or any other where the movement of balls is the
  154.  // main objective, the rolling friction is a real big problem.
  155.  TNewtonCustomJointDryRollingFriction = Class(TNewtonCustomBaseJoint)
  156.   private
  157.    FFrictionCoef   : Single;
  158.    FFrictionTorque : Single;
  159.   public
  160.    constructor Create(aRadius, aCoefficient : Single; aChild : PNewtonBody);
  161.   protected
  162.    procedure SubmitConstraint; override;
  163.   end;
  164.  // TNewtonCustomJointUniversal ================================================
  165.  TNewtonCustomJointUniversal = Class(TNewtonCustomBaseJoint)
  166.   private
  167.    FLocalMatrix0    : TMatrix4f;
  168.    FLocalMatrix1    : TMatrix4f;
  169.    FLimit0On        : Boolean;
  170.    FLimit1On        : Boolean;
  171.    FMinAngle0       : Single;
  172.    FMaxAngle0       : Single;
  173.    FMinAngle1       : Single;
  174.    FMaxAngle1       : Single;
  175.    FAngularMotor0On : Boolean;
  176.    FAngularMotor1On : Boolean;
  177.    FAngularDamp0    : Single;
  178.    FAngularAccel0   : Single;
  179.    FAngularDamp1    : Single;
  180.    FAngularAccel1   : Single;
  181.   public 
  182.    constructor Create(aPivot, aPin0, aPin1 : TVector3f; aChild, aParent : PNewtonBody);
  183.    procedure EnableLimit0(aEnabled : Boolean);
  184.    procedure EnableLimit1(aEnabled : Boolean);
  185.    procedure SetLimits0(aMinAngle, aMaxAngle : Single);
  186.    procedure SetLimits1(aMinAngle, aMaxAngle : Single);
  187.    procedure EnableMotor0(aEnabled : Boolean);
  188.    procedure EnableMotor1(aEnabled : Boolean);
  189.   protected
  190.    procedure SubmitConstraint; override;
  191.   end;
  192.  // TNewtonCustomJointPulley ===================================================
  193.  TNewtonCustomJointPulley = Class(TNewtonCustomBaseJoint)
  194.   private
  195.    FLocalMatrix0 : TMatrix4f;
  196.    FLocalMatrix1 : TMatrix4f;
  197.    FGearRatio    : Single;
  198.   public
  199.    property GearRatio : Single read FGearRatio write FGearRatio;
  200.    constructor Create(aGearRatio : Single; aChildPin, aParentPin : TVector3f; aParentBody, aChildBody : PNewtonBody);
  201.   protected
  202.    procedure SubmitConstraint; override;
  203.   end;
  204.  // TNewtonCustomJointGear =====================================================
  205.  TNewtonCustomJointGear = Class(TNewtonCustomBaseJoint)
  206.   private
  207.    FLocalMatrix0 : TMatrix4f;
  208.    FLocalMatrix1 : TMatrix4f;
  209.    FGearRatio    : Single;
  210.   public
  211.    property GearRatio : Single read FGearRatio write FGearRatio;
  212.    constructor Create(aGearRatio : Single; aChildPin, aParentPin : TVector3f; aParentBody, aChildBody : PNewtonBody);
  213.   protected
  214.    procedure SubmitConstraint; override;
  215.   end;
  216.  // TNewtonCustomJointWormGear =================================================
  217.  TNewtonCustomJointWormGear = Class(TNewtonCustomBaseJoint)
  218.   private
  219.    FLocalMatrix0 : TMatrix4f;
  220.    FLocalMatrix1 : TMatrix4f;
  221.    FGearRatio    : Single;
  222.   public
  223.    property GearRatio : Single read FGearRatio write FGearRatio;
  224.    constructor Create(aGearRatio : Single; aRotationalPin, aLinearPin : TVector3f; aRotationalBody, aLinearBody : PNewtonBody);
  225.   protected
  226.    procedure SubmitConstraint; override;
  227.   end;
  228. implementation
  229. const
  230.   MIN_JOINT_PIN_LENGTH : Single = 50.0;
  231. // =============================================================================
  232. //  MatrixGrammSchmidt
  233. // =============================================================================
  234. function MatrixGrammSchmidt(const aDir: TVector3f): TMatrix4f;
  235. var
  236.  LUp    : TVector4f;
  237.  LRight : TVector4f;
  238.  LFront : TVector4f;
  239. Begin
  240. LFront := V4(aDir[0], aDir[1], aDir[2], 0);
  241. LFront := VScale(LFront, 1.0 / sqrt(VDot(LFront, LFront)));
  242. if abs(LFront[2]) > 0.577 then
  243.  LRight := VCross(LFront, V4(-LFront[1], LFront[2], 0, 0))
  244. else
  245.  LRight := VCross(LFront, V4(-LFront[1], LFront[0], 0, 0));
  246. LRight := VScale(LRight, 1.0 / sqrt(VDot(LRight, LRight)));
  247. LUp    := VCross(LRight, LFront);
  248. LFront[3] := 0;
  249. LUp[3]    := 0;
  250. LRight[3] := 0;
  251. Matrix_SetColumn(Result, 0, LFront);
  252. Matrix_SetColumn(Result, 1, LUp);
  253. Matrix_SetColumn(Result, 2, LRight);
  254. Matrix_SetColumn(Result, 3, V4(0,0,0,1));
  255. end;
  256. // =============================================================================
  257. //  JointDestructor
  258. // =============================================================================
  259. procedure JointDestructor(const aJoint: PNewtonJoint); cdecl;
  260. var
  261.  LBaseJoint : TNewtonCustomBaseJoint;
  262. Begin
  263. LBaseJoint := TNewtonCustomBaseJoint(NewtonJointGetUserData(aJoint));
  264. NewtonJointSetDestructor(aJoint, nil);
  265. NewtonJointSetUserData(aJoint, nil);
  266. FreeAndNil(LBaseJoint);
  267. end;
  268. // =============================================================================
  269. //  SubmitJointConstraint
  270. // =============================================================================
  271. function SubmitJointConstraint(const aJoint: PNewtonJoint): unsigned_int; cdecl;
  272. var
  273.  LBaseJoint: TNewtonCustomBaseJoint;
  274. begin
  275. Result := 0;
  276. LBaseJoint := TNewtonCustomBaseJoint(NewtonJointGetUserData(aJoint));
  277. if LBaseJoint <> nil then
  278.  LBaseJoint.SubmitConstraint;
  279. end;
  280. // *****************************************************************************
  281. // *****************************************************************************
  282. //  Base Joint
  283. // *****************************************************************************
  284. // *****************************************************************************
  285. constructor TNewtonCustomBaseJoint.Create(aMaxDOF: Integer; aBody0, aBody1: PNewtonBody);
  286. begin
  287. FBody0  := aBody0;
  288. FBody1  := aBody1;
  289. FMaxDOF := aMaxDOF;
  290. FWorld := NewtonBodyGetWorld(aBody0);
  291. // @SubmitJointConstraint not working in FP
  292. FJoint := NewtonConstraintCreateUserJoint(FWorld, FMaxDOF, @SubmitJointConstraint, FBody0, FBody1);
  293. //FJoint := NewtonConstraintCreateUserJoint(FWorld, FMaxDOF, @SubmitJointConstraint, FBody0, FBody1);
  294. NewtonJointSetStiffness(FJoint, 1);
  295. NewtonJointSetUserData(FJoint, Self);
  296. NewtonJointSetDestructor(FJoint, @JointDestructor);
  297. end;
  298. destructor TNewtonCustomBaseJoint.Destroy;
  299. begin
  300. if NewtonJointGetUserData(FJoint) <> nil then
  301.  begin
  302.  NewtonJointSetDestructor(FJoint, nil);
  303.  NewtonDestroyJoint(FWorld, FJoint);
  304.  end;
  305. end;
  306. procedure TNewtonCustomBaseJoint.CalculateGlobalMatrix(const aLocalMatrix0, aLocalMatrix1: TMatrix4f; out aMatrix0, aMatrix1: TMatrix4f);
  307. var
  308.  LBody0Matrix: TMatrix4f;
  309.  LBody1Matrix: TMatrix4f;
  310. begin
  311. // get the global matrices of each body
  312. NewtonBodyGetMatrix(FBody0, @LBody0Matrix[0,0]);
  313. LBody1Matrix := IdentityMatrix;
  314. if FBody1 <> nil then
  315.  NewtonBodyGetMatrix(FBody1, @LBody1Matrix[0,0]);
  316. aMatrix0 := Matrix_Multiply(aLocalMatrix0, LBody0Matrix);
  317. aMatrix1 := Matrix_Multiply(aLocalMatrix1, LBody1Matrix);
  318. end;
  319. procedure TNewtonCustomBaseJoint.CalculateLocalMatrix(const aPivot, aDir: TVector3f; out aLocalMatrix0, aLocalMatrix1: TMatrix4f);
  320. var
  321.  LMatrix0             : TMatrix4f;
  322.  LMatrix1             : TMatrix4f;
  323.  LPinAndPivoTMatrix4f : TMatrix4f;
  324.  LInverseMatrix       : TMatrix4f;
  325. begin
  326. // get the global matrices of each body
  327. NewtonBodyGetMatrix(FBody0, @LMatrix0[0, 0]);
  328. LMatrix1 := IdentityMatrix;
  329. if FBody1 <> nil then
  330.  NewtonBodyGetMatrix(FBody1, @LMatrix1[0, 0]);
  331. // create a global matrix at the pivot point with front vector aligned to the pin vector
  332. LPinAndPivotMatrix4f := MatrixGrammSchmidt(aDir);
  333. Matrix_SetTransform(LPinAndPivotMatrix4f, aPivot);
  334. // calculate the relative matrix of the pin and pivot on each body
  335. LInverseMatrix := LMatrix0;
  336. Matrix_Inverse(LInverseMatrix);
  337. aLocalMatrix0 := Matrix_Multiply(LPinAndPivotMatrix4f, LInverseMatrix);
  338. LInverseMatrix := LMatrix1;
  339. Matrix_Inverse(LInverseMatrix);
  340. aLocalMatrix1 := Matrix_Multiply(LPinAndPivotMatrix4f, LInverseMatrix);
  341. end;
  342. // *****************************************************************************
  343. // *****************************************************************************
  344. //  Up Vector
  345. // *****************************************************************************
  346. // *****************************************************************************
  347. constructor TNewtonCustomJointUpVector.Create(aPin: TVector3f; aBody: PNewtonBody);
  348. var
  349.  LPivot    : TMatrix4f;
  350.  LPivotPos : TVector3f;
  351. begin
  352. inherited
  353. Create(2, aBody, nil);
  354. NewtonBodyGetMatrix(aBody, @LPivot[0, 0]);
  355. LPivotPos := V3(LPivot[3, 0], LPivot[3, 1], LPivot[3, 2]);
  356. CalculateLocalMatrix(LPivotPos, aPin, FLocalMatrix0, FLocalMatrix1);
  357. end;
  358. procedure TNewtonCustomJointUpVector.SetPinDir(const aDir: TVector3f);
  359. Begin
  360. FLocalMatrix1 := MatrixGrammSchmidt(aDir);
  361. end;
  362. procedure TNewtonCustomJointUpVector.SubmitConstraint;
  363. var
  364.  LMag        : Single;
  365.  LAngle      : Single;
  366.  LMatrix0    : TMatrix4f;
  367.  LMatrix1    : TMatrix4f;
  368.  LLateralDir : TVector4f;
  369.  LFrontDir   : TVector4f;
  370. begin
  371. // calculate the position of the pivot point and the jacoviam direction vectors, in global space.
  372. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, LMatrix0, LMatrix1);
  373. // if the body has rotated by some amount, there will be a plane of rotation
  374. LLateralDir := VCross(V4(LMatrix0[0,0], LMatrix0[1,0], LMatrix0[2,0], LMatrix0[3,0]),
  375.                       V4(LMatrix1[0,0], LMatrix1[1,0], LMatrix1[2,0], LMatrix1[3,0]));
  376. LMag := VDot(LLateralDir, LLateralDir);
  377. if LMag > 1.0e-6 then
  378.  begin
  379.  // if the vector is not 0 it means the body has rotated
  380.  LMag := sqrt(LMag);
  381.  VScale(LLateralDir, 1.0 / LMag);
  382.  LAngle := ArcSin(LMag);
  383.  // add an angular constraint to correct the error angle
  384.  NewtonUserJointAddAngularRow(FJoint, LAngle, @LLateralDir[0]);
  385.  // in theory only one correction is needed, but this produces instability as the body may move sideway.
  386.  // a lateral correction prevent this from happening.
  387.  LFrontDir := VCross(LLateralDir, V4(LMatrix1[0,0], LMatrix1[1,0], LMatrix1[2,0], LMatrix1[3,0]));
  388.  NewtonUserJointAddAngularRow(FJoint, 0.0, @LFrontDir[0]);
  389.  end
  390. else
  391.  begin
  392.  // if the angle error is very small then two angular correction along the plane axis do the trick
  393.  NewtonUserJointAddAngularRow(FJoint, 0.0, @LMatrix0[1, 0]);
  394.  NewtonUserJointAddAngularRow(FJoint, 0.0, @LMatrix0[2, 0]);
  395.  end;
  396. end;
  397. // *****************************************************************************
  398. // *****************************************************************************
  399. //  Ball and Socket
  400. // *****************************************************************************
  401. // *****************************************************************************
  402. constructor TNewtonCustomJointBallAndSocket.Create(aPivot: TVector3f; aChild, aParent: PNewtonBody);
  403. var
  404.  LMatrix : TMatrix4f;
  405.  LPin    : TVector4f;
  406. begin
  407. inherited
  408. Create(5, aChild, aParent);
  409. // use as primary pin vector the line that goes from the pivot to the origin of body zero
  410. // this eliminates some offset unwanted torques
  411. NewtonBodyGetMatrix(FBody0, @LMatrix[0, 0]);
  412. LPin := VSub(V4(LMatrix[0,3], LMatrix[1,3], LMatrix[2,3], LMatrix[3,3]), V4(aPivot[0], aPivot[1], aPivot[2], 0));
  413. // the the pivot is already at the origin
  414. if VDot(LPin, LPin) < 1.0e-3 then
  415.  LPin := V4(LMatrix[0,0], LMatrix[1,0], LMatrix[2,0], LMatrix[3,0]);
  416. // calculate the two local matrix of the pivot point
  417. CalculateLocalMatrix(aPivot, V3(LPin[0], LPin[1], LPin[2]), FLocalMatrix0, FLocalMatrix1);
  418. end;
  419. procedure TNewtonCustomJointBallAndSocket.SubmitConstraint;
  420. var
  421.  LMatrix0 : TMatrix4f;
  422.  LMatrix1 : TMatrix4f;
  423. Begin
  424. // calculate the position of the pivot point and the jacobian direction vectors, in global space.
  425. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, LMatrix0, LMatrix1);
  426. // Restrict the movement on the pivot point along all tree orthonormal direction
  427. NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix1[3, 0], @LMatrix0[0, 0]);
  428. NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix1[3, 0], @LMatrix0[1, 0]);
  429. NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix1[3, 0], @LMatrix0[2, 0]);
  430. end;
  431. // *****************************************************************************
  432. // *****************************************************************************
  433. //  Limited Ball And Socket
  434. // *****************************************************************************
  435. // *****************************************************************************
  436. constructor TNewtonCustomJointLimitedBallAndSocket.Create(aPivot, aConeDir: TVector3f; aConeAngle, aTwistAngle: Single; aChild, aParent: PNewtonBody);
  437. Begin
  438. inherited
  439. Create(aPivot, aChild, aParent);
  440. FConeAngle    := aConeAngle * PI / 180;
  441. FTwistAngle   := aTwistAngle * PI / 180;
  442. FCosConeAngle := Cos(FConeAngle);
  443. // Recalculate local matrices so that the front vector align with the cone pin
  444. CalculateLocalMatrix(aPivot, aConeDir, FLocalMatrix0, FLocalMatrix1);
  445. end;
  446. procedure TNewtonCustomJointLimitedBallAndSocket.SubmitConstraint;
  447. var
  448.  LConeCos        : Single;
  449.  LMatrix0        : TMatrix4f;
  450.  LMatrix1        : TMatrix4f;
  451.  LP0             : TVector4f;
  452.  LP1             : TVector4f;
  453.  LLateralDir     : TVector4f;
  454.  LUnitLateralDir : TVector4f;
  455.  LTangentDir     : TVector4f;
  456. begin
  457. // calculate the position of the pivot point and the Jacobian direction vectors, in global space.
  458. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, LMatrix0, LMatrix1);
  459. // Restrict the movement on the pivot point along all tree orthonormal direction
  460. NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix1[3, 0], @LMatrix0[0, 0]);
  461. NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix1[3, 0], @LMatrix0[1, 0]);
  462. NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix1[3, 0], @LMatrix0[2, 0]);
  463. // add a row to keep the child body inside the cone limit
  464. // The child is inside the cone if the cos of the angle between the pin and
  465. LConeCos := VDot(V4(LMatrix0[0,0], LMatrix0[1,0], LMatrix0[2,0], LMatrix0[3,0]), V4(LMatrix1[0,0], LMatrix1[1,0], LMatrix1[2,0], LMatrix1[3,0]));
  466. if LConeCos < FCosConeAngle then
  467.  begin
  468.  // the child body has violated the cone limit we need to stop it from keep moving
  469.  // for that we are going to pick a point along the the child body front vector
  470.  LP0 := VAdd(V4(LMatrix0, 3), VScale(V4(LMatrix0,0), MIN_JOINT_PIN_LENGTH));
  471.  LP1 := VAdd(V4(LMatrix1, 3), VScale(V4(LMatrix1,0), MIN_JOINT_PIN_LENGTH));
  472.  // get a vectors perpendicular to the plane of motion
  473.  LLateralDir := VCross(V4(LMatrix0,0), V4(LMatrix1,0));
  474.  // note this could fail if the angle between matrix0.m_front and matrix1.m_front is 90 degree
  475.  LUnitLateralDir := VScale(LLateralDir, 1.0 / sqrt(VDot(LLateralDir, LLateralDir)));
  476.  // now we will add a constraint row along the lateral direction,
  477.  // this will add stability as it will prevent the child body from moving sideways
  478.  NewtonUserJointAddLinearRow(FJoint, @LP0[0], @LP0[0], @LUnitLateralDir[0]);
  479.  // calculate the unit vector tangent to the trajectory
  480.  LTangentDir := VCross(LUnitLateralDir, V4(LMatrix0,0));
  481.  LP1 := VAdd(LP0, VScale(VSub(LP1, LP0), 0.2));
  482.  NewtonUserJointAddLinearRow(FJoint, @LP0[0], @LP1[0], @LTangentdir[0]);
  483.  // we need to allow the body to mo in opposite direction to the penetration
  484.  // that can be done by setting the min friction to zero
  485.  NewtonUserJointSetRowMinimumFriction(FJoint, 0.0);
  486.  end;
  487. end;
  488. // *****************************************************************************
  489. // *****************************************************************************
  490. //  Corkscrew
  491. // *****************************************************************************
  492. // *****************************************************************************
  493. constructor TNewtonCustomJointCorkScrew.Create(aPivot, aPin: TVector3f; aChild, aParent: PNewtonBody);
  494. Begin
  495. inherited
  496. Create(6, aChild, aParent);
  497. FLimitsOn       := False;
  498. FMinDist        := -1.0;
  499. FMaxDist        := 1.0;
  500. FAngularMotorOn := False;
  501. FAngularDamp    := 0.1;
  502. FAngularAccel   := 5.0;
  503. // Calculate the two local matrix of the pivot point
  504. CalculateLocalMatrix(aPivot, aPin, FLocalMatrix0, FLocalMatrix1);
  505. end;
  506. procedure TNewtonCustomJointCorkScrew.EnableLimits(aEnabled: Boolean);
  507. Begin
  508. FLimitsOn := aEnabled;
  509. end;
  510. procedure TNewtonCustomJointCorkScrew.SetLimits(aMinDist, aMaxDist: Single);
  511. Begin
  512. FMinDist := aMinDist;
  513. FMaxDist := aMaxDist;
  514. end;
  515. procedure TNewtonCustomJointCorkScrew.SubmitConstraint;
  516. var
  517.  LDist     : Single;
  518.  LMatrix0  : TMatrix4f;
  519.  LMatrix1  : TMatrix4f;
  520.  LP0       : TVector4f;
  521.  LP1       : TVector4f;
  522.  LQ0       : TVector4f;
  523.  LQ1       : TVector4f;
  524.  LRelOmega : Single;
  525.  LRelAccel : Single;
  526.  LOmega0   : TVector4f;
  527.  LOmega1   : TVector4f;
  528. begin
  529. // Calculate the position of the pivot point and the Jacobian direction vectors, in global space.
  530. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, LMatrix0, LMatrix1);
  531. // Restrict the movement on the pivot point along all tree orthonormal direction
  532. LP0 := V4(LMatrix0,3);
  533. LP1 := VAdd(V4(LMatrix1,3), VScale(V4(LMatrix1,0), VDot(VSub(LP0, V4(LMatrix1,3)), V4(LMatrix1,0))));
  534. NewtonUserJointAddLinearRow(FJoint, @LP0[0], @LP1[0], @LMatrix0[1, 0]);
  535. NewtonUserJointAddLInearRow(FJoint, @LP0[0], @LP1[0], @LMatrix1[2, 0]);
  536. // Get a point along the pin axis at some reasonable large distance from the pivot
  537. LQ0 := VAdd(LP0, VScale(V4(LMatrix0,0), MIN_JOINT_PIN_LENGTH));
  538. LQ1 := VAdd(LP1, VScale(V4(LMatrix1,0), MIN_JOINT_PIN_LENGTH));
  539. // Two constraints row perpendiculars to the hinge pin
  540. NewtonUserJointAddLinearRow(FJoint, @LQ0[0], @LQ1[0], @LMatrix0[1, 0]);
  541. NewtonUserJointAddLinearRow(FJoint, @LQ0[0], @LQ1[0], @LMatrix0[2, 0]);
  542. if FLimitsOn then
  543.  begin
  544.  LDist := VDot(VSub(V4(LMatrix0,3), V4(LMatrix1,3)), V4(LMatrix0,0));
  545.  if LDist < FMinDist then
  546.   begin
  547.   // get a point along the up vector and set a constraint
  548.   NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix0[3, 0], @LMatrix0[0, 0]);
  549.   // allow the object to return but not to kick going forward
  550.   NewtonUserJointSetRowMinimumFriction(FJoint, 0);
  551.   end
  552.  else
  553.   if LDist > FMaxDist then
  554.    begin
  555.    // get a point along the up vector and set a constraint
  556.    NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix0[3, 0], @LMatrix0[0, 0]);
  557.    //  allow the object to return but not to kick going forward
  558.    NewtonUserJointSetRowMaximumFriction(FJoint, 0);
  559.    end;
  560.   end;
  561.  if FAngularMotorOn then
  562.   begin
  563.   LOmega0 := V4(0, 0, 0);
  564.   LOmega1 := V4(0, 0, 0);
  565.   // get relative angular velocity
  566.   NewtonBodyGetOmega(FBody0, @LOmega0[0]);
  567.   if FBody1 <> nil then
  568.    NewtonBodyGetOmega(FBody1, @LOmega1[0]);
  569.   // calculate the desired acceleration
  570.   LRelOmega := VDot(VSub(LOmega0, LOmega1), V4(LMatrix0,0));
  571.   LRelAccel := FAngularAccel - FAngularDamp * LRelOmega;
  572.   // if the motor capability is on, then set angular acceleration with zero angular correction
  573.   NewtonUserJointAddAngularRow(FJoint, 0.0, @LMatrix0[0, 0]);
  574.   // override the angular acceleration for this Jacobian to the desired acceleration
  575.   NewtonUserJointSetRowAcceleration(FJoint, LRelAccel);
  576.   end;
  577. end;
  578. // *****************************************************************************
  579. // *****************************************************************************
  580. //  Slider
  581. // *****************************************************************************
  582. // *****************************************************************************
  583. constructor TNewtonCustomJointSlider.Create(aPivot, aPin: TVector3f; aChild, aParent: PNewtonBody);
  584. begin
  585. inherited
  586. Create(6, aChild, aParent);
  587. FLimitsOn := False;
  588. FMinDist  := -1.0;
  589. FMaxDist  := 1.0;
  590. // calculate the two local matrix of the pivot point
  591. CalculateLocalMatrix(aPivot, aPin, FLocalMatrix0, FLocalMatrix1);
  592. end;
  593. procedure TNewtonCustomJointSlider.EnableLimits(aEnabled: Boolean);
  594. Begin
  595. FLimitsOn := aEnabled;
  596. end;
  597. procedure TNewtonCustomJointSlider.SetLimits(aMinDist, aMaxDist: Single);
  598. Begin
  599. FMinDist := aMinDist;
  600. FMaxDist := aMaxDist;
  601. end;
  602. procedure TNewtonCustomJointSlider.SubmitConstraint;
  603. var
  604.  LDist    : Single;
  605.  LMatrix0 : TMatrix4f;
  606.  LMatrix1 : TMatrix4f;
  607.  LP0      : TVector4f;
  608.  LP1      : TVector4f;
  609.  LQ0      : TVector4f;
  610.  LQ1      : TVector4f;
  611.  LR0      : TVector4f;
  612.  LR1      : TVector4f;
  613. begin
  614. // calculate the position of the pivot point and the Jacobian direction vectors, in global space.
  615. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, LMatrix0, LMatrix1);
  616. // Restrict the movement on the pivot point along all tree orthonormal direction
  617. LP0 := V4(LMatrix0,3);
  618. LP1 := VAdd(V4(LMatrix1,3), VScale(V4(LMatrix1,0), VDot(VSub(LP0, V4(LMatrix1,3)), V4(LMatrix1,0))));
  619. NewtonUserJointAddLinearRow(FJoint, @LP0[0], @LP1[0], @LMatrix0[1, 0]);
  620. NewtonUserJointAddLinearRow(FJoint, @LP0[0], @LP1[0], @LMatrix0[2, 0]);
  621. // get a point along the ping axis at some reasonable large distance from the pivot
  622. LQ0 := VAdd(LP0, VScale(V4(LMatrix0,0), MIN_JOINT_PIN_LENGTH));
  623. LQ1 := VAdd(LP1, VScale(V4(LMatrix1,0), MIN_JOINT_PIN_LENGTH));
  624. // two constraints row perpendicular to the pin
  625. NewtonUserJointAddLinearRow(FJoint, @LQ0[0], @LQ1[0], @LMatrix0[1, 0]);
  626. NewtonUserJointAddLinearRow(FJoint, @LQ0[0], @LQ1[0], @LMatrix0[2, 0]);
  627. // get a point along the ping axis at some reasonable large distance from the pivot
  628. LR0 := VAdd(LP0, VScale(V4(LMatrix0,1), MIN_JOINT_PIN_LENGTH));
  629. LR1 := VAdd(LP0, VScale(V4(LMatrix1,1), MIN_JOINT_PIN_LENGTH));
  630. // one constraint row perpendicular to the pin
  631. NewtonUserJointAddLinearRow(FJoint, @LR0[0], @LR1[0], @LMatrix0[2, 0]);
  632. if FLimitsOn then
  633.  begin
  634.  LDist := VDot(VSub(V4(LMatrix0,3), V4(LMatrix1,3)), V4(LMatrix0,0));
  635.  if LDist < FMinDist then
  636.   begin
  637.   // get a point along the up vector and set a constraint
  638.   NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix0[3, 0], @LMatrix0[0, 0]);
  639.   // allow the object to return but not to kick going forward
  640.   NewtonUserJointSetRowMinimumFriction(FJoint, 0.0);
  641.   end
  642.  else
  643.   if LDist > FMaxDist then
  644.    begin
  645.    // invert the matrix for the stop limits on the other side. this is a bug fix for the origional SDK joint
  646.    Matrix_Inverse(LMatrix1);
  647.    // get a point along the up vector and set a constraint
  648.    NewtonUserJointAddLinearRow(FJoint, @LMatrix1[3, 0], @LMatrix1[3, 0], @LMatrix1[0, 0]);
  649.    // allow the object to return but not to kick going forward
  650.    NewtonUserJointSetRowMinimumFriction(FJoint, 0.0);
  651.    end;
  652.  end;
  653. end;
  654. // *****************************************************************************
  655. // *****************************************************************************
  656. //  Hinge
  657. // *****************************************************************************
  658. // *****************************************************************************
  659. constructor TNewtonCustomJointHinge.Create(aPivot, aPin: TVector3f; aChild, aParent: PNewtonBody);
  660. Begin
  661. inherited Create(6, aChild, aParent);
  662. FLimitsOn     := False;
  663. FMinAngle     := -45 * PI / 180;
  664. FMaxAngle     := 45 * PI / 180;
  665. // calculate the two local matrix of the pivot point
  666. CalculateLocalMatrix(aPivot, aPin, FLocalMatrix0, FLocalMatrix1);
  667. end;
  668. procedure TNewtonCustomJointHinge.EnableLimits(aEnabled: Boolean);
  669. begin
  670. FLimitsOn := aEnabled;
  671. end;
  672. procedure TNewtonCustomJointHinge.SetLimits(aMinAngle, aMaxAngle: Single);
  673. begin
  674. FMinAngle := aMinAngle * PI / 180;
  675. FMaxAngle := aMaxAngle * PI / 180;
  676. end;
  677. procedure TNewtonCustomJointHinge.SubmitConstraint;
  678. var
  679.  LAngle    : Single;
  680.  LSinAngle : Single;
  681.  LCosAngle : Single;
  682.  LRelAngle : Single;
  683.  LMatrix0  : TMatrix4f;
  684.  LMatrix1  : TMatrix4f;
  685.  LQ0       : TVector4f;
  686.  LQ1       : TVector4f;
  687. begin
  688. if FJoint = nil then
  689.  exit;
  690. // calculate the position of the pivot point and the Jacobian direction vectors, in global space.
  691. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, LMatrix0, LMatrix1);
  692. // Restrict the movement on the pivot point along all tree orthonormal direction
  693. NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix1[3, 0], @LMatrix0[0, 0]);
  694. NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix1[3, 0], @LMatrix0[1, 0]);
  695. NewtonUserJointAddLinearRow(FJoint, @LMatrix0[3, 0], @LMatrix1[3, 0], @LMatrix0[2, 0]);
  696. // get a point along the pin axis at some reasonable large distance from the pivot
  697. LQ0 := VAdd(V4(LMatrix0,3), VScale(V4(LMatrix0,0), MIN_JOINT_PIN_LENGTH));
  698. LQ1 := VAdd(V4(LMatrix0,3), VScale(V4(LMatrix0,0), MIN_JOINT_PIN_LENGTH));
  699. // two constraints row perpendiculars to the hinge pin
  700. NewtonUserJointAddLinearRow(FJoint, @LQ0[0], @LQ1[0], @LMatrix0[1, 0]);
  701. NewtonUserJointAddLinearRow(FJoint, @LQ0[0], @LQ1[0], @LMatrix0[2, 0]);
  702. // the joint angle can be determine by getting the angle between any two non parallel vectors
  703. LSinAngle := VDot(V4(LMatrix0,0), VCross(V4(LMatrix0,1), V4(LMatrix1,1)));
  704. LCosAngle := VDot(V4(LMatrix0,1), V4(LMatrix1,1));
  705. LAngle    := ArcTan2(LSinAngle, LCosAngle);
  706. // Limit angular movement
  707. if FLimitsOn then
  708.  begin
  709.  if LAngle < FMinAngle then
  710.   begin
  711.   LRelAngle := LAngle - FMinAngle;
  712.   // tell joint error will minimize the exceeded angle error
  713.   NewtonUserJointAddAngularRow(FJoint, LRelAngle, @LMatrix0[0, 0]);
  714.   // need high stiffness here
  715.   NewtonUserJointSetRowStiffness(FJoint, 1.0);
  716.   end
  717.  else
  718.   if LAngle > FMaxAngle then
  719.    begin
  720.    LRelAngle := LAngle - FMaxAngle;
  721.    // tell joint error will minimize the exceeded angle error
  722.    NewtonUserJointAddAngularRow(FJoint, LRelAngle, @LMatrix0[0, 0]);
  723.    // need high stiffness here
  724.    NewtonUserJointSetRowStiffness(FJoint, 1.0);
  725.    end;
  726.  end;
  727. end;
  728. // *****************************************************************************
  729. // *****************************************************************************
  730. //  Dry Rolling Friction
  731. // *****************************************************************************
  732. // *****************************************************************************
  733. constructor TNewtonCustomJointDryRollingFriction.Create(aRadius, aCoefficient: Single; aChild: PNewtonBody);
  734. var
  735.  LMass : Single;
  736.  LIxx  : Single;
  737.  LIyy  : Single;
  738.  LIzz  : Single;
  739. Begin
  740. inherited
  741. Create(1, aChild, nil);
  742. NewtonBodyGetMassMatrix(aChild, @LMass, @LIxx, @LIyy, @LIzz);
  743. FFrictionCoef   := aCoefficient;
  744. FFrictionTorque := LIxx * aRadius;
  745. end;
  746. // rolling friction works as follow: the idealization of the contact of a spherical object
  747. // with a another surface is a point that pass by the center of the sphere.
  748. // in most cases this is enough to model the collision but in insufficient for modeling
  749. // the rolling friction. In reality contact with the sphere with the other surface is not
  750. // a point but a contact patch. A contact patch has the property the it generates a fix
  751. // constant rolling torque that opposes the movement of the sphere.
  752. // we can model this torque by adding a clamped torque aligned to the instantaneously axis
  753. // of rotation of the ball. and with a magnitude of the stopping angular acceleration.
  754. procedure TNewtonCustomJointDryRollingFriction.SubmitConstraint;
  755. var
  756.  LOmega          : TVector3f;
  757.  LPin            : TVector3f;
  758.  LTime           : Single;
  759.  LOmegaMag       : Single;
  760.  LTorqueFriction : Single;
  761. Begin
  762. // get the omega vector
  763. NewtonBodyGetOmega(FBody0, @LOmega[0]);
  764. LOmegaMag := sqrt(VDot(LOmega, LOmega));
  765. if LOmegaMag > 0.1 then
  766.  begin
  767.  // Tell Newton to use the friction of the omega vector to apply the rolling friction
  768.  LPin := VScale(LOmega, 1.0 / LOmegaMag);
  769.  NewtonUserJointAddAngularRow(FJoint, 0.0, @LPin[0]);
  770.  // calculate the acceleration to stop the ball in one time step
  771.  LTime := NewtonGetTimeStep(FWorld);
  772.  NewtonUserJointSetRowAcceleration(FJoint, -LOmegaMag / LTime);
  773.  // set the friction limit proportional the sphere Inertia
  774.  LTorqueFriction := FFrictionTorque * FFrictionCoef;
  775.  NewtonUserJointSetRowMinimumFriction(FJoint, -LTorqueFriction);
  776.  NewtonUserJointSetRowMaximumFriction(FJoint, LTorqueFriction);
  777.  end
  778. else
  779.  begin
  780.  // when omega is too low scale a little bit and damp the omega directly
  781.  VScale(LOmega, 0.2);
  782.  NewtonBodySetOmega(FBody0, @LOmega[0]);
  783.  end;
  784. end;
  785. // *****************************************************************************
  786. // *****************************************************************************
  787. //  Universal
  788. // *****************************************************************************
  789. // *****************************************************************************
  790. constructor TNewtonCustomJointUniversal.Create(aPivot, aPin0, aPin1: TVector3f; aChild, aParent: PNewtonBody);
  791. var
  792.  LMatrix0      : TMatrix4f;
  793.  LMatrix1      : TMatrix4f;
  794.  LPinAndPivot  : TMatrix4f;
  795.  LMatrixInvert : TMatrix4f;
  796.  LPin0         : TVector4f;
  797.  LPin1         : TVector4f;
  798. begin
  799. inherited
  800. Create(6, aChild, aParent);
  801. LPin0 := V4(aPin0[0], aPin0[1], aPin0[2]);
  802. LPin1 := V4(aPin1[0], aPin1[1], aPin1[2]);
  803. FMinAngle0 := -45 * PI / 180;
  804. FMaxAngle0 :=  45 * PI / 180;
  805. FMinAngle1 := -45 * PI / 180;
  806. FMaxAngle1 :=  45 * PI / 180;
  807. FAngularDamp0  := 0.5;
  808. FAngularAccel0 := -4;
  809. FAngularDamp1  := 0.3;
  810. FAngularAccel1 := -4;
  811. // get the global matrices of each rigid body.
  812. NewtonBodyGetMatrix(FBody0, @LMatrix0[0, 0]);
  813. LMatrix1 := IdentityMatrix;
  814. if FBody1 <> nil then
  815.   NewtonBodyGetMatrix(FBody1, @LMatrix1[0, 0]);
  816. // create a global matrix at the pivot point with front vector aligned to the pin vector
  817. Matrix_SetColumn(LPinAndPivot, 0, VScale(LPin0, 1.0 / sqrt(VDot(LPin0, LPin0))));
  818. Matrix_SetColumn(LPinAndPivot, 2, VCross(LPin0, LPin1));
  819. Matrix_SetColumn(LPinAndPivot, 2, VScale(V4(LPinAndPivot,2), 1.0 / sqrt(VDot(V4(LPinAndPivot,2), V4(LPinAndPivot,2)))));
  820. Matrix_SetColumn(LPinAndPivot, 1, VCross(V4(LPinAndPivot,2), V4(LPinAndPivot,0)));
  821. Matrix_SetColumn(LPinAndPivot, 3, V4(aPivot[0], aPivot[1], aPivot[2], 1));
  822. // calculate the relative matrix of the pin and pivot on each body
  823. LMatrixInvert := LMatrix0;
  824. Matrix_Inverse(LMatrixInvert);
  825. FLocalMatrix0 := Matrix_Multiply(LPinAndPivot, LMatrixInvert);
  826. LMatrixInvert := LMatrix1;
  827. Matrix_Inverse(LMatrixInvert);
  828. FLocalMatrix1 := Matrix_Multiply(LPinAndPivot, LMatrixInvert);
  829. end;
  830. procedure TNewtonCustomJointUniversal.EnableLimit0(aEnabled: Boolean);
  831. begin
  832. FLimit0on := aEnabled;
  833. end;
  834. procedure TNewtonCustomJointUniversal.EnableLimit1(aEnabled: Boolean);
  835. begin
  836. FLimit1on := aEnabled;
  837. end;
  838. procedure TNewtonCustomJointUniversal.SetLimits0(aMinAngle, aMaxAngle: Single);
  839. begin
  840. FMinAngle0 := aMinAngle * PI / 180;
  841. FMaxAngle0 := aMaxAngle * PI / 180;
  842. end;
  843. procedure TNewtonCustomJointUniversal.SetLimits1(aMinAngle, aMaxAngle: Single);
  844. begin
  845. FMinAngle1 := aMinAngle * PI / 180;
  846. FMaxAngle1 := aMaxAngle * PI / 180;
  847. end;
  848. procedure TNewtonCustomJointUniversal.EnableMotor0(aEnabled: Boolean);
  849. begin
  850. FAngularMotor0On := aEnabled;
  851. end;
  852. procedure TNewtonCustomJointUniversal.EnableMotor1(aEnabled: Boolean);
  853. begin
  854. FAngularMotor1On := aEnabled;
  855. end;
  856. procedure TNewtonCustomJointUniversal.SubmitConstraint;
  857. var
  858.  LAngle    : Single;
  859.  LSinAngle : Single;
  860.  LCosAngle : Single;
  861.  LRelAngle : Single;
  862.  LRelOmega : Single;
  863.  LRelAccel : Single;
  864.  LMatrix0  : TMatrix4f;
  865.  LMatrix1  : TMatrix4f;
  866.  LDir0     : TVector4f;
  867.  LDir1     : TVector4f;
  868.  LDir2     : TVector4f;
  869.  LDir3     : TVector4f;
  870.  LP0       : TVector4f;
  871.  LP1       : TVector4f;
  872.  LQ0       : TVector4f;
  873.  LQ1       : TVector4f;
  874.  LOmega0   : TVector4f;
  875.  LOmega1   : TVector4f;
  876. begin
  877. // calculate the position of the pivot point and the Jacobian direction vectors, in global space.
  878. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, LMatrix0, LMatrix1);
  879. // get the pin fixed to the first body
  880. LDir0 := V4(LMatrix0, 0);
  881. // get the pin fixed to the second body
  882. LDir1 := V4(LMatrix1, 1);
  883. // construct an othoganal coordinate system with these two vectors
  884. LDir2 := VCross(LDir0, LDir1);
  885. LDir3 := VCross(LDir2, LDir0);
  886. LDir3 := VScale(LDir3, 1.0 / sqrt(VDot(LDir3, LDir3)));
  887. LP0 := V4(LMatrix0, 3);
  888. LP1 := V4(LMatrix1, 3);
  889. LQ0 := VAdd(LP0, VScale(LDir3, MIN_JOINT_PIN_LENGTH));
  890. LQ1 := VAdd(LP1, VScale(LDir1, MIN_JOINT_PIN_LENGTH));
  891. NewtonUserJointAddLinearRow(FJoint, @LP0[0], @LP1[0], @LDir0[0]);
  892. NewtonUserJointSetRowStiffness(FJoint, 1.0);
  893. NewtonUserJointAddLinearRow(FJoint, @LP0[0], @LP1[0], @LDir1[0]);
  894. NewtonUserJointSetRowStiffness(FJoint, 1.0);
  895. NewtonUserJointAddLinearRow(FJoint, @LP0[0], @LP1[0], @LDir2[0]);
  896. NewtonUserJointSetRowStiffness(FJoint, 1.0);
  897. NewtonUserJointAddLinearRow(FJoint, @LQ0[0], @LQ1[0], @LDir0[0]);
  898. NewtonUserJointSetRowStiffness(FJoint, 1.0);
  899. if FLimit0On then
  900.  begin
  901.  LSinAngle := VDot(V4(LMatrix1,1), VCross(V4(LMatrix0,0), V4(LMatrix1,0)));
  902.  LCosAngle := VDot(V4(LMatrix0,0), V4(LMatrix1,0));
  903.  LAngle    := ArcTan2(LSinAngle, LCosAngle);
  904.  if LAngle < FMinAngle0 then
  905.   begin
  906.   LRelAngle := LAngle - FMinAngle0;
  907.   // tell joint error will minimize the exceeded angle error
  908.   NewtonUserJointAddAngularRow(FJoint, LRelAngle, @LMatrix1[1, 0]);
  909.   // need high stiffness here
  910.   NewtonUserJointSetRowStiffness(FJoint, 1.0);
  911.   end
  912.  else
  913.   if LAngle > FMaxAngle0 then
  914.    begin
  915.    LRelAngle := LAngle - FMaxAngle0;
  916.    // tell joint error will minimize the exceeded angle error
  917.    NewtonUserJointAddAngularRow(FJoint, LRelAngle, @LMatrix1[1, 0]);
  918.    // need high stiffness here
  919.    NewtonUserJointSetRowStiffness(FJoint, 1.0);
  920.    end;
  921.  end
  922.  else
  923.   if FAngularMotor0On then
  924.    begin
  925.    // get relative angular velocity
  926.    NewtonBodyGetOmega(FBody0, @LOmega0[0]);
  927.    if FBody1 <> nil then
  928.     NewtonBodyGetOmega(FBody1, @LOmega1[0])
  929.    else
  930.     LOmega1 := V4(0,0,0,0);
  931.    // calculate the desired acceleration
  932.    LRelOmega := VDot(VSub(LOmega0, LOmega1), V4(LMatrix1, 1));
  933.    LRelAccel := FAngularAccel0 - FAngularDamp0 * LRelOmega;
  934.    // add an angular constraint row that will set the relative acceleration to zero
  935.    NewtonUserJointAddAngularRow(FJoint, 0.0, @LMatrix1[1, 0]);
  936.    NewtonUserJointSetRowAcceleration(FJoint, LRelAccel);
  937.    end;
  938. if FLimit1On then
  939.  begin
  940.  LSinAngle := VDot(V4(LMatrix0, 0), VCross(V4(LMatrix0, 1), V4(LMatrix1, 1)));
  941.  LCosAngle := VDot(V4(LMatrix0, 1), V4(LMatrix1, 1));
  942.  LAngle    := ArcTan2(LSinAngle, LCosAngle);
  943.  if LAngle < FMinAngle1 then
  944.   begin
  945.   LRelAngle := LAngle - FMinAngle1;
  946.   // tell joint error will minimize the exceeded angle error
  947.   NewtonUserJointAddAngularRow(FJoint, LRelAngle, @LMatrix0[0, 0]);
  948.   // need high stiffness here
  949.   NewtonUserJointSetRowStiffness(FJoint, 1.0);
  950.   end
  951.  else
  952.   if LAngle > FMaxAngle1 then
  953.    begin
  954.    LRelAngle := LAngle - FMaxAngle1;
  955.    // tell joint error will minimize the exceeded angle error
  956.    NewtonUserJointAddAngularRow(FJoint, LRelAngle, @LMatrix0[0, 0]);
  957.    // need high stiffness here
  958.    NewtonUserJointSetRowStiffness(FJoint, 1.0);
  959.    end;
  960.   end
  961.  else
  962.   if FAngularMotor1On then
  963.    begin
  964.    // get relative angular velocity
  965.    NewtonBodyGetOmega(FBody0, @LOmega0[0]);
  966.    if FBody1 <> nil then
  967.      NewtonBodyGetOmega(FBody1, @LOmega1[0])
  968.    else
  969.     LOmega1 := V4(0,0,0,0);
  970.    // calculate the desired acceleration
  971.    LRelOmega := VDot(VSub(LOmega0, LOmega1), V4(LMatrix0, 0));
  972.    LRelAccel := FAngularAccel1 - FAngularDamp1 * LRelOmega;
  973.    // add an angular constraint row that will set the relative acceleration to zero
  974.    NewtonUserJointAddAngularRow(FJoint, 0.0, @LMatrix0[0, 0]);
  975.    NewtonUserJointSetRowAcceleration(FJoint, LRelAccel);
  976.    end;
  977. end;
  978. // *****************************************************************************
  979. // *****************************************************************************
  980. //  Gear
  981. // *****************************************************************************
  982. // *****************************************************************************
  983. constructor TNewtonCustomJointGear.Create(aGearRatio : Single; aChildPin, aParentPin : TVector3f; aParentBody, aChildBody : PNewtonBody);
  984. var
  985.  Pivot       : TVector3f;
  986.  DummyMatrix : TMatrix4f;
  987. begin
  988. inherited Create(1, aChildBody, aParentBody);
  989. FGearRatio := aGearRatio;
  990. // calculate the two local matrix of the pivot point
  991. Pivot := V3(0, 0, 0);
  992. // calculate the local matrix for body body0
  993. CalculateLocalMatrix(Pivot, aChildPin, FLocalMatrix0, DummyMatrix);
  994. // calculate the local matrix for body body1
  995. CalculateLocalMatrix(Pivot, aParentPin, DummyMatrix, FlocalMatrix1);
  996. end;
  997. procedure TNewtonCustomJointGear.SubmitConstraint;
  998. var
  999.  w0, w1    : Single;
  1000.  Time      : Single;
  1001.  RelAccel  : Single;
  1002.  RelOmega  : Single;
  1003.  Omega0    : TVector3f;
  1004.  Omega1    : TVector3f;
  1005.  Matrix0   : TMatrix4f;
  1006.  Matrix1   : TMatrix4f;
  1007.  Jacobian0 : array[0..5] of Single;
  1008.  Jacobian1 : array[0..5] of Single;
  1009. begin
  1010. // calculate the position of the pivot point and the Jacobian direction vectors, in global space.
  1011. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, Matrix0, Matrix1);
  1012. // calculate the angular velocity for both bodies
  1013. NewtonBodyGetOmega(FBody0, @Omega0[0]);
  1014. NewtonBodyGetOmega(FBody1, @Omega1[0]);
  1015. // get angular velocity relative to the pin vector
  1016. w0 := VDot(Omega0, V3(Matrix0, 0));
  1017. w1 := VDot(Omega1, V3(Matrix1, 0));
  1018. // establish the gear equation.
  1019. RelOmega := w0 + FGearRatio * w1;
  1020. // calculate the relative angular acceleration by dividing by the time step
  1021. Time     := NewtonGetTimeStep(FWorld);
  1022. RelAccel := -RelOmega / Time;
  1023. // set the linear part of Jacobian 0 to zero
  1024. Jacobian0[0] := 0;
  1025. Jacobian0[1] := 0;
  1026. Jacobian0[2] := 0;
  1027. // set the angular part of Jacobian 0 pin vector
  1028. Jacobian0[3] := V3(Matrix0, 0)[0];
  1029. Jacobian0[4] := V3(Matrix0, 0)[1];
  1030. Jacobian0[5] := V3(Matrix0, 0)[2];
  1031. // set the linear part of Jacobian 1 to zero
  1032. Jacobian1[0] := 0;
  1033. Jacobian1[1] := 0;
  1034. Jacobian1[2] := 0;
  1035. // set the angular part of Jacobian 1 pin vector
  1036. Jacobian1[3] := V3(matrix1, 0)[0];
  1037. Jacobian1[4] := V3(matrix1, 0)[1];
  1038. Jacobian1[5] := V3(matrix1, 0)[2];
  1039. // add a angular constraint
  1040. NewtonUserJointAddGeneralRow(FJoint, @Jacobian0[0], @Jacobian1[0]);
  1041. // set the desired angular acceleration between the two bodies
  1042. NewtonUserJointSetRowAcceleration(FJoint, RelAccel);
  1043. end;
  1044. // *****************************************************************************
  1045. // *****************************************************************************
  1046. //  Pulley
  1047. // *****************************************************************************
  1048. // *****************************************************************************
  1049. constructor TNewtonCustomJointPulley.Create(aGearRatio : Single; aChildPin, aParentPin : TVector3f; aParentBody, aChildBody : PNewtonBody);
  1050. var
  1051.  Pivot       : TVector3f;
  1052.  DummyMatrix : TMatrix4f;
  1053. begin
  1054. inherited Create(1, aChildBody, aParentBody);
  1055. FGearRatio := aGearRatio;
  1056. // calculate the two local matrix of the pivot point
  1057. Pivot := V3(0, 0, 0);
  1058. // calculate the local matrix for body body0
  1059. CalculateLocalMatrix(Pivot, aChildPin, FLocalMatrix0, DummyMatrix);
  1060. // calculate the local matrix for body body1
  1061. CalculateLocalMatrix(Pivot, aParentPin, DummyMatrix, FlocalMatrix1);
  1062. end;
  1063. procedure TNewtonCustomJointPulley.SubmitConstraint;
  1064. var
  1065.  w0, w1    : Single;
  1066.  Time      : Single;
  1067.  RelAccel  : Single;
  1068.  RelVeloc  : Single;
  1069.  Veloc0    : TVector3f;
  1070.  Veloc1    : TVector3f;
  1071.  Matrix0   : TMatrix4f;
  1072.  Matrix1   : TMatrix4f;
  1073.  Jacobian0 : array[0..5] of Single;
  1074.  Jacobian1 : array[0..5] of Single;
  1075. begin
  1076. // calculate the position of the pivot point and the Jacobian direction vectors, in global space.
  1077. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, Matrix0, Matrix1);
  1078. // calculate the angular velocity for both bodies
  1079. NewtonBodyGetVelocity(FBody0, @Veloc0[0]);
  1080. NewtonBodyGetVelocity(FBody1, @Veloc1[0]);
  1081. // get angular velocity relative to the pin vector
  1082. w0 := VDot(Veloc0, V3(Matrix0, 0));
  1083. w1 := VDot(Veloc1, V3(Matrix1, 0));
  1084. // establish the gear equation.
  1085. RelVeloc := w0 + FGearRatio * w1;
  1086. // calculate the relative angular acceleration by dividing by the time step
  1087. Time     := NewtonGetTimeStep(FWorld);
  1088. RelAccel := -RelVeloc / Time;
  1089. // set the linear part of Jacobian 0 to translational pin vector
  1090. Jacobian0[0] := V3(Matrix0, 0)[0];
  1091. Jacobian0[1] := V3(Matrix0, 0)[1];
  1092. Jacobian0[2] := V3(Matrix0, 0)[2];
  1093. // set the rotational part of Jacobian 0 to zero
  1094. Jacobian0[3] := 0;
  1095. Jacobian0[4] := 0;
  1096. Jacobian0[5] := 0;
  1097. // set the linear part of Jacobian 1 to translational pin vector
  1098. Jacobian1[0] := V3(matrix1, 0)[0];
  1099. Jacobian1[1] := V3(matrix1, 0)[1];
  1100. Jacobian1[2] := V3(matrix1, 0)[2];
  1101. // set the rotational part of Jacobian 1 to zero
  1102. Jacobian1[3] := 0;
  1103. Jacobian1[4] := 0;
  1104. Jacobian1[5] := 0;
  1105. // add a angular constraint
  1106. NewtonUserJointAddGeneralRow(FJoint, @Jacobian0[0], @Jacobian1[0]);
  1107. // set the desired angular acceleration between the two bodies
  1108. NewtonUserJointSetRowAcceleration(FJoint, RelAccel);
  1109. end;
  1110. // *****************************************************************************
  1111. // *****************************************************************************
  1112. //  Worm Gear
  1113. // *****************************************************************************
  1114. // *****************************************************************************
  1115. constructor TNewtonCustomJointWormGear.Create(aGearRatio : Single; aRotationalPin, aLinearPin : TVector3f; aRotationalBody, aLinearBody : PNewtonBody);
  1116. var
  1117.  Pivot       : TVector3f;
  1118.  DummyMatrix : TMatrix4f;
  1119. begin
  1120. inherited Create(1, aRotationalBody, aLinearBody);
  1121. FGearRatio := aGearRatio;
  1122. // calculate the two local matrix of the pivot point
  1123. Pivot := V3(0, 0, 0);
  1124. // calculate the local matrix for body body0
  1125. CalculateLocalMatrix(Pivot, aRotationalPin, FLocalMatrix0, DummyMatrix);
  1126. // calculate the local matrix for body body1
  1127. CalculateLocalMatrix(Pivot, aLinearPin, DummyMatrix, FlocalMatrix1);
  1128. end;
  1129. procedure TNewtonCustomJointWormGear.SubmitConstraint;
  1130. var
  1131.  w0, w1    : Single;
  1132.  Time      : Single;
  1133.  RelAccel  : Single;
  1134.  RelVeloc  : Single;
  1135.  Omega0    : TVector3f;
  1136.  Veloc1    : TVector3f;
  1137.  Matrix0   : TMatrix4f;
  1138.  Matrix1   : TMatrix4f;
  1139.  Jacobian0 : array[0..5] of Single;
  1140.  Jacobian1 : array[0..5] of Single;
  1141. begin
  1142. // calculate the position of the pivot point and the Jacobian direction vectors, in global space.
  1143. CalculateGlobalMatrix(FLocalMatrix0, FLocalMatrix1, Matrix0, Matrix1);
  1144. // calculate the angular velocity for both bodies
  1145. NewtonBodyGetOmega(FBody0, @Omega0[0]);
  1146. NewtonBodyGetVelocity(FBody1, @Veloc1[0]);
  1147. // get angular velocity relative to the pin vector
  1148. w0 := VDot(Omega0, V3(Matrix0, 0));
  1149. w1 := VDot(Veloc1, V3(Matrix1, 0));
  1150. // establish the gear equation.
  1151. RelVeloc := w0 + FGearRatio * w1;
  1152. // calculate the relative angular acceleration by dividing by the time step
  1153. Time     := NewtonGetTimeStep(FWorld);
  1154. RelAccel := -RelVeloc / Time;
  1155. // set the linear part of Jacobian 0 to zero
  1156. Jacobian0[0] := 0;
  1157. Jacobian0[1] := 0;
  1158. Jacobian0[2] := 0;
  1159. // set the rotational part of Jacobian 0 to pin vector
  1160. Jacobian0[3] := V3(Matrix0, 0)[0];
  1161. Jacobian0[4] := V3(Matrix0, 0)[0];
  1162. Jacobian0[5] := V3(Matrix0, 0)[0];
  1163. // set the linear part of Jacobian 1 to translational pin vector
  1164. Jacobian1[0] := V3(matrix1, 0)[0];
  1165. Jacobian1[1] := V3(matrix1, 0)[1];
  1166. Jacobian1[2] := V3(matrix1, 0)[2];
  1167. // set the rotational part of Jacobian 1 to zero
  1168. Jacobian1[3] := 0;
  1169. Jacobian1[4] := 0;
  1170. Jacobian1[5] := 0;
  1171. // add a angular constraint
  1172. NewtonUserJointAddGeneralRow(FJoint, @Jacobian0[0], @Jacobian1[0]);
  1173. // set the desired angular acceleration between the two bodies
  1174. NewtonUserJointSetRowAcceleration(FJoint, RelAccel);
  1175. end;
  1176. end.