GLVerletTypes.pas 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLVerletTypes;
  5. (*
  6. Base Verlet modelling/simulation classes.
  7. This unit is generic, GLScene-specific sub-classes are in GLVerletClasses.
  8. Note that currently, the SatisfyConstraintForEdge methods push the nodes in
  9. the edge uniformly - it should push the closer node more for correct physics.
  10. It's a matter of leverage.
  11. *)
  12. interface
  13. {$I GLScene.inc}
  14. uses
  15. System.Classes,
  16. System.SysUtils,
  17. System.Types,
  18. GLObjects,
  19. GLScene,
  20. GLCoordinates,
  21. GLVectorGeometry,
  22. GLVectorLists,
  23. GLSpacePartition,
  24. GLGeometryBB,
  25. GLVectorTypes;
  26. const
  27. G_DRAG = 0.0001;
  28. cDEFAULT_CONSTRAINT_FRICTION = 0.6;
  29. type
  30. TGLVerletEdgeList = class;
  31. TGLVerletWorld = class;
  32. TVerletProgressTimes = packed record
  33. deltaTime, newTime: Double;
  34. sqrDeltaTime, invSqrDeltaTime: Single;
  35. end;
  36. // Basic verlet node
  37. TVerletNode = class(TSpacePartitionLeaf)
  38. private
  39. FForce: TAffineVector;
  40. FOwner: TGLVerletWorld;
  41. FWeight, FInvWeight: Single;
  42. FRadius: Single;
  43. FNailedDown: Boolean;
  44. FFriction: Single;
  45. FChangedOnStep: Integer;
  46. function GetSpeed: TAffineVector;
  47. protected
  48. FLocation, FOldLocation: TAffineVector;
  49. procedure SetLocation(const Value: TAffineVector); virtual;
  50. procedure SetWeight(const Value: Single);
  51. procedure AfterProgress; virtual;
  52. public
  53. constructor CreateOwned(const aOwner: TGLVerletWorld); virtual;
  54. destructor Destroy; override;
  55. // Applies friction
  56. procedure ApplyFriction(const friction, penetrationDepth: Single;
  57. const surfaceNormal: TAffineVector);
  58. // Simple and less accurate method for friction
  59. procedure OldApplyFriction(const friction, penetrationDepth: Single);
  60. // Perform Verlet integration
  61. procedure Verlet(const vpt: TVerletProgressTimes); virtual;
  62. (* Initlializes the node. For the base class, it just makes sure that
  63. FOldPosition = FPosition, so that speed is zero *)
  64. procedure Initialize; dynamic;
  65. // Calculates the distance to another node
  66. function DistanceToNode(const node: TVerletNode): Single;
  67. // Calculates the movement of the node
  68. function GetMovement: TAffineVector;
  69. (* The TVerletNode inherits from TSpacePartitionLeaf, and it needs to
  70. know how to publish itself. The owner ( a TGLVerletWorld ) has a spatial
  71. partitioning object *)
  72. procedure UpdateCachedAABBAndBSphere; override;
  73. { The VerletWorld that owns this verlet }
  74. property Owner: TGLVerletWorld read FOwner;
  75. { The location of the verlet }
  76. property Location: TAffineVector read FLocation write SetLocation;
  77. { The old location of the verlet. This is used for verlet integration }
  78. property OldLocation: TAffineVector read FOldLocation write FOldLocation;
  79. { The radius of the verlet node - this has been more or less deprecated }
  80. property Radius: Single read FRadius write FRadius;
  81. { A sum of all forces that has been applied to this verlet node during a step }
  82. property Force: TAffineVector read FForce write FForce;
  83. { If the node is nailed down, it can't be moved by either force,
  84. constraint or verlet integration - but you can still move it by hand }
  85. property NailedDown: Boolean read FNailedDown write FNailedDown;
  86. { The weight of a node determines how much it's affected by a force }
  87. property Weight: Single read FWeight write SetWeight;
  88. { InvWeight is 1/Weight, and is kept up to date automatically }
  89. property InvWeight: Single read FInvWeight;
  90. { Returns the speed of the verlet node. Speed = Movement / deltatime }
  91. property Speed: TAffineVector read GetSpeed;
  92. { Each node has a friction that effects how it reacts during contacts. }
  93. property friction: Single read FFriction write FFriction;
  94. { What phyisics step was this node last changed? Used to keep track
  95. of when the spatial partitioning needs to be updated }
  96. property ChangedOnStep: Integer read FChangedOnStep;
  97. end;
  98. TGLVerletNodeClass = class of TVerletNode;
  99. TVerletNodeList = class(TList)
  100. private
  101. function GetItems(i: Integer): TVerletNode;
  102. procedure SetItems(i: Integer; const Value: TVerletNode);
  103. public
  104. property Items[i: Integer]: TVerletNode read GetItems write SetItems; default;
  105. end;
  106. TVerletConstraint = class(TObject)
  107. private
  108. FOwner: TGLVerletWorld;
  109. FEnabled: Boolean;
  110. FTag: Integer;
  111. public
  112. constructor Create(const aOwner: TGLVerletWorld); virtual;
  113. destructor Destroy; override;
  114. { Updates the position of one or several nodes to make sure that they
  115. don't violate the constraint }
  116. procedure SatisfyConstraint(const iteration, maxIterations: Integer); virtual; abstract;
  117. { Notifies removal of a node }
  118. procedure RemoveNode(const aNode: TVerletNode); virtual; abstract;
  119. { Method that's fired before the physics iterations are performed }
  120. procedure BeforeIterations; virtual;
  121. { Onwer of the constraint }
  122. property Owner: TGLVerletWorld read FOwner;
  123. { Determines if the constraint should be enforced or not }
  124. property Enabled: Boolean read FEnabled write FEnabled;
  125. { Tag field reserved for the user. }
  126. property Tag: Integer read FTag write FTag;
  127. end;
  128. TGLVerletDualConstraint = class(TVerletConstraint)
  129. private
  130. FNodeA, FNodeB: TVerletNode;
  131. public
  132. procedure RemoveNode(const aNode: TVerletNode); override;
  133. { Reference to NodeA. }
  134. property NodeA: TVerletNode read FNodeA write FNodeA;
  135. { Reference to NodeB. }
  136. property NodeB: TVerletNode read FNodeB write FNodeB;
  137. end;
  138. TVerletGroupConstraint = class(TVerletConstraint)
  139. private
  140. FNodes: TVerletNodeList;
  141. public
  142. constructor Create(const aOwner: TGLVerletWorld); override;
  143. destructor Destroy; override;
  144. procedure RemoveNode(const aNode: TVerletNode); override;
  145. { The list of nodes that this constraint will effect }
  146. property Nodes: TVerletNodeList read FNodes;
  147. end;
  148. // Verlet edges simulate rigid collission edges
  149. TGLVerletEdge = class(TSpacePartitionLeaf)
  150. private
  151. FNodeA: TVerletNode;
  152. FNodeB: TVerletNode;
  153. public
  154. { The TGLVerletEdge inherits from TSpacePartitionLeaf, and it needs to
  155. know how to publish itself. The owner ( a TGLVerletWorld ) has a spatial
  156. partitioning object }
  157. procedure UpdateCachedAABBAndBSphere; override;
  158. constructor CreateEdgeOwned(const aNodeA, aNodeB: TVerletNode);
  159. { One of the nodes in the edge }
  160. property NodeA: TVerletNode read FNodeA write FNodeA;
  161. { One of the nodes in the edge }
  162. property NodeB: TVerletNode read FNodeB write FNodeB;
  163. end;
  164. TGLVerletEdgeList = class(TList)
  165. private
  166. function GetItems(i: Integer): TGLVerletEdge;
  167. procedure SetItems(i: Integer; const Value: TGLVerletEdge);
  168. public
  169. property Items[i: Integer]: TGLVerletEdge read GetItems write SetItems; default;
  170. end;
  171. TGLVerletGlobalConstraint = class(TVerletConstraint)
  172. private
  173. FKickbackForce: TAffineVector;
  174. FKickbackTorque: TAffineVector;
  175. FLocation: TAffineVector;
  176. procedure SetLocation(const Value: TAffineVector); virtual;
  177. public
  178. constructor Create(const aOwner: TGLVerletWorld); override;
  179. destructor Destroy; override;
  180. procedure RemoveNode(const aNode: TVerletNode); override;
  181. procedure BeforeIterations; override;
  182. procedure SatisfyConstraint(const iteration, maxIterations: Integer); override;
  183. procedure SatisfyConstraintForNode(const aNode: TVerletNode;
  184. const iteration, maxIterations: Integer); virtual; abstract;
  185. procedure SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
  186. const iteration, maxIterations: Integer); virtual;
  187. property Location: TAffineVector read FLocation write SetLocation;
  188. { The force that this collider has experienced while correcting the
  189. verlet possitions. This force can be applied to ODE bodies, for
  190. instance }
  191. property KickbackForce: TAffineVector read FKickbackForce write FKickbackForce;
  192. { The torque that this collider has experienced while correcting the
  193. verlet possitions, in reference to the center of the collider. The
  194. torque force can be applied to ODE bodies, but it must first be
  195. translated. A torque can be trasnalted by
  196. EM(b) = EM(a) + EF x VectorSubtract(b, a).
  197. Simply adding the torque to the body will NOT work correctly. See
  198. TranslateKickbackTorque }
  199. property KickbackTorque: TAffineVector read FKickbackTorque write FKickbackTorque;
  200. procedure AddKickbackForceAt(const Pos: TAffineVector; const Force: TAffineVector);
  201. function TranslateKickbackTorque(const TorqueCenter: TAffineVector): TAffineVector;
  202. end;
  203. TGLVerletGlobalFrictionConstraint = class(TGLVerletGlobalConstraint)
  204. private
  205. FFrictionRatio: Single;
  206. public
  207. constructor Create(const aOwner: TGLVerletWorld); override;
  208. property FrictionRatio: Single read FFrictionRatio write FFrictionRatio;
  209. end;
  210. TGLVerletGlobalFrictionConstraintSP = class(TGLVerletGlobalFrictionConstraint)
  211. public
  212. procedure SatisfyConstraint(const iteration, maxIterations: Integer); override;
  213. procedure PerformSpaceQuery; virtual; abstract;
  214. end;
  215. TGLVerletGlobalFrictionConstraintSphere = class(TGLVerletGlobalFrictionConstraintSP)
  216. private
  217. FCachedBSphere: TBSphere;
  218. procedure SetLocation(const Value: TAffineVector); override;
  219. public
  220. procedure UpdateCachedBSphere;
  221. procedure PerformSpaceQuery; override;
  222. function GetBSphere: TBSphere; virtual; abstract;
  223. property CachedBSphere: TBSphere read FCachedBSphere;
  224. end;
  225. TGLVerletGlobalFrictionConstraintBox = class(TGLVerletGlobalFrictionConstraintSP)
  226. private
  227. FCachedAABB: TAABB;
  228. procedure SetLocation(const Value: TAffineVector); override;
  229. public
  230. procedure UpdateCachedAABB;
  231. procedure PerformSpaceQuery; override;
  232. function GetAABB: TAABB; virtual; abstract;
  233. property CachedAABB: TAABB read FCachedAABB;
  234. end;
  235. TVerletConstraintList = class(TList)
  236. private
  237. function GetItems(i: Integer): TVerletConstraint;
  238. procedure SetItems(i: Integer; const Value: TVerletConstraint);
  239. public
  240. property Items[i: Integer]: TVerletConstraint read GetItems write SetItems; default;
  241. end;
  242. // Generic verlet force.
  243. TGLVerletForce = class(TObject)
  244. private
  245. FOwner: TGLVerletWorld;
  246. public
  247. constructor Create(const aOwner: TGLVerletWorld); virtual;
  248. destructor Destroy; override;
  249. // Implementation should add force to force resultant for all relevant nodes
  250. procedure AddForce(const vpt: TVerletProgressTimes); virtual; abstract;
  251. // Notifies removal of a node
  252. procedure RemoveNode(const aNode: TVerletNode); virtual; abstract;
  253. property Owner: TGLVerletWorld read FOwner;
  254. end;
  255. // A verlet force that applies to two specified nodes.
  256. TGLVerletDualForce = class(TGLVerletForce)
  257. private
  258. FNodeA, FNodeB: TVerletNode;
  259. public
  260. procedure RemoveNode(const aNode: TVerletNode); override;
  261. { Reference to NodeA. }
  262. property NodeA: TVerletNode read FNodeA write FNodeA;
  263. { Reference to NodeB. }
  264. property NodeB: TVerletNode read FNodeB write FNodeB;
  265. end;
  266. // A verlet force that applies to a specified group of nodes.
  267. TVerletGroupForce = class(TGLVerletForce)
  268. private
  269. FNodes: TVerletNodeList;
  270. public
  271. constructor Create(const aOwner: TGLVerletWorld); override;
  272. destructor Destroy; override;
  273. procedure RemoveNode(const aNode: TVerletNode); override;
  274. // Nodes of the force group, referred, NOT owned.
  275. property Nodes: TVerletNodeList read FNodes;
  276. end;
  277. // A global force (applied to all verlet nodes).
  278. TGLVerletGlobalForce = class(TGLVerletForce)
  279. public
  280. procedure RemoveNode(const aNode: TVerletNode); override;
  281. procedure AddForce(const vpt: TVerletProgressTimes); override;
  282. procedure AddForceToNode(const aNode: TVerletNode); virtual; abstract;
  283. end;
  284. TGLVerletForceList = class(TList)
  285. private
  286. function GetItems(i: Integer): TGLVerletForce;
  287. procedure SetItems(i: Integer; const Value: TGLVerletForce);
  288. public
  289. property Items[i: Integer]: TGLVerletForce read GetItems write SetItems; default;
  290. end;
  291. TVCStick = class;
  292. TVFSpring = class;
  293. TVCSlider = class;
  294. TUpdateSpacePartion = (uspEveryIteration, uspEveryFrame, uspNever);
  295. TCollisionConstraintTypes = (cctEdge, cctNode);
  296. TCollisionConstraintTypesSet = set of TCollisionConstraintTypes;
  297. TGLVerletWorld = class(TObject)
  298. private
  299. FIterations: Integer;
  300. FNodes: TVerletNodeList;
  301. FConstraints: TVerletConstraintList;
  302. FForces: TGLVerletForceList;
  303. FMaxDeltaTime, FSimTime: Single;
  304. FDrag: Single;
  305. FCurrentDeltaTime: Single;
  306. FInvCurrentDeltaTime: Single;
  307. FSolidEdges: TGLVerletEdgeList;
  308. FSpacePartition: TBaseSpacePartition;
  309. FCurrentStepCount: Integer;
  310. FUpdateSpacePartion: TUpdateSpacePartion;
  311. FCollisionConstraintTypes: TCollisionConstraintTypesSet;
  312. FConstraintsWithBeforeIterations: TVerletConstraintList;
  313. FVerletNodeClass: TGLVerletNodeClass;
  314. FInertia: Boolean;
  315. FInertaPauseSteps: Integer;
  316. protected
  317. procedure AccumulateForces(const vpt: TVerletProgressTimes); virtual;
  318. procedure Verlet(const vpt: TVerletProgressTimes); virtual;
  319. procedure SatisfyConstraints(const vpt: TVerletProgressTimes); virtual;
  320. procedure DoUpdateSpacePartition;
  321. public
  322. constructor Create; virtual;
  323. destructor Destroy; override;
  324. function AddNode(const aNode: TVerletNode): Integer;
  325. procedure RemoveNode(const aNode: TVerletNode);
  326. function AddConstraint(const aConstraint: TVerletConstraint): Integer;
  327. procedure RemoveConstraint(const aConstraint: TVerletConstraint);
  328. function AddForce(const aForce: TGLVerletForce): Integer;
  329. procedure RemoveForce(const aForce: TGLVerletForce);
  330. procedure AddSolidEdge(const aNodeA, aNodeB: TVerletNode);
  331. procedure PauseInertia(const IterationSteps: Integer);
  332. function CreateOwnedNode(const Location: TAffineVector;
  333. const aRadius: Single = 0;
  334. const aWeight: Single = 1): TVerletNode;
  335. function CreateStick(const aNodeA, aNodeB: TVerletNode;
  336. const Slack: Single = 0): TVCStick;
  337. function CreateSpring(const aNodeA, aNodeB: TVerletNode;
  338. const aStrength, aDamping: Single; const aSlack: Single = 0): TVFSpring;
  339. function CreateSlider(const aNodeA, aNodeB: TVerletNode;
  340. const aSlideDirection: TAffineVector): TVCSlider;
  341. procedure Initialize; virtual;
  342. procedure CreateOctree(const OctreeMin, OctreeMax: TAffineVector;
  343. const LeafThreshold, MaxTreeDepth: Integer);
  344. function Progress(const deltaTime, newTime: Double): Integer; virtual;
  345. function FirstNode: TVerletNode;
  346. function LastNode: TVerletNode;
  347. property Drag: Single read FDrag write FDrag;
  348. property Iterations: Integer read FIterations write FIterations;
  349. property Nodes: TVerletNodeList read FNodes;
  350. property Constraints: TVerletConstraintList read FConstraints;
  351. property ConstraintsWithBeforeIterations: TVerletConstraintList read FConstraintsWithBeforeIterations;
  352. property SimTime: Single read FSimTime write FSimTime;
  353. property MaxDeltaTime: Single read FMaxDeltaTime write FMaxDeltaTime;
  354. property CurrentDeltaTime: Single read FCurrentDeltaTime;
  355. property SolidEdges: TGLVerletEdgeList read FSolidEdges write FSolidEdges;
  356. property CurrentStepCount: Integer read FCurrentStepCount;
  357. property SpacePartition: TBaseSpacePartition read FSpacePartition;
  358. property UpdateSpacePartion: TUpdateSpacePartion read FUpdateSpacePartion write FUpdateSpacePartion;
  359. property CollisionConstraintTypes: TCollisionConstraintTypesSet read FCollisionConstraintTypes
  360. write FCollisionConstraintTypes;
  361. property VerletNodeClass: TGLVerletNodeClass read FVerletNodeClass write FVerletNodeClass;
  362. property Inertia: Boolean read FInertia write FInertia;
  363. end;
  364. TVFGravity = class(TGLVerletGlobalForce)
  365. private
  366. FGravity: TAffineVector;
  367. public
  368. constructor Create(const aOwner: TGLVerletWorld); override;
  369. procedure AddForceToNode(const aNode: TVerletNode); override;
  370. property Gravity: TAffineVector read FGravity write FGravity;
  371. end;
  372. TVFAirResistance = class(TGLVerletGlobalForce)
  373. private
  374. FDragCoeff: Single;
  375. FWindDirection: TAffineVector;
  376. FWindMagnitude: Single;
  377. FWindChaos: Single;
  378. procedure SetWindDirection(const Value: TAffineVector);
  379. public
  380. constructor Create(const aOwner: TGLVerletWorld); override;
  381. procedure AddForceToNode(const aNode: TVerletNode); override;
  382. property DragCoeff: Single read FDragCoeff write FDragCoeff;
  383. property WindDirection: TAffineVector read FWindDirection write SetWindDirection;
  384. property WindMagnitude: Single read FWindMagnitude write FWindMagnitude;
  385. // Measures how chaotic the wind is, as a fraction of the wind magnitude
  386. property WindChaos: Single read FWindChaos write FWindChaos;
  387. end;
  388. TVFSpring = class(TGLVerletDualForce)
  389. private
  390. FRestLength: Single;
  391. FStrength: Single;
  392. FDamping: Single;
  393. FSlack: Single;
  394. FForceFactor: Single;
  395. protected
  396. procedure SetSlack(const Value: Single);
  397. public
  398. procedure AddForce(const vpt: TVerletProgressTimes); override;
  399. // Must be invoked after adjust node locations or strength
  400. procedure SetRestLengthToCurrent;
  401. property Strength: Single read FStrength write FStrength;
  402. property Damping: Single read FDamping write FDamping;
  403. property Slack: Single read FSlack write SetSlack;
  404. end;
  405. // Floor collision constraint
  406. TVCFloor = class(TGLVerletGlobalFrictionConstraintSP)
  407. private
  408. FBounceRatio, FFloorLevel: Single;
  409. FNormal: TAffineVector;
  410. protected
  411. procedure SetNormal(const Value: TAffineVector);
  412. public
  413. constructor Create(const aOwner: TGLVerletWorld); override;
  414. procedure PerformSpaceQuery; override;
  415. procedure SatisfyConstraintForNode(const aNode: TVerletNode;
  416. const iteration, maxIterations: Integer); override;
  417. property BounceRatio: Single read FBounceRatio write FBounceRatio;
  418. property FloorLevel: Single read FFloorLevel write FFloorLevel;
  419. property Normal: TAffineVector read FNormal write SetNormal;
  420. end;
  421. TVCHeightField = class;
  422. TVCHeightFieldOnNeedHeight = function(hfConstraint: TVCHeightField; node: TVerletNode): Single of object;
  423. // HeightField collision constraint (punctual!)
  424. TVCHeightField = class(TVCFloor)
  425. private
  426. FOnNeedHeight: TVCHeightFieldOnNeedHeight;
  427. public
  428. procedure SatisfyConstraintForNode(const aNode: TVerletNode;
  429. const iteration, maxIterations: Integer); override;
  430. property OnNeedHeight: TVCHeightFieldOnNeedHeight read FOnNeedHeight write FOnNeedHeight;
  431. end;
  432. { Stick constraint.
  433. Imposes a fixed distance between two nodes. }
  434. TVCStick = class(TGLVerletDualConstraint)
  435. private
  436. FSlack: Single;
  437. FRestLength: Single;
  438. public
  439. procedure SatisfyConstraint(const iteration, maxIterations: Integer); override;
  440. procedure SetRestLengthToCurrent;
  441. property Slack: Single read FSlack write FSlack;
  442. property RestLength: Single read FRestLength write FRestLength;
  443. end;
  444. { Rigid body constraint.
  445. Regroups several nodes in a rigid body conformation, somewhat similar
  446. to a stick but for multiple nodes.
  447. EXPERIMENTAL, DOES NOT WORK! }
  448. TVCRigidBody = class(TVerletGroupConstraint)
  449. private
  450. FNodeParams: array of TAffineVector;
  451. FNodeCoords: array of TAffineVector;
  452. FNatMatrix, FInvNatMatrix: TAffineMatrix;
  453. protected
  454. procedure ComputeBarycenter(var barycenter: TAffineVector);
  455. procedure ComputeNaturals(const barycenter: TAffineVector;
  456. var natX, natY, natZ: TAffineVector);
  457. public
  458. procedure ComputeRigidityParameters;
  459. procedure SatisfyConstraint(const iteration, maxIterations: Integer); override;
  460. end;
  461. { Slider constraint.
  462. Imposes that two nodes be aligned on a defined direction, on which they
  463. can slide freely. Note that the direction is fixed and won't rotate
  464. with the verlet assembly!. }
  465. TVCSlider = class(TGLVerletDualConstraint)
  466. private
  467. FSlideDirection: TAffineVector;
  468. FConstrained: Boolean;
  469. protected
  470. procedure SetSlideDirection(const Value: TAffineVector);
  471. public
  472. procedure SatisfyConstraint(const iteration, maxIterations: Integer); override;
  473. property SlideDirection: TAffineVector read FSlideDirection write SetSlideDirection;
  474. { Constrain NodeB to the halfplane defined by NodeA and SlideDirection. }
  475. property Constrained: Boolean read FConstrained write FConstrained;
  476. end;
  477. { Sphere collision constraint. }
  478. TVCSphere = class(TGLVerletGlobalFrictionConstraintSphere)
  479. private
  480. FRadius: Single;
  481. public
  482. function GetBSphere: TBSphere; override;
  483. procedure SatisfyConstraintForNode(const aNode: TVerletNode;
  484. const iteration, maxIterations: Integer); override;
  485. procedure SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
  486. const iteration, maxIterations: Integer); override;
  487. property Radius: Single read FRadius write FRadius;
  488. end;
  489. { Cylinder collision constraint.
  490. The cylinder is considered infinite by this constraint. }
  491. TVCCylinder = class(TGLVerletGlobalFrictionConstraint)
  492. private
  493. FAxis: TAffineVector;
  494. FRadius, FRadius2: Single;
  495. protected
  496. procedure SetRadius(const val: Single);
  497. public
  498. procedure SatisfyConstraintForNode(const aNode: TVerletNode;
  499. const iteration, maxIterations: Integer); override;
  500. { A base point on the cylinder axis.
  501. Can theoretically be anywhere, however, to reduce floating point
  502. precision issues, choose it in the area where collision detection
  503. will occur. }
  504. // property Base : TAffineVector read FBase write FBase;
  505. { Cylinder axis vector. Must be normalized. }
  506. property Axis: TAffineVector read FAxis write FAxis;
  507. { Cylinder radius. }
  508. property Radius: Single read FRadius write SetRadius;
  509. end;
  510. { Cube collision constraint. }
  511. TVCCube = class(TGLVerletGlobalFrictionConstraintBox)
  512. private
  513. FHalfSides: TAffineVector;
  514. FSides: TAffineVector;
  515. FDirection: TAffineVector;
  516. procedure SetSides(const Value: TAffineVector);
  517. public
  518. function GetAABB: TAABB; override;
  519. procedure SatisfyConstraintForNode(const aNode: TVerletNode;
  520. const iteration, maxIterations: Integer); override;
  521. // Broken and very slow!
  522. procedure SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
  523. const iteration, maxIterations: Integer); override;
  524. property Direction: TAffineVector read FDirection write FDirection;
  525. property Sides: TAffineVector read FSides write SetSides;
  526. end;
  527. // Capsule collision constraint.
  528. TVCCapsule = class(TGLVerletGlobalFrictionConstraintSphere)
  529. private
  530. FAxis: TAffineVector;
  531. FRadius, FRadius2, FLength, FLengthDiv2: Single;
  532. protected
  533. procedure SetAxis(const val: TAffineVector);
  534. procedure SetRadius(const val: Single);
  535. procedure SetLength(const val: Single);
  536. public
  537. function GetBSphere: TBSphere; override;
  538. procedure SatisfyConstraintForNode(const aNode: TVerletNode;
  539. const iteration, maxIterations: Integer); override;
  540. procedure SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
  541. const iteration, maxIterations: Integer); override;
  542. // property Base : TAffineVector read FBase write FBase;
  543. property Axis: TAffineVector read FAxis write SetAxis;
  544. property Radius: Single read FRadius write SetRadius;
  545. property Length: Single read FLength write SetLength;
  546. end;
  547. (* Specialized verlet node that can be anchored to a GLScene object. If it's
  548. anchored and has the property "NailedDown" set, it will remain in the same
  549. relative position to the GLScene object. *)
  550. TGLVerletNode = class(TVerletNode)
  551. private
  552. FRelativePosition: TAffineVector;
  553. FGLBaseSceneObject: TGLBaseSceneObject;
  554. procedure SetGLBaseSceneObject(const Value: TGLBaseSceneObject);
  555. protected
  556. procedure SetLocation(const Value: TAffineVector); override;
  557. public
  558. procedure Verlet(const vpt: TVerletProgressTimes); override;
  559. property GLBaseSceneObject: TGLBaseSceneObject read FGLBaseSceneObject write SetGLBaseSceneObject;
  560. property RelativePosition: TAffineVector read FRelativePosition write FRelativePosition;
  561. end;
  562. function CreateVCPlaneFromGLPlane(Plane: TGLPlane; VerletWorld: TGLVerletWorld; Offset: Single): TVCFloor;
  563. // ------------------------------------------------------------------
  564. implementation
  565. // ------------------------------------------------------------------
  566. function CreateVCPlaneFromGLPlane(Plane: TGLPlane; VerletWorld: TGLVerletWorld; Offset: Single): TVCFloor;
  567. begin
  568. result := TVCFloor.Create(VerletWorld);
  569. with result do
  570. begin
  571. Normal := VectorNormalize(Plane.Direction.AsAffineVector);
  572. Location := VectorAdd(Plane.Position.AsAffineVector, VectorScale(Normal, Offset));
  573. end;
  574. end;
  575. // ----------------------------
  576. { TGLVerletNode }
  577. // ----------------------------
  578. procedure TGLVerletNode.SetGLBaseSceneObject(const Value: TGLBaseSceneObject);
  579. begin
  580. FGLBaseSceneObject := Value;
  581. if Assigned(GLBaseSceneObject) and NailedDown then
  582. FRelativePosition := AffineVectorMake(GLBaseSceneObject.AbsoluteToLocal(VectorMake(FLocation, 1)));
  583. end;
  584. procedure TGLVerletNode.SetLocation(const Value: TAffineVector);
  585. begin
  586. inherited;
  587. if Assigned(GLBaseSceneObject) and NailedDown then
  588. FRelativePosition := GLBaseSceneObject.AbsoluteToLocal(Value);
  589. end;
  590. procedure TGLVerletNode.Verlet(const vpt: TVerletProgressTimes);
  591. begin
  592. if Assigned(GLBaseSceneObject) and NailedDown then
  593. begin
  594. FLocation := GLBaseSceneObject.LocalToAbsolute(FRelativePosition);
  595. end
  596. else
  597. inherited;
  598. end;
  599. // ------------------
  600. // ------------------ TVerletNode ------------------
  601. // ------------------
  602. constructor TVerletNode.CreateOwned(const aOwner: TGLVerletWorld);
  603. begin
  604. inherited CreateOwned(aOwner.SpacePartition);
  605. if Assigned(aOwner) then
  606. aOwner.AddNode(Self);
  607. FWeight := 1;
  608. FInvWeight := 1;
  609. FRadius := 0;
  610. FFriction := 1;
  611. end;
  612. destructor TVerletNode.Destroy;
  613. begin
  614. if Assigned(FOwner) then
  615. FOwner.RemoveNode(Self);
  616. inherited;
  617. end;
  618. { TODO: Improve the friction calculations
  619. Friction = - NormalForce * FrictionConstant
  620. To compute the NormalForce, which is the force acting on the normal of the
  621. collider, we can use the fact that F = m*a.
  622. m is the weight of the node, a is the acceleration (retardation) caused by the
  623. collission.
  624. Acceleration := - PenetrationDepth / Owner.FCurrentDeltaTime;
  625. The force with which the node has been "stopped" from penetration
  626. NormalForce := Weight * Acceleration;
  627. This force should be applied to stopping the movement.
  628. }
  629. procedure TVerletNode.ApplyFriction(const friction, penetrationDepth: Single;
  630. const surfaceNormal: TAffineVector);
  631. var
  632. frictionMove, move, moveNormal: TAffineVector;
  633. realFriction: Single;
  634. begin
  635. if (penetrationDepth > 0) then
  636. begin
  637. realFriction := friction * FFriction;
  638. if realFriction > 0 then
  639. begin
  640. VectorSubtract(Location, OldLocation, move);
  641. moveNormal := VectorScale(surfaceNormal, VectorDotProduct(move, surfaceNormal));
  642. frictionMove := VectorSubtract(move, moveNormal);
  643. if penetrationDepth > Radius then
  644. ScaleVector(frictionMove, realFriction)
  645. else
  646. ScaleVector(frictionMove, realFriction * Sqrt(penetrationDepth / Radius));
  647. VectorAdd(OldLocation, frictionMove, FOldLocation);
  648. end;
  649. end;
  650. end;
  651. procedure TVerletNode.OldApplyFriction(const friction, penetrationDepth: Single);
  652. var
  653. frictionMove, move: TAffineVector;
  654. // pd : Single;
  655. begin
  656. VectorSubtract(Location, OldLocation, move);
  657. VectorScale(move, friction * FFriction, frictionMove);
  658. // pd:=Abs(penetrationDepth);
  659. // ScaleVector(frictionMove, friction*pd);
  660. VectorAdd(OldLocation, frictionMove, FOldLocation);
  661. end;
  662. function TVerletNode.DistanceToNode(const node: TVerletNode): Single;
  663. begin
  664. Result := VectorDistance(Location, node.Location);
  665. end;
  666. function TVerletNode.GetMovement: TAffineVector;
  667. begin
  668. Result := VectorSubtract(Location, OldLocation);
  669. end;
  670. procedure TVerletNode.Initialize;
  671. begin
  672. FOldLocation := Location;
  673. end;
  674. procedure TVerletNode.SetWeight(const Value: Single);
  675. begin
  676. FWeight := Value;
  677. if Value <> 0 then
  678. FInvWeight := 1 / Value
  679. else
  680. FInvWeight := 1;
  681. end;
  682. procedure TVerletNode.Verlet(const vpt: TVerletProgressTimes);
  683. var
  684. newLocation, temp, move, accel: TAffineVector;
  685. begin
  686. if NailedDown then
  687. begin
  688. FOldLocation := Location;
  689. end
  690. else
  691. begin
  692. if Owner.Inertia then
  693. begin
  694. temp := Location;
  695. VectorSubtract(Location, OldLocation, move);
  696. ScaleVector(move, 1 - Owner.Drag); // *Sqr(deltaTime));
  697. VectorAdd(Location, move, newLocation);
  698. VectorScale(Force, vpt.sqrDeltaTime * FInvWeight, accel);
  699. AddVector(newLocation, accel);
  700. Location := newLocation;
  701. FOldLocation := temp;
  702. end
  703. else
  704. begin
  705. newLocation := Location;
  706. VectorScale(Force, vpt.sqrDeltaTime * FInvWeight, accel);
  707. AddVector(newLocation, accel);
  708. Location := newLocation;
  709. FOldLocation := Location;
  710. end;
  711. end;
  712. end;
  713. procedure TVerletNode.AfterProgress;
  714. begin
  715. // nothing here, reserved for subclass use
  716. end;
  717. // ------------------
  718. // ------------------ TVerletNodeList ------------------
  719. // ------------------
  720. function TVerletNodeList.GetItems(i: Integer): TVerletNode;
  721. begin
  722. result := Get(i);
  723. end;
  724. procedure TVerletNodeList.SetItems(i: Integer; const Value: TVerletNode);
  725. begin
  726. Put(i, Value);
  727. end;
  728. function TVerletNode.GetSpeed: TAffineVector;
  729. begin
  730. result := VectorScale(VectorSubtract(FLocation, FOldLocation), 1 / Owner.CurrentDeltaTime);
  731. end;
  732. // ------------------
  733. // ------------------ TVerletConstraint ------------------
  734. // ------------------
  735. constructor TVerletConstraint.Create(const aOwner: TGLVerletWorld);
  736. begin
  737. inherited Create;
  738. if Assigned(aOwner) then
  739. aOwner.AddConstraint(Self);
  740. FEnabled := True;
  741. end;
  742. destructor TVerletConstraint.Destroy;
  743. begin
  744. if Assigned(FOwner) then
  745. FOwner.RemoveConstraint(Self);
  746. inherited;
  747. end;
  748. procedure TVerletConstraint.BeforeIterations;
  749. begin
  750. // NADA!
  751. end;
  752. // ------------------
  753. // ------------------ TGLVerletDualConstraint ------------------
  754. // ------------------
  755. procedure TGLVerletDualConstraint.RemoveNode(const aNode: TVerletNode);
  756. begin
  757. if FNodeA = aNode then
  758. FNodeA := nil;
  759. if FNodeB = aNode then
  760. FNodeB := nil;
  761. if (FNodeA = nil) and (FNodeA = nil) then
  762. Free;
  763. end;
  764. // ------------------
  765. // ------------------ TVerletGroupConstraint ------------------
  766. // ------------------
  767. constructor TVerletGroupConstraint.Create(const aOwner: TGLVerletWorld);
  768. begin
  769. inherited Create(aOwner);
  770. FNodes := TVerletNodeList.Create;
  771. end;
  772. destructor TVerletGroupConstraint.Destroy;
  773. begin
  774. FNodes.Free;
  775. inherited;
  776. end;
  777. procedure TVerletGroupConstraint.RemoveNode(const aNode: TVerletNode);
  778. begin
  779. FNodes.Remove(aNode);
  780. end;
  781. // ------------------
  782. // ------------------ TGLVerletGlobalConstraint ------------------
  783. // ------------------
  784. procedure TGLVerletGlobalConstraint.AddKickbackForceAt(const Pos: TAffineVector; const Force: TAffineVector);
  785. var
  786. dPos: TAffineVector;
  787. begin
  788. // Sum forces
  789. AddVector(FKickbackForce, Force);
  790. // Sum torques
  791. dPos := VectorSubtract(Pos, FLocation);
  792. AddVector(FKickbackTorque, VectorCrossProduct(dPos, Force));
  793. end;
  794. function TGLVerletGlobalConstraint.TranslateKickbackTorque(const TorqueCenter: TAffineVector): TAffineVector;
  795. begin
  796. // EM(b) = EM(a) + EF x VectorSubtract(b, a).
  797. result := VectorAdd(FKickbackTorque, VectorCrossProduct(VectorSubtract(TorqueCenter, FLocation), FKickbackForce));
  798. end;
  799. procedure TGLVerletGlobalConstraint.BeforeIterations;
  800. begin
  801. inherited;
  802. FKickbackForce := NullVector;
  803. FKickbackTorque := NullVector;
  804. end;
  805. procedure TGLVerletGlobalConstraint.RemoveNode(const aNode: TVerletNode);
  806. begin
  807. // nothing to do here
  808. end;
  809. procedure TGLVerletGlobalConstraint.SetLocation(const Value: TAffineVector);
  810. begin
  811. FLocation := Value;
  812. end;
  813. procedure TGLVerletGlobalConstraint.SatisfyConstraint(const iteration, maxIterations: Integer);
  814. var
  815. i: Integer;
  816. node: TVerletNode;
  817. begin
  818. if cctNode in Owner.CollisionConstraintTypes then
  819. for i := 0 to Owner.Nodes.Count - 1 do
  820. begin
  821. node := TVerletNode(Owner.Nodes[i]);
  822. if not node.NailedDown then
  823. SatisfyConstraintForNode(node, iteration, maxIterations);
  824. end; // }
  825. if cctEdge in Owner.CollisionConstraintTypes then
  826. for i := 0 to Owner.SolidEdges.Count - 1 do
  827. begin
  828. SatisfyConstraintForEdge(Owner.SolidEdges[i], iteration, maxIterations);
  829. end; // }
  830. end;
  831. procedure TGLVerletGlobalConstraint.SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
  832. const iteration, maxIterations: Integer);
  833. begin
  834. // Purely virtual, but can't be abstract...
  835. end;
  836. // ------------------
  837. // ------------------ TGLVerletGlobalFrictionConstraint ------------------
  838. // ------------------
  839. constructor TGLVerletGlobalFrictionConstraint.Create(const aOwner: TGLVerletWorld);
  840. begin
  841. inherited;
  842. FFrictionRatio := cDEFAULT_CONSTRAINT_FRICTION;
  843. end;
  844. // ------------------
  845. // ------------------ TGLVerletGlobalFrictionConstraintSP ------------------
  846. // ------------------
  847. procedure TGLVerletGlobalFrictionConstraintSP.SatisfyConstraint(const iteration, maxIterations: Integer);
  848. var
  849. i: Integer;
  850. node: TVerletNode;
  851. edge: TGLVerletEdge;
  852. SP: TBaseSpacePartition;
  853. Leaf: TSpacePartitionLeaf;
  854. begin
  855. if Owner.SpacePartition = nil then
  856. begin
  857. inherited;
  858. Exit;
  859. end;
  860. PerformSpaceQuery;
  861. SP := Owner.SpacePartition;
  862. for i := 0 to SP.QueryResult.Count - 1 do
  863. begin
  864. Leaf := SP.QueryResult[i];
  865. if Leaf is TVerletNode then
  866. begin
  867. if cctNode in Owner.CollisionConstraintTypes then
  868. begin
  869. node := Leaf as TVerletNode;
  870. if not node.NailedDown then
  871. SatisfyConstraintForNode(node, iteration, maxIterations);
  872. end;
  873. end
  874. else if Leaf is TGLVerletEdge then
  875. begin
  876. if cctEdge in Owner.CollisionConstraintTypes then
  877. begin
  878. edge := Leaf as TGLVerletEdge;
  879. SatisfyConstraintForEdge(edge, iteration, maxIterations);
  880. end;
  881. end
  882. else
  883. Assert(False, 'Bad objects in list!');
  884. end;
  885. end;
  886. // ------------------
  887. // ------------------ TVerletConstraintList ------------------
  888. // ------------------
  889. function TVerletConstraintList.GetItems(i: Integer): TVerletConstraint;
  890. begin
  891. result := Get(i);
  892. end;
  893. procedure TVerletConstraintList.SetItems(i: Integer; const Value: TVerletConstraint);
  894. begin
  895. Put(i, Value);
  896. end;
  897. // ------------------
  898. // ------------------ TGLVerletForce ------------------
  899. // ------------------
  900. constructor TGLVerletForce.Create(const aOwner: TGLVerletWorld);
  901. begin
  902. inherited Create;
  903. if Assigned(aOwner) then
  904. aOwner.AddForce(Self);
  905. end;
  906. destructor TGLVerletForce.Destroy;
  907. begin
  908. if Assigned(FOwner) then
  909. FOwner.RemoveForce(Self);
  910. inherited;
  911. end;
  912. // ------------------
  913. // ------------------ TVerletGroupForce ------------------
  914. // ------------------
  915. constructor TVerletGroupForce.Create(const aOwner: TGLVerletWorld);
  916. begin
  917. inherited Create(aOwner);
  918. FNodes := TVerletNodeList.Create;
  919. end;
  920. destructor TVerletGroupForce.Destroy;
  921. begin
  922. FNodes.Free;
  923. inherited;
  924. end;
  925. procedure TVerletGroupForce.RemoveNode(const aNode: TVerletNode);
  926. begin
  927. FNodes.Remove(aNode);
  928. end;
  929. // ------------------
  930. // ------------------ TGLVerletGlobalForce ------------------
  931. // ------------------
  932. procedure TGLVerletGlobalForce.RemoveNode(const aNode: TVerletNode);
  933. begin
  934. // nothing to do here
  935. end;
  936. procedure TGLVerletGlobalForce.AddForce;
  937. var
  938. i: Integer;
  939. node: TVerletNode;
  940. begin
  941. for i := 0 to Owner.Nodes.Count - 1 do
  942. begin
  943. node := TVerletNode(Owner.Nodes.List[i]);
  944. if not node.NailedDown then
  945. AddForceToNode(node);
  946. end;
  947. end;
  948. // ------------------
  949. // ------------------ TGLVerletDualForce ------------------
  950. // ------------------
  951. procedure TGLVerletDualForce.RemoveNode(const aNode: TVerletNode);
  952. begin
  953. if FNodeA = aNode then
  954. FNodeA := nil;
  955. if FNodeB = aNode then
  956. FNodeB := nil;
  957. end;
  958. // ------------------
  959. // ------------------ TGLVerletForceList ------------------
  960. // ------------------
  961. function TGLVerletForceList.GetItems(i: Integer): TGLVerletForce;
  962. begin
  963. result := Get(i);
  964. end;
  965. procedure TGLVerletForceList.SetItems(i: Integer; const Value: TGLVerletForce);
  966. begin
  967. Put(i, Value);
  968. end;
  969. // ------------------
  970. // ------------------ TGLVerletWorld ------------------
  971. // ------------------
  972. constructor TGLVerletWorld.Create;
  973. begin
  974. inherited;
  975. FDrag := G_DRAG;
  976. FNodes := TVerletNodeList.Create;
  977. FConstraints := TVerletConstraintList.Create;
  978. FConstraintsWithBeforeIterations := TVerletConstraintList.Create;
  979. FForces := TGLVerletForceList.Create;
  980. FMaxDeltaTime := 0.02;
  981. FIterations := 3;
  982. FSolidEdges := TGLVerletEdgeList.Create;
  983. FCurrentStepCount := 0;
  984. FUpdateSpacePartion := uspNever;
  985. FCollisionConstraintTypes := [cctNode, cctEdge];
  986. FSpacePartition := nil;
  987. FVerletNodeClass := TVerletNode;
  988. FInertia := True;
  989. end;
  990. destructor TGLVerletWorld.Destroy;
  991. var
  992. i: Integer;
  993. begin
  994. // Delete all nodes
  995. for i := 0 to FNodes.Count - 1 do
  996. with FNodes[i] do
  997. begin
  998. FOwner := nil;
  999. Free;
  1000. end;
  1001. FreeAndNil(FNodes);
  1002. // Delete all constraints
  1003. for i := 0 to FConstraints.Count - 1 do
  1004. with FConstraints[i] do
  1005. begin
  1006. FOwner := nil;
  1007. Free;
  1008. end;
  1009. FreeAndNil(FConstraints);
  1010. // Delete all forces
  1011. for i := 0 to FForces.Count - 1 do
  1012. with FForces[i] do
  1013. begin
  1014. FOwner := nil;
  1015. Free;
  1016. end;
  1017. FreeAndNil(FForces);
  1018. FreeAndNil(FConstraintsWithBeforeIterations);
  1019. for i := 0 to FSolidEdges.Count - 1 do
  1020. FSolidEdges[i].Free;
  1021. FreeAndNil(FSolidEdges);
  1022. FreeAndNil(FSpacePartition);
  1023. inherited;
  1024. end;
  1025. procedure TGLVerletWorld.AccumulateForces(const vpt: TVerletProgressTimes);
  1026. var
  1027. i: Integer;
  1028. begin
  1029. // First of all, reset all forces
  1030. for i := 0 to FNodes.Count - 1 do
  1031. FNodes[i].FForce := NullVector;
  1032. // Now, update all forces in the assembly!
  1033. for i := 0 to FForces.Count - 1 do
  1034. FForces[i].AddForce(vpt);
  1035. end;
  1036. function TGLVerletWorld.AddNode(const aNode: TVerletNode): Integer;
  1037. begin
  1038. if Assigned(aNode.FOwner) then
  1039. aNode.Owner.FNodes.Remove(aNode);
  1040. result := FNodes.Add(aNode);
  1041. aNode.FOwner := Self;
  1042. end;
  1043. procedure TGLVerletWorld.RemoveNode(const aNode: TVerletNode);
  1044. var
  1045. i: Integer;
  1046. begin
  1047. if aNode.Owner = Self then
  1048. begin
  1049. FNodes.Remove(aNode);
  1050. aNode.FOwner := nil;
  1051. // drop refs in constraints
  1052. for i := FConstraints.Count - 1 downto 0 do
  1053. FConstraints[i].RemoveNode(aNode);
  1054. // drop refs in forces
  1055. for i := FForces.Count - 1 downto 0 do
  1056. FForces[i].RemoveNode(aNode);
  1057. end;
  1058. end;
  1059. function TGLVerletWorld.AddConstraint(const aConstraint: TVerletConstraint): Integer;
  1060. begin
  1061. if Assigned(aConstraint.FOwner) then
  1062. aConstraint.Owner.FConstraints.Remove(aConstraint);
  1063. result := FConstraints.Add(aConstraint);
  1064. aConstraint.FOwner := Self;
  1065. end;
  1066. procedure TGLVerletWorld.RemoveConstraint(const aConstraint: TVerletConstraint);
  1067. begin
  1068. if aConstraint.Owner = Self then
  1069. begin
  1070. FConstraints.Remove(aConstraint);
  1071. aConstraint.FOwner := nil;
  1072. end;
  1073. end;
  1074. function TGLVerletWorld.AddForce(const aForce: TGLVerletForce): Integer;
  1075. begin
  1076. if Assigned(aForce.FOwner) then
  1077. aForce.Owner.FForces.Remove(aForce);
  1078. result := FForces.Add(aForce);
  1079. aForce.FOwner := Self;
  1080. end;
  1081. procedure TGLVerletWorld.RemoveForce(const aForce: TGLVerletForce);
  1082. begin
  1083. if aForce.Owner = Self then
  1084. begin
  1085. FForces.Remove(aForce);
  1086. aForce.FOwner := nil;
  1087. end;
  1088. end;
  1089. procedure TGLVerletWorld.AddSolidEdge(const aNodeA, aNodeB: TVerletNode);
  1090. var
  1091. VerletEdge: TGLVerletEdge;
  1092. begin
  1093. VerletEdge := TGLVerletEdge.CreateEdgeOwned(aNodeA, aNodeB);
  1094. SolidEdges.Add(VerletEdge);
  1095. end;
  1096. function TGLVerletWorld.FirstNode: TVerletNode;
  1097. begin
  1098. Assert(FNodes.Count > 0, 'There are no nodes in the assembly!');
  1099. result := FNodes[0];
  1100. end;
  1101. function TGLVerletWorld.LastNode: TVerletNode;
  1102. begin
  1103. Assert(FNodes.Count > 0, 'There are no nodes in the assembly!');
  1104. result := FNodes[FNodes.Count - 1];
  1105. end;
  1106. function TGLVerletWorld.CreateOwnedNode(const Location: TAffineVector;
  1107. const aRadius: Single = 0; const aWeight: Single = 1): TVerletNode;
  1108. begin
  1109. Result:=VerletNodeClass.CreateOwned(Self);
  1110. Result.Location:=Location;
  1111. Result.OldLocation:=Location;
  1112. Result.Weight:=aWeight;
  1113. Result.Radius:=aRadius;
  1114. end;
  1115. function TGLVerletWorld.CreateStick(const aNodeA, aNodeB: TVerletNode; const Slack: Single = 0): TVCStick;
  1116. begin
  1117. Assert(aNodeA <> aNodeB, 'Can''t create stick between same node!');
  1118. Result:=TVCStick.Create(Self);
  1119. Result.NodeA:=aNodeA;
  1120. Result.NodeB:=aNodeB;
  1121. Result.SetRestLengthToCurrent;
  1122. Result.Slack := Slack;
  1123. end;
  1124. function TGLVerletWorld.CreateSpring(const aNodeA, aNodeB: TVerletNode;
  1125. const aStrength, aDamping: Single; const aSlack: Single = 0): TVFSpring;
  1126. begin
  1127. Result:=TVFSpring.Create(Self);
  1128. Result.NodeA:=aNodeA;
  1129. Result.NodeB:=aNodeB;
  1130. Result.Strength:=aStrength;
  1131. Result.Damping:=aDamping;
  1132. Result.Slack:=aSlack;
  1133. Result.SetRestLengthToCurrent;
  1134. end;
  1135. function TGLVerletWorld.CreateSlider(const aNodeA, aNodeB: TVerletNode;
  1136. const aSlideDirection: TAffineVector): TVCSlider;
  1137. begin
  1138. Result:=TVCSlider.Create(Self);
  1139. Result.NodeA:=aNodeA;
  1140. Result.NodeB:=aNodeB;
  1141. Result.SlideDirection:=aSlideDirection;
  1142. end;
  1143. procedure TGLVerletWorld.Initialize;
  1144. var
  1145. i: Integer;
  1146. begin
  1147. for i := 0 to FNodes.Count - 1 do
  1148. FNodes[i].Initialize;
  1149. end;
  1150. function TGLVerletWorld.Progress(const deltaTime, newTime: Double): Integer;
  1151. var
  1152. i: Integer;
  1153. ticks: Integer;
  1154. myDeltaTime: Single;
  1155. vpt: TVerletProgressTimes;
  1156. begin
  1157. ticks := 0;
  1158. myDeltaTime := FMaxDeltaTime;
  1159. FCurrentDeltaTime := FMaxDeltaTime;
  1160. FInvCurrentDeltaTime := 1 / FCurrentDeltaTime;
  1161. vpt.deltaTime := myDeltaTime;
  1162. vpt.sqrDeltaTime := Sqr(myDeltaTime);
  1163. vpt.invSqrDeltaTime := 1 / vpt.sqrDeltaTime;
  1164. while FSimTime < newTime do
  1165. begin
  1166. Inc(ticks);
  1167. FSimTime := FSimTime + myDeltaTime;
  1168. vpt.newTime := FSimTime;
  1169. Verlet(vpt);
  1170. AccumulateForces(vpt);
  1171. SatisfyConstraints(vpt);
  1172. if FInertaPauseSteps > 0 then
  1173. begin
  1174. dec(FInertaPauseSteps);
  1175. if FInertaPauseSteps = 0 then
  1176. Inertia := True;
  1177. end;
  1178. Break;
  1179. end;
  1180. result := ticks;
  1181. for i := 0 to FNodes.Count - 1 do
  1182. FNodes[i].AfterProgress;
  1183. end;
  1184. procedure TGLVerletWorld.DoUpdateSpacePartition;
  1185. var
  1186. i: Integer;
  1187. begin
  1188. if Assigned(SpacePartition) then
  1189. begin
  1190. for i := 0 to FSolidEdges.Count - 1 do
  1191. if (FSolidEdges[i].FNodeA.FChangedOnStep = FCurrentStepCount) or
  1192. (FSolidEdges[i].FNodeB.FChangedOnStep = FCurrentStepCount) then
  1193. FSolidEdges[i].Changed;
  1194. for i := 0 to FNodes.Count - 1 do
  1195. if (FNodes[i].FChangedOnStep = FCurrentStepCount) then
  1196. FNodes[i].Changed;
  1197. end;
  1198. end;
  1199. procedure TGLVerletWorld.SatisfyConstraints(const vpt: TVerletProgressTimes);
  1200. var
  1201. i, j: Integer;
  1202. Constraint: TVerletConstraint;
  1203. begin
  1204. for i := 0 to FConstraintsWithBeforeIterations.Count - 1 do
  1205. begin
  1206. Constraint := FConstraintsWithBeforeIterations[i];
  1207. Constraint.BeforeIterations;
  1208. end;
  1209. if UpdateSpacePartion = uspEveryFrame then
  1210. Inc(FCurrentStepCount);
  1211. for j := 0 to Iterations - 1 do
  1212. begin
  1213. for i := 0 to FConstraints.Count - 1 do
  1214. with FConstraints[i] do
  1215. if Enabled then
  1216. SatisfyConstraint(j, Iterations); // }
  1217. if UpdateSpacePartion = uspEveryIteration then
  1218. DoUpdateSpacePartition;
  1219. end;
  1220. if UpdateSpacePartion = uspEveryFrame then
  1221. DoUpdateSpacePartition; // }
  1222. end;
  1223. procedure TGLVerletWorld.Verlet(const vpt: TVerletProgressTimes);
  1224. var
  1225. i: Integer;
  1226. begin
  1227. if UpdateSpacePartion <> uspNever then
  1228. Inc(FCurrentStepCount);
  1229. for i := 0 to FNodes.Count - 1 do
  1230. FNodes[i].Verlet(vpt);
  1231. if UpdateSpacePartion <> uspNever then
  1232. DoUpdateSpacePartition;
  1233. end;
  1234. // ------------------
  1235. // ------------------ TVFGravity ------------------
  1236. // ------------------
  1237. constructor TVFGravity.Create(const aOwner: TGLVerletWorld);
  1238. begin
  1239. inherited;
  1240. FGravity.X := 0;
  1241. FGravity.Y := -9.81;
  1242. FGravity.Z := 0;
  1243. end;
  1244. procedure TVFGravity.AddForceToNode(const aNode: TVerletNode);
  1245. begin
  1246. CombineVector(aNode.FForce, Gravity, @aNode.Weight);
  1247. end;
  1248. // ------------------
  1249. // ------------------ TVFSpring ------------------
  1250. // ------------------
  1251. procedure TVFSpring.SetSlack(const Value: Single);
  1252. begin
  1253. if Value <= 0 then
  1254. FSlack := 0
  1255. else
  1256. FSlack := Value;
  1257. end;
  1258. procedure TVFSpring.AddForce;
  1259. var
  1260. hTerm, dTerm: Single;
  1261. deltaV, Force: TAffineVector;
  1262. deltaLength: Single;
  1263. begin
  1264. VectorSubtract(NodeA.Location, NodeB.Location, Force);
  1265. deltaLength := VectorLength(Force);
  1266. if deltaLength > FSlack then
  1267. begin
  1268. hTerm := (FRestLength - deltaLength) * FForceFactor;
  1269. Force := VectorScale(Force, hTerm / deltaLength);
  1270. end
  1271. else
  1272. Force := NullVector;
  1273. if FDamping <> 0 then
  1274. begin
  1275. VectorSubtract(NodeA.GetMovement, NodeB.GetMovement, deltaV);
  1276. dTerm := -0.25 * FDamping * vpt.invSqrDeltaTime;
  1277. CombineVector(Force, deltaV, dTerm);
  1278. end;
  1279. AddVector(NodeA.FForce, Force);
  1280. SubtractVector(NodeB.FForce, Force);
  1281. end;
  1282. procedure TVFSpring.SetRestLengthToCurrent;
  1283. begin
  1284. FRestLength := VectorDistance(NodeA.Location, NodeB.Location);
  1285. FForceFactor := FStrength / FRestLength;
  1286. end;
  1287. // ------------------
  1288. // ------------------ TVFAirResistance ------------------
  1289. // ------------------
  1290. procedure TVFAirResistance.AddForceToNode(const aNode: TVerletNode);
  1291. var
  1292. s, F, FCurrentWindBurst: TAffineVector;
  1293. sMag: Single;
  1294. r: Single;
  1295. Chaos: Single;
  1296. begin
  1297. s := aNode.Speed;
  1298. if FWindMagnitude <> 0 then
  1299. begin
  1300. Chaos := FWindMagnitude * FWindChaos;
  1301. FCurrentWindBurst.X := FWindDirection.X * FWindMagnitude + Chaos * (random - 0.5) * 2;
  1302. FCurrentWindBurst.Y := FWindDirection.Y * FWindMagnitude + Chaos * (random - 0.5) * 2;
  1303. FCurrentWindBurst.Z := FWindDirection.Z * FWindMagnitude + Chaos * (random - 0.5) * 2;
  1304. s := VectorSubtract(s, FCurrentWindBurst);
  1305. end;
  1306. sMag := VectorLength(s);
  1307. r := aNode.Radius + 1;
  1308. if sMag <> 0 then
  1309. begin
  1310. F := VectorScale(s, -Sqr(sMag) * Sqr(r) * pi * FDragCoeff);
  1311. aNode.FForce := VectorAdd(aNode.FForce, F);
  1312. end;
  1313. end;
  1314. constructor TVFAirResistance.Create(const aOwner: TGLVerletWorld);
  1315. begin
  1316. inherited;
  1317. FDragCoeff := 0.001;
  1318. FWindDirection.X := 0;
  1319. FWindDirection.Y := 0;
  1320. FWindDirection.Z := 0;
  1321. FWindMagnitude := 0;
  1322. FWindChaos := 0;
  1323. end;
  1324. procedure TVFAirResistance.SetWindDirection(const Value: TAffineVector);
  1325. begin
  1326. FWindDirection := VectorNormalize(Value);
  1327. end;
  1328. // ------------------
  1329. // ------------------ TVCFloor ------------------
  1330. // ------------------
  1331. constructor TVCFloor.Create(const aOwner: TGLVerletWorld);
  1332. begin
  1333. inherited;
  1334. MakeVector(FNormal, 0, 1, 0);
  1335. MakeVector(FLocation, 0, 0, 0);
  1336. end;
  1337. procedure TVCFloor.PerformSpaceQuery;
  1338. begin
  1339. Owner.SpacePartition.QueryPlane(FLocation, FNormal);
  1340. end;
  1341. procedure TVCFloor.SatisfyConstraintForNode(const aNode: TVerletNode;
  1342. const iteration, maxIterations: Integer);
  1343. var
  1344. penetrationDepth: Single;
  1345. currentPenetrationDepth: Single;
  1346. d: TAffineVector;
  1347. correction: TAffineVector;
  1348. begin
  1349. currentPenetrationDepth := -PointPlaneDistance(aNode.Location, FLocation, FNormal)
  1350. + aNode.Radius + FFloorLevel;
  1351. // Record how far down the node goes
  1352. penetrationDepth := currentPenetrationDepth;
  1353. // Correct the node location
  1354. if currentPenetrationDepth > 0 then
  1355. begin
  1356. correction := VectorScale(FNormal, currentPenetrationDepth);
  1357. if BounceRatio > 0 then
  1358. begin
  1359. d := VectorSubtract(aNode.FLocation, aNode.FOldLocation);
  1360. if FrictionRatio > 0 then
  1361. aNode.ApplyFriction(FrictionRatio, penetrationDepth, FNormal);
  1362. AddVector(aNode.FLocation, correction);
  1363. aNode.FOldLocation := VectorAdd(aNode.FLocation, VectorScale(d, BounceRatio));
  1364. end
  1365. else
  1366. begin
  1367. AddVector(aNode.FLocation, correction);
  1368. if FrictionRatio > 0 then
  1369. aNode.ApplyFriction(FrictionRatio, penetrationDepth, FNormal);
  1370. aNode.FChangedOnStep := Owner.CurrentStepCount;
  1371. end;
  1372. end;
  1373. end;
  1374. procedure TVCFloor.SetNormal(const Value: TAffineVector);
  1375. begin
  1376. FNormal := Value;
  1377. NormalizeVector(FNormal);
  1378. end;
  1379. // ------------------
  1380. // ------------------ TVCHeightField ------------------
  1381. // ------------------
  1382. procedure TVCHeightField.SatisfyConstraintForNode(const aNode: TVerletNode;
  1383. const iteration, maxIterations: Integer);
  1384. var
  1385. penetrationDepth: Single;
  1386. currentPenetrationDepth: Single;
  1387. d: TAffineVector;
  1388. correction: TAffineVector;
  1389. begin
  1390. currentPenetrationDepth := -PointPlaneDistance(aNode.Location, FLocation, FNormal) + aNode.Radius;
  1391. if Assigned(FOnNeedHeight) then
  1392. currentPenetrationDepth := currentPenetrationDepth + FOnNeedHeight(Self, aNode);
  1393. // Record how far down the node goes
  1394. penetrationDepth := currentPenetrationDepth;
  1395. // Correct the node location
  1396. if currentPenetrationDepth > 0 then
  1397. begin
  1398. correction := VectorScale(FNormal, currentPenetrationDepth);
  1399. if BounceRatio > 0 then
  1400. begin
  1401. d := VectorSubtract(aNode.FLocation, aNode.FOldLocation);
  1402. if FrictionRatio > 0 then
  1403. aNode.ApplyFriction(FrictionRatio, penetrationDepth, FNormal);
  1404. AddVector(aNode.FLocation, correction);
  1405. aNode.FOldLocation := VectorAdd(aNode.FLocation, VectorScale(d, BounceRatio));
  1406. end
  1407. else
  1408. begin
  1409. AddVector(aNode.FLocation, correction);
  1410. if FrictionRatio > 0 then
  1411. aNode.ApplyFriction(FrictionRatio, penetrationDepth, FNormal);
  1412. aNode.FChangedOnStep := Owner.CurrentStepCount;
  1413. end;
  1414. end;
  1415. end;
  1416. // ------------------
  1417. // ------------------ TVCStick ------------------
  1418. // ------------------
  1419. procedure TVCStick.SatisfyConstraint(const iteration, maxIterations: Integer);
  1420. var
  1421. delta: TAffineVector;
  1422. F, r: Single;
  1423. deltaLength, diff: Single;
  1424. const
  1425. cDefaultDelta: TAffineVector = (X: 0.01; Y: 0; Z: 0);
  1426. begin
  1427. Assert((NodeA <> NodeB), 'The nodes are identical - that causes division by zero!');
  1428. VectorSubtract(NodeB.Location, NodeA.Location, delta);
  1429. deltaLength := VectorLength(delta);
  1430. // Avoid div by zero!
  1431. if deltaLength < 1E-3 then
  1432. begin
  1433. delta := cDefaultDelta;
  1434. deltaLength := 0.01;
  1435. end;
  1436. diff := (deltaLength - RestLength) / deltaLength;
  1437. if Abs(diff) > Slack then
  1438. begin
  1439. r := 1 / (NodeA.InvWeight + NodeB.InvWeight);
  1440. if diff < 0 then
  1441. diff := (diff + Slack) * r
  1442. else
  1443. diff := (diff - Slack) * r;
  1444. // Take into acount the different weights of the nodes!
  1445. if not NodeA.NailedDown then
  1446. begin
  1447. F := diff * NodeA.InvWeight;
  1448. CombineVector(NodeA.FLocation, delta, F);
  1449. NodeA.FChangedOnStep := Owner.CurrentStepCount;
  1450. end;
  1451. if not NodeB.NailedDown then
  1452. begin
  1453. F := -diff * NodeB.InvWeight;
  1454. CombineVector(NodeB.FLocation, delta, F);
  1455. NodeB.FChangedOnStep := Owner.CurrentStepCount;
  1456. end;
  1457. end;
  1458. end;
  1459. procedure TVCStick.SetRestLengthToCurrent;
  1460. begin
  1461. FRestLength := VectorDistance(NodeA.Location, NodeB.Location);
  1462. end;
  1463. // ------------------
  1464. // ------------------ TVCRigidBody ------------------
  1465. // ------------------
  1466. procedure TVCRigidBody.ComputeBarycenter(var barycenter: TAffineVector);
  1467. var
  1468. i: Integer;
  1469. totWeight: Single;
  1470. begin
  1471. // first we compute the barycenter
  1472. totWeight := 0;
  1473. barycenter := NullVector;
  1474. for i := 0 to Nodes.Count - 1 do
  1475. with Nodes[i] do
  1476. begin
  1477. CombineVector(barycenter, Location, @Weight);
  1478. totWeight := totWeight + Weight;
  1479. end;
  1480. if totWeight > 0 then
  1481. ScaleVector(barycenter, 1 / totWeight);
  1482. end;
  1483. procedure TVCRigidBody.ComputeNaturals(const barycenter: TAffineVector;
  1484. var natX, natY, natZ: TAffineVector);
  1485. var
  1486. i: Integer;
  1487. delta: TAffineVector;
  1488. begin
  1489. natX := NullVector;
  1490. natY := NullVector;
  1491. natZ := NullVector;
  1492. for i := 0 to Nodes.Count - 1 do
  1493. begin
  1494. delta := VectorSubtract(Nodes[i].Location, barycenter);
  1495. CombineVector(natX, delta, FNodeParams[i].X);
  1496. CombineVector(natY, delta, FNodeParams[i].Y);
  1497. CombineVector(natZ, delta, FNodeParams[i].Z);
  1498. end;
  1499. end;
  1500. procedure TVCRigidBody.ComputeRigidityParameters;
  1501. var
  1502. i: Integer;
  1503. barycenter: TAffineVector;
  1504. d: Single;
  1505. begin
  1506. // first we compute the barycenter
  1507. ComputeBarycenter(barycenter);
  1508. // next the parameters
  1509. SetLength(FNodeParams, Nodes.Count);
  1510. SetLength(FNodeCoords, Nodes.Count);
  1511. for i := 0 to Nodes.Count - 1 do
  1512. begin
  1513. FNodeCoords[i] := VectorSubtract(Nodes[i].Location, barycenter);
  1514. d := Nodes[i].Weight / VectorLength(FNodeCoords[i]);
  1515. FNodeParams[i].X := FNodeCoords[i].X * d;
  1516. FNodeParams[i].Y := FNodeCoords[i].Y * d;
  1517. FNodeParams[i].Z := FNodeCoords[i].Z * d;
  1518. end;
  1519. ComputeNaturals(barycenter, FNatMatrix.X, FNatMatrix.Y, FNatMatrix.Z);
  1520. FNatMatrix.Z:=VectorCrossProduct(FNatMatrix.X, FNatMatrix.Y);
  1521. FNatMatrix.Y:=VectorCrossProduct(FNatMatrix.Z, FNatMatrix.X);
  1522. NormalizeVector(FNatMatrix.X);
  1523. NormalizeVector(FNatMatrix.Y);
  1524. NormalizeVector(FNatMatrix.Z);
  1525. FInvNatMatrix := FNatMatrix;
  1526. // TransposeMatrix(FInvNatMatrix);
  1527. InvertMatrix(FInvNatMatrix);
  1528. end;
  1529. procedure TVCRigidBody.SatisfyConstraint(const iteration, maxIterations: Integer);
  1530. var
  1531. i: Integer;
  1532. barycenter, delta: TAffineVector;
  1533. nrjBase, nrjAdjust: TAffineVector;
  1534. natural: array [0 .. 2] of TAffineVector;
  1535. deltas: array of TAffineVector;
  1536. begin
  1537. Assert(Nodes.Count = Length(FNodeParams), 'You forgot to call ComputeRigidityParameters!');
  1538. // compute the barycenter
  1539. ComputeBarycenter(barycenter);
  1540. // compute the natural axises
  1541. ComputeNaturals(barycenter, natural[0], natural[1], natural[2]);
  1542. natural[2] := VectorCrossProduct(natural[0], natural[1]);
  1543. natural[1] := VectorCrossProduct(natural[2], natural[0]);
  1544. for i := 0 to 2 do
  1545. NormalizeVector(natural[i]);
  1546. natural[0] := VectorTransform(natural[0], FInvNatMatrix);
  1547. natural[1] := VectorTransform(natural[1], FInvNatMatrix);
  1548. natural[2] := VectorTransform(natural[2], FInvNatMatrix);
  1549. // make the natural axises orthonormal, by picking the longest two
  1550. { for i:=0 to 2 do
  1551. vectNorm[i]:=VectorNorm(natural[i]);
  1552. if (vectNorm[0]<vectNorm[1]) and (vectNorm[0]<vectNorm[2]) then begin
  1553. natural[0]:=VectorCrossProduct(natural[1], natural[2]);
  1554. natural[1]:=VectorCrossProduct(natural[2], natural[0]);
  1555. end else if (vectNorm[1]<vectNorm[0]) and (vectNorm[1]<vectNorm[2]) then begin
  1556. natural[1]:=VectorCrossProduct(natural[2], natural[0]);
  1557. natural[2]:=VectorCrossProduct(natural[0], natural[1]);
  1558. end else begin
  1559. natural[2]:=VectorCrossProduct(natural[0], natural[1]);
  1560. natural[0]:=VectorCrossProduct(natural[1], natural[2]);
  1561. end; }
  1562. // now the axises are back, recompute the position of all points
  1563. SetLength(deltas, Nodes.Count);
  1564. nrjBase := NullVector;
  1565. for i := 0 to Nodes.Count - 1 do
  1566. begin
  1567. nrjBase := VectorAdd(nrjBase, VectorCrossProduct(VectorSubtract(Nodes[i].Location, barycenter),
  1568. Nodes[i].GetMovement));
  1569. end;
  1570. nrjAdjust := NullVector;
  1571. for i := 0 to Nodes.Count - 1 do
  1572. begin
  1573. delta := VectorCombine3(natural[0], natural[1], natural[2],
  1574. FNodeCoords[i].X, FNodeCoords[i].Y, FNodeCoords[i].Z);
  1575. deltas[i] := VectorSubtract(VectorAdd(barycenter, delta), Nodes[i].Location);
  1576. nrjAdjust := VectorAdd(nrjBase, VectorCrossProduct(VectorSubtract(Nodes[i].Location, barycenter), deltas[i]));
  1577. Nodes[i].Location := VectorAdd(Nodes[i].Location, deltas[i]);
  1578. Nodes[i].FOldLocation := VectorAdd(Nodes[i].FOldLocation, deltas[i]);
  1579. // Nodes[i].FOldLocation:=Nodes[i].Location;
  1580. end;
  1581. deltas[0] := nrjBase;
  1582. deltas[1] := nrjAdjust;
  1583. end;
  1584. // ------------------
  1585. // ------------------ TVCSlider ------------------
  1586. // ------------------
  1587. procedure TVCSlider.SetSlideDirection(const Value: TAffineVector);
  1588. begin
  1589. FSlideDirection := VectorNormalize(Value);
  1590. end;
  1591. procedure TVCSlider.SatisfyConstraint(const iteration, maxIterations: Integer);
  1592. var
  1593. delta: TAffineVector;
  1594. F, r: Single;
  1595. projB: TAffineVector;
  1596. begin
  1597. Assert((NodeA <> NodeB), 'The nodes are identical - that causes division by zero!');
  1598. // project B in the plane defined by A and SlideDirection
  1599. projB := VectorSubtract(NodeB.Location, NodeA.Location);
  1600. F := VectorDotProduct(projB, SlideDirection);
  1601. projB := VectorCombine(NodeB.Location, SlideDirection, 1, -F);
  1602. if Constrained and (F < 0) then
  1603. NodeB.Location := projB;
  1604. VectorSubtract(projB, NodeA.Location, delta);
  1605. // Take into acount the different weights of the nodes!
  1606. r := 1 / (NodeA.InvWeight + NodeB.InvWeight);
  1607. if not NodeA.NailedDown then
  1608. begin
  1609. F := r * NodeA.InvWeight;
  1610. CombineVector(NodeA.FLocation, delta, F);
  1611. NodeA.FChangedOnStep := Owner.CurrentStepCount;
  1612. end;
  1613. if not NodeB.NailedDown then
  1614. begin
  1615. F := -r * NodeB.InvWeight;
  1616. CombineVector(NodeB.FLocation, delta, F);
  1617. NodeB.FChangedOnStep := Owner.CurrentStepCount;
  1618. end;
  1619. end;
  1620. // ------------------
  1621. // ------------------ TVCSphere ------------------
  1622. // ------------------
  1623. function TVCSphere.GetBSphere: TBSphere;
  1624. begin
  1625. result.Center := FLocation;
  1626. result.Radius := FRadius;
  1627. end;
  1628. procedure TVCSphere.SatisfyConstraintForEdge(const aEdge: TGLVerletEdge; const iteration, maxIterations: Integer);
  1629. var
  1630. closestPoint, move, delta, contactNormal: TAffineVector;
  1631. deltaLength, diff: Single;
  1632. begin
  1633. // If the edge penetrates the sphere, try pushing the nodes until it no
  1634. // longer does
  1635. closestPoint := PointSegmentClosestPoint(FLocation, aEdge.NodeA.FLocation, aEdge.NodeB.FLocation);
  1636. // Find the distance between the two
  1637. VectorSubtract(closestPoint, Location, delta);
  1638. deltaLength := VectorLength(delta);
  1639. if deltaLength < Radius then
  1640. begin
  1641. if deltaLength > 0 then
  1642. begin
  1643. contactNormal := VectorScale(delta, 1 / deltaLength);
  1644. aEdge.NodeA.ApplyFriction(FFrictionRatio, Radius - Abs(deltaLength), contactNormal);
  1645. aEdge.NodeB.ApplyFriction(FFrictionRatio, Radius - Abs(deltaLength), contactNormal);
  1646. end;
  1647. // Move it outside the sphere!
  1648. diff := (Radius - deltaLength) / deltaLength;
  1649. VectorScale(delta, diff, move);
  1650. AddVector(aEdge.NodeA.FLocation, move);
  1651. AddVector(aEdge.NodeB.FLocation, move);
  1652. // Add the force to the kickback
  1653. // F = a * m
  1654. // a = move / deltatime
  1655. AddKickbackForceAt(FLocation,
  1656. VectorScale(move, -(aEdge.NodeA.FWeight + aEdge.NodeB.FWeight) * Owner.FInvCurrentDeltaTime));
  1657. aEdge.NodeA.FChangedOnStep := Owner.CurrentStepCount;
  1658. aEdge.NodeB.FChangedOnStep := Owner.CurrentStepCount;
  1659. end;
  1660. end;
  1661. procedure TVCSphere.SatisfyConstraintForNode(const aNode: TVerletNode;
  1662. const iteration, maxIterations: Integer);
  1663. var
  1664. delta, move, contactNormal: TAffineVector;
  1665. deltaLength, diff: Single;
  1666. begin
  1667. // Find the distance between the two
  1668. VectorSubtract(aNode.Location, Location, delta);
  1669. // Is it inside the sphere?
  1670. deltaLength := VectorLength(delta) - aNode.Radius;
  1671. if Abs(deltaLength) < Radius then
  1672. begin
  1673. if deltaLength > 0 then
  1674. begin
  1675. contactNormal := VectorScale(delta, 1 / deltaLength);
  1676. aNode.ApplyFriction(FFrictionRatio, Radius - Abs(deltaLength), contactNormal);
  1677. end
  1678. else
  1679. // Slow it down - this part should not be fired
  1680. aNode.OldApplyFriction(FFrictionRatio, Radius - Abs(deltaLength));
  1681. // Move it outside the sphere!
  1682. diff := (Radius - deltaLength) / deltaLength;
  1683. VectorScale(delta, diff, move);
  1684. AddVector(aNode.FLocation, move);
  1685. aNode.FChangedOnStep := Owner.CurrentStepCount;
  1686. // Add the force to the kickback
  1687. // F = a * m
  1688. // a = move / deltatime
  1689. AddKickbackForceAt(FLocation,
  1690. VectorScale(move, -aNode.FWeight * Owner.FInvCurrentDeltaTime));
  1691. end;
  1692. end;
  1693. // ------------------
  1694. // ------------------ TVCCylinder ------------------
  1695. // ------------------
  1696. procedure TVCCylinder.SetRadius(const val: Single);
  1697. begin
  1698. FRadius := val;
  1699. FRadius2 := Sqr(val);
  1700. end;
  1701. procedure TVCCylinder.SatisfyConstraintForNode(const aNode: TVerletNode;
  1702. const iteration, maxIterations: Integer);
  1703. var
  1704. proj, newLocation, move: TAffineVector;
  1705. F, dist2, penetrationDepth: Single;
  1706. begin
  1707. // Compute projection of node position on the axis
  1708. F := PointProject(aNode.Location, FLocation, FAxis);
  1709. proj := VectorCombine(FLocation, FAxis, 1, F);
  1710. // Sqr distance
  1711. dist2 := VectorDistance2(proj, aNode.Location);
  1712. if dist2 < FRadius2 then
  1713. begin
  1714. // move out of the cylinder
  1715. VectorLerp(proj, aNode.Location, FRadius * RSqrt(dist2), newLocation);
  1716. move := VectorSubtract(aNode.FLocation, newLocation);
  1717. penetrationDepth := VectorLength(move);
  1718. aNode.ApplyFriction(FFrictionRatio, penetrationDepth, VectorScale(move, 1 / penetrationDepth));
  1719. aNode.FLocation := newLocation;
  1720. aNode.FChangedOnStep := Owner.CurrentStepCount;
  1721. end;
  1722. end;
  1723. // ------------------
  1724. // ------------------ TVCCube ------------------
  1725. // ------------------
  1726. function TVCCube.GetAABB: TAABB;
  1727. begin
  1728. VectorAdd(FLocation, FHalfSides, result.max);
  1729. VectorSubtract(FLocation, FHalfSides, result.min);
  1730. end;
  1731. // BROKEN AND VERY SLOW!
  1732. procedure TVCCube.SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
  1733. const iteration, maxIterations: Integer);
  1734. var
  1735. Corners: array [0 .. 7] of TAffineVector;
  1736. EdgeRelative: array [0 .. 1] of TAffineVector;
  1737. shortestMove { , contactNormal } : TAffineVector;
  1738. shortestDeltaLength: Single;
  1739. procedure AddCorner(CornerID: Integer; X, Y, Z: Single);
  1740. begin
  1741. X := (X - 0.5) * 2;
  1742. Y := (Y - 0.5) * 2;
  1743. Z := (Z - 0.5) * 2;
  1744. MakeVector(Corners[CornerID], FHalfSides.X * X, FHalfSides.Y * Y, FHalfSides.Z * Z);
  1745. AddVector(Corners[CornerID], FLocation);
  1746. end;
  1747. procedure TryEdge(Corner0, Corner1: Integer);
  1748. var
  1749. CubeEdgeClosest, aEdgeClosest: TAffineVector;
  1750. CenteraEdge, move: TAffineVector;
  1751. deltaLength: Single;
  1752. begin
  1753. SegmentSegmentClosestPoint(
  1754. Corners[Corner0],
  1755. Corners[Corner1],
  1756. aEdge.NodeA.FLocation,
  1757. aEdge.NodeB.FLocation,
  1758. CubeEdgeClosest,
  1759. aEdgeClosest);
  1760. CenteraEdge := VectorSubtract(aEdgeClosest, FLocation);
  1761. if (Abs(CenteraEdge.X) < FHalfSides.X) and
  1762. (Abs(CenteraEdge.Y) < FHalfSides.Y) and
  1763. (Abs(CenteraEdge.Z) < FHalfSides.Z) then
  1764. begin
  1765. // The distance to move the edge is the difference between CenterCubeEdge and
  1766. // CenteraEdge
  1767. move := VectorSubtract(CubeEdgeClosest, aEdgeClosest);
  1768. deltaLength := VectorLength(move);
  1769. if (deltaLength > 0) and (deltaLength < shortestDeltaLength) then
  1770. begin
  1771. shortestDeltaLength := deltaLength;
  1772. shortestMove := move;
  1773. end;
  1774. end;
  1775. end;
  1776. begin
  1777. // DISABLED!
  1778. Exit;
  1779. // Early out test
  1780. EdgeRelative[0] := VectorSubtract(aEdge.FNodeA.FLocation, FLocation);
  1781. EdgeRelative[1] := VectorSubtract(aEdge.FNodeB.FLocation, FLocation);
  1782. // If both edges are on the same side of _any_ box side, the edge can't
  1783. // cut the box
  1784. if ((EdgeRelative[0].X > FHalfSides.X) and (EdgeRelative[1].X > FHalfSides.X)) or
  1785. ((EdgeRelative[0].X < -FHalfSides.X) and (EdgeRelative[1].X < -FHalfSides.X)) or
  1786. ((EdgeRelative[0].Y > FHalfSides.Y) and (EdgeRelative[1].Y > FHalfSides.Y)) or
  1787. ((EdgeRelative[0].Y < -FHalfSides.Y) and (EdgeRelative[1].Y < -FHalfSides.Y)) or
  1788. ((EdgeRelative[0].Z > FHalfSides.Z) and (EdgeRelative[1].Z > FHalfSides.Z)) or
  1789. ((EdgeRelative[0].Z < -FHalfSides.Z) and (EdgeRelative[1].Z < -FHalfSides.Z)) then
  1790. begin
  1791. Exit;
  1792. end;
  1793. // For each cube edge:
  1794. // find closest positions between CubeEdge and aEdge
  1795. // if aEdgeClosestPosition within cube then
  1796. // move nodes until closest position is outside cube
  1797. // exit
  1798. AddCorner(0, 0, 0, 0);
  1799. AddCorner(1, 1, 0, 0);
  1800. AddCorner(2, 1, 1, 0);
  1801. AddCorner(3, 0, 1, 0);
  1802. AddCorner(4, 0, 0, 1);
  1803. AddCorner(5, 1, 0, 1);
  1804. AddCorner(6, 1, 1, 1);
  1805. AddCorner(7, 0, 1, 1);
  1806. shortestDeltaLength := 10E30;
  1807. TryEdge(0, 1);
  1808. TryEdge(1, 2);
  1809. TryEdge(2, 3);
  1810. TryEdge(3, 0);
  1811. TryEdge(4, 5);
  1812. TryEdge(5, 6);
  1813. TryEdge(6, 7);
  1814. TryEdge(7, 4);
  1815. TryEdge(0, 3);
  1816. TryEdge(1, 5);
  1817. TryEdge(2, 6);
  1818. TryEdge(3, 7);
  1819. if shortestDeltaLength < 10E8 then
  1820. begin
  1821. // contactNormal := VectorScale(shortestMove, 1/shortestDeltaLength);
  1822. { aEdge.NodeA.ApplyFriction(FFrictionRatio, shortestDeltaLength, contactNormal);
  1823. aEdge.NodeB.ApplyFriction(FFrictionRatio, shortestDeltaLength, contactNormal);// }
  1824. AddVector(aEdge.NodeA.FLocation, shortestMove);
  1825. AddVector(aEdge.NodeB.FLocation, shortestMove);
  1826. aEdge.NodeA.Changed;
  1827. aEdge.NodeB.Changed;
  1828. aEdge.NodeA.FChangedOnStep := Owner.CurrentStepCount;
  1829. aEdge.NodeB.FChangedOnStep := Owner.CurrentStepCount;
  1830. end;
  1831. end;
  1832. procedure TVCCube.SatisfyConstraintForNode(const aNode: TVerletNode;
  1833. const iteration, maxIterations: Integer);
  1834. var
  1835. p, absP, contactNormal: TAffineVector;
  1836. dp: Single;
  1837. smallestSide: Integer;
  1838. begin
  1839. // TODO: Direction of Cube should be used to rotate the nodes location, as it
  1840. // stands, the cube can only face in one direction.
  1841. p := VectorSubtract(aNode.FLocation, FLocation);
  1842. absP.X := FHalfSides.X - Abs(p.X);
  1843. absP.Y := FHalfSides.Y - Abs(p.Y);
  1844. absP.Z := FHalfSides.Z - Abs(p.Z);
  1845. if (PInteger(@absP.X)^ <= 0) or (PInteger(@absP.Y)^ <= 0) or (PInteger(@absP.Z)^ <= 0) then
  1846. Exit;
  1847. if absP.X < absP.Y then
  1848. if absP.X < absP.Z then
  1849. smallestSide := 0
  1850. else
  1851. smallestSide := 2
  1852. else if absP.Y < absP.Z then
  1853. smallestSide := 1
  1854. else
  1855. smallestSide := 2;
  1856. contactNormal := NullVector;
  1857. // Only move along the "shortest" axis
  1858. if PInteger(@p.V[smallestSide])^ >= 0 then
  1859. begin
  1860. dp := absP.V[smallestSide];
  1861. contactNormal.V[smallestSide] := 1;
  1862. aNode.ApplyFriction(FFrictionRatio, dp, contactNormal);
  1863. aNode.FLocation.V[smallestSide] := aNode.FLocation.V[smallestSide] + dp;
  1864. end
  1865. else
  1866. begin
  1867. dp := absP.V[smallestSide];
  1868. contactNormal.V[smallestSide] := -1;
  1869. aNode.ApplyFriction(FFrictionRatio, dp, contactNormal);
  1870. aNode.FLocation.V[smallestSide] := aNode.FLocation.V[smallestSide] - dp;
  1871. end;
  1872. aNode.FChangedOnStep := Owner.CurrentStepCount;
  1873. end;
  1874. procedure TVCCube.SetSides(const Value: TAffineVector);
  1875. begin
  1876. FSides := Value;
  1877. FHalfSides := VectorScale(Sides, 0.5);
  1878. UpdateCachedAABB;
  1879. end;
  1880. // ------------------
  1881. // ------------------ TVCCapsule ------------------
  1882. // ------------------
  1883. procedure TVCCapsule.SetAxis(const val: TAffineVector);
  1884. begin
  1885. FAxis := VectorNormalize(val);
  1886. UpdateCachedBSphere;
  1887. end;
  1888. procedure TVCCapsule.SetLength(const val: Single);
  1889. begin
  1890. FLength := val;
  1891. FLengthDiv2 := val * 0.5;
  1892. UpdateCachedBSphere;
  1893. end;
  1894. procedure TVCCapsule.SetRadius(const val: Single);
  1895. begin
  1896. FRadius := val;
  1897. FRadius2 := Sqr(val);
  1898. UpdateCachedBSphere;
  1899. end;
  1900. function TVCCapsule.GetBSphere: TBSphere;
  1901. begin
  1902. result.Center := FLocation;
  1903. result.Radius := Length + Radius;
  1904. end;
  1905. procedure TVCCapsule.SatisfyConstraintForNode(const aNode: TVerletNode;
  1906. const iteration, maxIterations: Integer);
  1907. var
  1908. p, n2, penetrationDepth: Single;
  1909. closest, v: TAffineVector;
  1910. newLocation, move: TAffineVector;
  1911. begin
  1912. // Find the closest point to location on the capsule axis
  1913. p := ClampValue(PointProject(aNode.Location, FLocation, FAxis), -FLengthDiv2, FLengthDiv2);
  1914. closest := VectorCombine(FLocation, FAxis, 1, p);
  1915. // vector from closest to location
  1916. VectorSubtract(aNode.Location, closest, v);
  1917. // should it be altered?
  1918. n2 := VectorNorm(v);
  1919. if n2 < FRadius2 then
  1920. begin
  1921. newLocation := VectorCombine(closest, v, 1, Sqrt(FRadius2 / n2));
  1922. // Do friction calculations
  1923. move := VectorSubtract(newLocation, aNode.FLocation);
  1924. penetrationDepth := VectorLength(move);
  1925. // aNode.OldApplyFriction(FFrictionRatio, penetrationDepth);
  1926. aNode.ApplyFriction(FFrictionRatio, penetrationDepth, VectorScale(move, 1 / penetrationDepth));
  1927. aNode.FLocation := newLocation;
  1928. aNode.FChangedOnStep := Owner.CurrentStepCount;
  1929. AddKickbackForceAt(FLocation,
  1930. VectorScale(move, -aNode.FWeight * Owner.FInvCurrentDeltaTime));
  1931. end;
  1932. end;
  1933. procedure TVCCapsule.SatisfyConstraintForEdge(const aEdge: TGLVerletEdge;
  1934. const iteration, maxIterations: Integer);
  1935. var
  1936. sphereLocation, closestPoint, dummy, delta, move, contactNormal: TAffineVector;
  1937. Ax0, Ax1: TAffineVector;
  1938. deltaLength, diff, penetrationDepth: Single;
  1939. begin
  1940. VectorScale(FAxis, FLengthDiv2, Ax0);
  1941. AddVector(Ax0, FLocation);
  1942. VectorScale(FAxis, -FLengthDiv2, Ax1);
  1943. AddVector(Ax1, FLocation);
  1944. SegmentSegmentClosestPoint(aEdge.NodeA.FLocation, aEdge.NodeB.FLocation, Ax0, Ax1, dummy, sphereLocation);
  1945. // If the edge penetrates the sphere, try pushing the nodes until it no
  1946. // longer does
  1947. closestPoint := PointSegmentClosestPoint(sphereLocation, aEdge.NodeA.FLocation, aEdge.NodeB.FLocation);
  1948. // Find the distance between the two
  1949. VectorSubtract(closestPoint, sphereLocation, delta);
  1950. deltaLength := VectorLength(delta);
  1951. if deltaLength < Radius then
  1952. begin
  1953. // Move it outside the sphere!
  1954. diff := (Radius - deltaLength) / deltaLength;
  1955. VectorScale(delta, diff, move);
  1956. penetrationDepth := VectorLength(move);
  1957. contactNormal := VectorScale(move, 1 / penetrationDepth);
  1958. aEdge.NodeA.ApplyFriction(FFrictionRatio, penetrationDepth, contactNormal);
  1959. aEdge.NodeB.ApplyFriction(FFrictionRatio, penetrationDepth, contactNormal);
  1960. AddVector(aEdge.NodeA.FLocation, move);
  1961. AddVector(aEdge.NodeB.FLocation, move);
  1962. aEdge.NodeA.FChangedOnStep := Owner.CurrentStepCount;
  1963. aEdge.NodeB.FChangedOnStep := Owner.CurrentStepCount;
  1964. AddKickbackForceAt(FLocation,
  1965. VectorScale(move, -(aEdge.NodeA.FWeight + aEdge.NodeB.FWeight) * Owner.FInvCurrentDeltaTime));
  1966. end;
  1967. end;
  1968. // ------------------
  1969. // ------------------ TGLVerletEdge ------------------
  1970. // ------------------
  1971. constructor TGLVerletEdge.CreateEdgeOwned(const aNodeA, aNodeB: TVerletNode);
  1972. begin
  1973. FNodeA := aNodeA;
  1974. FNodeB := aNodeB;
  1975. inherited CreateOwned(aNodeA.Owner.SpacePartition);
  1976. end;
  1977. procedure TGLVerletEdge.UpdateCachedAABBAndBSphere;
  1978. begin
  1979. FCachedAABB.min := FNodeA.FLocation;
  1980. FCachedAABB.max := FNodeA.FLocation;
  1981. AABBInclude(FCachedAABB, FNodeB.FLocation);
  1982. AABBToBSphere(FCachedAABB, FCachedBSphere);
  1983. end;
  1984. // ------------------
  1985. // ------------------ TGLVerletEdgeList ------------------
  1986. // ------------------
  1987. function TGLVerletEdgeList.GetItems(i: Integer): TGLVerletEdge;
  1988. begin
  1989. result := Get(i);
  1990. end;
  1991. procedure TGLVerletEdgeList.SetItems(i: Integer; const Value: TGLVerletEdge);
  1992. begin
  1993. Put(i, Value);
  1994. end;
  1995. procedure TVerletNode.UpdateCachedAABBAndBSphere;
  1996. begin
  1997. FCachedAABB.min := FLocation;
  1998. FCachedAABB.max := FLocation;
  1999. FCachedBSphere.Center := FLocation;
  2000. FCachedBSphere.Radius := 0;
  2001. end;
  2002. procedure TVerletNode.SetLocation(const Value: TAffineVector);
  2003. begin
  2004. FLocation := Value;
  2005. FChangedOnStep := Owner.CurrentStepCount;
  2006. end;
  2007. procedure TGLVerletWorld.CreateOctree(const OctreeMin,
  2008. OctreeMax: TAffineVector; const LeafThreshold, MaxTreeDepth: Integer);
  2009. var
  2010. Octree: TOctreeSpacePartition;
  2011. begin
  2012. Assert(FNodes.Count = 0, 'You can only create an octree while the world is empty!');
  2013. FreeAndNil(FSpacePartition);
  2014. Octree := TOctreeSpacePartition.Create;
  2015. Octree.SetSize(OctreeMin, OctreeMax);
  2016. Octree.MaxTreeDepth := MaxTreeDepth;
  2017. Octree.LeafThreshold := LeafThreshold;
  2018. Octree.CullingMode := cmGrossCulling;
  2019. FSpacePartition := Octree;
  2020. if FUpdateSpacePartion = uspNever then
  2021. FUpdateSpacePartion := uspEveryFrame;
  2022. end;
  2023. procedure TGLVerletWorld.PauseInertia(const IterationSteps: Integer);
  2024. begin
  2025. FInertaPauseSteps := IterationSteps + 1;
  2026. Inertia := False;
  2027. end;
  2028. { TGLVerletGlobalFrictionConstraintBox }
  2029. procedure TGLVerletGlobalFrictionConstraintBox.PerformSpaceQuery;
  2030. begin
  2031. Owner.SpacePartition.QueryAABB(FCachedAABB);
  2032. end;
  2033. procedure TGLVerletGlobalFrictionConstraintBox.SetLocation(const Value: TAffineVector);
  2034. begin
  2035. inherited;
  2036. UpdateCachedAABB;
  2037. end;
  2038. procedure TGLVerletGlobalFrictionConstraintBox.UpdateCachedAABB;
  2039. begin
  2040. FCachedAABB := GetAABB;
  2041. end;
  2042. { TGLVerletGlobalFrictionConstraintSphere }
  2043. procedure TGLVerletGlobalFrictionConstraintSphere.PerformSpaceQuery;
  2044. begin
  2045. Owner.SpacePartition.QueryBSphere(FCachedBSphere);
  2046. end;
  2047. procedure TGLVerletGlobalFrictionConstraintSphere.SetLocation(const Value: TAffineVector);
  2048. begin
  2049. inherited;
  2050. UpdateCachedBSphere;
  2051. end;
  2052. procedure TGLVerletGlobalFrictionConstraintSphere.UpdateCachedBSphere;
  2053. begin
  2054. FCachedBSphere := GetBSphere;
  2055. end;
  2056. constructor TGLVerletGlobalConstraint.Create(const aOwner: TGLVerletWorld);
  2057. begin
  2058. inherited;
  2059. if Assigned(aOwner) then
  2060. aOwner.ConstraintsWithBeforeIterations.Add(Self);
  2061. end;
  2062. destructor TGLVerletGlobalConstraint.Destroy;
  2063. begin
  2064. if Assigned(Owner) then
  2065. Owner.ConstraintsWithBeforeIterations.Remove(Self);
  2066. inherited;
  2067. end;
  2068. end.