Coordinates of the tip of the bone

Moho allows users to write new tools and plugins. Discuss scripting ideas and problems here.

Moderators: Víctor Paredes, Belgarath, slowtiger

lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Coordinates of the tip of the bone

Post by lehtiniemi »

Thanks! Got it to work now, here's the resulting script: viewtopic.php?f=12&t=29029

My biggest mistake, however was that I went through the fMovedMatrix recursively. You only need to read the fMovedMatrix from the first parent. That matrix includes all the transformations that its parents cause. When I went through the whole skeleton recursively, this resulted that the earlier the parent, the more times its effect would be applied to the last bone.
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Coordinates of the tip of the bone

Post by lehtiniemi »

Oh, I came up way the most simple way to calculate this!

Basing on that you can get the transformation effect of the whole parent skeleton to the current bone by transforming the current bone with fMovedMatrix of the parent bone, you can think like this: the tip of the current bone is basically the base of the next child bone. Even if there is no child bone, the current bone still has fMovedMatrix which you can apply to the current bone coordinates. This will give you the base of the imaginary child bone. This way you have the tip coordinates of the current bone.

So instead of doing

Code: Select all

skel:Bone(current bone parent).fMovedMatrix:Transform(current bone fPos)
, to get the tip coordinates just do

Code: Select all

skel:Bone(current bone).fMovedMatrix:Transform(current bone fPos)
User avatar
hayasidist
Posts: 3492
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: Coordinates of the tip of the bone

Post by hayasidist »

That sounded so simple and straightforward - so I gave it a go ... but I'm getting different results from the "longhand" (seems to be right) and your shorter approach (can't get it to give the right answer!?)

Code: Select all

	vec:Set(bone.fPos)
	bone.fMovedMatrix:Transform(vec)
	print (vec.x, vec.y) -- not consistent with observed tip position?
I've made glaring errors in 2 lines of code before, and doubtless I will again -- but I just don't see what's fundamentally different between the above and your
skel:Bone(current bone).fMovedMatrix:Transform(current bone fPos)
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Coordinates of the tip of the bone

Post by lehtiniemi »

hayasidist wrote:That sounded so simple and straightforward - so I gave it a go ... but I'm getting different results from the "longhand" (seems to be right) and your shorter approach (can't get it to give the right answer!?)

Code: Select all

	vec:Set(bone.fPos)
	bone.fMovedMatrix:Transform(vec)
	print (vec.x, vec.y) -- not consistent with observed tip position?
I've made glaring errors in 2 lines of code before, and doubtless I will again -- but I just don't see what's fundamentally different between the above and your
skel:Bone(current bone).fMovedMatrix:Transform(current bone fPos)
I can't tell... it looks the same. You must also remember to take the layer transform into account.

Code: Select all

	local m= LM.Matrix:new_local()
	moho.layer:GetLayerTransform(frame,m, nil) -- bypass camera transformations by passing nil as document object
Here's my whole function that calculates either base or tip position. It's a bit uncleaned in code, but maybe you'll find the problem there if I forgot to mention something... It works in my script.

Code: Select all

-- Calculates bone position and returns the coordinates within the current layer
function JL_walk_tool:CalculateBonePosition(moho, bone, trackBoneBase, frame)
	local skel

	skel = moho:Skeleton()

	if (skel == nil) then return end

	local i
	local vec = LM.Vector2:new_local()

	local boneId
	local parent
	local curFrame = moho.layer:CurFrame()

	-- Save current frame
	if not (frame == curFrame) then
		moho:SetCurFrame(frame)
	end

	boneId = moho:Skeleton():BoneID(bone)

	vec:Set(bone.fPos)

	parent = bone.fParent

	-- Apply parent transformation to the current bone. This seems to include all the transformations caused by the following parents so
	-- you only need to read it from the first parent.
	-- If user wants to track bone tip, this can be calculated by applying CURRENT bone transformation to the 
	-- current position instead, returning the child bone base coordinate (which equals current bone tip)

	if (parent >= 0) then
		-- Calculate base or tip coordinates?
		if (trackBoneBase) then
			skel:Bone(parent).fMovedMatrix:Transform(vec)
		else
			bone.fMovedMatrix:Transform(vec)
		end
	end
	
	-- Lastly, apply transformations by the current layer
	local m= LM.Matrix:new_local()
	moho.layer:GetLayerTransform(frame,m, nil) -- bypass camera transformations by passing nil as document object

	m:Transform(vec)

	-- Move back to current original frame
	if not (frame == curFrame) then
		moho:SetCurFrame(curFrame)
	end

	return vec

end
User avatar
hayasidist
Posts: 3492
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: Coordinates of the tip of the bone

Post by hayasidist »

sorry - I can't make it work. It's close but ...

I took your routine and hardwired a call to it

Code: Select all

	Print ("Bone", bone:Name(), "Base x, y", bone.fPos.x, bone.fPos.y, "angle/length/scale", bone.fAngle, bone.fLength, bone.fScale) -- confirms correct bone
	vec = CalculateBonePosition (moho, bone, false, moho.frame)
	Print ("Returned vec is", vec.x, vec.y) -- does not match the bone tip as observed by placing a vector shape inside or outside the bone group at the bone tip
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Coordinates of the tip of the bone

Post by lehtiniemi »

hayasidist wrote:sorry - I can't make it work. It's close but ...

I took your routine and hardwired a call to it

Code: Select all

	Print ("Bone", bone:Name(), "Base x, y", bone.fPos.x, bone.fPos.y, "angle/length/scale", bone.fAngle, bone.fLength, bone.fScale) -- confirms correct bone
	vec = CalculateBonePosition (moho, bone, false, moho.frame)
	Print ("Returned vec is", vec.x, vec.y) -- does not match the bone tip as observed by placing a vector shape inside or outside the bone group at the bone tip
Ah, but sorry I'm not using my function to get absolute coordinates. I'm only calculating movement in the local Bone layer, so I haven't tried absolute coordinates and how they match. But you should get absolute coordinates by changing the transform matrix at the end to:

Code: Select all

moho.layer:GetFullTransform(frame,m, moho.document)
After calling that function we have the coordinates in the local bone layer coordinates so they just need translation to real world. This is without current layer, parent layers and camera transformation. GetFullTransform should do just that.

I also assume that fPos is all the bone movement the parent bone can contain and it doesn't exclude something that fAnimPos contains. I don't think so. But if you are calculating coordinates at frame 0, then you have to use fRestMatrix instead of fMovedMatrix, I think.
Post Reply