Character Height Modification
✍ Last Updated : August 24, 2022
🚪 Prequisite Knowledge (Optional)
UploadKnow Inhow Progressto use Unity
C# programming
❓ Key Question / Problem / Issue
How to set character’s height without making the character looks distorted
✅ Expected Output/Definition of Done
User able to set character height
🎁 Resulting Solution
When setting character height, simply setting transform.localScale.y wont work since the character will looks distorted.
The scaling must be applied selectively to selected bones. The common bones that need to be scaled are torso, arms, forearms, thighs, and calves.
The script assume that the bone orientation is y = Up
Character scaled at y = 1.1
Rules in scaling bones
When an affected bone is scaled, their children (and the children’s children) will also be scaled. This is Unity’s default behavior
Example in this case, character’s thigh(red) and calve(yellow) is in the list of affected bones. When the thigh is scaled by 1.5, then the calve will also be scaled by 1.5 since it’s the thigh’s child, but it will also be scaled by 1.5 again since it’s a member of the affected bones, resulting in it scaled by 2.25, which is not the right result.
To handle above case, simply reset the scale to previous scale, which is 1.
The character’s feet(green) which is a child of calve, will also be scaled by 1.5 even if the calve scale is reset to 1 (due to calve is the child of thigh). To handle this, simply divide the feet scale by the scale modifier (1.5).
[SerializeField] Transform[] affectedBones;
public void SetHeight(float _height)
{
height = _height;
List<Transform> transformToAdjust = new List<Transform>();
for(int i = 0; i < affectedBones.Length; i++)
{
//Store affected bone children to be adjusted later
for(int c = 0; c < affectedBones[i].childCount; c++)
transformToAdjust.Add(affectedBones[i].GetChild(c));
Vector3 scale = affectedBones[i].localScale;
//use other axis if the bone Up is not y
scale.y = _height;
affectedBones[i].localScale = scale;
}
for(int i = 0; i < transformToAdjust.Count; i++)
{
bool isAffectedBones = false;
//Check if currentBone is one of the affectedBones
for(int c = 0; c < affectedBones.Length; c++)
{
if(transformToAdjust[i] == affectedBones[c])
{
isAffectedBones = true;
break;
}
}
//If bone is an affectedbones, reset to 1 since it's already affected by their parent
//Else 'undo' the scaling by dividing with scale
if(isAffectedBones)
{
transformToAdjust[i].localScale = Vector3.one;
}else
{
Vector3 scale = transformToAdjust[i].localScale;
scale.y = 1/height;//1 + (1 - _height);
transformToAdjust[i].localScale = scale;
Debug.Log($"{transformToAdjust[i].name} {transformToAdjust[i].localScale}");
}
}
RecalculateHeight(_height);
}
The script works by iterating through the affected bones and set the height (in this case, localScale.y), as well as storing their transform children to a list.
Then iterate through the list to check if the children are member of the affectedBones them selves or not. If it’s a member of the affectedBones, the simply reset it’s height since it’s already affected by it’s parent’s scale. If it’s not one of the affectedBones, then it need to ‘undo’ the scaling affected by it’s parent by dividing the height (scale y) by the set height.
Female character HeightHandler setup
Height at 0.9
Height at 1
Height at 1.1