Advanced programming fro 3D Apps

Report
Advanced Programming for 3D
Applications
CE00383-3
Data Structures for
Human Motion
Lecture 5
Bob Hobbs
Staffordshire university
Example Joint Hierarchy
Root
Torso
2
Pelvis
Neck
ShoulderL
ShoulderR
HipL
HipR
Head
ElbowL
ElbowR
KneeL
KneeR
WristL
WristR
AnkleL
AnkleR
Skeleton Posing Process
1. Specify all DOF values for the skeleton
2. Recursively traverse through the hierarchy starting at
the root and use forward kinematics to compute the
world matrices
3. Use world matrices to deform skin & render
Note: the matrices can also be used for other things such
as collision detection, FX, etc.
3
Joint Offsets
• It is convenient to have a 3D offset vector
r for every joint which represents its pivot
point relative to its parent’s matrix
L offset
4
1
0

0

rx
0
1
0
0
0
ry
1
rz
0

0
0

1
DOF Limits
• It is nice to be able to limit a DOF to some
range (for example, the elbow could be
limited from 0º to 150º)
• Usually, in a realistic character, all DOFs
will be limited except the ones controlling
the root
5
Skeleton Rigging
• Setting up the skeleton is an important and early
•
•
part of the rigging process
Sometimes, character skeletons are built before
the skin, while other times, it is the opposite
To set up a skeleton, an artist uses an
interactive tool to:
–
–
–
–
–
6
Construct the tree
Place joint offsets
Configure joint types
Specify joint limits
Possibly more…
Poses
• Once the skeleton is set up, one can then adjust each of
•
the DOFs to specify the pose of the skeleton
We can define a pose Φ more formally as a vector of N
numbers that maps to a set of DOFs in the skeleton
Φ = [φ1 φ2 … φN]
• A pose is a convenient unit that can be manipulated by a
•
7
higher level animation system and then handed down to
the skeleton
Usually, each joint will have around 1-6 DOFs, but an
entire character might have 100+ DOFs in the skeleton
Hinge Joints (1-DOF Rotational)
• Rotation around the x-axis:
1
0
L Rx  x   
0

rx
8
0
cos  x
0
sin  x
 sin  x
cos  x
ry
rz
0
0
0

1
Hinge Joints (1-DOF Rotational)
• Rotation around the y-axis:
cos  y
 0
L Ry  y   
 sin  y

 rx
9
0
1
 sin  y
0
0
cos  y
ry
rz
0
0
0

1
Hinge Joints (1-DOF Rotational)
• Rotation around the z-axis:
 cos  z
 sin 
z

L Rz  z  
 0

 rx
10
sin  z
cos  z
0
0
0
1
ry
rz
0
0
0

1
Hinge Joints (1-DOF Rotational)
• Rotation around an arbitrary axis a:
L Ra   
 a x2  c (1  a x2 )

a x a y (1  c )  a z s
a x a z (1  c )  a y s

rx

11
a x a y (1  c )  a z s
a y2  c (1  a y2 )
a y a z (1  c )  a x s
ry
a x a z (1  c )  a y s
a y a z (1  c )  a x s
a z2  c (1  a z2 )
rz
0

0
0

1
Universal Joints (2-DOF)
• For a 2-DOF joint that first rotates around
x and then around y:
 cy
s s
x y

L Rxy  x , y  
c x s y

 rx
0
cx
 sy
sxcy
 sx
cxc y
ry
rz
0
0
0

1
• Different matrices can be formed for
12
different axis combinations
Ball & Socket (3-DOF)
• For a 3-DOF joint that first rotates around
x, y, then z:
c y cz

s s c  c s
x y z
x z

L Rxyz  x , y , z  
c x s y c z  s x s z

rx

cy sz
sx s y sz  cx cz
 sy
sxcy
cx s y sz  sx cz
ry
cx c y
rz
• Different matrices can be formed for
13
different axis combinations
0
0
0

1
Prismatic Joints (1-DOF Translation)
• 1-DOF translation along an arbitrary axis a:


L Ta t   


rx
14
1
0
0
 t  ax
0
1
0
0
0
ry  t  a y
1
rz  t  a z
0

0
0

1
Translational Joints (3-DOF)
• For a more general 3-DOF translation:


L Txyz t   


rx
15
1
0
0
0
1
0
0
0
1
ry  t y
rz  t z
 tx
0
0
0

1
Software Architecture
• Object oriented
• Make objects for things that should be
objects
• Avoid global data & functions
• Encapsulate information
• Provide useful interfaces
• Put different objects in different files
16
Sample Code
• Classes Required:
–
–
–
–
–
–
17
Vector3
Matrix34
Tokenizer
Camera
SpinningCube
Tester
Sample Skeleton File
balljoint root {
[data for root]
balljoint head {
[data for head]
[children of head]
}
balljoint leg_l {
[data for leg]
[children of leg]
}
[more children of root]
18}
Skeleton File Data Tokens
offset
boxmin
boxmax
draw)
rotxlimit
rotylimit
rotzlimit
pose
balljoint
19
xyz
xyz
xyz
(joint offset vector)
(min corner of box to draw)
(max corner of box to
min max
min max
min max
xyz
name { }
(x rotation DOF limits)
(y rotation DOF limits)
(z rotation DOF limits)
(values to pose DOFs)
(child joint)
Possible Object Breakdown
• One should consider making objects
(classes) for the following:
– DOF
– Joint
– Skeleton
20
Common Routines
• Many classes will need functions for some
or all of the following:
– Constructor / destructor
– Initialize
– Load
– Update (move things, pose, animate…)
– Draw
– Reset
21
What is a DOF?
• Data
– Value
– Min, max
• Functions
– SetValue() (can clamp value at the time of
setting)
– GetValue()
– SetMinMax()…
22
What is a Joint?
• Data
– Local & World matrices
– Array of DOFs
– Tree data (child/sibling/parent pointers, etc.)
• Functions
–
–
–
–
Update() (recursively generate local matrix & concatenate)
Load()
AddChild()
Draw()
• Note: One could also make a Joint base class and derive
various specific joint types. In this case, it would be a
good idea to make a virtual function for
MakeLocalMatrix() that the base traversal routine calls
23
What is a Skeleton?
• Data
– Joint tree (might only need a pointer to the
root joint)
• Functions
– Load
– Update (traverses tree & computes joint
matrices)
– Draw
24
Tree Data Structures
• The skeleton requires only the most basic N-tree
•
•
data structure
The main thing the tree needs is an easy way to
perform a depth-first traversal
There are several options:
–
–
–
–
25
Use STL
Implement a tree data structure
Store sibling & first child pointers in the Joint itself
Store a linearized tree as an array in the skeleton
Update & Draw
void Joint::Update(Matrix &parent) {
… // Compute LocalMatrix
… // Compute WorldMatrix
… // Recursively call Update() on children
}
void Joint::Draw() {
.. // Do some OpenGL
.. // Recursively call Draw() on children
}
26
Load
bool Skeleton::Load(const char *file) {
Tokenizer token;
token.Open(file,"skel"));
token.FindToken("balljoint"));
// Parse tree
Root=new Joint;
Root->Load(token);
// Finish
token.Close();
return true;
}
27
bool Joint::Load(Tokenizer &t) {
token.FindToken("{"));
while(1) {
char temp[256];
token.GetToken(temp);
if(strcmp(temp,"offset")==0) {
Offset.x=token.GetFloat();
Offset.y=token.GetFloat();
Offset.z=token.GetFloat();
}
else // Check for other tokens
else if(strcmp(temp,"balljoint")==0) {
Joint *jnt=new Joint;
jnt->Load(token);
AddChild(*jnt);
}
else if(strcmp(temp,"}")==0) return true;
else token.SkipLine(); // Unrecognized token
}
28}

similar documents