How It Works
The general model for simulating grass blade behavior is as follows:
The grass blade itself is a line split into segments that form an arc.
Wind is a function that describes horizontal influence on the blade.
Wind distribution along the stem describes how strongly wind affects the blade depending on height.
Now let's look at each of these parameters separately.
Grass Blade
As mentioned earlier, the grass blade consists of segments. Let blade height be
H, and number of segments be
N. Then the height of each segment is
L=NH. We also need the concept of relative segment height
S=Ni∈[0,1], where
i is the segment index. One more required parameter in this model is
αi, the angle that defines how far segment
i is tilted from its vertical position. This parameter will later be determined by wind and influence functions.
Wind
Generation
The key idea here is that wind is a function
ω(t)∈[−1,1] that defines how strongly the wind blows to the right or left at time
t. This function can be defined in different ways, for example by a sine function. However, to get closer to realistic behavior, we will use a smoothed deterministic noise function.
Assume wind changes every
Δt seconds. Let the time step be
j. That means wind changes at time
j⋅Δt. For example, if
Δt=0.5, then wind changes at times
0.5,1.0,1.5,2.0,...
Now let's see how to get wind values at each step. For this we need a generator that returns a deterministic value in the range
[−1,1] for each
j. There are many possible implementations. Here is one of them:
Hash(j)=2⋅(sin(j∗127.1)⋅43758.5453−⌊sin(j∗127.1)⋅43758.5453⌋)−1
The coefficients
127.1 and
43758.5453 were chosen arbitrarily.
Smoothing
Now the wind generator is defined, but if we change wind values abruptly, the blade will instantly change its position. To avoid that, we need to smooth transitions between steps. For this we need a smoothing function. As with the generator, there are several options. We will use one of the most common ones: ease-in/ease-out interpolation.
Smooth(u)=u2⋅(3−2⋅u)
u=t/Δt−j
Here,
u is the normalized time offset between step
j−1 and step
j, so
u∈[0,1].
To keep this function between
Hash(j) and
Hash(j−1), we interpolate it: take
Smooth(u) as the interpolation parameter and smoothly blend values
Hash(j−1) and
Hash(j).
Lerp(a,b,c)=a+(b−a)⋅c
a=Hash(j−1)
b=Hash(j)
c=Smooth(u)
So we can define the resulting smoothed deterministic function at time
t:
F(t,Δt)=Lerp(Hash(j),Hash(j+1),Smooth(u(t)))
u(t)=t/Δt−j
j=⌊Δtt⌋
Additional Approximation
As a final step to make behavior more realistic, we combine slow and fast wind oscillations. For this, we take values
F(t,Δt) with different
Δt and corresponding coefficients. As a result, we get the wind function we need:
ω(t)=0.9⋅F(t,0.8)+0.1⋅F(t,0.15)
Thus,
F(t,0.8) gives slow smooth oscillations with higher weight, while
F(t,0.15) gives faster oscillations with lower weight, adding realism.
Wind Influence Along the Stem
To make the blade behave naturally, its root should stay firmly attached to the ground, while the tip is freer and affected the most. In other words, wind should contribute differently at different heights. This introduces the function
Influence(S),S∈[0,1]. Here,
S=0 is the root and
S=1 is the tip. From this behavior we can conclude that the function should be increasing, but not too steep, otherwise the blade will simply be pressed to the ground. In general, there is room to experiment here. The simplest and most straightforward option is a linear increasing function:
Influence(S)=S
In this case, wind influence increases uniformly from root to tip. The behavior is reasonably realistic. You can also use a parabolic function:
Influence(S)=Sp
where
p is a coefficient chosen manually, for example
p=2. With this function, influence near the tip becomes much stronger than near the root. You can increase this effect even more:
Influence(S)=Sp+S
Overall, there is room for tuning and experimentation.
Result
After everything above, only one step remains: compute the final coordinates of each segment. For this we calculate the deviation angle. It cannot exceed 90 degrees or
2π, so the blade does not bend below the ground. The final deviation angle for segment
i is:
αi(t)=2π⋅Influence(Si)⋅ω(t)
And coordinates of segment
i:
xi(t)=xi−1(t)+sin(αi(t))⋅L
yi(t)=yi−1(t)+cos(αi(t))⋅L
At the same time,
x0(t),y0(t) are always fixed, because the blade is rigidly attached to the ground.
Now that we have the formula for computing coordinates of each segment, take this challenge and implement this logic. Good luck.