2
// This unit is part of the GLScene Engine https://github.com/glscene
5
Creates a single strand of hair using verlet classes. Can be used to simulate
9
29/05/08 - DaStr - Added $I GLScene.inc
10
06/03/04 - MF - Creation
13
unit GLVerletHairClasses;
21
GLVerletTypes, GLVectorTypes, GLVectorLists, GLVectorGeometry;
24
TVHStiffness = (vhsFull, vhsSkip1Node, vhsSkip2Node, vhsSkip3Node,
25
vhsSkip4Node, vhsSkip5Node, vhsSkip6Node, vhsSkip7Node, vhsSkip8Node,
27
TVHStiffnessSet = set of TVHStiffness;
31
FNodeList: TVerletNodeList;
34
FVerletWorld: TGLVerletWorld;
37
FStiffness: TVHStiffnessSet;
38
FStiffnessList : TList;
39
function GetAnchor: TVerletNode;
40
function GetRoot: TVerletNode;
41
function GetLinkLength: single;
42
procedure AddStickStiffness(const ANodeSkip : integer);
43
procedure SetStiffness(const Value: TVHStiffnessSet);
45
procedure BuildHair(const AAnchorPosition, AHairDirection: TAffineVector);
47
procedure BuildStiffness;
48
procedure ClearStiffness;
51
constructor Create(const AVerletWorld : TGLVerletWorld;
52
const ARootDepth, AHairLength : single; ALinkCount : integer;
53
const AAnchorPosition, AHairDirection : TAffineVector;
54
const AStiffness : TVHStiffnessSet);
56
destructor Destroy; override;
58
property NodeList : TVerletNodeList read FNodeList;
59
property VerletWorld : TGLVerletWorld read FVerletWorld;
61
property RootDepth : single read FRootDepth;
62
property LinkLength : single read GetLinkLength;
63
property LinkCount : integer read FLinkCount;
64
property HairLength : single read FHairLength;
66
property Stiffness : TVHStiffnessSet read FStiffness write SetStiffness;
68
property Data : pointer read FData write FData;
70
{ Anchor should be nailed down to give the hair stability }
71
property Anchor : TVerletNode read GetAnchor;
73
{ Root should be nailed down to give the hair stability }
74
property Root : TVerletNode read GetRoot;
81
procedure TGLVerletHair.AddStickStiffness(const ANodeSkip: integer);
85
for i := 0 to NodeList.Count-(1+ANodeSkip*2) do
86
FStiffnessList.Add(VerletWorld.CreateStick(NodeList[i], NodeList[i+2*ANodeSkip]));
89
procedure TGLVerletHair.BuildHair(const AAnchorPosition, AHairDirection: TAffineVector);
92
Position : TAffineVector;
93
Node, PrevNode : TVerletNode;
94
Direction : TAffineVector;
98
Direction := VectorNormalize(AHairDirection);
100
// Fix the root of the hair
101
Position := VectorAdd(AAnchorPosition, VectorScale(Direction, -FRootDepth));
102
Node := VerletWorld.CreateOwnedNode(Position);
104
Node.NailedDown := true;
107
// Now add the links in the hair
108
for i := 0 to FLinkCount-1 do
110
Position := VectorAdd(AAnchorPosition, VectorScale(Direction, HairLength * (i/LinkCount)));
112
Node := VerletWorld.CreateOwnedNode(Position);
115
// first one is the anchor
117
Node.NailedDown := true
119
// Create the hair link
120
VerletWorld.CreateStick(PrevNode, Node);
125
// Now we must stiffen the hair with either sticks or springs
129
procedure TGLVerletHair.BuildStiffness;
135
if vhsFull in FStiffness then
138
AddStickStiffness(i);
143
if vhsSkip1Node in FStiffness then AddStickStiffness(1);
144
if vhsSkip2Node in FStiffness then AddStickStiffness(2);
145
if vhsSkip3Node in FStiffness then AddStickStiffness(3);
146
if vhsSkip4Node in FStiffness then AddStickStiffness(4);
147
if vhsSkip5Node in FStiffness then AddStickStiffness(5);
148
if vhsSkip6Node in FStiffness then AddStickStiffness(6);
149
if vhsSkip7Node in FStiffness then AddStickStiffness(7);
150
if vhsSkip8Node in FStiffness then AddStickStiffness(8);
151
if vhsSkip9Node in FStiffness then AddStickStiffness(9);
154
procedure TGLVerletHair.Clear;
159
for i := FNodeList.Count-1 downto 0 do
163
FStiffnessList.Clear;
166
procedure TGLVerletHair.ClearStiffness;
170
for i := 0 to FStiffnessList.Count-1 do
171
TVerletConstraint(FStiffnessList[i]).Free;
173
FStiffnessList.Clear;
176
constructor TGLVerletHair.Create(const AVerletWorld : TGLVerletWorld;
177
const ARootDepth, AHairLength : single; ALinkCount : integer;
178
const AAnchorPosition, AHairDirection : TAffineVector;
179
const AStiffness : TVHStiffnessSet);
181
FVerletWorld := AVerletWorld;
182
FRootDepth := ARootDepth;
183
FLinkCount := ALinkCount;
184
FHairLength := AHairLength;
186
FNodeList := TVerletNodeList.Create;
187
FStiffness := AStiffness;
188
FStiffnessList := TList.Create;
190
BuildHair(AAnchorPosition, AHairDirection);
193
destructor TGLVerletHair.Destroy;
196
FreeAndNil(FNodeList);
197
FreeAndNil(FStiffnessList);
201
function TGLVerletHair.GetAnchor: TVerletNode;
203
result := NodeList[1];
206
function TGLVerletHair.GetLinkLength: single;
209
result := HairLength / LinkCount
214
function TGLVerletHair.GetRoot: TVerletNode;
216
result := NodeList[0];
219
procedure TGLVerletHair.SetStiffness(const Value: TVHStiffnessSet);