Rthro Scaling Specification


#1

image

The goal of this tutorial is to provide a technical specification for how Rthro avatars are scaled, so that you can understand and predict it’s behavior when using custom rigs, and so you may create your own Rthro avatars that can be scaled down to the classic character proportions.


Scaling Constants

When an R15 avatar has its proportions scaled up to Rthro proportions, it uses a pre-defined set of scales for each R15 limb. Accessories are scaled relative to the R15 limb they are attached to.

Rthro has two sets of pre-defined portions, known as Normal and Slender.

  • The Normal proportions are fully applied when BodyTypeScale = 1 and BodyProportionScale = 0

  • The Slender proportions are fully applied when BodyTypeScale = 1 and BodyProportionScale = 1

Here is some code that describes the scaling constants as a dictionary, where the keys are limb names, and the values are the fully applied scale for each proportion model:

local ProportionsNormal =
{
    LeftHand      = Vector3.new(1.066, 1.151, 1.231);
    LeftLowerArm  = Vector3.new(1.129, 1.315, 1.132);
    LeftUpperArm  = Vector3.new(1.129, 1.315, 1.132);
    RightHand     = Vector3.new(1.066, 1.151, 1.231);
    RightLowerArm = Vector3.new(1.129, 1.315, 1.132);
    RightUpperArm = Vector3.new(1.129, 1.315, 1.132);
    UpperTorso    = Vector3.new(1.033, 1.283, 1.140);
    LeftFoot      = Vector3.new(1.079, 1.242, 1.129);
    LeftLowerLeg  = Vector3.new(1.023, 1.476, 1.023);
    LeftUpperLeg  = Vector3.new(1.023, 1.476, 1.023);
    RightFoot     = Vector3.new(1.079, 1.242, 1.129);
    RightLowerLeg = Vector3.new(1.023, 1.476, 1.023);
    RightUpperLeg = Vector3.new(1.023, 1.476, 1.023);
    LowerTorso    = Vector3.new(1.033, 1.283, 1.140);
    Head          = Vector3.new(0.942, 0.942, 0.942);
}

local ProportionsSlender =
{
    LeftHand      = Vector3.new(0.948, 1.151, 1.094);
    LeftLowerArm  = Vector3.new(1.004, 1.184, 1.006);
    LeftUpperArm  = Vector3.new(1.004, 1.184, 1.006);
    RightHand     = Vector3.new(0.948, 1.151, 1.094);
    RightLowerArm = Vector3.new(1.004, 1.184, 1.006);
    RightUpperArm = Vector3.new(1.004, 1.184, 1.006);
    UpperTorso    = Vector3.new(0.905, 1.180, 1.013);
    LeftFoot      = Vector3.new(1.030, 1.111, 1.004);
    LeftLowerLeg  = Vector3.new(0.976, 1.275, 0.909);
    LeftUpperLeg  = Vector3.new(0.976, 1.373, 0.909);
    RightFoot     = Vector3.new(1.030, 1.111, 1.004);
    RightLowerLeg = Vector3.new(0.976, 1.275, 0.909);
    RightUpperLeg = Vector3.new(0.976, 1.373, 0.909);
    LowerTorso    = Vector3.new(0.986, 0.985, 1.013);
    Head          = Vector3.new(0.896, 0.942, 0.896);
}


Proportion Scaling & Blending Behavior

The values of ProportionsNormal and ProportionsSlender are blended between [0-1] using the BodyProportionScale value inside of the Humanoid. If the value is 0, then the proportions are normal. If the value is 1, then the proportions are slender.

The overall Rthro scaling is blended between [0-1] using the BodyTypeScale value. If the value is 0, the character uses the classic character proportions. If the value is 1, then the character uses the rthro character proportions.

This is the reason why BodyProportionScale has no effect when the BodyTypeScale is set to 0. It is used to blend between the two proportions and the proportions that are selected from this blending control how much each limb is scaled by using the BodyTypeScale value.


The AvatarPartScaleType Value

Ever wonder how rthro avatars are scaled back to the classic avatar proportions? Well, it’s sort of like what is described above, but in reverse!

Rthro avatars are not created with classic avatar proportions (except for R6) so instead, each limb and accessory handle in an Rthro avatar has a StringValue inside of it named AvatarPartScaleType.

This StringValue is used to hint that the original size of the limb corresponds to one of the two Rthro proportions described above.

image

If it’s value is set to “ProportionsNormal” then the limb will be scaled relative to its value in the ProportionsNormal dictionary. Similarly, if it’s value is set to “ProportionsSlender” then the limb will be scaled relative to its value in the ProportionsSlender dictionary.


Conclusion

Now you should hopefully have a general understanding of how the Rthro scaling system works. If you have any questions, feel free to post them below. Hope this was informative!



Announcing Unlocked Avatar Scaling: Expanding the Roblox Universe
#2

Body parts that are “Rthro Native”, and tagged with ProportionsNormal or ProportionsSlender are scaled down using different scaling factors than are used to scale non-Rthro avatars up to Rthro stature. It’s asymmetric. So there are actually 4 scaling tables in use. Additionally, a few of the values in your tables don’t match what my game is generating on production right now, so just for the sake of completeness, here is what are currently in use (valid 11/16/2018 subject to change). The first two tables are generated by looping over the body parts of a default R15 Block figure scaled with BodyType=1 and BodyProportion 0 and 1 respectively. The second set are generated by iterating over City Life Man and City Life Woman with their BodyType set to 0. In every case, the value in the table is adjusted part size / native size.

R15toRthroNormal = {
	LeftHand = Vector3.new(1.06599998, 1.17400002, 1.23099995),
	LeftLowerArm = Vector3.new(1.12899995, 1.34200001, 1.13199997),
	LeftUpperArm = Vector3.new(1.12899995, 1.34200001, 1.13199997),
	RightHand = Vector3.new(1.06599998, 1.17400002, 1.23099995),
	RightLowerArm = Vector3.new(1.12899995, 1.34200001, 1.13199997),
	RightUpperArm = Vector3.new(1.12899995, 1.34200001, 1.13199997),
	UpperTorso = Vector3.new(1.03299999, 1.30900002, 1.13999999),
	LeftFoot = Vector3.new(1.079, 1.26700008, 1.12899995),
	LeftLowerLeg = Vector3.new(1.023, 1.50600028, 1.023),
	LeftUpperLeg = Vector3.new(1.023, 1.50600028, 1.023),
	RightFoot = Vector3.new(1.079, 1.26699996, 1.12899995),
	RightLowerLeg = Vector3.new(1.023, 1.50600004, 1.023),
	RightUpperLeg = Vector3.new(1.023, 1.50600004, 1.023),
	LowerTorso = Vector3.new(1.03299999, 1.30900002, 1.13999999),
	Head = Vector3.new(0.941999972, 0.941999972, 0.941999972),
}

R15toRthroSlender = {
	LeftHand = Vector3.new(0.947555542, 1.17400002, 1.09422219),
	LeftLowerArm = Vector3.new(1.00355554, 1.20792091, 1.00622225),
	LeftUpperArm = Vector3.new(1.00355554, 1.20792091, 1.00622225),
	RightHand = Vector3.new(0.947555542, 1.17400002, 1.09422219),
	RightLowerArm = Vector3.new(1.00355554, 1.20792091, 1.00622225),
	RightUpperArm = Vector3.new(1.00355554, 1.20792091, 1.00622225),
	UpperTorso = Vector3.new(0.905346155, 1.20423186, 1.01333332),
	LeftFoot = Vector3.new(1.02958012, 1.1332736, 1.00355554),
	LeftLowerLeg = Vector3.new(0.976145089, 1.30051816, 0.909333348),
	LeftUpperLeg = Vector3.new(0.976145089, 1.40093017, 0.909333348),
	RightFoot = Vector3.new(1.02958012, 1.13328028, 1.00355554),
	RightLowerLeg = Vector3.new(0.976145089, 1.30052578, 0.909333348),
	RightUpperLeg = Vector3.new(0.976145089, 1.40093839, 0.909333348),
	LowerTorso = Vector3.new(0.985687017, 1.00460482, 1.01333332),
	Head = Vector3.new(0.896289229, 0.941999972, 0.896289229),
}

RthroManToR15 = {
	LeftHand = Vector3.new(1.38999999, 0.967000008, 1.20099998),
	LeftLowerArm = Vector3.new(1.12100005, 0.680999994, 0.968000114),
	LeftUpperArm = Vector3.new(1.12100005, 0.680999994, 0.968000054),
	RightHand = Vector3.new(1.38999999, 0.967000008, 1.20099998),
	RightLowerArm = Vector3.new(1.12100005, 0.680999994, 0.968000114),
	RightUpperArm = Vector3.new(1.12100005, 0.680999994, 0.968000054),
	UpperTorso = Vector3.new(1.01400006, 0.81400001, 0.924000025),
	LeftFoot = Vector3.new(1.40400004, 0.953000069, 0.930999994),
	LeftLowerLeg = Vector3.new(0.977999926, 0.81400001, 1.05599999),
	LeftUpperLeg = Vector3.new(0.978000045, 0.81400001, 1.05599999),
	RightFoot = Vector3.new(1.40400004, 0.953000188, 0.930999994),
	RightLowerLeg = Vector3.new(0.977999926, 0.814000189, 1.05599999),
	RightUpperLeg = Vector3.new(0.978000045, 0.81400013, 1.05599999),
	LowerTorso = Vector3.new(1.01400006, 0.81400001, 0.924000025),
	Head = Vector3.new(1.60000002, 1.60000002, 1.60000002),
}

RthroWomanToR15 = {
	LeftHand = Vector3.new(1.56375003, 0.967000008, 1.351125),
	LeftLowerArm = Vector3.new(1.26112509, 0.756590962, 1.08899999),
	LeftUpperArm = Vector3.new(1.26112509, 0.756590962, 1.08899999),
	RightHand = Vector3.new(1.56375003, 0.967000067, 1.351125),
	RightLowerArm = Vector3.new(1.26112509, 0.756590962, 1.08899999),
	RightUpperArm = Vector3.new(1.26112509, 0.756590962, 1.08899999),
	UpperTorso = Vector3.new(1.15697408, 0.884817958, 1.0395),
	LeftFoot = Vector3.new(1.47139204, 1.06545448, 1.04737496),
	LeftLowerLeg = Vector3.new(1.02494395, 0.942612529, 1.18799996),
	LeftUpperLeg = Vector3.new(1.02494395, 0.875050426, 1.18799996),
	RightFoot = Vector3.new(1.47139204, 1.06545401, 1.04737496),
	RightLowerLeg = Vector3.new(1.02494395, 0.942612052, 1.18799996),
	RightUpperLeg = Vector3.new(1.02494395, 0.875050068, 1.18799996),
	LowerTorso = Vector3.new(1.06267202, 1.060642, 1.0395),
	Head = Vector3.new(1.68160009, 1.60000002, 1.68160009),
}

Your description of lerping between two tables based on BodyProportionScale is the case with both pairs of tables.


#3

Hmmm, alright.

I used the same technique as you to compute the scale constants, but rounded my values to 3 decimal places, as the data trends suggested that the values below that point were just floating point precision errors.

The values may have been tuned partially since I calibrated my values (which was about a month ago). I implemented it in C# for my Rbx2Source program, which is what I based the tables on.

(Rbx2Source converts Roblox avatars into ragdolls that can be used in the Source Engine, it’s something that I have been developing for a few years now.)

My scaling constants:

My function for scaling:


#4

Yes, the tables were being tuned adjusted as the Rthro models were being created and tested, right up until release. The most significant change was the addition of the tables for scaling Rthro down to classic Robloxian stature, which are not the reciprocals of the Robloxian-to-Rthro scalings.