-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "AE_SeamlessRotationSmartMaker" -- ************************************************** -- General information about this script -- ************************************************** AE_SeamlessRotationSmartMaker = {} function AE_SeamlessRotationSmartMaker:Name() return 'Seamlessly rotating smartbone on/off' end function AE_SeamlessRotationSmartMaker:Version() return '1.0' end function AE_SeamlessRotationSmartMaker:UILabel() return 'Seamlessly rotating smartbone on/off' end function AE_SeamlessRotationSmartMaker:Creator() return 'Alexandra Evseeva' end function AE_SeamlessRotationSmartMaker:Description() return 'Create or discard a bone system to make smartbone joints rotaing seamlessly' end -- ************************************************** -- Is Relevant / Is Enabled -- ************************************************** function AE_SeamlessRotationSmartMaker:IsRelevant(moho) return true end function AE_SeamlessRotationSmartMaker:IsEnabled(moho) return true end -- ************************************************** -- The guts of this script -- ************************************************** function AE_SeamlessRotationSmartMaker:ReparentPoints(moho, layer, sourceBone, targetBone) if moho:LayerAsGroup(layer) then local group = moho:LayerAsGroup(layer) for i=0, group:CountLayers()-1 do self:ReparentPoints(moho, group:Layer(i), sourceBone, targetBone) end elseif moho:LayerAsVector(layer) then local skel = moho:Skeleton() local sourceID = skel:BoneID(sourceBone) local targetID = skel:BoneID(targetBone) local mesh = moho:LayerAsVector(layer):Mesh() for p = 0, mesh:CountPoints()-1 do local point = mesh:Point(p) if point.fParent == sourceID then point.fParent = targetID end end end end function AE_SeamlessRotationSmartMaker:MoveAngleAnimation(moho, sourceBone, targetBone) --copy animation from source to target in any of sources's smart actions (removing previously existing in target) local actionNames = {sourceBone:Name(), (sourceBone:Name().." 2")} for i, actionName in pairs(actionNames) do if moho.layer:HasAction(actionName) then local oldSmartRotation = sourceBone.fAnimAngle:ActionByName(actionName) if not oldSmartRotation then return string.format("Something went wrong: %s is not animated in its own action %s", sourceBone:Name(), actionName) end oldSmartRotation = moho:ChannelAsAnimVal(oldSmartRotation) if not targetBone.fAnimAngle:ActionByName(actionName) then targetBone.fAnimAngle:ActivateAction(actionName) end local newSmartRotation = moho:ChannelAsAnimVal(targetBone.fAnimAngle:ActionByName(actionName)) newSmartRotation:Clear() for k=0, oldSmartRotation:CountKeys()-1 do newSmartRotation:SetValue(oldSmartRotation:GetKeyWhen(k), oldSmartRotation:GetValueByID(k)) local interp = MOHO.InterpSetting:new_local() oldSmartRotation:GetKeyInterpByID(k, interp) newSmartRotation:SetKeyInterp(oldSmartRotation:GetKeyWhen(k), interp) end oldSmartRotation:Clear() end end --rename actions for i, actionName in pairs(actionNames) do local newName = targetBone:Name() .. string.sub(actionName, #sourceBone:Name()+1) moho.layer:RenameAction(actionName, newName) end --rebind angle-dependent bones local skel = moho:Skeleton() local sourceID = skel:BoneID(sourceBone) local targetID = skel:BoneID(targetBone) for b=0, skel:CountBones()-1 do local nextBone = skel:Bone(b) if nextBone.fAngleControlParent == sourceID then nextBone.fAngleControlParent = targetID end end --[[ --if arm has points bind to it, lets rebind them self:ReparentPoints(moho, moho.layer, sourceBone, targetBone) --]] return nil end function AE_SeamlessRotationSmartMaker:CreateSeamlessSystem(moho, armBone) local skel = moho:Skeleton() local baseName = armBone:Name() armBone.fConstraints = false --find or create target bone local targetName = baseName .. "_smartTarget" local targetBone = skel:BoneByName(targetName) if not targetBone then targetBone = skel:AddBone(0) targetBone:SetName(targetName) targetBone.fAnimParent:SetValue(0, skel:BoneID(armBone)) local tipVector = LM.Vector2:new_local() tipVector:Set(armBone.fLength, 0) targetBone.fAnimPos:SetValue(0, tipVector) targetBone.fLength = 0.0001 targetBone.fShy = true targetBone.fHidden = true end --find or create joint bone local jointName = baseName .. "_smartElbow" local jointBone = skel:BoneByName(jointName) if not jointBone then jointBone = skel:AddBone(0) jointBone:SetName(jointName) jointBone.fAnimParent:SetValue(0, armBone.fAnimParent:GetValue(0)) jointBone.fAnimPos:SetValue(0, armBone.fAnimPos:GetValue(0)) jointBone.fAnimAngle:SetValue(0, 0) jointBone.fLength = 0 jointBone.fPosControlParent = skel:BoneID(armBone) jointBone.fMaxConstraint = 0 jointBone.fMinConstraint = 0 jointBone.fShy = true jointBone.fHidden = true end --find or create smartBone local smartName = baseName .. "_smart" local smartBone = skel:BoneByName(smartName) if not smartBone then smartBone = skel:AddBone(0) smartBone:SetName(smartName) smartBone.fAnimParent:SetValue(0, skel:BoneID(jointBone)) --[[]] --if no points to rebind smartBone.fLength = 0.0001 -- --[[ --if arm has points bind to it, lets rebind them smartBone.fLength = armBone.fLength smartBone.fMaxAutoScaling = 1000 smartBone.fSquashStretchScaling = armBone.fSquashStretchScaling --]] local zeroVector = LM.Vector2:new_local() smartBone.fAnimPos:SetValue(0, zeroVector) smartBone.fAnimAngle:SetValue(0, armBone.fAnimAngle:GetValue(0)) smartBone.fTargetBone:SetValue(0, skel:BoneID(targetBone)) smartBone.fShy = true smartBone.fHidden = true end --create smartBone animation for any of arm's smart actions (removing previously existing) return self:MoveAngleAnimation(moho, armBone, smartBone) end function AE_SeamlessRotationSmartMaker:DiscardSeamlessSystem(moho, armBone, smartBone) local skel = moho:Skeleton() local baseName = armBone:Name() local smartName = baseName .. "_smart" --if smartBone provided, test if this is the bone user wanted. Then rename it and all its friends. if smartBone then local userReturn = LM.GUI.Alert(LM.GUI.ALERT_INFO, "There are no "..smartName.." bone in skeleton. But "..smartBone:Name().." seems to be the fake smartBone to turn off. It will be renamed.", "", "", "OK", "Cancel") if userReturn > 0 then return end --find joint and target bones and rename them first local targetBone = skel:Bone(smartBone.fTargetBone:GetValue(0)) if targetBone then targetBone:SetName(baseName .. "_smartTarget") else return LM.GUI.Alert(LM.GUI.ALERT_WARNING, smartBone:Name().." has no target. Aborting.") end local jointBone = skel:Bone(smartBone.fAnimParent:GetValue(0)) if jointBone then jointBone:SetName(baseName .. "_smartElbow") end else smartBone = skel:BoneByName(smartName) end --create animation for armBone in smartBone actions local errorText = self:MoveAngleAnimation(moho, smartBone, armBone) if not errorText then smartBone:SetName(smartName) else return LM.GUI.Alert(LM.GUI.ALERT_WARNING, errorText) end end function AE_SeamlessRotationSmartMaker:Run(moho) moho.document:SetDirty() moho.document:PrepUndo(nil) --test if selected bone has smart actions and call create or discard the system respecively local skel = moho:Skeleton() if not skel then return LM.GUI.Alert(LM.GUI.ALERT_WARNING, "Please select a bone layer") end local selBone = skel:Bone(skel:SelectedBoneID()) if not selBone then return LM.GUI.Alert(LM.GUI.ALERT_WARNING, "Please select any bone") end local selName = selBone:Name() if moho.layer:HasAction(selName) then return self:CreateSeamlessSystem(moho, selBone) end local smartName = selName .. "_smart" if moho.layer:HasAction(smartName) then return self:DiscardSeamlessSystem(moho, selBone) end if skel:BoneByName(smartName) then return LM.GUI.Alert(LM.GUI.ALERT_WARNING, string.format("Something went wrong: You have %s bone, but no action for it", smartName)) end local armParentID = selBone.fAnimParent:GetValue(moho.frame) for b=0, skel:CountBones()-1 do if b ~= skel:SelectedBoneID() and skel:Bone(b).fAnimParent:GetValue(moho.frame) == armParentID then for bb =0, skel:CountBones()-1 do if skel:Bone(bb).fAnimParent:GetValue(moho.frame) == b then local targetID = skel:Bone(bb).fTargetBone:GetValue(moho.frame) if targetID >= 0 and skel:Bone(targetID).fAnimParent:GetValue(moho.frame) == skel:SelectedBoneID() then local smartBone = skel:Bone(bb) if moho.layer:HasAction(smartBone:Name()) then return self:DiscardSeamlessSystem(moho, selBone, smartBone) end end end end end local targetID = skel:Bone(b).fTargetBone:GetValue(moho.frame) if targetID >= 0 and skel:Bone(targetID).fAnimParent:GetValue(moho.frame) == skel:SelectedBoneID() then local smartBone = skel:Bone(b) if moho.layer:HasAction(smartBone:Name()) then return self:DiscardSeamlessSystem(moho, selBone, smartBone) end end end return LM.GUI.Alert(LM.GUI.ALERT_WARNING, "Something went wrong: did not find any action related to selected bone, neither seamless, nor common") end
Seamless rotation maker
Listed
Author: A.Evseeva
View Script
Script type: Button/Menu
Uploaded: Aug 26 2022, 07:35
Script Version: 1.0
Create bone system to seamlessly rotate bone 360+ with correct use of smartbone actions associated with it.
Select bone whish have to rotate 360+ (forearm with elbow smart actions, for example) and use the script.
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: 1163
Seamless rotation maker
Listed
Author: A.Evseeva
View Script
Script type: Button/Menu
Uploaded: Aug 26 2022, 07:35
Script Version: 1.0
Create bone system to seamlessly rotate bone 360+ with correct use of smartbone actions associated with it.
Select bone whish have to rotate 360+ (forearm with elbow smart actions, for example) and use the script.
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: 1163