I want to manipulate scale of bone such as increasing character leg length for character customization. How can I do this with new animation rigging?
If I directly scale character leg bone, foot is not lock at root level anymore.
I want to manipulate scale of bone such as increasing character leg length for character customization. How can I do this with new animation rigging?
If I directly scale character leg bone, foot is not lock at root level anymore.
void LateUpdate()
{
foreach (PData _data in data)
{
_data.bone.transform.localScale = _data.scale;
}
}
I want to lock bone at the root level but have no idea how to get that.
Hi Ruberta,
Thanks for your questions about scale. I can explain a bit more about whatās going on hereā¦
There are known limitations with how non-uniform scale currently works in Unity with regard to skeletal animation. There are artifacts with shearing that happen when using non-uniform scale (for example, only the X axis) on animated bones that have animated child bones. Since this limitation exists with the underlying animation system, this is why it is out of scope for the Animation Rigging package to attempt to solve this.
If squash and stretch animation is the desired effect there are ways to do this in your rigging setups using leaf-node bones that have no animated child bones. I can explain more about this if thatās the way you want to go. However, from your description it sounds like you are attempting to do something different with static variations of character proportions. I am hopeful that we will be able to support this in the future, but at this time I canāt make any guarantees.
The type of animated scale that is supported by Animation Rigging is: object-level uniform scale. This is where you can scale the top game object evenly on all axes at once to make variations in overall size. If you encounter issues with Animation Rigging in this area please submit a bug report because we intend for that to work and will attempt to fix those bugs.
I hope that explanation helps and let me know if there are any further questions I can help with.
Thank you for reply. I make system for character customization. I have solution for myself now. Instead of scale the leg bone, I adjust position of upper leg bone and pelvis. This way the foot will not move away from the root. Then I can scale only y and z if I want the leg bigger a little bit.
Hey @davehunt_unity - thanks for clearing this up, Iāve been looking into the non uniform scale stuff for a while and getting nowhere. Iād love to ask a couple of questions if thatās OK?
Is there any plans to change this at all? Is there any other way to get parity with Maya Segment scale compensate on a traditional skeleton or is a flat hiearchy / leaf joints on a traditional skeleton the only way you think?
cheers
Hi theazzz,
In response to your question above, these are some of the things that will be possible with the new DOTS Animation architecture. We are aware of the need from user requests such as this (and from myself!) and we are currently working on the foundation that will make it possible. Iām not able to make any specific statements about when it will be available, but just to reassure you we have heard the request and we are taking it into account.
skƄl
Hi @davehunt_unity !!
Weāve been getting into this new animation rigging package lately and we have some problems about scale transformations as mentioned above.
Doing some tests weāve discovered that the Two Bone IK constraint doesnāt perform correctly when scaling the animation root, even itās a proportional scale.
Isnāt this supposed to be supported?
Thanks!
Hi,
TwoBoneIK will work with different uniform root scale values.
How did you setup your character rig? Maybe some other constraints are preventing your Two Bone IK to work when its scale value changes.
Hello @simonbz and thank you for your quick reply!
Weāve made several tests using only the Two Bone IK constraint to avoid other interactions and the problem persistsā¦ The character rig setup has been done following the package guide and we are scaling a parent object of the whole rig system.
After seeing your screenshot I made further investigation and I achieved an important conclusion: Uniform scaling do work only if itās made before pressing the play button. It wonāt work if you try to scale the rig on runtime.
I guess that constraints calculate some initial data on startup and maybe are not prepared for further scales beyond that point.
Our current requirements are to scale the rig during runtime, so it would be great if you could help us on this.
Thank you very much!
Hey Virtualware,
Thanks for pointing this out! You are right. When entering playmode the TwoBoneIKConstraintJob is created, as an optimization we are storing the lengths of the bones during creation. So that the run-time algorithm does not have to calculate the bone lengths every frame. This of course assumes that the bone lengths do not change at runtime. Which is not a valid assumption if the scaling changes during runtimeā¦
I can offer you two solutions that you can try to work around this limitation straight away. You can either rebuild the Rig when scaling is applied, this will recreate the job with the new bone lengths. You can force a rebuild of a rig through code by calling RigBuilder.Build() on a rig. Rebuilding, however, can become quite costlyā¦ And thus I would strongly recommend looking into my next proposed solution.
Namely. modifying or creating a custom version of the TwoBoneIKConstraint inside your project. Inside the animation rigging package in Runtime/AnimationJobs/TwoBoneIKConstriantJob.cs you will find the code for the TwoBoneIKConstriant. You can duplicate this code into your project to create a custom version of the constraint or modify the code there if the package is embedded locally. In both cases you will want to modify ProcessAnimation to do something like this:
public void ProcessAnimation(AnimationStream stream)
{
float w = jobWeight.Get(stream);
if (w > 0f)
{
// Use Tip, Mid and Root handles to get bone positions
// Recompute bone lengths
// Use the recomputed lengths for the solve call below
AnimationRuntimeUtils.SolveTwoBoneIK(
stream, root, mid, tip, target, hint,
targetPositionWeight.Get(stream) * w,
targetRotationWeight.Get(stream) * w,
hintWeight.Get(stream) * w,
linkLengths,
targetOffset
);
}
else
{
AnimationRuntimeUtils.PassThrough(stream, root);
AnimationRuntimeUtils.PassThrough(stream, mid);
AnimationRuntimeUtils.PassThrough(stream, tip);
}
}
}
Please have a look at this Unite talk for more information on writing custom constraints:
I apologize that the only solutions that will help you straight away requires coding. I will bring this case up with the team and see if we want to reconsider our optimization here. I hope this helps!
We had a look at the implementation and decided to modify the constraint to support dynamic limb lengths. The next version of the package should support your use case out of the box. Thanks for bringing this to our attention
Hello @Jebtor and thank you very much for your quick and detailed response!!
Weāre glad to hear that dynamic limb lengths are going to come out of the box with the next package release
Meanwhile, we have implemented our own TwoBoneIKConstraint to fix it. Itās been very easy since we already had implemented a few custom made constraints for this project.
Thank you again for the good support!
Iām scaling a rig builder object uniformly at runtime and the Two Bone IK Constraint does not seem work correctly. Iām looking at where the IK target is positioned and it is correct. Has dynamic limb lengths made it into a released version yet?
Yes it did
In the changelog you can see it should be fixed from 0.3.3 on wards. Please reach out if you still encounter problems, any extra information will be helpful.
@Jebtor Iām working on an āavatarā system for VR. The idea is that you have a source avatar that tracks the head/hands. You can add other avatars that have their hands/head follow the hands head of the source avatar using a script I wrote called XRAvatarBinder. You assign the source head/head transforms and target head/hand transforms to the script and it updates the target transforms to have the same position/rotation. Thereās some extra math to make all the calculations relative to each avatars parent container to allow moving an avatar separately from the source.
Hereās the script if anyone needs it
using System;
using UnityEngine;
[DefaultExecutionOrder(1)]
public class XRAvatarBinder : MonoBehaviour
{
// A utility class to make converting between avatar spaces easier
public class BindSpace
{
public Transform targetContainer { get; private set; }
public Transform sourceContainer { get; private set; }
public BindSpace(Transform targetContainer, Transform sourceContainer)
{
this.targetContainer = targetContainer;
this.sourceContainer = sourceContainer;
}
public Vector3 WorldSourceToWorldTargetPoint(Vector3 worldSourcePoint)
{
return LocalSourceToWorldTargetPoint(sourceContainer.InverseTransformPoint(worldSourcePoint));
}
public Vector3 LocalSourceToWorldTargetPoint(Vector3 localSourcePoint)
{
return targetContainer.TransformPoint(localSourcePoint);
}
public Vector3 WorldSourceToWorldTargetDirection(Vector3 worldSourceDirection)
{
return targetContainer.TransformDirection(sourceContainer.InverseTransformDirection(worldSourceDirection));
}
public Quaternion WorldSourceToWorldTargetRotation(Quaternion worldSourceRotation)
{
return targetContainer.rotation * Quaternion.Inverse(sourceContainer.rotation) * worldSourceRotation;
}
}
[Serializable]
public class Binding
{
public Transform source;
public Transform target;
public Vector3 positionOffset;
public Vector3 rotationOffset;
public virtual void Bind(BindSpace bindSpace)
{
Vector3 position = bindSpace.WorldSourceToWorldTargetPoint(source.TransformPoint(positionOffset));
Quaternion rotation = bindSpace.WorldSourceToWorldTargetRotation(source.rotation * Quaternion.Euler(rotationOffset));
target.SetPositionAndRotation(position, rotation);
}
public virtual bool IsValid() => source != null && target != null;
public bool TryBind(BindSpace bindSpace)
{
bool isValid = IsValid();
if (isValid)
Bind(bindSpace);
return isValid;
}
}
[Serializable]
public class BodyBinding : Binding
{
public float rotationSpeed = 3f;
public override void Bind(BindSpace bindSpace) => Bind(bindSpace, Time.deltaTime);
public void Bind(BindSpace bindSpace, float deltaTime)
{
Vector3 position = bindSpace.LocalSourceToWorldTargetPoint(bindSpace.sourceContainer.InverseTransformPoint(source.position) + positionOffset);
Vector3 direction = bindSpace.WorldSourceToWorldTargetDirection(source.forward);
direction = bindSpace.targetContainer.InverseTransformDirection(direction);
direction.y = 0f;
direction = bindSpace.targetContainer.TransformDirection(direction);
Quaternion targetRotation = Quaternion.LookRotation(direction, bindSpace.targetContainer.up) * Quaternion.Euler(rotationOffset);
Quaternion rotation = Quaternion.Lerp(target.rotation, targetRotation, rotationSpeed * deltaTime);
target.SetPositionAndRotation(position, rotation);
}
}
public Transform sourceContainer;
public Transform targetContainer;
public bool bindContainers = true;
public Binding head, leftHand, rightHand;
public BodyBinding body;
private BindSpace bindSpace;
private void Start()
{
if (sourceContainer == null)
{
sourceContainer = transform;
}
if (targetContainer == null)
{
targetContainer = transform;
}
bindSpace = new BindSpace(targetContainer, sourceContainer);
}
private void LateUpdate()
{
if (bindContainers)
{
if (sourceContainer != null && targetContainer != null)
{
targetContainer.SetPositionAndRotation(sourceContainer.position, sourceContainer.rotation);
Vector3 sourceScale = sourceContainer.lossyScale;
if (targetContainer.parent == null)
targetContainer.localScale = sourceScale;
else
targetContainer.localScale = targetContainer.parent.InverseTransformPoint(targetContainer.parent.rotation * sourceScale);
}
}
head.TryBind(bindSpace);
leftHand.TryBind(bindSpace);
rightHand.TryBind(bindSpace);
body.TryBind(bindSpace);
}
}
This makes it easy to setup the different versions of the player required for VR. For example, the āvisualsā avatar is just a pair of hands which is only seen by the HMD. We also have a āmirrorā avatar which is an entire upper body. This is only seen by external cameras and mirrors. The mirror avatar uses the animation rigging package (preview - 0.2.6) for the arm IK.
Hereās what my hierarchy looks like. You can see thereās a Source avatar with head (āHMDā) and hands. Then thereās a Visuals and Mirror avatar. They both have an XRAvatarBinder component which binds their target transforms to the source transforms.
The scale of the Visuals and Mirror transform are updated constantly to match the Source transform scale. The Visuals avatar works correctly when scaled since it doesnāt use any IK. The Mirror avatar does not work when scaled unless I enable/disable or call Build(). Iām using the XRAvatarBinder to bind the IK target transforms to the source hand transforms. I added gizmo icons to the source and IK target transforms in the following video so you can see they are positioned at exactly the same place. Even though the IK targets are positioned correctly via the XRAvatarBinder, the Two Bone IK Constraint doesnāt update the arm joints correctly.
Hereās the video: 3hfdeo
I have both the Visuals and Mirror avatar visible to the game camera for debugging. The white hands are part of the Visuals avatar (positioned correctly) and the blue-ish hands are part of the Mirror avatar which uses the animation rigging package (not positioned correctly). In the video I am gripping both controllers and moving my hands closer/further to scale up/down. Itās kinda hard to see the labels in the video, but they flicker because the source/ik target transforms are positioned directly on top of eachother. This is why I was curious if dynamic limb length was working. The IK target is positioned correctly but the arms are not.
Thanks for working on this awesome package, and let me know if you need any more info!
Cool project! The version you are using does not support dynamic link lengths for the two bone IK. Dynamic lengths are supported in 0.3.3+, you mention you are using 0.2.6. To resolve the issues you are seeing you would either have to upgrade to 0.3.3+ or embed the package locally and modify the constraint, as described in my first reply in this thread. Apologies for the inconvenience.
Ah my bad! For some reason the package manager wasnāt showing a newer version so I had a brainfart and assumed I was on the version you mentioned. įµįµįµāæ įµŹ°įµįµįµŹ° į¶¦ Ė”į¶¦įµįµŹ³įµĖ”Ė”Źø įµŹøįµįµįµ įµįµįµ įµŹø įµĖ”įµįµŹ³ įµįµŹ³Ė¢į¶¦įµāæ į¶¦āæ įµŹø Ź³įµĖ¢įµįµāæĖ¢įµā¦įµįµį¶
If I donāt see the newer version does that mean itās only supported on newer version of Unity (Iām on 2019.3.10), or do I just need to change the version in the manifest manually?
I tried setting the version to ācom.unity.animation.riggingā: ā0.3.3-previewā manually but got a bunch of errors
Correct, the 0.2.X line is tied to 2019.3, the 0.3.X line on the other hand is linked to 2020.1. The errors you see in the console are things that only exist in Unity 2020.1.
Is changing the root scale at runtime also supported? I have a very simple setup with some TwoBoneIKConstraints. If I change the root scale at runtime, and then move an IK target, the position of the target seems to be scaled. E.g. if I scale the root to 0.5, the IK systems seems to think the target it at half the distance to the root.
Root
Animator, RigBuilder
SkinnedMeshRenderer
SkeletonRoot
....
Rig
TwoBoneIKConstraint
Target
Hint
@Jebtor Any plan to backport this to 2019.3?