Programming Skeletal Mesh Bones

advertisement
Programming Skeletal Mesh Bones : A Swimming Fish
[C.B.Price init. 24-01-13]
[C.B.Price rev. 12-04-13]
[C.B.Price rev. 13-04-13]
Basic Model
We model the fish backbone as a series of bones with joints. Each bone has an associated processing unit as
shown below. The output of this unit drives the muscles associated with each bone-joint. Also each
processing unit is connected to its neighbour. This basic model is illustrated below.
Now the question is how do we choose the processing unit? One model used extensively in the literature is a
simple oscillator. This makes sense, since the wiggling of a swimming fish has the nature of an oscillator. So
our conceptual model is a series of coupled oscillators, each oscillator has a state which drives the associated
muscle making the bone segment rotate. This is illustrated below, where the angles of each segment for a
short fish are shown. We use the notation πœ™π‘– to denote the angle of bone i in the backbone
Now let’s see how to make the simplest mathematical model of an oscillator. From your experiments with
the monster truck suspension (without damping), you will have found out that the vertical displacement of
the truck has the shape of a cosine curve shown below on the left, where the horizontal axis is time. Also
trigonometry tells us how to calculate the cos of an angle, shown on the right. Of course the angle πœƒ is
steadily increasing with time as the truck oscillates up and down. In other words we can think of an abstract
oscillator as a point moving around a circle with a constant speed.
2
1.5
1
0.5
0
-0.5
-1
-1.5
-2
0
2
4
6
8
10
12
14
16
18
20
If we call the angle πœƒ then the value of this increases steadily with time. We can express this relationship as
Δπœƒ
=πœ”
Δ𝑑
where πœ” is the speed of rotation around the circle (angular velocity). Now let’s consider our model of a
backbone. We have a series of bones driven by their own oscillator, so we must write the above equation for
each oscillator, like this
Δπœƒ1
= πœ”1
Δ𝑑
Δπœƒ2
= πœ”2
Δ𝑑
Δπœƒπ‘–
= πœ”π‘–
Δ𝑑
Here we are saying that oscillator 1,2, …i have their individual angular speed of rotation πœ”π‘– around their
circle. The variables πœƒπ‘– are known as the “phase” of each oscillator. The next stage in the model
development is to couple each oscillator to its neighbours. The literature of mathematical biology directs us
here. Let’s take the example of just two bones, therefore two oscillators. The above two equations are
extended to account for the coupling like this
Δπœƒ1
= πœ”1 + 𝛼sin⁑(πœƒ2 − πœƒ1 )
Δ𝑑
Δπœƒ2
= πœ”2 + 𝛼sin⁑(πœƒ1 − πœƒ2 )
Δ𝑑
We see there are extra terms on the right which represent the coupling. First note that there is a sin function
involved. This takes the difference between the phase of each oscillator, calculates the sin of this difference
then multiplies by a coefficient 𝛼 which sets the strength of the coupling between the oscillators.
Now let’s extend this to a system of four bones and therefore four oscillators. The equations then become
Δπœƒ1
= πœ”1 + 𝛼sin⁑(πœƒ2 − πœƒ1 )
Δ𝑑
Δπœƒ2
= πœ”2 + 𝛼sin⁑(πœƒ1 − πœƒ2 ) + 𝛼sin⁑(πœƒ3 − πœƒ2 )
Δ𝑑
Δπœƒ3
= πœ”3 + 𝛼sin⁑(πœƒ2 − πœƒ3 ) + 𝛼sin⁑(πœƒ4 − πœƒ3 )
Δ𝑑
Δπœƒ4
= πœ”4 + 𝛼sin⁑(πœƒ3 − πœƒ4 )
Δ𝑑
The first thing you notice is that there is an additional term in the equations for bones 2 and 3. This is
because bone 2 is connected to both bone 1 and 3, and bone 3 is connected to two bones, 2 and 4. On the
other hand bone 1 (the head of the fish) is only connected to bone 2 and bone 4 (the tail of the fish) is only
connected to bone 3.
Simulation Results for a Series of 4 Bones.
Here we present some initial simulations for a 4-bone system which displays the behaviour of a swimming
fish. The parameters are as follows ………….. . Let’s first look at plots of the phases πœƒπ‘– of the four
oscillators, shown in the plot below on the left. The horizontal axis is time and the vertical axis shows how
the phase of each coupled oscillator changes with time
Looking at the phase plots, we notice two things. First all the phases πœƒπ‘– ⁑increase on straight lines with time.
Second, there is a difference between the phases of neighbouring bone-oscillators and this phase difference
remains the same. What does this mean? Well, remember that the phase of an oscillator is how far it is
around on its circle, so here the bone-oscillators are at different points around their circle, and this difference
is constant between each bone. So the bones are oscillating, but there is a lag between the movement of each
bone. Could this generate a swimming motion? Well, yes, so let’s see how.
We cannot use the phase to drive the bone muscles (and therefore rotate the bones) since the phases are
linearly increasing. We need to convert these phases into an oscillating drive for each muscle. This can be
easily done by using a sin function. So we calculate the rotation of each bone in the real world using this
simple expression
πœ™π‘– = 𝐴𝑠𝑖𝑛(πœƒπ‘– )
where A is a scaling factor. The results of doing this are shown in the above figure (right) where πœ™π‘– has been
plotted against time for all four bones. You will see that all bones are rotated with the same angle, but the
rotation of each bone is lagged in time. This time lag produces the swimming motion. Here are some screen
shots of the backbone at increasing times.
Fig.
The Model for N-Bones.
The above model can easily be extended for a chain of N-bones where each bone-oscillator is connected
only to its two neighbours. A fuller mathematical analysis not reproduced here [ cite ..] gives the following
conditions for the model to work, to produce swimming movement:
(a) All πœ”π‘– should be set to the same valueβ‘πœ”, except the head oscillator where πœ”0 should be slightly larger
than this value and the tail oscillator where πœ”π‘ should be smaller than this value.
(b) We have seen that there is a constant phase difference between the oscillators, as shown in Fig.?? We
can choose the value of this phase difference as we wish. Let’s call this value 𝛿.
(c) We are free to investigate changing 𝛼, the coupling strength
(d) Having chosen 𝛿 and 𝛼 then the angular velocity of the head oscillator must be set to
πœ”β„Žπ‘’π‘Žπ‘‘ = πœ” + 𝛼sin⁑(𝛿)
(e) Also the angular velocity of the tail oscillator must be set to
πœ”π‘‘π‘Žπ‘–π‘™ = πœ” − 𝛼sin⁑(𝛿)
Let’s see how this was applied to run the 4-bone simulation shown in the figures above.
(a) Set πœ” = 1
(b) Set 𝛿 = πœ‹⁄4 corresponding to 45 degrees (free choice)
(c) Set 𝛼 = 0.2 (free choice)
(d) Calculate πœ”β„Žπ‘’π‘Žπ‘‘ = 1.14
(e) Calculate πœ”π‘‘π‘Žπ‘–π‘™ = 0.86
Possible Investigations
There are two interesting parameters which could be explored, 𝛿 and 𝛼. Perhaps the coupling strength would
be a good place to start. Changing this value will change the values of πœ”β„Žπ‘’π‘Žπ‘‘ and πœ”π‘‘π‘Žπ‘–π‘™ and therefore change
the behaviour of the fish.
Here’s a comparison (below) of 𝛼 = 0.2 (left) and 𝛼 = 1.0 (right) where we have plotted the angle
difference between bone-oscillators 3 and 4. (We have recalculated the head and tail frequencies which
become πœ”β„Žπ‘’π‘Žπ‘‘ = 1.7071 and πœ”π‘‘π‘Žπ‘–π‘™ = 0.2929). Note that the frequency of the angle difference remains the
same, and the size of the angle difference looks the same. However, tighter coupling means that the final
swimming state is achieved more rapidly.
Now let’s have a look at changing the value of the desired phase shift 𝛿. Let’s set this to 0.3491 (which
corresponds to 20 degrees). Returning to 𝛼 = 0.2 we now recalculate the head and tail frequencies which
become πœ”β„Žπ‘’π‘Žπ‘‘ = 1.0684 and πœ”π‘‘π‘Žπ‘–π‘™ = 0.9316 for this new value of 𝛿. Here’s a comparison of the new
behaviour, again compared with the baseline parameters.
Now we see again the same number of cycles, and the same slow rate of growth, but the difference lies in
the amplitude of the swimming oscillations. They are now considerably smaller.
It looks as though the parameters 𝛼 and 𝛿 can provide us with a means to design a swimming fish whose
behaviour we can specify according to (i) how fast the fish moves from rest and gets into the stable
swimming mode and (ii) the size (amplitude) of the fish swimming motion
Code for the Phases, the Bone angles and the visualisation
Let’s look at the equation for the second oscillator copied from above.
Δπœƒ2
= πœ”2 + 𝛼sin⁑(πœƒ1 − πœƒ2 ) + 𝛼sin⁑(πœƒ3 − πœƒ2 )
Δ𝑑
Multiplying both sides by Δ𝑑 puts this in a form suitable for coding like this
Δπœƒ2 = [πœ”2 + 𝛼sin⁑(πœƒ1 − πœƒ2 ) + 𝛼sin⁑(πœƒ3 − πœƒ2 )]⁑Δ𝑑
which would result in code looking like this,
theta2 += (omega2 + alpha*sin(theta1 – theta2) + alpha*sin(theta3 – theta2))*dT;
This would be followed by the calculation of the bone angular displacement,
boneAngle2 = sin(theta2);
and finally visualisation using UDK functions as,
SkelControlSingleBone2.BoneRotation.Pitch = scaling*boneAngle2
Of course the code for a series of bones would use an array structure to hold individual values of phase
(theta) and bone angles. This can be reviewed in CBP74_Backbone_Fish.uc
Code to link the above computations with the UDK Skeletal Mesh
It is assumed that the skeletal mesh is created using 3DSMax or Maya. It is important to remember that no
animation should be created in these packages. The mesh is imported into UDK (see UDK documentation)
and can be viewed in the AnimSetEditor as shown below. Note the default names of the bones applied by
the package.
Next, an animation tree must be constructed since this is used to link the skeletal mesh to our code. As
shown below in the AnimTreeEditor, the AnimTree node is linked to the skeletal mesh and picks up the
bone names as imported from the Max or Maya file. Each bone is then assigned a SkelControlSingleBone
which is assigned a name and linked to the appropriate skeletal mesh bones. The names of these nodes are
picked up by the UDK code. See UDK documentation for details on how to set up the animation tree.
The actual code (in the class CBP74_Backbone_Fish.uc) which picks up the animation tree, accesses the
single bone nodes and uses these to move the bones contains a number of elements. First in the default
properties of this class we find the declaration of the following skeletal mesh component which is added to
the actor. Two links are made, first with the skeletal mesh and second with the animation tree, using their
respective names.
Begin Object class=SkeletalMeshComponent Name=SkeletalMeshComponent0
SkeletalMesh=SkeletalMesh'CBP74_Assets_Extra.SkeletalMeshes.boned-cylinder'
AnimTreeTemplate=AnimTree'CBP74_Assets_Extra.Animations.Backbone'
End Object
Components.Add(SkeletalMeshComponent0)
smesh=SkeletalMeshComponent0
Let’s look at the declarations of various arrays needed to link with the bones. At the top of the class code we
find two arrays
var() array<name> SCSBNameArray;
var array<SkelControlSingleBone> SCSBArray;
The first array will contain the names of the bones as identified in the animation tree (“Contbone1”, etc).
These will be specified using UnreadEd. The second array holds the links to the skeletal mesh single bone
controllers which will be used to rotate the bones. This array is populated as follows. Within the class there
is a function PostInitAnimTree( …) executed automatically by the engine. This scans the list of bone
controller names supplied in UnrealEd and finds the associated SCSB (Skeletal control single bone
controller) and stuffs this into the SCSBArray, like this.
for(i=0;i<nrBones;i++) {
SCSB = SkelControlSingleBone(smesh.FindSkelControl(SCSBNameArray[i]));
SCSBArray[i] = SCSB;
}
Now our code has access to the single bone controllers and can use these to uprate their rotation in the
Visualization() function like this, using the values of the bone angles computed and stored in the bone
angle array.
for(i=0;i<nrBones;i++) {
SCSBArray[i].BoneRotation.Pitch = scaling*boneAngleArray[i];
}
Download