Getting position for bone that's moved by other bones

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

Moderators: Víctor Paredes, Belgarath, slowtiger

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

Getting position for bone that's moved by other bones

Post by lehtiniemi »

How can I get coordinates for a bone that's not animated but is moved by other bones?

fAnimPos doesn't seem to return anything. I tried to use bone.fAnimPos:GetValue(frameNumber) to get coordinates for a bone that's not animated by itself but is moved by the rest of the skeleton. It returns no movement. Then I figured that maybe fPos contains the absolute position even though it's not animated, but bone.fPos:GetValue(frameNumber) returns an error - there doesn't seem to be get-function for this.

Any ideas on how to get access to this position data?
User avatar
synthsin75
Posts: 9934
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Getting position for bone that's moved by other bones

Post by synthsin75 »

Off the top of my head... bone.fPos and bone.fPos.x for specific axis.
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Getting position for bone that's moved by other bones

Post by lehtiniemi »

synthsin75 wrote:Off the top of my head... bone.fPos.value and bone.fPos.value.x for specific axis.
Hmm, but how can I specify the frame where I want the bone position at? fAnimPos:GetValue(frameNumber) returns the bone position at the specified frame number, but for some reason it doesn't return the bone position when it's animated by other bones.

Can I somehow get fPos at a specified frame? Or is this the bone position at frame 0?
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Getting position for bone that's moved by other bones

Post by lehtiniemi »

Here's modified code that I found on the forum. It should do something like what I'm trying to achieve: when you give it bone and atFrame, it should calculate the position of the bone at that frame. But bone base coordinates (vec1) doesn't seem to return anything and bone tip (vec2) coordinates are "stuttering" somehow and don't correspond tip position exactly.

Any idea what could the problem?

Code: Select all

function JL_compensate_bone_movement:CalculateBonePosition(moho, bone, atFrame)
   local skel

   if (moho.layer:LayerType() == MOHO.LT_BONE) then
      skel= moho:Skeleton()
   else
      skel= moho:ParentSkeleton()
   end

   if (skel == nil) then return end

   local vec1= LM.Vector2:new_local()
   local vec2= LM.Vector2:new_local()

   local pt1= LM.Point:new_local()
   local pt2= LM.Point:new_local()



   local m= LM.Matrix:new_local()
   moho.layer:GetFullTransform(atFrame,m,moho.document)


--root
      if (atFrame == 0) then
         vec1:Set(bone.fAnimPos:GetValue(0))

         if (bone.fParent >= 0) then
            skel:Bone(bone.fParent).fRestMatrix:Transform(vec1)
         end
      else
         vec1:Set(bone.fPos)
         if (bone.fParent >= 0) then
            skel:Bone(bone.fParent).fMovedMatrix:Transform(vec1)
         end
      end
      m:Transform(vec1)
--tip
      vec2:Set(bone.fLength,0)
      vec2:Rotate(bone.fAnimAngle:GetValue(atFrame))

      if (atFrame == 0) then
         vec2= vec2 + bone.fAnimPos:GetValue(0)

         if (bone.fParent >= 0) then
            skel:Bone(bone.fParent).fRestMatrix:Transform(vec2)
         end
      else
         vec2= vec2 + bone.fPos
         if (bone.fParent >= 0) then
            skel:Bone(bone.fParent).fMovedMatrix:Transform(vec2)
         end
      end
      m:Transform(vec2)

      return vec2

end
User avatar
synthsin75
Posts: 9934
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Getting position for bone that's moved by other bones

Post by synthsin75 »

Temporarily select the frame, get the .fPos, and select the original frame again.
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Getting position for bone that's moved by other bones

Post by lehtiniemi »

synthsin75 wrote: Temporarily select the frame, get the .fPos, and select the original frame again.
Thanks for the idea! I tried this, but this doesn't return the absolute position of the bone either. It also only returns values if the bone is animated with keyframes:

Code: Select all

	for i = newStartFrame, newEndFrame do
		moho:SetCurFrame(i)
		
		bonePosition = skel:Bone(skel:SelectedBoneID()).fPos
		print(bonePosition.x)
        end
This returns no movement when the bone is moved by the skeleton.

What else could I try...?
User avatar
synthsin75
Posts: 9934
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Getting position for bone that's moved by other bones

Post by synthsin75 »

lehtiniemi wrote:Thanks for the idea! I tried this, but this doesn't return the absolute position of the bone either. It also only returns values if the bone is animated with keyframes:

Code: Select all

	for i = newStartFrame, newEndFrame do
		moho:SetCurFrame(i)
		
		bonePosition = skel:Bone(skel:SelectedBoneID()).fPos
		print(bonePosition.x)
        end
This returns no movement when the bone is moved by the skeleton.

What else could I try...?
An unanimated bone will never show a different position than frame zero. See my response in your other thread.
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Getting position for bone that's moved by other bones

Post by lehtiniemi »

Anyone who looks for answer to this, here's how you do it. This function returns the position of the bone in the current layer coordinates. If you want global coordinates, there's a change in the Transform-sentence at the end, just switch from GetLayerTransform to GetFullTransform and add moho.document as last argument to take camera transformation into account.

Code: Select all

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

	skel = moho:Skeleton()

	if (skel == nil) then return end

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

	local boneId
	local parent


	-- Save current frame before jumping to frame given as argument
	-- This is because fPos is the bone position at current keyframe so you have to jump there to get it
	local curFrame = moho.layer:CurFrame()

	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 (parent >= 0) then skel:Bone(parent).fMovedMatrix:Transform(vec) end


	-- Lastly, apply transformations by the current layer and its parents
	local m= LM.Matrix:new_local()
	moho.layer:GetLayerTransform(frame,m, nil) -- bypass camera transformations by passing nil as document object
	-- As a sidenote, if you want to take parent and camera transformations into account, you should use this instead:
	-- moho.layer:GetFullTransform(frame,m, moho.document)

	m:Transform(vec)

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

	return vec

end
Post Reply