2
0

GXS.VerletTypes.pas 84 KB

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