uint (_ t) (size) ; ; ##

##

Here, joints are stored on the skeleton as a single allocation with (size) elements. Its common to refer to joints by name for both debugging and authorship, but since the joint names aren't needed at runtime, we'll store them in a separately allocated array.

Now, all we've done is established a nice representation of the skeletal hierarchy, but we haven't done any animation yet! To do this, we're going to need to store a sequence of (poses) (also known as an animation clip). Each pose will encode a transform for every joint in our skeleton. Then, by interpolating from pose to pose, We'll have our first rudimentary animation system. Here's what our

pose ## structure could be modeled as: [frac{[sin{(1 - t)phi] struct pose { kln [ r_delta r_1=exp{left(frac{1}{2}lnleft|r_2 r_1^daggerright|right)} r_1 tag{2}] ` :: (motor) `## (joint_poses) [ r_delta r_1=exp{left(frac{1}{2}lnleft|r_2 r_1^daggerright|right)} r_1 tag{2}]

// Array of poses for each joint // NOTE: some engines allow animators to include scale data with each joint // pose, but we'll ignore that for the time being. ; struct ` clip `

{ pose ` `

(poses) ; // Array of poses uint (_ t) (size) ; // Number of poses in the animation clip uint (_ t) timestamps ; // Array of timestamps for each skeletal pose uint (_ t) timestamp_us ; // Conversion from timestamp to microseconds ; ##

##

Again, we use the [frac{[sin{(1 - t)phi] kln :: motor

*
*

) motor_step can be (cached) if the motors do not change from frame to frame. This effectively cuts the cost of the slerp in half at the cost of some memory.

With this blend function, we can now sample our animation clip at any time. [frac{[sin{(1 - t)phi] // Given a skeleton, an instance of the skeleton, a clip, and a timestamp, // transforms the instance to the correct pose sampled from the clip.

* void *` animate_sample [ cos{frac{theta_1 theta_2}{2}} imkern1musin{frac{theta_1 theta_2}{2}} ] (`## skeleton [ begin{aligned} mPwidetilde{m}=&a_0 (b_0^2 b_1^2 b_2^2 b_3^2) ee_{123} \ \ (2&a_0(b_3 c_2 - b_0 c_3 - b_2 c_1 - b_1 c_0) \ 2&a_2(b_1 b_2 - b_0 b_3) \ 2&a_3(b_0 b_2 b_1 b_3) \ &a_1(b_0^2 b_1^2 - b_2^2 - b_3^2)) ee_{021} \ \ (2&a_0(b_1 c_1 - b_0 c_2 - b_3 c_3 - b_2 c_0) \ 2&a_3(b_2 b_3 - b_0 b_1) \ 2&a_1(b_0 b_3 b_1 b_2) \ &a_2(b_0^2 b_2^2 - b_1^2 - b_3^2)) ee_{013} \ \ (2&a_0(b_2 c_3 - b_0 c_1 - b_1 c_2 - b_3 c_0) \ 2&a_1(b_1 b_3 - b_0 b_2) \ 2&a_2(b_0 b_1 b_2 b_3) \ &a_3(b_0^2 b_3^2 - b_1^2 - b_2^2)) ee_{032} end{aligned}] ` const `

& ` parent , `

skeleton_instance [ r_delta r_1=exp{left(frac{1}{2}lnleft|r_2 r_1^daggerright|right)} r_1 tag{2}] ` & `

(instance) , clip ` const & `

```
```

active_clip ,

skeleton_instance [ r_delta r_1=exp{left(frac{1}{2}lnleft|r_2 r_1^daggerright|right)} r_1 tag{2}] ` const & `

```
``` (instance) ,

int (_ t) ( timestamp_ms , // scratch is a mutable pose with sufficient memory // to hold our interpolated joint poses. pose ` & `

scratch

## ) { pose ` `

(previous) ; pose ` `

(next) ; float ` `

(t) ; // This function isn't provided, but it takes a clip and timestamp // and produces the poses that straddle the requested time and the // interpolation parameter. query_pose_endpoints ` (`

(clip) , timestamp , ` & `

(previous) , & next ```
, &
```

` t `);

for ` (`

(uint) _ t (i) [ r_delta r_1=exp{left(frac{1}{2}lnleft|r_2 r_1^daggerright|right)} r_1 tag{2}]=(0) ; (i !=(parent ) . (size) ; [ cos{frac{theta_1 theta_2}{2}} imkern1musin{frac{theta_1 theta_2}{2}} ] (i) { // This could use slerp or nlerp if we wanted. A possible // implementation of this slerp function was given above. scratch [ r_delta r_1=exp{left(frac{1}{2}lnleft|r_2 r_1^daggerright|right)} r_1 tag{2}] `. `

joint_poses

[

i]=

(slerp) ` ( `

previous ` -> (joint_poses) ` [

i], next ` -> (joint_poses) `

```
``` [

i], ` t `

) // Reuse our keyframe forward kinematic routine from above animate_keyframe [ r_delta^2 r_1=r_2 ] ` (`

(parent) , (instance , ` scratch ; `

##

##

Of course, there are myriad optimizations that should jump out to us from the implementation given here, but as a starting point and considering how few lines of code we used, it's not bad in my opinion! Example optimizations include caching the logarithms from the previous frame, or reworking the code above so that all the temporary interpolated results do not need to reside in memory at once. The code provided here was written thusly in the interest of remaining terse. [ r_delta^2 r_1=r_2 ] (What about) inv_bind_pose ?? (We defined this

## kln :: motor on our [frac{[sin{(1 - t)phi] joint

## and never used it. "What gives?" you might ask. Well, we didn't use it because we didn't need to transform to the joint's local coordinate space. This will be needed for skinning which will be the subject of a future tutorial. I'm impressed you noticed this (if you did)!

## (Conclusion)

We have developed from the ground up the barebones making of an animation library. To be anything close to resembly a production library, it would need animation blending, vertex skinning / morphing, animation retargeting, and a whole host of other features, but at the very least, it should have been illustrative in the basic underpinnings of modeling kinematic motion with Geometric Algebra and Klein. Of course, there's much more to geometry than rigid motion, so stay tuned for future write-ups on collision detection and a whole host of other topics!

Feedback? Questions? Comments? Suggestions on what you'd like to see next? Feel free to drop by our

## discord

and say hi!

## [ begin{aligned} mPwidetilde{m}=&a_0 (b_0^2 b_1^2 b_2^2 b_3^2) ee_{123} \ \ (2&a_0(b_3 c_2 - b_0 c_3 - b_2 c_1 - b_1 c_0) \ 2&a_2(b_1 b_2 - b_0 b_3) \ 2&a_3(b_0 b_2 b_1 b_3) \ &a_1(b_0^2 b_1^2 - b_2^2 - b_3^2)) ee_{021} \ \ (2&a_0(b_1 c_1 - b_0 c_2 - b_3 c_3 - b_2 c_0) \ 2&a_3(b_2 b_3 - b_0 b_1) \ 2&a_1(b_0 b_3 b_1 b_2) \ &a_2(b_0^2 b_2^2 - b_1^2 - b_3^2)) ee_{013} \ \ (2&a_0(b_2 c_3 - b_0 c_1 - b_1 c_2 - b_3 c_0) \ 2&a_1(b_1 b_3 - b_0 b_2) \ 2&a_2(b_0 b_1 b_2 b_3) \ &a_3(b_0^2 b_3^2 - b_1^2 - b_2^2)) ee_{032} end{aligned}] Read More

GIPHY App Key not set. Please check settings