-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "AM_Create_Limb" -- ************************************************** -- General information about this script -- ************************************************** AM_Create_Limb = {} function AM_Create_Limb:Name() return 'Create Limb' end function AM_Create_Limb:Version() return '1.0' end function AM_Create_Limb:UILabel() return 'Create Limb' end function AM_Create_Limb:Creator() return 'Aleksei Maletin' end function AM_Create_Limb:Description() return 'Hold <Alt> and drag side to side to adjust radius of joints' end -- ************************************************** -- Is Relevant / Is Enabled -- ************************************************** function AM_Create_Limb:IsRelevant(moho) if moho:Skeleton() then return true else return false end end function AM_Create_Limb:IsEnabled(moho) if moho:Skeleton() then return true else return false end end -- ************************************************** -- Recurring Values -- ************************************************** AM_Create_Limb.radius = 0.05 AM_Create_Limb.enableArrows = true AM_Create_Limb.savedVal = 0 AM_Create_Limb.createDeformer = false AM_Create_Limb.bodyPartName = 'Forearm L' AM_Create_Limb.stroke = false AM_Create_Limb.fill = false AM_Create_Limb.selRect = LM.Rect:new_local() AM_Create_Limb.startJoint = true AM_Create_Limb.endJoint = true AM_Create_Limb.startJointTest = true -- ************************************************** -- Prefs -- ************************************************** function AM_Create_Limb:LoadPrefs(prefs) self.radius = prefs:GetFloat("AM_Create_Limb.radius", 0) self.bodypartName = prefs:GetString("AM_Create_Limb.bodypartName", 'Forearm L') self.stroke = prefs:GetBool("AM_Create_Limb.stroke", false) self.fill = prefs:GetBool("AM_Create_Limb.fill", false) self.startJoint = prefs:GetBool("AM_Create_Limb.startJoint", true) self.endJoint = prefs:GetBool("AM_Create_Limb.endJoint", true) end function AM_Create_Limb:SavePrefs(prefs) prefs:SetFloat("AM_Create_Limb.radius", self.radius) prefs:SetString("AM_Create_Limb.bodypartName", self.bodypartName) prefs:SetBool("AM_Create_Limb.stroke", self.stroke) prefs:SetBool("AM_Create_Limb.fill", self.fill) prefs:SetBool("AM_Create_Limb.startJoint", self.startJoint) prefs:SetBool("AM_Create_Limb.endJoint", self.endJoint) end function AM_Create_Limb:ResetPrefs() self.radius = 0 self.bodypartName = 'Forearm L' self.stroke = false self.fill = false self.startJoint = true self.endJoint = true end -- ************************************************** -- Keyboard/Mouse Control -- ************************************************** function AM_Create_Limb:Select(moho, mousePt, mouseVec, mouseView, shiftSelect, ctrlSelect, altSelect) self.selBoneID = -1 local parentSkeleton = false local skel = moho:Skeleton() if (skel == nil) then if (self:ShouldUseParentSkeleton(moho)) then skel = moho:ParentSkeleton() parentSkeleton = true end if (skel == nil) then return end end local id = -1 if (parentSkeleton) then id = mouseView:PickBone(mousePt, mouseVec, moho.layer:ControllingBoneLayer(), true) else id = mouseView:PickBone(mousePt, mouseVec, moho.layer, true) end self.selBoneID = id if (shiftSelect) then if (id >= 0) then skel:Bone(id).fSelected = true end elseif (ctrlSelect) then if (id >= 0) then skel:Bone(id).fSelected = not skel:Bone(id).fSelected end elseif (altSelect) then else for i = 0, skel:CountBones() - 1 do skel:Bone(i).fSelected = (i == id) end end moho:UpdateBonePointSelection() mouseView:DrawMe() moho:UpdateSelectedChannels() end function AM_Create_Limb:OnMouseDown(moho, mouseEvent) if not (mouseEvent.altKey) then self.isMouseDragging = true end self.selRect.left = mouseEvent.startPt.x self.selRect.top = mouseEvent.startPt.y self.selRect.right = mouseEvent.pt.x self.selRect.bottom = mouseEvent.pt.y mouseEvent.view:Graphics():SelectionRect(self.selRect) mouseEvent.view:DrawMe() self.savedVal = 0 self:Select(moho, mouseEvent.pt, mouseEvent.vec, mouseEvent.view, mouseEvent.shiftKey, mouseEvent.ctrlKey, mouseEvent.altKey) end function AM_Create_Limb:OnMouseMoved(moho, mouseEvent) local skel = moho:Skeleton() if (mouseEvent.altKey) then if (skel == nil) then return end local newVal = 1 * (mouseEvent.pt.x - mouseEvent.startPt.x) / mouseEvent.view:Graphics():Width() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if (bone.fSelected) then self.radius = self.radius - self.savedVal + newVal if (self.radius < 0) then self.radius = 0 end end end self.savedVal = newVal else mouseEvent.view:Graphics():SelectionRect(self.selRect) self.selRect.right = mouseEvent.pt.x self.selRect.bottom = mouseEvent.pt.y mouseEvent.view:Graphics():SelectionRect(self.selRect) mouseEvent.view:RefreshView() end mouseEvent.view:DrawMe() end function AM_Create_Limb:OnMouseUp(moho, mouseEvent) local skel = moho:Skeleton() local mouseDist = math.abs(mouseEvent.pt.x - mouseEvent.startPt.x) + math.abs(mouseEvent.pt.y - mouseEvent.startPt.y) self.isMouseDragging = false local v = LM.Vector2:new_local() local screenPt = LM.Point:new_local() local m = LM.Matrix:new_local() self.selRect:Normalize() moho.drawingLayer:GetFullTransform(moho.frame, m, moho.document) if skel then for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) local boneMatrix = bone.fMovedMatrix for j = 0, 10 do v:Set(bone.fLength * j / 10.0, 0) boneMatrix:Transform(v) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, screenPt) if (self.selRect:Contains(screenPt)) then if mouseEvent.ctrlKey then bone.fSelected = not bone.fSelected else bone.fSelected = true end break end end end end moho:UpdateSelectedChannels() end function AM_Create_Limb:GetGlobalBonePos(moho, bone) local skel = moho:Skeleton() local selBonePos = LM.Vector2:new_local() selBonePos:Set(bone.fAnimPos:GetValue(0)) if bone.fParent >-1 then local selBoneParentMatrix = LM.Matrix:new_local() selBoneParentMatrix:Set(skel:Bone(bone.fParent).fRestMatrix) selBoneParentMatrix:Transform(selBonePos) end return selBonePos end function AM_Create_Limb:GetGlobalAngle(moho, v1, v2) v2 = v2 - v1 newAngle = math.atan2(v2.y, v2.x) return newAngle end function AM_Create_Limb:DrawBothJoints(moho, srcVec1, srcVec2, srcMesh) local circleVec = LM.Vector2:new_local() circleVec.x = srcVec1.x - self.radius circleVec.y = srcVec1.y srcMesh:AddLonePoint(circleVec, 0) circleVec.x = srcVec1.x circleVec.y = srcVec1.y - self.radius srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec1.x + self.radius circleVec.y = srcVec1.y srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec1.x circleVec.y = srcVec1.y + self.radius srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec1.x - self.radius circleVec.y = srcVec1.y srcMesh:AppendPoint(circleVec, 0) srcMesh:WeldPoints(4, 0, 0) circleVec.x = srcVec2.x - self.radius circleVec.y = srcVec2.y srcMesh:AddLonePoint(circleVec, 0) circleVec.x = srcVec2.x circleVec.y = srcVec2.y - self.radius srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec2.x + self.radius circleVec.y = srcVec2.y srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec2.x circleVec.y = srcVec2.y + self.radius srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec2.x - self.radius circleVec.y = srcVec2.y srcMesh:AppendPoint(circleVec, 0) srcMesh:WeldPoints(8, 4, 0) for i = 0, srcMesh:CountPoints()-1 do srcMesh:Point(i):SetCurvature(0.391379, 0) end srcMesh:DeselectPoints() end function AM_Create_Limb:DrawStartJoint(moho, srcVec1, srcMesh) local circleVec = LM.Vector2:new_local() circleVec.x = srcVec1.x - self.radius circleVec.y = srcVec1.y srcMesh:AddLonePoint(circleVec, 0) circleVec.x = srcVec1.x circleVec.y = srcVec1.y - self.radius srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec1.x + self.radius circleVec.y = srcVec1.y srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec1.x circleVec.y = srcVec1.y + self.radius srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec1.x - self.radius circleVec.y = srcVec1.y srcMesh:AppendPoint(circleVec, 0) srcMesh:WeldPoints(4, 0, 0) for i = 0, srcMesh:CountPoints()-1 do srcMesh:Point(i):SetCurvature(0.391379, 0) end srcMesh:DeselectPoints() end function AM_Create_Limb:DrawEndJoint(moho, srcVec2, srcMesh) local circleVec = LM.Vector2:new_local() circleVec.x = srcVec2.x - self.radius circleVec.y = srcVec2.y srcMesh:AddLonePoint(circleVec, 0) circleVec.x = srcVec2.x circleVec.y = srcVec2.y - self.radius srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec2.x + self.radius circleVec.y = srcVec2.y srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec2.x circleVec.y = srcVec2.y + self.radius srcMesh:AppendPoint(circleVec, 0) circleVec.x = srcVec2.x - self.radius circleVec.y = srcVec2.y srcMesh:AppendPoint(circleVec, 0) srcMesh:WeldPoints(4, 0, 0) for i = 0, srcMesh:CountPoints()-1 do srcMesh:Point(i):SetCurvature(0.391379, 0) end srcMesh:DeselectPoints() end function AM_Create_Limb:DrawMe(moho, view) local skel = moho:Skeleton() if skel then local g = view:Graphics() local matrix = LM.Matrix:new_local() local bonePt = LM.Vector2:new_local() local bonePt2 = LM.Vector2:new_local() moho.layer:GetFullTransform(moho.frame, matrix, moho.document) g:Push() g:ApplyMatrix(matrix) g:SetColor(50, 255, 50, 50) g:SetSmoothing(true) for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if bone.fSelected then local parentBone = skel:Bone(bone.fAngleControlParent) bonePt:Set(bone.fLength, 0) bone.fMovedMatrix:Transform(bonePt) bonePt2:Set(0, 0) bone.fMovedMatrix:Transform(bonePt2) g:FrameCircle(bonePt, self.radius) g:FrameCircle(bonePt2, self.radius) g:FillCircle(bonePt, self.radius) g:FillCircle(bonePt2, self.radius) end end if self.isMouseDragging then local g = view:Graphics() g:SelectionRect(self.selRect) end g:Pop() end end -- ************************************************** -- Tool Panel Layout -- ************************************************** AM_Create_Limb.CREATE_LIMB = MOHO.MSG_BASE AM_Create_Limb.RADIUS = MOHO.MSG_BASE + 1 AM_Create_Limb.BODYPART_NAME = MOHO.MSG_BASE + 2 AM_Create_Limb.STROKE = MOHO.MSG_BASE + 3 AM_Create_Limb.FILL = MOHO.MSG_BASE + 4 AM_Create_Limb.READ_RADIUS_FROM_BONE = MOHO.MSG_BASE + 5 AM_Create_Limb.START_JOINT = MOHO.MSG_BASE + 6 AM_Create_Limb.END_JOINT = MOHO.MSG_BASE + 7 function AM_Create_Limb:DoLayout(moho, layout) self.createLimbButton = LM.GUI.Button('Create Limb', self.CREATE_LIMB) layout:AddChild(self.createLimbButton, LM.GUI.ALIGN_LEFT, 0) self.radiusInput = LM.GUI.TextControl(0, ' ', self.RADIUS, LM.GUI.FIELD_FLOAT, 'Radius') self.radiusInput:SetWheelInc(0.001) layout:AddChild(self.radiusInput, LM.GUI.ALIGN_LEFT, 0) self.bodyPartNameInput = LM.GUI.TextControl(0, 'Forearm L', self.BODYPART_NAME, LM.GUI.FIELD_TEXT, 'Bodypart Name:') layout:AddChild(self.bodyPartNameInput, LM.GUI.ALIGN_LEFT, 0) self.strokeCheckbox = LM.GUI.CheckBox('Stroke', self.STROKE) layout:AddChild(self.strokeCheckbox, LM.GUI.ALIGN_LEFT, 0) self.fillCheckbox = LM.GUI.CheckBox('Fill', self.FILL) layout:AddChild(self.fillCheckbox, LM.GUI.ALIGN_LEFT, 0) self.readRadiusFromBoneButton = LM.GUI.Button('Read radius', self.READ_RADIUS_FROM_BONE) layout:AddChild(self.readRadiusFromBoneButton, LM.GUI.ALIGN_LEFT, 0) self.readRadiusFromBoneButton:SetToolTip('Radius = Length of selected bone') self.startJointCheckbox = LM.GUI.CheckBox('Start joint', self.START_JOINT) layout:AddChild(self.startJointCheckbox, LM.GUI.ALIGN_LEFT, 0) self.endJointCheckbox = LM.GUI.CheckBox('End joint', self.END_JOINT) layout:AddChild(self.endJointCheckbox, LM.GUI.ALIGN_LEFT, 0) end function AM_Create_Limb:UpdateWidgets(moho) AM_Create_Limb.radiusInput:SetValue(self.radius) AM_Create_Limb.bodyPartNameInput:SetValue(self.bodyPartName) AM_Create_Limb.strokeCheckbox:SetValue(self.stroke) AM_Create_Limb.fillCheckbox:SetValue(self.fill) AM_Create_Limb.startJointCheckbox:SetValue(self.startJoint) AM_Create_Limb.endJointCheckbox:SetValue(self.endJoint) end function AM_Create_Limb:HandleMessage(moho, view, msg) if msg == self.RADIUS then self.radius = self.radiusInput:Value() elseif msg == self.CREATE_LIMB then if (curFrame ~= frame0) then moho:SetCurFrame(frame0) end moho.document:SetDirty() moho.document:PrepUndo(nil) local boneLayer = moho:LayerAsBone(moho.layer) local skel = moho:Skeleton() for iBone = 0, skel:CountBones()-1 do local bone = skel:Bone(iBone) if (bone.fSelected) then local boneparent = skel:Bone(bone.fAnimParent:GetValue()) if boneparent and boneparent.fSelected then self.startJointTest = false else self.startJointTest = true end local boneLength = bone.fLength bone.fStrength = 0 local boneStart = skel:AddBone(0) boneStart.fParent = iBone boneStart.fAnimParent:SetValue(0, iBone) boneStart.fAnimAngle:SetValue(0, math.rad(0)) boneStart.fIgnoredByIK = true boneStart:SetName(self.bodyPartName .. " start") boneStart.fShy = true boneStart.fLength = self.radius boneStart.fStrength = 0 local boneStartGlobalPose = self:GetGlobalBonePos(moho, boneStart) local boneLengthPos = LM.Vector2:new_local() local boneStartParentID = skel:BoneID(boneStart) boneLengthPos.x = boneStartGlobalPose.x + boneLength boneLengthPos.y = boneStartGlobalPose.y local boneEnd = skel:AddBone(0) local boneEndPos = LM.Vector2:new_local() boneEndPos:Set(boneLength, 0) boneEnd.fParent = iBone boneEnd.fAnimParent:SetValue(0, iBone) boneEnd.fAnimAngle:SetValue(0, math.rad(180)) boneEnd.fIgnoredByIK = true boneEnd:SetName(self.bodyPartName .. " end") boneEnd.fShy = true boneEnd.fAnimPos:SetValue(0, boneEndPos) boneEnd.fLength = self.radius boneEnd.fStrength = 0 local boneEndGlobalPose = self:GetGlobalBonePos(moho, boneEnd) local boneEndParentID = skel:BoneID(boneEnd) local boneGlobalAngle = self:GetGlobalAngle(moho, boneStartGlobalPose, boneEndGlobalPose) local bodypartGroup = moho:CreateNewLayer(MOHO.LT_GROUP, false) bodypartGroup:SetName(self.bodyPartName) bodypartGroup.fRotationZ:SetValue(0, boneGlobalAngle) bodypartGroup:SetOrigin(boneStartGlobalPose) moho:PlaceLayerInGroup(bodypartGroup, boneLayer, true, false) local jointsLayer = moho:LayerAsVector(moho:CreateNewLayer(MOHO.LT_VECTOR, false)) if self.stroke then jointsLayer:ShowConstructionCurves(false) elseif self.fill then jointsLayer:ShowConstructionCurves(false) else jointsLayer:ShowConstructionCurves(true) end jointsLayer:SetName(self.bodyPartName .. " joints") moho:PlaceLayerInGroup(jointsLayer, bodypartGroup, true, false) local jointsMesh = jointsLayer:Mesh() if self.startJoint and self.endJoint and self.startJointTest then self:DrawBothJoints(moho, boneStartGlobalPose, boneLengthPos, jointsMesh) jointsMesh:Point(0).fParent = boneStartParentID jointsMesh:Point(1).fParent = boneStartParentID jointsMesh:Point(2).fParent = boneStartParentID jointsMesh:Point(3).fParent = boneStartParentID jointsMesh:Point(4).fParent = boneEndParentID jointsMesh:Point(5).fParent = boneEndParentID jointsMesh:Point(6).fParent = boneEndParentID jointsMesh:Point(7).fParent = boneEndParentID elseif self.startJointTest and self.startJoint then self:DrawStartJoint(moho, boneStartGlobalPose, jointsMesh) jointsMesh:Point(0).fParent = boneStartParentID jointsMesh:Point(1).fParent = boneStartParentID jointsMesh:Point(2).fParent = boneStartParentID jointsMesh:Point(3).fParent = boneStartParentID elseif self.endJoint then self:DrawEndJoint(moho, boneLengthPos, jointsMesh) jointsMesh:Point(0).fParent = boneEndParentID jointsMesh:Point(1).fParent = boneEndParentID jointsMesh:Point(2).fParent = boneEndParentID jointsMesh:Point(3).fParent = boneEndParentID elseif self.startJoint and self.endJoint and not self.startJointTest then self:DrawEndJoint(moho, boneLengthPos, jointsMesh) jointsMesh:Point(0).fParent = boneEndParentID jointsMesh:Point(1).fParent = boneEndParentID jointsMesh:Point(2).fParent = boneEndParentID jointsMesh:Point(3).fParent = boneEndParentID else end if self.startJoint and not self.endJoint and not self.startJointTest then else jointsMesh:SelectAll() if moho:CountSelectedPoints() > 0 then local jointsShapeID = moho:CreateShape(true) local jointsShape = jointsMesh:Shape(jointsShapeID) jointsShape.fHasFill = self.fill jointsShape.fHasOutline = self.stroke end end moho:SetSelLayer(boneLayer, false, true) local bodypartLayer = moho:LayerAsVector(moho:CreateNewLayer(MOHO.LT_VECTOR, false)) if self.stroke then bodypartLayer:ShowConstructionCurves(false) elseif self.fill then bodypartLayer:ShowConstructionCurves(false) else bodypartLayer:ShowConstructionCurves(true) end bodypartLayer:SetName(self.bodyPartName) moho:PlaceLayerInGroup(bodypartLayer, bodypartGroup, true, false) local bodypartMesh = bodypartLayer:Mesh() local rectStart = LM.Vector2:new_local() rectStart.x = boneStartGlobalPose.x rectStart.y = boneStartGlobalPose.y + self.radius bodypartMesh:AddLonePoint(rectStart, 0) rectStart.x = boneStartGlobalPose.x + boneLength bodypartMesh:AppendPoint(rectStart, 0) rectStart.y = boneStartGlobalPose.y - self.radius bodypartMesh:AppendPoint(rectStart, 0) rectStart.x = boneStartGlobalPose.x bodypartMesh:AppendPoint(rectStart, 0) rectStart.y = boneStartGlobalPose.y + self.radius bodypartMesh:AppendPoint(rectStart, 0) bodypartMesh:WeldPoints(4, 0, 0) bodypartMesh:Point(0).fParent = boneStartParentID bodypartMesh:Point(3).fParent = boneStartParentID bodypartMesh:Point(1).fParent = boneEndParentID bodypartMesh:Point(2).fParent = boneEndParentID for i = 0, bodypartMesh:CountPoints()-1 do bodypartMesh:Point(i):SetCurvature(0, 0) end bodypartMesh:SelectNone() bodypartMesh:Point(0).fSelected = true bodypartMesh:Point(1).fSelected = true bodypartMesh:Point(2).fSelected = true bodypartMesh:Point(3).fSelected = true local bodypartCurve = bodypartMesh:Curve() if self.endJoint then bodypartCurve:SetSegmentOn(1, false) end bodypartCurve:SetSegmentOn(3, false) local limbShapeID = moho:CreateShape(true) local limbShape = bodypartMesh:Shape(limbShapeID) limbShape.fHasFill = self.fill limbShape.fHasOutline = self.stroke moho:SetSelLayer(boneLayer, false, true) end moho:UpdateUI() moho.layer:UpdateCurFrame() end elseif msg == self.BODYPART_NAME then self.bodyPartName = self.bodyPartNameInput:Value() elseif msg == self.STROKE then self.stroke = self.strokeCheckbox:Value() elseif msg == self.FILL then self.fill = self.fillCheckbox:Value() elseif msg == self.READ_RADIUS_FROM_BONE then local skel = moho:Skeleton() for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if bone.fSelected then self.radius = bone.fLength break end end self:UpdateWidgets(moho) elseif msg == self.START_JOINT then self.startJoint = self.startJointCheckbox:Value() elseif msg == self.END_JOINT then self.endJoint = self.endJointCheckbox:Value() else end end
Create Limb
Listed
Author: Danfield
View Script
Script type: Tool
Uploaded: Jan 24 2022, 11:14
Script Version: 1.0
Simple tool for rigging arms/legs
Note: The newer, better version is available here
Hold Alt and drag side to side to adjust radius of joints
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: 2245
Create Limb
Listed
Author: Danfield
View Script
Script type: Tool
Uploaded: Jan 24 2022, 11:14
Script Version: 1.0
Simple tool for rigging arms/legs
Note: The newer, better version is available here
Hold Alt and drag side to side to adjust radius of joints
Hold Alt and drag side to side to adjust radius of joints
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: 2245