Page 2 of 2
Re: Coordinates of the tip of the bone
Posted: Sun Mar 20, 2016 12:47 pm
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.
Re: Coordinates of the tip of the bone
Posted: Mon Mar 21, 2016 9:04 am
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)
Re: Coordinates of the tip of the bone
Posted: Mon Mar 21, 2016 11:30 am
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)
Re: Coordinates of the tip of the bone
Posted: Mon Mar 21, 2016 11:40 am
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
Re: Coordinates of the tip of the bone
Posted: Mon Mar 21, 2016 2:39 pm
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
Re: Coordinates of the tip of the bone
Posted: Mon Mar 21, 2016 2:52 pm
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.