Try dragging on the Emotion wheel to see the face change accordingly! <iframe style="border: none" width="375" height="700" src="https://rive.app/s/prkQY3ESnEGSvUb1vrJnsQ/embed?runtime=rive-renderer" allowfullscreen allow="autoplay"></iframe> Keep reading to find out how to interpolate smoothly beyond the native 2 dimensions that Rive Joysticks by default provide~ ## Inspiration 🔥 I saw this great demo from JCToon at Rive for animating thru facial expressions https://rive.app/community/files/669-1300-facial-expression-demo/ ![[JCToonAimationDemoFast.mov]] It was so cool to animate thru different emotions smoothly using the state machine! But I wished for a better UX than adding buttons, and I didn't want to reach for a deeper Runtime driven integration just yet! I want to be able to create more expressions for my character, _Aam_ in my app, [Bolo Baccho](https://bolobaccho.imagimationstudios.org) ## Setup ### Rigging states I started with a simple face, grouping all the parts ![[01_Simple_face.png]] Then, I added some bones for the paths I want to move and weighted them accordingly This picture shows the hilightedbones associated with the Mouth's path ![[02_Bones_face.png]] Next, add unique timelines for each individual facial movement, these will be used later <iframe style="border: none" width="375" height="375" src="https://rive.app/s/rGQP46R6vU29fW4ymFy39Q/embed?runtime=rive-renderer" allowfullscreen allow="autoplay"></iframe> Next, add joysticks to drive each of these facial movements The joystics should be mapped accordingly to each timeline we created for the facial movements ![[03_Joystick_face.png]] Next, add a unique timeline for each emotion by adjusting the joysticks until you get your desired expression for each primary emotion - Anticipation - Joy - Acceptance - Fear - Surprise - Sadness - Disgust - Anger - Neutral Interpolate from neutral to the extreme <iframe style="border: none" width="375" height="375" src="https://rive.app/s/e6M3KR4tzkySKYiGA1i2-g/embed?runtime=rive-renderer" allowfullscreen allow="autoplay"></iframe> ## Composing the Emotion Animations ### "Dial" control We want to create a target that has its movement constrained to a circle, similar to a dial. ![[Dial constraint.mov]] - We create a target `group` in the _center_ (I've added a red and green big circle to make it more visible) - We create a `bone` from the _center_ out to the max distance we want - Create a target`group` to the rod end (cyan and orange circle) - (This is important for our `mix` controls later) - Create a target `group` to later track the position of the pointer - Create an `IK Constraint` on the bone to the pointer target - Create a `Distance Constraint` on the pointer target to the center group (to keep it closer than the max distance of the rod) - ![[IK_Dial_Constraint.png]] With this ready, we can use the dial to drive the interpolated emotion dimensions we'll use in the next step ### Emotion Dimension For each emotion to work in a designated direction for our rig, we'll need to achieve 3 things - Control the `intensity` on the main-axis - Control the `mix` on the cross-axis - Prevent the opposite emotion from interfering with our `mix` Below, you can see how we achieve the first to goals using this `T` arrangement of Joysticks The cross-axis controls the `mix` animating from 0 at the extremes, to 100 in the center The main-axis animated from 0 to 100 monotonically - Set the cross axis control's `Handle Source` to target the _rod end_ `group` from the previous section - Set the main axis control's `Handle Source` to target the _pointer target_ `group` from the previous section ![[Composed Emotion Vector.mov]] ### Solving the opposite emotion `mix` issues By just using this, we'll run into a problem when we include opposite emotions Since opposite emotions share a common axis, their `mix`es will interfere with eachother and the most extremes of emotions will actually be pulled back down to neutral 😁😐😢 When we try to interpolate at the extremes, `Rive` thinks that both Joy and Sadness should be mixed to 100%, so they cancel out and we underwhelmingly get a neutral face when we expect a happy face To prevent this, you'll need a trick! - Ensure sure the `joystick`s have ticked, the `Draw in World Space` option - Make a `group` to hold the cross axis (cmd + g) - In the _intensity_ timeline of the Joy emotion, set the rotation of the `group` we just created to 90 degrees This will create this cool mechanical effect which solves our conflicting mapping issue since at the intensity extreme of Joy, the `mix` for Sadness will be sent to 0 via the combined effect of the handle source and the rotation of the `joystick` Cosine ftw! ![[Opposite Axis Mix Solution.mov]] ### Interpolating all the emotions You can now repeat this process for all of the emotion dimensions and you'll end up with this really satisfying effect that is reminiscent of the `Trammel of Archimedes` ![[Trammel of Archimedes.mov]] I hope you found this useful and _Rive_ -eting