GLVerletHairClasses.pas 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLVerletHairClasses;
  5. (*
  6. Creates a single strand of hair using verlet classes. Can be used to simulate
  7. ropes, fur or hair.
  8. *)
  9. interface
  10. {$I GLScene.inc}
  11. uses
  12. System.Classes,
  13. System.SysUtils,
  14. GLVerletTypes,
  15. GLVectorTypes,
  16. GLVectorLists,
  17. GLVectorGeometry;
  18. type
  19. TVHStiffness = (vhsFull, vhsSkip1Node, vhsSkip2Node, vhsSkip3Node,
  20. vhsSkip4Node, vhsSkip5Node, vhsSkip6Node, vhsSkip7Node, vhsSkip8Node,
  21. vhsSkip9Node);
  22. TVHStiffnessSet = set of TVHStiffness;
  23. TGLVerletHair = class
  24. private
  25. FNodeList: TVerletNodeList;
  26. FLinkCount: integer;
  27. FRootDepth: single;
  28. FVerletWorld: TGLVerletWorld;
  29. FHairLength: single;
  30. FData: pointer;
  31. FStiffness: TVHStiffnessSet;
  32. FStiffnessList : TList;
  33. function GetAnchor: TVerletNode;
  34. function GetRoot: TVerletNode;
  35. function GetLinkLength: single;
  36. procedure AddStickStiffness(const ANodeSkip : integer);
  37. procedure SetStiffness(const Value: TVHStiffnessSet);
  38. public
  39. procedure BuildHair(const AAnchorPosition, AHairDirection: TAffineVector);
  40. procedure BuildStiffness;
  41. procedure ClearStiffness;
  42. procedure Clear;
  43. constructor Create(const AVerletWorld : TGLVerletWorld;
  44. const ARootDepth, AHairLength : single; ALinkCount : integer;
  45. const AAnchorPosition, AHairDirection : TAffineVector;
  46. const AStiffness : TVHStiffnessSet);
  47. destructor Destroy; override;
  48. property NodeList : TVerletNodeList read FNodeList;
  49. property VerletWorld : TGLVerletWorld read FVerletWorld;
  50. property RootDepth : single read FRootDepth;
  51. property LinkLength : single read GetLinkLength;
  52. property LinkCount : integer read FLinkCount;
  53. property HairLength : single read FHairLength;
  54. property Stiffness : TVHStiffnessSet read FStiffness write SetStiffness;
  55. property Data : pointer read FData write FData;
  56. {Anchor should be nailed down to give the hair stability }
  57. property Anchor : TVerletNode read GetAnchor;
  58. {Root should be nailed down to give the hair stability }
  59. property Root : TVerletNode read GetRoot;
  60. end;
  61. //------------------------------------------------------------------
  62. implementation
  63. //------------------------------------------------------------------
  64. { TGLVerletHair }
  65. procedure TGLVerletHair.AddStickStiffness(const ANodeSkip: integer);
  66. var
  67. i : integer;
  68. begin
  69. for i := 0 to NodeList.Count-(1+ANodeSkip*2) do
  70. FStiffnessList.Add(VerletWorld.CreateStick(NodeList[i], NodeList[i+2*ANodeSkip]));
  71. end;
  72. procedure TGLVerletHair.BuildHair(const AAnchorPosition, AHairDirection: TAffineVector);
  73. var
  74. i : integer;
  75. Position : TAffineVector;
  76. Node, PrevNode : TVerletNode;
  77. Direction : TAffineVector;
  78. begin
  79. Clear;
  80. Direction := VectorNormalize(AHairDirection);
  81. // Fix the root of the hair
  82. Position := VectorAdd(AAnchorPosition, VectorScale(Direction, -FRootDepth));
  83. Node := VerletWorld.CreateOwnedNode(Position);
  84. NodeList.Add(Node);
  85. Node.NailedDown := true;
  86. PrevNode := Node;
  87. // Now add the links in the hair
  88. for i := 0 to FLinkCount-1 do
  89. begin
  90. Position := VectorAdd(AAnchorPosition, VectorScale(Direction, HairLength * (i/LinkCount)));
  91. Node := VerletWorld.CreateOwnedNode(Position);
  92. NodeList.Add(Node);
  93. // first one is the anchor
  94. if i=0 then
  95. Node.NailedDown := true
  96. else
  97. // Creates the hair link
  98. VerletWorld.CreateStick(PrevNode, Node);
  99. PrevNode := Node;
  100. end;
  101. // Now we must stiffen the hair with either sticks or springs
  102. BuildStiffness;
  103. end;
  104. procedure TGLVerletHair.BuildStiffness;
  105. var
  106. i : integer;
  107. begin
  108. ClearStiffness;
  109. if vhsFull in FStiffness then
  110. begin
  111. for i := 1 to 100 do
  112. AddStickStiffness(i);
  113. exit;
  114. end;
  115. if vhsSkip1Node in FStiffness then AddStickStiffness(1);
  116. if vhsSkip2Node in FStiffness then AddStickStiffness(2);
  117. if vhsSkip3Node in FStiffness then AddStickStiffness(3);
  118. if vhsSkip4Node in FStiffness then AddStickStiffness(4);
  119. if vhsSkip5Node in FStiffness then AddStickStiffness(5);
  120. if vhsSkip6Node in FStiffness then AddStickStiffness(6);
  121. if vhsSkip7Node in FStiffness then AddStickStiffness(7);
  122. if vhsSkip8Node in FStiffness then AddStickStiffness(8);
  123. if vhsSkip9Node in FStiffness then AddStickStiffness(9);
  124. end;
  125. procedure TGLVerletHair.Clear;
  126. var
  127. i : integer;
  128. begin
  129. ClearStiffness;
  130. for i := FNodeList.Count-1 downto 0 do
  131. FNodeList[i].Free;
  132. FNodeList.Clear;
  133. FStiffnessList.Clear;
  134. end;
  135. procedure TGLVerletHair.ClearStiffness;
  136. var
  137. i : integer;
  138. begin
  139. for i := 0 to FStiffnessList.Count-1 do
  140. TVerletConstraint(FStiffnessList[i]).Free;
  141. FStiffnessList.Clear;
  142. end;
  143. constructor TGLVerletHair.Create(const AVerletWorld : TGLVerletWorld;
  144. const ARootDepth, AHairLength : single; ALinkCount : integer;
  145. const AAnchorPosition, AHairDirection : TAffineVector;
  146. const AStiffness : TVHStiffnessSet);
  147. begin
  148. FVerletWorld := AVerletWorld;
  149. FRootDepth := ARootDepth;
  150. FLinkCount := ALinkCount;
  151. FHairLength := AHairLength;
  152. FNodeList := TVerletNodeList.Create;
  153. FStiffness := AStiffness;
  154. FStiffnessList := TList.Create;
  155. BuildHair(AAnchorPosition, AHairDirection);
  156. end;
  157. destructor TGLVerletHair.Destroy;
  158. begin
  159. Clear;
  160. FreeAndNil(FNodeList);
  161. FreeAndNil(FStiffnessList);
  162. inherited;
  163. end;
  164. function TGLVerletHair.GetAnchor: TVerletNode;
  165. begin
  166. result := NodeList[1];
  167. end;
  168. function TGLVerletHair.GetLinkLength: single;
  169. begin
  170. if LinkCount>0 then
  171. result := HairLength / LinkCount
  172. else
  173. result := 0;
  174. end;
  175. function TGLVerletHair.GetRoot: TVerletNode;
  176. begin
  177. result := NodeList[0];
  178. end;
  179. procedure TGLVerletHair.SetStiffness(const Value: TVHStiffnessSet);
  180. begin
  181. FStiffness := Value;
  182. BuildStiffness;
  183. end;
  184. end.