Help With Skinned Mesh Scaling

Hello! I’m working on a game where your character is a custom Skinned Mesh character. When you eat fruit your character will get bigger. To achieve this I update the Humanoid Description’s properties (DepthScale, HeightScale, WidthScale, etc).

My first issue was that although I was scaling the mesh of my character, the armature/skeleton wasn’t being scaled. Which created weird issues like this:
image
image

For reference, this is what it’s suppose to look like:
image
image

I took me a long time to figure out, that I needed to scale the armature. Once I figured that out, I found a function on Devforum that achieves this:

local function scaleRecursive(part, instance, scaleFactor)
	if instance:isA("Bone") then
		local bone = instance
		local parentCFrame
		
		if (bone.Parent:IsA("Bone")) then -- parent can be either the MeshPart or another Bone
			parentCFrame = bone.Parent.WorldCFrame
		else
			parentCFrame = bone.Parent.CFrame
		end
		
		local parentInPartCFrame = Monke.CFrame:Inverse() * parentCFrame
		local parentInPartRotationCFrame = parentInPartCFrame - parentInPartCFrame.Position
		local pivotOffsetInPartSpace = parentInPartRotationCFrame * bone.Position 
		local scaledPivotOffsetInPartSpace = pivotOffsetInPartSpace * Vector3.new(scaleFactor, scaleFactor, scaleFactor)
		local partToParentRotationCFrame = parentInPartRotationCFrame:inverse()  
		bone.Position = partToParentRotationCFrame * scaledPivotOffsetInPartSpace
	end
	local children = instance:GetChildren()
	for i = 1, #children do
		local child = children[i]
		scaleRecursive(part, child, scaleFactor)
	end
end

Credits to this post.

My issue with this function is it Multiplies the existing size of the model with a scale factor. Which means for example if the model is scaled to 2 (twice it’s original size), and I want to set the scale to 3. Rather than increasing it’s size by 1, it will set the size to 2 * 3, which is 6. The issue is my game’s code works by setting the scale to a specific value and increasing that value when the player eats fruit.

So to sum up my question, how could I make this function set the scale rather than multiply it exponentially. I’m not very experienced with Skinned Meshes and Bones, so I figured I would ask here :‎P

Thanks in advance

3 Likes

If your current scale is 1.2 and you want to change it to 1.5, you need to multiply it by 1.5/1.2, so pass that to the function. This requires you to know both the old and new scale of course, but I assume you have that.

2 Likes

Thank you! That seems to work, although I noticed it still distorts my rig.

image

local function scaleRecursive(part, instance, scaleFactor)
	if instance:isA("Bone") then
		-- move bone local translation to part space, scale xyz in part space, then move back to bone parent space
		
		local bone = instance
		local parentCFrame
		
		if (bone.Parent:IsA("Bone")) then -- parent can be either the MeshPart or another Bone
			parentCFrame = bone.Parent.WorldCFrame
		else
			parentCFrame = bone.Parent.CFrame
		end
		
		local parentInPartCFrame = Monke.CFrame:Inverse() * parentCFrame
		local parentInPartRotationCFrame = parentInPartCFrame - parentInPartCFrame.Position
		local pivotOffsetInPartSpace = parentInPartRotationCFrame * bone.Position 

		local Scale = scaleFactor / CurrentSize

		local scaledPivotOffsetInPartSpace = pivotOffsetInPartSpace * Vector3.new(Scale, Scale, Scale)
		local partToParentRotationCFrame = parentInPartRotationCFrame:inverse()  
		bone.Position = partToParentRotationCFrame * scaledPivotOffsetInPartSpace
	end
	local children = instance:GetChildren()
	for i = 1, #children do
		local child = children[i]
		scaleRecursive(part, child, scaleFactor)
	end
end

For the Humanoid Description I am setting DepthScale, WidthScale, and HeightScale all to the scale of the gorilla.

Do you have any ideas for why this could be happening?

1 Like

I noticed that this issue only occurs when the gorilla is playing it’s “all fours” animations (like standing on all four legs).

But when the falling animation plays it looks normal.
image

Probably because that’s how it was originally modeled.
image

The animations look completely normal when they are in their default size, but not when scaled. Does anyone know how I could correct this?

1 Like

The code you found might not be right for how your character is structured. If you have a pure Bone-based character, where all the Bone instances are in a tree under the same part (e.g. your root part), then scaling the armature is a whole lot simpler, since you just need to scale Bone.Position. Bone.Position is aready a translation in the space of the parent. So no CFrame math is needed, just scaling Vector3s.

If you have more than one tree of Bones, parented to different parts that are connected with Motor6Ds, the situation gets more complicated.

1 Like

Thank you! It seems to have a little bit better proportions although it is still pretty cursed XD

image

I think this definitely has to do with the animations not being designed for such a large character. Do you think there’s a way I could correct/alter the animations with code? Or could these issues be fixed in blender?

1 Like

Does your animation have translation in the poses? Character animation usually has just pure joint rotations on all but the root-most joint, and rotations are not affected by scaling.

1 Like

instead of applying the scale factor to the existing size, you can replace the size completely with the desired scale:

local function scaleRecursive(part, instance, scaleFactor)
	if instance:IsA("Bone") then
		local bone = instance
		local parentCFrame
		
		if bone.Parent:IsA("Bone") then -- parent can be either the MeshPart or another Bone
			parentCFrame = bone.Parent.WorldCFrame
		else
			parentCFrame = bone.Parent.CFrame
		end
		
		local parentInPartCFrame = part.CFrame:Inverse() * parentCFrame
		local parentInPartRotationCFrame = parentInPartCFrame - parentInPartCFrame.Position
		local pivotOffsetInPartSpace = parentInPartRotationCFrame * bone.Position 
		local scaledPivotOffsetInPartSpace = pivotOffsetInPartSpace * Vector3.new(scaleFactor.X, scaleFactor.Y, scaleFactor.Z)
		local partToParentRotationCFrame = parentInPartRotationCFrame:Inverse()  
		bone.Position = partToParentRotationCFrame * scaledPivotOffsetInPartSpace
	end
	
	local children = instance:GetChildren()
	for i = 1, #children do
		local child = children[i]
		scaleRecursive(part, child, scaleFactor)
	end
end

I don’t know what you mean by translation in the poses as I’m not very familiar with this topic. Although I do agree it’s a little strange as animations typically just change the degrees of joints. The only reason why I think it has to do with animations is because when it’s standing like a human it’s scaled correctly, and it’s only when it’s “all fours” animations are played that is has issues.

A handy scale API was recently released for models. Works perfectly on skinned meshes. There is noticeable ‘rubber banding’ when scaling a moving character though. Hopefully they’ll fix that soon.

Something like this:

char:ScaleTo(char:GetScale() * 1.1)

Yeah I originally used that, but the replication/rubber banding issues were a deal breaker as the character scales about 1000 times in total.

1 Like

Right, for our game we can get away with doing a scale once every two minutes, which isn’t that detrimental to gameplay.

Does using the humanoid scale not cause rubber banding?

Yeah that’s why I went with it. I use a function from HD admin as I felt it was the most reliable.

local function ChangeProperties(plr, properties) -- Forked from HD Admin
	if Humanoid then
		for a,b in pairs(Humanoid:GetChildren()) do
			local targetName = string.lower(b.Name)
			for propName, propValue in pairs(properties) do
				propName = string.lower(propName)
				if string.sub(targetName, -#propName) == propName then
					b.Value = propValue
					break
				end
			end
		end
	end
end

ChangeProperties(Player, {DepthScale = 1 * MonkeySize, HeightScale = 1 * MonkeySize, WidthScale = 1 * MonkeySize, HeadScale = 1 * MonkeySize})

But the bones are broken when scaled that way right?

Anims should keep working as long as the bone mesh proportions scale the same. I.e. it’s rescaled evenly in all directions.

Exactly, relying on the Humanoid Description just changes the mesh for Skinned Meshes, but it doesn’t change bones at all. That’s why I created this post as I’m unsure of a bug free way to scale bones correctly.

1 Like

Indeed. The first thing I do with any Bone-based character is set Humanoid.AutomaticScalingEnabled to false, and manually set the HipHeight. This makes sure that the body scale value things aren’t messing with the character scaling. Those body width, height, depth, etc. are only for Motor6D-based avatars with the standard R15 parts and joint names; they will give you nothing but problems with a custom skinned character with Bones.

Alright so I disabled Humanoid.AutomaticScalingEnabled and I commented out all code involving the body scale values. I figured it would be easier to just change MeshPart.Size which ended up working well (feel free to suggest a better method). I still have my distortion issue which makes me believe something is wrong with the function? But then again the issues only occur when the “all fours” animations are playing. So I’m a little bit stumped on this one.

Alright so my new solution is to just use Character:ScaleTo() on the client, which doesn’t have it’s lag issues. This will just be a temporary fix until changing the Character on the server gets fixed, which is luckily already a known issue and is going to be fixed soon.

Keep in mind using Character:ScaleTo() doesn’t replicate to the server, so if you have any weapons or features that requires the server to handle, I recommend waiting until this is fixed in a few days.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.