-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "MR_MoveTargetedJoint" -- ************************************************** -- General information about this script -- ************************************************** MR_MoveTargetedJoint = {} function MR_MoveTargetedJoint:Name() return self:Localize('UILabel') end function MR_MoveTargetedJoint:Version() return '1.2' end function MR_MoveTargetedJoint:UILabel() return self:Localize('UILabel') end function MR_MoveTargetedJoint:Creator() return 'Eugene Babich' end function MR_MoveTargetedJoint:Description() return self:Localize('Description') end -- ************************************************** -- Is Relevant / Is Enabled -- ************************************************** function MR_MoveTargetedJoint:IsRelevant(moho) local skel = moho:Skeleton() if (skel == nil) then return false end return true end function MR_MoveTargetedJoint:IsEnabled(moho) if (moho:CountBones() < 3) then return false end if moho.frame == 0 then return false end return true end -- ************************************************** -- Recurring Values -- ************************************************** MR_MoveTargetedJoint.hideBonesWhileMoving = false MR_MoveTargetedJoint.leaveBonesSelected = true MR_MoveTargetedJoint.bakeAdjacentFrames = false MR_MoveTargetedJoint.maintainProportions = false MR_MoveTargetedJoint.firstBoneVisibility = true MR_MoveTargetedJoint.secondBoneVisibility = true MR_MoveTargetedJoint.firstBone = -1 MR_MoveTargetedJoint.firstBonePos = LM.Vector2:new_local() MR_MoveTargetedJoint.firstBoneScalePercent = 50 MR_MoveTargetedJoint.clickOffset = LM.Vector2:new_local() MR_MoveTargetedJoint.secondBone = -1 MR_MoveTargetedJoint.targetBonePos = LM.Vector2:new_local() MR_MoveTargetedJoint.targetBone = 0 MR_MoveTargetedJoint.boneAngle = 0 MR_MoveTargetedJoint.isFlipped = false MR_MoveTargetedJoint.isParentfliped = false MR_MoveTargetedJoint.isMore = false MR_MoveTargetedJoint.isActive = true MR_MoveTargetedJoint.childsList = {} MR_MoveTargetedJoint.firstBoneOffset = 0 MR_MoveTargetedJoint.secondBoneOffset = 0 -- ************************************************** -- Prefs -- ************************************************** function MR_MoveTargetedJoint:LoadPrefs(prefs) self.hideBonesWhileMoving = prefs:GetBool("MR_MoveTargetedJoint.hideBonesWhileMoving", false) self.leaveBonesSelected = prefs:GetBool("MR_MoveTargetedJoint.leaveBonesSelected", false) self.bakeAdjacentFrames = prefs:GetBool("MR_MoveTargetedJoint.bakeAdjacentFrames", false) self.maintainProportions = prefs:GetBool("MR_MoveTargetedJoint.maintainProportions", false) end function MR_MoveTargetedJoint:SavePrefs(prefs) prefs:SetBool("MR_MoveTargetedJoint.hideBonesWhileMoving", self.hideBonesWhileMoving) prefs:SetBool("MR_MoveTargetedJoint.leaveBonesSelected", self.leaveBonesSelected) prefs:SetBool("MR_MoveTargetedJoint.bakeAdjacentFrames", self.bakeAdjacentFrames) prefs:SetBool("MR_MoveTargetedJoint.maintainProportions", self.maintainProportions) end function MR_MoveTargetedJoint:ResetPrefs() self.hideBonesWhileMoving = false self.leaveBonesSelected = true self.bakeAdjacentFrames = false self.maintainProportions = false end -- ************************************************** -- Keyboard/Mouse Control -- ************************************************** function MR_MoveTargetedJoint:OnMouseDown(moho, mouseEvent) local skel = moho:Skeleton() if (skel == nil) then return end if (moho:CountSelectedBones() > 0) then for i = 0, skel:CountBones() - 1 do skel:Bone(i).fSelected = false end end local id = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, false) local boneCandidate = skel:Bone(id) if not self:IsBoneIK(moho, boneCandidate) then self.isActive = false return end if boneCandidate.fFlipH:GetValue(moho.layerFrame) or boneCandidate.fFlipV:GetValue(moho.layerFrame) then self.isActive = false return end local boneCandidateTargetID = skel:TargetOfBone(id, moho.layerFrame) if boneCandidateTargetID == -1 then local boneCandidateParentID = boneCandidate.fParent local isParentOk = true if boneCandidateParentID > -1 then local parentChilds = self:CountBoneChildren(moho, skel, boneCandidateParentID, true) if parentChilds == 1 then local bCandParent = skel:Bone(boneCandidateParentID) if self:IsBoneIK(moho, bCandParent) then self.isActive = false return end end end local childs = self:CountBoneChildren(moho, skel, id, true) if childs ~= 1 then self.isActive = false return end local found = false for q in pairs(self.childsList) do local bone = skel:Bone(self.childsList[q]) if self:IsBoneIK(moho, bone) then if skel:TargetOfBone(self.childsList[q], moho.layerFrame) > -1 then local tBone = skel:Bone(self.childsList[q]) if self:Round(tBone.fPos.y) == 0 then if not tBone.fFlipH:GetValue(moho.layerFrame) and not tBone.fFlipV:GetValue(moho.layerFrame) then skel:Bone(id).fSelected = true tBone.fSelected = true self.firstBone = id self.secondBone = self.childsList[q] found = true end end end end end if found then self.isActive = true else self.isActive = false return end else if self:Round(boneCandidate.fPos.y) ~= 0 then self.isActive = false return end local boneCandidateFirstID = boneCandidate.fParent if boneCandidateFirstID > -1 then local bCandFirst = skel:Bone(boneCandidateFirstID) if not self:IsBoneIK(moho, bCandFirst) then self.isActive = false return end local bCandFirstParentID = bCandFirst.fParent if bCandFirstParentID > -1 then local bCandFirstParent = skel:Bone(bCandFirstParentID) local parentFirstChilds = self:CountBoneChildren(moho, skel, bCandFirstParentID, true) if parentFirstChilds == 1 then if self:IsBoneIK(moho, bCandFirstParent) then self.isActive = false return end end end local childs = self:CountBoneChildren(moho, skel, boneCandidateFirstID, true) if childs ~= 1 then self.isActive = false return end if bCandFirst.fFlipH:GetValue(moho.layerFrame) or bCandFirst.fFlipV:GetValue(moho.layerFrame) then self.isActive = false return end if skel:TargetOfBone(boneCandidateFirstID, moho.layerFrame) > -1 then self.isActive = false return end bCandFirst.fSelected = true skel:Bone(id).fSelected = true self.firstBone = boneCandidateFirstID self.secondBone = id self.isActive = true else self.isActive = false return end end if self.isActive == false then return end moho.document:PrepUndo(moho.layer) moho.document:SetDirty() self.isFlipped = false local bone = skel:Bone(self.firstBone) local secondBone = skel:Bone(self.secondBone) if self.maintainProportions then local boneFirstLenght = secondBone.fPos.x local boneSecondLenght = secondBone.fLength local boneFirstScale = bone.fScale local boneSecondScale = secondBone.fScale self.firstBoneScalePercent = ((boneFirstLenght * boneFirstScale) / ((boneFirstLenght * boneFirstScale) + (boneSecondLenght * boneSecondScale))) * 100 end local secondBonePos = LM.Vector2:new_local() secondBonePos:Set(secondBone.fPos) local firstBoneMatrix = LM.Matrix:new_local() firstBoneMatrix:Set(bone.fMovedMatrix) firstBoneMatrix:Transform(secondBonePos) local mousePos = mouseEvent.vec self.clickOffset = secondBonePos - mousePos if self.bakeAdjacentFrames then if moho.layerFrame - 1 > 0 then local boneFAngle = bone.fAnimAngle:GetValue(moho.layerFrame - 1) local boneFScale = bone.fAnimScale:GetValue(moho.layerFrame - 1) local boneSAngle = secondBone.fAnimAngle:GetValue(moho.layerFrame - 1) local boneSScale = secondBone.fAnimScale:GetValue(moho.layerFrame - 1) bone.fAnimAngle:SetValue(moho.layerFrame - 1, boneFAngle) secondBone.fAnimAngle:SetValue(moho.layerFrame - 1, boneSAngle) bone.fAnimScale:SetValue(moho.layerFrame - 1, boneFScale) secondBone.fAnimScale:SetValue(moho.layerFrame - 1, boneSScale) end if moho.layerFrame + 1 > 0 then local boneFAngle = bone.fAnimAngle:GetValue(moho.layerFrame + 1) local boneFScale = bone.fAnimScale:GetValue(moho.layerFrame + 1) local boneSAngle = secondBone.fAnimAngle:GetValue(moho.layerFrame + 1) local boneSScale = secondBone.fAnimScale:GetValue(moho.layerFrame + 1) bone.fAnimAngle:SetValue(moho.layerFrame + 1, boneFAngle) secondBone.fAnimAngle:SetValue(moho.layerFrame + 1, boneSAngle) bone.fAnimScale:SetValue(moho.layerFrame + 1, boneFScale) secondBone.fAnimScale:SetValue(moho.layerFrame + 1, boneSScale) end end if self.hideBonesWhileMoving then self.firstBoneVisibility = bone.fHidden self.secondBoneVisibility = secondBone.fHidden bone.fHidden = true secondBone.fHidden = true end local firstBoneStretching = bone.fMaxAutoScaling local secondBoneStretching = secondBone.fMaxAutoScaling bone.fMaxAutoScaling = 1 secondBone.fMaxAutoScaling = 1 moho.layer:UpdateCurFrame() self.firstBoneOffset = bone.fScale - bone.fAnimScale:GetValue(moho.layerFrame) self.secondBoneOffset = secondBone.fScale - secondBone.fAnimScale:GetValue(moho.layerFrame) bone.fMaxAutoScaling = firstBoneStretching secondBone.fMaxAutoScaling = secondBoneStretching local bonePose = LM.Vector2:new_local() bonePose:Set(bone.fPos) local boneTarget = skel:TargetOfBone(self.secondBone, moho.layerFrame) self.targetBone = boneTarget local targetPos = LM.Vector2:new_local() local target = skel:Bone(boneTarget) local targetParent = target.fParent targetPos:Set(target.fPos) if targetParent > -1 then local targetParentBone = skel:Bone(targetParent) local targetParentMatrix = LM.Matrix:new_local() targetParentMatrix:Set(targetParentBone.fMovedMatrix) targetParentMatrix:Transform(targetPos) end self.targetBonePos = targetPos local parentBoneID = bone.fParent if parentBoneID > -1 then local parentBone = skel:Bone(parentBoneID) local parentMatrix = LM.Matrix:new_local() parentMatrix:Set(parentBone.fMovedMatrix) parentMatrix:Transform(bonePose) end self.bonePose = bonePose local vectorBonePos = targetPos - bonePose local boneAngle = math.atan2(vectorBonePos.y, vectorBonePos.x) if boneAngle < 0 then boneAngle = (math.pi * 2) + boneAngle end self.boneAngle = boneAngle local secondBoneAngle = secondBone.fAnimAngle:GetValue(moho.layerFrame) if secondBoneAngle > math.pi * 2 then secondBoneAngle = secondBoneAngle - (math.pi * 2) elseif secondBoneAngle < 0 then secondBoneAngle = secondBoneAngle + (math.pi * 2) end isParentfliped = false if parentBoneID > -1 then local nextBone = skel:Bone(parentBoneID) repeat local prevBone = nextBone if nextBone.fFlipH:GetValue(moho.layerFrame) then isParentfliped = not isParentfliped end if nextBone.fFlipV:GetValue(moho.layerFrame) then isParentfliped = not isParentfliped end if nextBone.fParent > -1 then nextBone = skel:Bone(nextBone.fParent) end until nextBone == prevBone end if secondBoneAngle < math.pi then self.isMore = true else self.isMore = false end if isParentfliped then self.isMore = not self.isMore end self:OnMouseMoved(moho, mouseEvent) end function MR_MoveTargetedJoint:IsBoneIK(moho, bone) if (bone.fAngleControlParent >= 0 or bone.fPosControlParent >= 0 or bone.fScaleControlParent >= 0 or bone.fBoneDynamics.value or bone.fIgnoredByIK) then return false else return true end end function MR_MoveTargetedJoint:OnMouseMoved(moho, mouseEvent) local skel = moho:Skeleton() if (skel == nil) then return end if self.isActive == false then return end local bone = skel:Bone(self.firstBone) local secondBone = skel:Bone(self.secondBone) local bonePose = LM.Vector2:new_local() bonePose = self.bonePose local targetPos = LM.Vector2:new_local() local boneLenght = secondBone.fPos.x local dist = self:GetDistance(bonePose, mouseEvent.vec + self.clickOffset) local boneNewScale = dist / boneLenght bone.fAnimScale:SetValue(moho.layerFrame, boneNewScale - self.firstBoneOffset) local secondDist = self:GetDistance(self.targetBonePos, mouseEvent.vec + self.clickOffset) local secondBoneLenght = secondBone.fLength local secondBoneNewScale = secondDist / secondBoneLenght secondBone.fAnimScale:SetValue(moho.layerFrame, secondBoneNewScale - self.secondBoneOffset) if self.maintainProportions then local totalDist = dist + secondDist local distP = (totalDist / 100) * self.firstBoneScalePercent distP = distP / boneLenght local secondDistP = (totalDist / 100) * (100 - self.firstBoneScalePercent) secondDistP = secondDistP / secondBoneLenght bone.fAnimScale:SetValue(moho.layerFrame, distP - self.firstBoneOffset) secondBone.fAnimScale:SetValue(moho.layerFrame, secondDistP - self.secondBoneOffset) end local vectorMousePos = (mouseEvent.vec + self.clickOffset) - bonePose local mouseAngle = math.atan2(vectorMousePos.y, vectorMousePos.x) if mouseAngle < 0 then mouseAngle = (math.pi * 2) + mouseAngle end mouseAngle = mouseAngle - self.boneAngle if mouseAngle < 0 then mouseAngle = (math.pi * 2) + mouseAngle end local turnToRight = 0.17 local turnToLeft = 3.31 if isParentfliped then turnToRight = 3.31 turnToLeft = 0.17 end if self.isMore then if mouseAngle < math.pi and not self.isFlipped then local boneAngle = bone.fAnimAngle:GetValue(moho.layerFrame) local secondBoneAngle = secondBone.fAnimAngle:GetValue(moho.layerFrame) bone.fAnimAngle:SetValue(moho.layerFrame, turnToLeft) secondBone.fAnimAngle:SetValue(moho.layerFrame, turnToLeft) self.isFlipped = true end if mouseAngle > math.pi and self.isFlipped then local boneAngle = bone.fAnimAngle:GetValue(moho.layerFrame) local secondBoneAngle = secondBone.fAnimAngle:GetValue(moho.layerFrame) bone.fAnimAngle:SetValue(moho.layerFrame, turnToRight) secondBone.fAnimAngle:SetValue(moho.layerFrame, turnToRight) self.isFlipped = false end else if mouseAngle < math.pi and self.isFlipped then local boneAngle = bone.fAnimAngle:GetValue(moho.layerFrame) local secondBoneAngle = secondBone.fAnimAngle:GetValue(moho.layerFrame) bone.fAnimAngle:SetValue(moho.layerFrame, turnToLeft) secondBone.fAnimAngle:SetValue(moho.layerFrame, turnToLeft) self.isFlipped = false end if mouseAngle > math.pi and not self.isFlipped then local boneAngle = bone.fAnimAngle:GetValue(moho.layerFrame) local secondBoneAngle = secondBone.fAnimAngle:GetValue(moho.layerFrame) bone.fAnimAngle:SetValue(moho.layerFrame, turnToRight) secondBone.fAnimAngle:SetValue(moho.layerFrame, turnToRight) self.isFlipped = true end end moho.layer:UpdateCurFrame() mouseEvent.view:DrawMe() end function MR_MoveTargetedJoint:Round(x, n) n = math.pow(10, n or 3) x = x * n if x >= 0 then x = math.floor(x + 0.5) else x = math.ceil(x - 0.5) end return x / n end function MR_MoveTargetedJoint:GetDistance(Pos1, Pos2) return math.sqrt((Pos2.x-Pos1.x)^2+(Pos2.y-Pos1.y)^2) end function MR_MoveTargetedJoint:CountBoneChildren(moho, skel, boneID, ignoreControlledBones) for q in pairs(self.childsList) do self.childsList[q] = nil end local n = 0 for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fParent == boneID) then n = n + 1 table.insert(self.childsList, i) if (ignoreControlledBones) then if (bone.fAngleControlParent >= 0 or bone.fPosControlParent >= 0 or bone.fScaleControlParent >= 0 or bone.fBoneDynamics.value or bone.fIgnoredByIK) then n = n - 1 end end end end return n end function MR_MoveTargetedJoint:OnMouseUp(moho, mouseEvent) local skel = moho:Skeleton() if (skel == nil) then return end if self.isActive == false then return end local bone = skel:Bone(self.firstBone) local secondBone = skel:Bone(self.secondBone) if self.hideBonesWhileMoving then bone.fHidden = self.firstBoneVisibility secondBone.fHidden = self.secondBoneVisibility end bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAngle) secondBone.fAnimAngle:SetValue(moho.layerFrame, secondBone.fAngle) moho:NewKeyframe(CHANNEL_BONE_S) moho:NewKeyframe(CHANNEL_BONE) if not self.leaveBonesSelected then bone.fSelected = false secondBone.fSelected = false end moho:UpdateUI() mouseEvent.view:DrawMe() moho:UpdateSelectedChannels() end -- ************************************************** -- Tool Panel Layout -- ************************************************** MR_MoveTargetedJoint.HIDE_BONES_WHILE_MOVING = MOHO.MSG_BASE MR_MoveTargetedJoint.LEAVE_BONES_SELECTED = MOHO.MSG_BASE +1 MR_MoveTargetedJoint.BAKE_ADJACENT_FRAMES = MOHO.MSG_BASE +2 MR_MoveTargetedJoint.MAINTAIN_PROPORTIONS = MOHO.MSG_BASE +3 function MR_MoveTargetedJoint:DoLayout(moho, layout) self.hideBonesWhileMovingCheckbox = LM.GUI.CheckBox(self:Localize('Hide bones while moving'), self.HIDE_BONES_WHILE_MOVING) layout:AddChild(self.hideBonesWhileMovingCheckbox, LM.GUI.ALIGN_LEFT, 0) self.leaveBonesSelectedCheckbox = LM.GUI.CheckBox(self:Localize('Leave Bones Selected'), self.LEAVE_BONES_SELECTED) layout:AddChild(self.leaveBonesSelectedCheckbox, LM.GUI.ALIGN_LEFT, 0) self.bakeAdjacentFramesCheckbox = LM.GUI.CheckBox(self:Localize('Bake Adjacent Frames'), self.BAKE_ADJACENT_FRAMES) layout:AddChild(self.bakeAdjacentFramesCheckbox, LM.GUI.ALIGN_LEFT, 0) self.maintainProportionsCheckbox = LM.GUI.CheckBox(self:Localize('Maintain Proportions'), self.MAINTAIN_PROPORTIONS) layout:AddChild(self.maintainProportionsCheckbox, LM.GUI.ALIGN_LEFT, 0) end function MR_MoveTargetedJoint:UpdateWidgets(moho) MR_MoveTargetedJoint.hideBonesWhileMovingCheckbox:SetValue(self.hideBonesWhileMoving) MR_MoveTargetedJoint.leaveBonesSelectedCheckbox:SetValue(self.leaveBonesSelected) MR_MoveTargetedJoint.bakeAdjacentFramesCheckbox:SetValue(self.bakeAdjacentFrames) MR_MoveTargetedJoint.maintainProportionsCheckbox:SetValue(self.maintainProportions) end function MR_MoveTargetedJoint:HandleMessage(moho, view, msg) if msg == self.HIDE_BONES_WHILE_MOVING then self.hideBonesWhileMoving = self.hideBonesWhileMovingCheckbox:Value() elseif msg == self.LEAVE_BONES_SELECTED then self.leaveBonesSelected = self.leaveBonesSelectedCheckbox:Value() elseif msg == self.BAKE_ADJACENT_FRAMES then self.bakeAdjacentFrames = self.bakeAdjacentFramesCheckbox:Value() elseif msg == self.MAINTAIN_PROPORTIONS then self.maintainProportions = self.maintainProportionsCheckbox:Value() end end -- ************************************************** -- Localization -- ************************************************** function MR_MoveTargetedJoint:Localize(text) local phrase = {} phrase['Description'] = 'Precisely control knees and elbows when using target bones.' phrase['UILabel'] = 'Move Targeted Joint' phrase['Hide bones while moving'] = 'Hide bones while moving' phrase['Leave Bones Selected'] = 'Leave bones selected' phrase['Bake Adjacent Frames'] = 'Bake adjacent frames' phrase['Maintain Proportions'] = 'Maintain proportions' local fileWord = MOHO.Localize("/Menus/File/File=File") if fileWord == "Файл" then phrase['Description'] = 'Тонко контролируйте колени и локти перÑонажей подконтрольные целевым коÑÑ‚Ñм.' phrase['UILabel'] = 'Контроль целевого ÑуÑтава' phrase['Hide bones while moving'] = 'ПрÑтать коÑти при движении' phrase['Leave Bones Selected'] = 'ОÑтавить коÑти выделенными' phrase['Bake Adjacent Frames'] = 'Запечь ÑоÑедние кадры' phrase['Maintain Proportions'] = 'Соблюдать пропорции' end return phrase[text] end
Move Targeted Joint
Listed
Author: eugenebabich
View Script
Script type: Tool
Uploaded: Jan 08 2021, 09:07
Last modified: May 12 2021, 09:00
Script Version: 1.2
This tool allows you to easily fine-tune the elbows and knees of your character when target bones are in use.
To work correctly it requires a hierarchical pair of bones controlled by a target. The bones must not be flipped. The lower bone (the shin or the forearm) must not have any Y-axis translation.
This script is no longer supported, please download MR Pose Tool instead. https://mohoscripts.com/script/mr_pose_tool MR Pose Tool has the functionality of this tool and even more.
This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 2761
Move Targeted Joint
Listed
Author: eugenebabich
View Script
Script type: Tool
Uploaded: Jan 08 2021, 09:07
Last modified: May 12 2021, 09:00
Script Version: 1.2
This tool allows you to easily fine-tune the elbows and knees of your character when target bones are in use.
To work correctly it requires a hierarchical pair of bones controlled by a target. The bones must not be flipped. The lower bone (the shin or the forearm) must not have any Y-axis translation.
This script is no longer supported, please download MR Pose Tool instead. https://mohoscripts.com/script/mr_pose_tool MR Pose Tool has the functionality of this tool and even more.
This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 2761