VRIK

VRIK is a high speed full body solver dedicated to animating VR avatars. The solver was originally developed for the game "Dead and Buried" by Oculus Studios.

A detailed description of the inner workings of VRIK can be found in this article originally published in Oculus Developer Blog.

**Getting started:**

- Add VRIK to your character root. If it is a Humanoid, References will be automatically filled in using the Animator. If not, the bones used by the solvers will have to be manually assigned to the "References".
- Move the camera to the avatar's eyes, move hand controllers to the avatar's hands as if they were worn by the avatar.
- Make duplicates of the avatar's head and hand bones.
- Parent the duplicates to the camera/hand controllers.
- Assign the duplicates as Head/Hand Targets in VRIK.
- VRIK samples the pose of the avatar at Start to find out which way to bend the limbs. Make sure that the elbow/knee bones are rotated so that the limbs are slightly bent in their natural bending directions, they must not be completely straight.
- Examples of VRIK setup for Oculus and SteamVR can be found in "Plugins/RootMotion/FinalIK/_Integration". Oculus/SteamVR utilities packages from the Asset Store are required to run these demos.

**Performance:**

VRIK is about 2-3 times faster than FullBodyBipedIK. In Dead and Buried 2, it was used on 6 avatars simultaneously visible on screen and running on Oculus Quest hardware. Since Final IK v1.9 VRIK has a 3-level LOD system with level 1 providing roughly 30% gain and level 2 solver disabled with only the root position and rotation updated if the built-in locomotion solver was used.

**Adding VRIK component in run-time:**

void LateUpdate () {

var ik = gameObject.AddComponent<VRIK>();

ik.AutoDetectReferences();

}

**Using VRIK with Rotation Limits:**

VRIK has it's own set of built-in constraints and RotationLimits can not be used in the solving process. It is possible however to apply RotationLimits on top of VRIK for instance to make sure that the hand bones do not bend unnaturally beyond reasonable limits. To do this, we would have to disable the rotation limits in Start to take control of their updating, then update them after VRIK using the VRIK.solver.OnPostUpdate delegate::

public VRIK ik;

public RotationLimit[] rotationLimits;

void Start() {

foreach (RotationLimit limit in rotationLimits) {

limit.enabled = false;

}

ik.solver.OnPostUpdate += AfterVRIK;

}

private void AfterVRIK() {

foreach (RotationLimit limit in rotationLimits) {

limit.Apply();

}

}

**Calibration:**

Please take a look at the "VRIK (Calibration)" demo on how to use the VRIKCalibrator to help with calibrating avatars to head and hand controllers plus additional trackers on the body and feet. If you only need to calibrate the size of the avatar, it is easiest to do so by having the player stand up straight, then comparing the height of the head target to the height of the avatar's head bone:

float sizeF = (ik.solver.spine.headTarget.position.y - ik.references.root.position.y) / (ik.references.head.position.y - ik.references.root.position.y);

ik.references.root.localScale *= sizeF;

**Locomotion:**

The built-in procedural locomotion was developed in the early days of VR and designed for foot shuffling around a few square meters space. It does not work well for room-scale or thumbstick locomotion. For that it would be best to use an animated approach - make a simple 8-direction strafing animation blend tree and use that to make the character follow the horizontal direction towards the HMD by root motion or scripted transformation.

**Component variables:**

**VRIK.fixTransforms**- if true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance**VRIK.references**- bone mapping. Right-click on the component header and select 'Auto-detect References' of fill in manually if not a Humanoid character. Chest, neck, shoulder and toe bones are optional. VRIK also supports legless characters. If you do not wish to use legs, leave all leg references empty.

**Solver variables:**

**VRIK.solver.IKPositionWeight**- master weight of the solver.**VRIK.solver.LOD**- LOD 0: Full quality solving. LOD 1: Shoulder solving, stretching plant feet disabled, spine solving quality reduced. This provides about 30% of performance gain. LOD 2: Culled, but updating root position and rotation if locomotion is enabled.**VRIK.solver.plantFeet**- if true, will keep the toes planted even if head target is out of reach, so this can cause the camera to exit the head if it is too high for the model to reach. Enabling this increases the cost of the solver as the legs will have to be solved multiple times.

**Spine variables:**

**VRIK.solver.spine.headTarget**- the head target. This should not be the camera Transform itself, but a child GameObject parented to it so you could adjust it's position/rotation to match the orientation of the head bone. The best practice for setup would be to move the camera to the avatar's eyes, duplicate the avatar's head bone and parent it to the camera. Then assign the duplicate to this slot.**VRIK.solver.spine.pelvisTarget**- the pelvis target (optional), useful for seated rigs or if you had an additional tracker on the backpack or belt are. The best practice for setup would be to duplicate the avatar's pelvis bone and parenting it to the pelvis tracker. Then assign the duplicate to this slot.**VRIK.solver.spine.positionWeight**- positional weight of the head target. Note that if you have nulled the headTarget, the head will still be pulled to the last position of the headTarget until you set this value to 0.**VRIK.solver.spine.rotationWeight**- rotational weight of the head target. Note that if you have nulled the headTarget, the head will still be rotated to the last rotation of the headTarget until you set this value to 0.**VRIK.solver.spine.pelvisPositionWeight**- positional weight of the pelvis target. Note that if you have nulled the pelvisTarget, the pelvis will still be pulled to the last position of the pelvisTarget until you set this value to 0.**VRIK.solver.spine.pelvisRotationWeight**- Rotational weight of the pelvis target. Note that if you have nulled the pelvisTarget, the pelvis will still be rotated to the last rotation of the pelvisTarget until you set this value to 0.**VRIK.solver.spine.chestGoal**- if chestGoalWeight is greater than 0, the chest will be turned towards this Transform.**VRIK.solver.spine.chestGoalWeight**- weight of turning the chest towards the chestGoal.**VRIK.solver.spine.minHeadHeight**- minimum height of the head from the root of the character.**VRIK.solver.spine.bodyPosStiffness**- determines how much the body will follow the position of the head.**VRIK.solver.spine.bodyRotStiffness**- determines how much the body will follow the rotation of the head.**VRIK.solver.spine.neckStiffness**- determines how much the chest will rotate to the rotation of the head.**VRIK.solver.spine.rotateChestByHands**- the amount of rotation applied to the chest based on hand positions.**VRIK.solver.spine.chestClampWeight**- clamps chest rotation. Value of 0.5 allows 90 degrees of rotation for the chest relative to the head. Value of 0 allows 180 degrees and value of 1 means the chest will be locked relative to the head.**VRIK.solver.spine.headClampWeight**- clamps head rotation. Value of 0.5 allows 90 degrees of rotation for the head relative to the headTarget. Value of 0 allows 180 degrees and value of 1 means head rotation will be locked to the target.**VRIK.solver.spine.moveBodyBackWhenCrouching**- moves the body horizontally along -character.forward axis by that value when the player is crouching.**VRIK.solver.spine.maintainPelvisPosition**- how much will the pelvis maintain it's animated position?**VRIK.solver.spine.maxRootAngle**- will automatically rotate the root of the character if the head target has turned past this angle.**VRIK.solver.spine.rootHeadingOffset**- angular offset for root heading. Adjust this value to turn the root relative to the HMD around the vertical axis. Usefulf for fighting or shooting games where you would sometimes want the avatar to stand at an angled stance.

**Arm variables:**

**VRIK.solver.leftArm.target**- the hand target. This should not be the hand controller itself, but a child GameObject parented to it so you could adjust it's position/rotation to match the orientation of the hand bone. The best practice for setup would be to move the hand controller to the avatar's hand as it it was held by the avatar, duplicate the avatar's hand bone and parent it to the hand controller. Then assign the duplicate to this slot.**VRIK.solver.leftArm.bendGoal**- the elbow will be bent towards this Transform if 'Bend Goal Weight' > 0.**VRIK.solver.leftArm.positionWeight**- positional weight of the hand target. Note that if you have nulled the target, the hand will still be pulled to the last position of the target until you set this value to 0.**VRIK.solver.leftArm.rotationWeight**- rotational weight of the hand target. Note that if you have nulled the target, the hand will still be rotated to the last rotation of the target until you set this value to 0.**VRIK.solver.leftArm.shoulderRotationMode**- different techniques for shoulder bone rotation.**VRIK.solver.leftArm.shoulderRotationWeight**- the weight of shoulder rotation.**VRIK.solver.leftArm.shoulderTwistWeight**- the weight of twisting the shoulders backwards when arms are lifted up.**VRIK.solver.leftArm.bendGoalWeight**- if greater than 0, will bend the elbow towards the 'Bend Goal' Transform.**VRIK.solver.leftArm.swivelOffset**- angular offset of the elbow bending direction.**VRIK.solver.leftArm.wristToPalmAxis**- local axis of the hand bone that points from the wrist towards the palm. Used for defining hand bone orientation. If you have copied VRIK component from another avatar that has different bone orientations, right-click on VRIK header and select "Guess Hand Orientations" from the context menu.**VRIK.solver.leftArm.palmToThumbAxis**- local axis of the hand bone that points from the palm towards the thumb. Used for defining hand bone orientation If you have copied VRIK component from another avatar that has different bone orientations, right-click on VRIK header and select 'Guess Hand Orientations' from the context menu..**VRIK.solver.leftArm.armLengthMlp**- use this to make the arm shorter/longer. Works by displacement of hand and forearm localPosition.**VRIK.solver.leftArm.stretchCurve**- evaluates stretching of the arm by target distance relative to arm length. Value at time 1 represents stretching amount at the point where distance to the target is equal to arm length. Value at time 2 represents stretching amount at the point where distance to the target is double the arm length. Value represents the amount of stretching. Linear stretching would be achieved with a linear curve going up by 45 degrees. Increase the range of stretching by moving the last key up and right at the same amount. Smoothing in the curve can help reduce elbow snapping (start stretching the arm slightly before target distance reaches arm length). To get a good optimal value for this curve, please go to the 'VRIK (Basic)' demo scene and copy the stretch curve over from the Pilot character.

**Leg variables:**

**VRIK.solver.leftLeg.target**- the foot/toe target. This should not be the foot tracker itself, but a child GameObject parented to it so you could adjust it's position/rotation to match the orientation of the foot/toe bone. If a toe bone is assigned in the References, the solver will match the toe bone to this target. If no toe bone assigned, foot bone will be used instead.**VRIK.solver.leftLeg.bendGoal**- the knee will be bent towards this Transform if 'Bend Goal Weight' > 0.**VRIK.solver.leftLeg.positionWeight**- positional weight of the toe/foot target. Note that if you have nulled the target, the foot will still be pulled to the last position of the target until you set this value to 0.**VRIK.solver.leftLeg.rotationWeight**- rotational weight of the toe/foot target. Note that if you have nulled the target, the foot will still be rotated to the last rotation of the target until you set this value to 0.**VRIK.solver.leftLeg.bendGoalWeight**- if greater than 0, will bend the knee towards the 'Bend Goal' Transform.**VRIK.solver.leftLeg.swivelOffset**- angular offset of knee bending direction.**VRIK.solver.leftLeg.bendToTargetWeight**- if 0, the bend plane will be locked to the rotation of the pelvis and rotating the foot will have no effect on the knee direction. If 1, to the target rotation of the leg so that the knee will bend towards the forward axis of the foot. Values in between will be slerped between the two.**VRIK.solver.leftLeg.legLengthMlp**- use this to make the leg shorter/longer. Works by displacement of foot and calf localPosition.**VRIK.solver.leftLeg.stretchCurve**- evaluates stretching of the leg by target distance relative to leg length. Value at time 1 represents stretching amount at the point where distance to the target is equal to leg length. Value at time 1 represents stretching amount at the point where distance to the target is double the leg length. Value represents the amount of stretching. Linear stretching would be achieved with a linear curve going up by 45 degrees. Increase the range of stretching by moving the last key up and right at the same amount. Smoothing in the curve can help reduce knee snapping (start stretching the arm slightly before target distance reaches leg length). To get a good optimal value for this curve, please go to the 'VRIK (Basic)' demo scene and copy the stretch curve over from the Pilot character.

**Locomotion variables:**

**VRIK.solver.locomotion.weight**- used for blending in/out of procedural locomotion.**VRIK.solver.locomotion.footDistance**- tries to maintain this distance between the legs.**VRIK.solver.locomotion.stepThreshold**- makes a step only if step target position is at least this far from the current footstep or the foot does not reach the current footstep anymore or footstep angle is past the 'Angle Threshold'.**VRIK.solver.locomotion.angleThreshold**- makes a step only if step target position is at least 'Step Threshold' far from the current footstep or the foot does not reach the current footstep anymore or footstep angle is past this value.**VRIK.solver.locomotion.comAngleMlp**- multiplies angle of the center of mass - center of pressure vector. Larger value makes the character step sooner if losing balance.**VRIK.solver.locomotion.maxVelocity**- maximum magnitude of head/hand target velocity used in prediction.**VRIK.solver.locomotion.velocityFactor**- the amount of head/hand target velocity prediction.**VRIK.solver.locomotion.maxLegStretch**- how much can a leg be extended before it is forced to step to another position? 1 means fully stretched.**VRIK.solver.locomotion.rootSpeed**- the speed of lerping the root of the character towards the horizontal mid-point of the footsteps.**VRIK.solver.locomotion.stepSpeed**- the speed of moving a foot to the next position.**VRIK.solver.locomotion.stepHeight**- the height of the foot by normalized step progress (0 - 1).**VRIK.solver.locomotion.heelHeight**- the height offset of the heel by normalized step progress (0 - 1).**VRIK.solver.locomotion.relaxLegTwistMinAngle**- rotates the foot while the leg is not stepping to relax the twist rotation of the leg if ideal rotation is past this angle.**VRIK.solver.locomotion.relaxLegTwistSpeed**- the speed of rotating the foot while the leg is not stepping to relax the twist rotation of the leg.**VRIK.solver.locomotion.stepInterpolation**- tnterpolation mode of the step.**VRIK.solver.locomotion.offset**- offset for the approximated center of mass.

**Script References:**

Generated by 1.8.4