GLS.VerletTypes.pas 84 KB

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