Image
-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************

ScriptName = "AM_Bone_Constraints_Helper"

-- **************************************************
-- General information about this script
-- **************************************************

AM_Bone_Constraints_Helper = {}

function AM_Bone_Constraints_Helper:Name()
	return self:Localize('UILabel')
end

function AM_Bone_Constraints_Helper:Version()
	return '1.0'
end

function AM_Bone_Constraints_Helper:UILabel()
	return self:Localize('UILabel')
end

function AM_Bone_Constraints_Helper:Creator()
	return 'Aleksei Maletin'
end

function AM_Bone_Constraints_Helper:Description()
	return MOHO.Localize("/Scripts/Tool/Autorig/Description=Click to select a new bone (hold <shift> to select a angle control bone , <alt> to select a position control bone , <ctrl/cmd> to select a scale control bone ). Angle = GREEN arrow , Scale = RED arrow , Position = BLUE arrow")
end

function AM_Bone_Constraints_Helper:ColorizeIcon()
	return false
end

-- **************************************************
-- Is Relevant / Is Enabled
-- **************************************************
function AM_Bone_Constraints_Helper:ShouldUseParentSkeleton(moho)
	if (not moho.layer:IsBoneType()) then
		return true
	end
	return false
end

function AM_Bone_Constraints_Helper:IsRelevant(moho)
	local skel = moho:Skeleton()
	if skel then
		return true
	else
		return false
	end
end

function AM_Bone_Constraints_Helper:IsEnabled(moho)
	local skel = moho:Skeleton()
	if skel then
		return true
	else
		return false
	end
end

-- **************************************************
-- Recurring Values
-- **************************************************

AM_Bone_Constraints_Helper.bonename = ''
AM_Bone_Constraints_Helper.angleControl = 0
AM_Bone_Constraints_Helper.posControlX = 0
AM_Bone_Constraints_Helper.posControlY = 0
AM_Bone_Constraints_Helper.scaleControl = 0
AM_Bone_Constraints_Helper.enableArrows = true
AM_Bone_Constraints_Helper.selRect = LM.Rect:new_local()
AM_Bone_Constraints_Helper.selBoneID = -1

-- **************************************************
-- Keyboard/Mouse Control
-- **************************************************

function AM_Bone_Constraints_Helper: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

	elseif (ctrlSelect) then

	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_Bone_Constraints_Helper:OnMouseDown(moho, mouseEvent)
	local skel = moho:Skeleton()
	local parentID = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, true)


	self.isMouseDragging = true

	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()


	-- Try to select a bone by clicking on it
	self:Select(moho, mouseEvent.pt, mouseEvent.vec, mouseEvent.view, mouseEvent.shiftKey, mouseEvent.ctrlKey, mouseEvent.altKey)

	if (mouseEvent.ctrlKey) then
		moho.document:SetDirty()
		moho.document:PrepUndo(nil)
		self.controlKeyPressed = true
		for i = 0, skel:CountBones() - 1 do
			local bone = skel:Bone(i)

			if (bone.fSelected and i ~= parentID and parentID ~= bone.fScaleControlParent) then
				bone.fScaleControlParent = parentID
			end
		end
		moho.layer:UpdateCurFrame()
	end
	if (mouseEvent.altKey) then
		moho.document:SetDirty()
		moho.document:PrepUndo(nil)
		for i = 0, skel:CountBones() - 1 do
			local bone = skel:Bone(i)

			if (bone.fSelected and i ~= parentID and parentID ~= bone.fPosControlParent) then
				bone.fPosControlParent = parentID
			end

		end
		moho.layer:UpdateCurFrame()
	end
	if (mouseEvent.shiftKey) then
		moho.document:SetDirty()
		moho.document:PrepUndo(nil)
		for i = 0, skel:CountBones() - 1 do
			local bone = skel:Bone(i)

			if (bone.fSelected and i ~= parentID and parentID ~= bone.fAngleControlParent) then
				bone.fAngleControlParent = parentID
			end
			
		end
		moho.layer:UpdateCurFrame()
	end
end


function AM_Bone_Constraints_Helper:OnMouseMoved(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	local skel = moho:Skeleton()
	
	if moho.layer:LayerType() == MOHO.LT_VECTOR then	
		if (mesh == nil) then
			return
		end
	else 
		if (skel == nil) then
			return
		end
	end

	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()
	mouseEvent.view:DrawMe()
end



function AM_Bone_Constraints_Helper:OnMouseUp(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	local skel = moho:Skeleton()
	
	if moho.layer:LayerType() == MOHO.LT_VECTOR then	
		if (mesh == nil) then
			return
		end
	else 
		if (skel == nil) then
			return
		end
	end

	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
					
						bone.fSelected = true
						--self:Select(moho, mouseEvent.pt, mouseEvent.vec, mouseEvent.view, mouseEvent.shiftKey, mouseEvent.ctrlKey, mouseEvent.altKey)
					break
				end
			end
		end
	end

	moho:UpdateSelectedChannels()
end

function AM_Bone_Constraints_Helper:OnKeyDown(moho, keyEvent)
	
end

function AM_Bone_Constraints_Helper:OnKeyUp(moho, keyEvent)
	
end

function AM_Bone_Constraints_Helper:DrawAngleControlArrows(moho, view)
	if self.enableArrows then
		local skel = moho:Skeleton()
	if (skel == nil) then
		return
	end

	local g = view:Graphics()
	local matrix = LM.Matrix:new_local()
	local bonePt = LM.Vector2:new_local()
	local parentPt = LM.Vector2:new_local()
	local arrowPt1 = LM.Vector2:new_local()
	local arrowPt2 = LM.Vector2:new_local()

	moho.layer:GetFullTransform(moho.frame, matrix, moho.document)
	g:Push()
	g:ApplyMatrix(matrix)

	g:SetSmoothing(true)
	for i = 0, skel:CountBones() - 1 do
		local bone = skel:Bone(i)
		if (bone.fAngleControlParent >= 0) then
			local parentBone = skel:Bone(bone.fAngleControlParent)

			bonePt:Set(bone.fLength / 2, 0)
			bone.fMovedMatrix:Transform(bonePt)

			parentPt:Set(parentBone.fLength / 2, 0)
			parentBone.fMovedMatrix:Transform(parentPt)

			local v = parentPt - bonePt
			local mag = v:Mag()
			local f = mag
			if (f > 0.2) then
				f = 0.2
			end
			arrowPt1:Set(mag - f / 4, -f / 16)
			arrowPt2:Set(mag - f / 4, f / 16)
			f = math.atan2(v.y, v.x)
			arrowPt1:Rotate(f)
			arrowPt2:Rotate(f)
			arrowPt1.x = arrowPt1.x + bonePt.x
			arrowPt1.y = arrowPt1.y + bonePt.y
			arrowPt2.x = arrowPt2.x + bonePt.x
			arrowPt2.y = arrowPt2.y + bonePt.y

			if (bone.fSelected) then
				g:SetColor(0, 255, 0, 255)
			else
				g:SetColor(50, 200, 50, 255)
			end
			g:DrawLine(bonePt.x, bonePt.y, parentPt.x, parentPt.y)
			g:BeginShape()
			g:AddLine(parentPt, arrowPt1)
			g:AddLine(arrowPt1, arrowPt2)
			g:AddLine(arrowPt2, parentPt)
			g:EndShape()
		end
	end

	g:Pop()
	end
end

function AM_Bone_Constraints_Helper:DrawPosControlArrows(moho, view)
	if self.enableArrows then
		local skel = moho:Skeleton()
	if (skel == nil) then
		return
	end

	local g = view:Graphics()
	local matrix = LM.Matrix:new_local()
	local bonePt = LM.Vector2:new_local()
	local parentPt = LM.Vector2:new_local()
	local arrowPt1 = LM.Vector2:new_local()
	local arrowPt2 = LM.Vector2:new_local()

	moho.layer:GetFullTransform(moho.frame, matrix, moho.document)
	g:Push()
	g:ApplyMatrix(matrix)

	g:SetSmoothing(true)
	for i = 0, skel:CountBones() - 1 do
		local bone = skel:Bone(i)
		if (bone.fPosControlParent >= 0) then
			local parentBone = skel:Bone(bone.fPosControlParent)

			bonePt:Set(bone.fLength / 2, 0)
			bone.fMovedMatrix:Transform(bonePt)

			parentPt:Set(parentBone.fLength / 2, 0)
			parentBone.fMovedMatrix:Transform(parentPt)

			local v = parentPt - bonePt
			local mag = v:Mag()
			local f = mag
			if (f > 0.2) then
				f = 0.2
			end
			arrowPt1:Set(mag - f / 4, -f / 16)
			arrowPt2:Set(mag - f / 4, f / 16)
			f = math.atan2(v.y, v.x)
			arrowPt1:Rotate(f)
			arrowPt2:Rotate(f)
			arrowPt1.x = arrowPt1.x + bonePt.x
			arrowPt1.y = arrowPt1.y + bonePt.y
			arrowPt2.x = arrowPt2.x + bonePt.x
			arrowPt2.y = arrowPt2.y + bonePt.y

			if (bone.fSelected) then
				g:SetColor(0, 0, 255, 255)
			else
				g:SetColor(50, 50, 200, 255)
			end
			g:DrawLine(bonePt.x, bonePt.y, parentPt.x, parentPt.y)
			g:BeginShape()
			g:AddLine(parentPt, arrowPt1)
			g:AddLine(arrowPt1, arrowPt2)
			g:AddLine(arrowPt2, parentPt)
			g:EndShape()
		end
	end

	g:Pop()
	end
end

function AM_Bone_Constraints_Helper:DrawScaleControlArrows(moho, view)
	if self.enableArrows then
		local skel = moho:Skeleton()
	if (skel == nil) then
		return
	end

	local g = view:Graphics()
	local matrix = LM.Matrix:new_local()
	local bonePt = LM.Vector2:new_local()
	local parentPt = LM.Vector2:new_local()
	local arrowPt1 = LM.Vector2:new_local()
	local arrowPt2 = LM.Vector2:new_local()

	moho.layer:GetFullTransform(moho.frame, matrix, moho.document)
	g:Push()
	g:ApplyMatrix(matrix)

	g:SetSmoothing(true)
	for i = 0, skel:CountBones() - 1 do
		local bone = skel:Bone(i)
		if (bone.fScaleControlParent >= 0) then
			local parentBone = skel:Bone(bone.fScaleControlParent)
			if parentBone then

				bonePt:Set(bone.fLength / 2, 0)
				bone.fMovedMatrix:Transform(bonePt)

				parentPt:Set(parentBone.fLength / 2, 0)
				parentBone.fMovedMatrix:Transform(parentPt)

				local v = parentPt - bonePt
				local mag = v:Mag()
				local f = mag
				if (f > 0.2) then
					f = 0.2
				end
				arrowPt1:Set(mag - f / 4, -f / 16)
				arrowPt2:Set(mag - f / 4, f / 16)
				f = math.atan2(v.y, v.x)
				arrowPt1:Rotate(f)
				arrowPt2:Rotate(f)
				arrowPt1.x = arrowPt1.x + bonePt.x
				arrowPt1.y = arrowPt1.y + bonePt.y
				arrowPt2.x = arrowPt2.x + bonePt.x
				arrowPt2.y = arrowPt2.y + bonePt.y

				if (bone.fSelected) then
					g:SetColor(255, 0, 0, 255)
				else
					g:SetColor(200, 50, 50, 255)
				end
				g:DrawLine(bonePt.x, bonePt.y, parentPt.x, parentPt.y)
				g:BeginShape()
				g:AddLine(parentPt, arrowPt1)
				g:AddLine(arrowPt1, arrowPt2)
				g:AddLine(arrowPt2, parentPt)
				g:EndShape()
			end
		end
	end

	g:Pop()
	end
end

function AM_Bone_Constraints_Helper:DrawMe(moho, view)
	if self.enableArrows then
		self:DrawAngleControlArrows(moho, view)
		self:DrawScaleControlArrows(moho, view)
		self:DrawPosControlArrows(moho, view)

	end
	if self.isMouseDragging then
		local g = view:Graphics()
		g:SelectionRect(self.selRect)
	end
	
	-- Draw bezier handles
	if AE_Utilities then
		if (self.showBezierHandles and self.useCurvature) then
			local mesh = moho:DrawingMesh()
			if (mesh == nil) then
				return
			end
			
			local g = view:Graphics()
			local layerMatrix = LM.Matrix:new_local()
			moho.drawingLayer:GetFullTransform(moho.frame, layerMatrix, moho.document)
			g:Push()
			g:ApplyMatrix(layerMatrix)
			g:SetSmoothing(true)
			
			local meshLayer = moho:LayerAsVector(moho.drawingLayer)
			if (moho:CountSelectedPoints() > 0) then
				meshLayer:DrawHandles(moho.document, g, true)
			else	
				meshLayer:DrawHandles(moho.document, g, false)
			end
			
			g:Pop()
		end
	end
end

-- **************************************************
-- Tool Panel Layout
-- **************************************************

AM_Bone_Constraints_Helper.BONENAME = MOHO.MSG_BASE 
AM_Bone_Constraints_Helper.ANGLECONTROL = MOHO.MSG_BASE + 1
AM_Bone_Constraints_Helper.POSCONTROLX = MOHO.MSG_BASE + 2
AM_Bone_Constraints_Helper.POSCONTROLY = MOHO.MSG_BASE + 3
AM_Bone_Constraints_Helper.SCALECONTROL = MOHO.MSG_BASE + 4
AM_Bone_Constraints_Helper.DUMMY = MOHO.MSG_BASE + 5
AM_Bone_Constraints_Helper.SELECTITEM = MOHO.MSG_BASE + 7
AM_Bone_Constraints_Helper.SELECTCONTROL = MOHO.MSG_BASE + 6

function AM_Bone_Constraints_Helper:DoLayout(moho, layout)
	self.menu = LM.GUI.Menu(self:Localize('Select Bone'))
	self.menu_popup = LM.GUI.PopupMenu(120, false)
	self.menu_popup:SetMenu(self.menu)
	layout:AddChild(self.menu_popup)

	self.boneName = LM.GUI.TextControl(0, '                  ', self.BONENAME, LM.GUI.FIELD_TEXT)
	layout:AddChild(self.boneName)
	self.boneName:SetValue("")

	self.angleControlBoneText = LM.GUI.DynamicText(self:Localize('Angle control:'), 0)
	layout:AddChild(self.angleControlBoneText, LM.GUI.ALIGN_LEFT, 0)

	self.angleControlInput = LM.GUI.TextControl(0, '00.0000', self.ANGLECONTROL, LM.GUI.FIELD_FLOAT, self:Localize(''))
	layout:AddChild(self.angleControlInput, LM.GUI.ALIGN_LEFT, 0)

	self.positionControlBoneText = LM.GUI.DynamicText(self:Localize('Position control:'), 0)
	layout:AddChild(self.positionControlBoneText, LM.GUI.ALIGN_LEFT, 0)

	self.posControlXInput = LM.GUI.TextControl(0, '00.000', self.POSCONTROLX, LM.GUI.FIELD_FLOAT, self:Localize('X'))
	layout:AddChild(self.posControlXInput, LM.GUI.ALIGN_LEFT, 0)

	self.posControlYInput = LM.GUI.TextControl(0, '00.000', self.POSCONTROLY, LM.GUI.FIELD_FLOAT, self:Localize('Y'))
	layout:AddChild(self.posControlYInput, LM.GUI.ALIGN_LEFT, 0)

	self.scaleControlBoneText = LM.GUI.DynamicText(self:Localize('Scale control:'), 0)
	layout:AddChild(self.scaleControlBoneText, LM.GUI.ALIGN_LEFT, 0)

	self.scaleControlInput = LM.GUI.TextControl(0, '00.0000', self.SCALECONTROL, LM.GUI.FIELD_FLOAT, self:Localize(''))
	layout:AddChild(self.scaleControlInput, LM.GUI.ALIGN_LEFT, 0)
end

function AM_Bone_Constraints_Helper:UpdateWidgets(moho)
	local skel = moho:Skeleton()
	if (skel == nil) then
		if (self:ShouldUseParentSkeleton(moho)) then
			skel = moho:ParentSkeleton()
		end
		if (skel == nil) then
			return
		end
	end
	
	local selID = skel:SelectedBoneID()
	local bone = skel:Bone(selID)

	MOHO.BuildBoneMenu(self.menu, skel, self.SELECTITEM, self.DUMMY)

	if (selID >= 0) then
		local bone = skel:Bone(selID)
		self.boneName:SetValue(bone:Name())
	else
		self.boneName:SetValue("")
	end
	if bone then
		if bone.fAngleControlParent >= 0 then
			self.angleControlInput:Enable(true)
		else
			self.angleControlInput:Enable(false)
		end

		if bone.fScaleControlParent >= 0 then
			self.scaleControlInput:Enable(true)
		else
			self.scaleControlInput:Enable(false)
		end

		if bone.fPosControlParent >=0 then
			self.posControlXInput:Enable(true)
			self.posControlYInput:Enable(true)		
		else
			self.posControlXInput:Enable(false)
			self.posControlYInput:Enable(false)		
		end
		AM_Bone_Constraints_Helper.angleControlInput:SetValue(bone.fAngleControlScale)
		AM_Bone_Constraints_Helper.posControlXInput:SetValue(bone.fPosControlScale.x)
		AM_Bone_Constraints_Helper.posControlYInput:SetValue(bone.fPosControlScale.y)
		AM_Bone_Constraints_Helper.scaleControlInput:SetValue(bone.fScaleControlScale)
	else
		self.angleControlInput:Enable(false)
		self.scaleControlInput:Enable(false)	
		self.posControlXInput:Enable(false)
		self.posControlYInput:Enable(false)	
		AM_Bone_Constraints_Helper.angleControlInput:SetValue('00.0000')
		AM_Bone_Constraints_Helper.posControlXInput:SetValue('00.0000')
		AM_Bone_Constraints_Helper.posControlYInput:SetValue('00.0000')
		AM_Bone_Constraints_Helper.scaleControlInput:SetValue('00.0000')
	end
end

function AM_Bone_Constraints_Helper:HandleMessage(moho, view, msg)
	local skel = moho:Skeleton()
	local layer = moho.layer
	if (skel == nil) then
		if (self:ShouldUseParentSkeleton(moho)) then
			skel = moho:ParentSkeleton()
		end
		if (skel == nil) then
			return
		end
		layer = moho.layer:ControllingBoneLayer()
	end
	local selID = skel:SelectedBoneID()
	local bone = skel:Bone(selID)


	if msg == self.BONENAME then

		if (skel:SelectedBoneID() >= 0) then
			moho.document:PrepUndo(layer, true)
			moho.document:SetDirty()
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if (bone.fSelected) then
					bone:SetName(self.boneName:Value())
					skel:MakeBoneNameUnique(i)
				end
			end
			moho:UpdateUI()
		end
	

	elseif msg == self.ANGLECONTROL then
		if (skel:SelectedBoneID() >= 0) then
			moho.document:PrepUndo(layer, true)
			moho.document:SetDirty()
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if (bone.fSelected) then
				bone.fAngleControlScale = self.angleControlInput:Value()
				end
			end
			moho:UpdateUI()
		end

		
	elseif msg == self.POSCONTROLX then
		if (skel:SelectedBoneID() >= 0) then
			moho.document:PrepUndo(layer, true)
			moho.document:SetDirty()
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if (bone.fSelected) then
					bone.fPosControlScale.x = self.posControlXInput:Value()
				end
			end
			moho:UpdateUI()
		end

	elseif msg == self.POSCONTROLY then
		if (skel:SelectedBoneID() >= 0) then
			moho.document:PrepUndo(layer, true)
			moho.document:SetDirty()
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if (bone.fSelected) then
					bone.fPosControlScale.y = self.posControlYInput:Value()
				end
			end
			moho:UpdateUI()
		end

	elseif msg == self.SCALECONTROL then
		if (skel:SelectedBoneID() >= 0) then
			moho.document:PrepUndo(layer, true)
			moho.document:SetDirty()
			for i = 0, skel:CountBones() - 1 do
				local bone = skel:Bone(i)
				if (bone.fSelected) then
					bone.fScaleControlScale = self.scaleControlInput:Value()
				end
			end
			moho:UpdateUI()
		end
		
	elseif (msg >= self.SELECTITEM) then
		for i = 0, skel:CountBones() - 1 do
			skel:Bone(i).fSelected = (i == msg - self.SELECTITEM)
		end
		moho:UpdateUI()

	else
		
	end

end

-- **************************************************
-- Localization
-- **************************************************

function AM_Bone_Constraints_Helper:Localize(text)
	local phrase = {}

	phrase['Description'] = ''
	phrase['UILabel'] = 'Bone Constraints Helper'

	phrase['Select Bone'] = 'Select Bone'
	phrase['Angle control:'] = 'Angle control:'
	phrase['<None>'] = '<None>'
	phrase['Position control:'] = 'Position control:'
	phrase['<None>'] = '<None>'
	phrase['X'] = 'X'
	phrase['Y'] = 'Y'
	phrase['Scale control:'] = 'Scale control:'
	phrase['<None>'] = '<None>'


	local fileWord = MOHO.Localize("/Menus/File/File=File")
	if fileWord == "Файл" then
		phrase['Description'] = ''
		phrase['UILabel'] = 'Bone Constraints Helper'

		phrase['Select Bone'] = 'Select Bone'
		phrase['Angle control:'] = 'Angle control:'
		phrase['<None>'] = '<None>'
		phrase['Position control:'] = 'Position control:'
		phrase['<None>'] = '<None>'
		phrase['X'] = 'X'
		phrase['Y'] = 'Y'
		phrase['Scale control:'] = 'Scale control:'
		phrase['<None>'] = '<None>'

	end

	return phrase[text]
end

Icon
Bone Constraints Helper
Listed

Script type: Tool

Uploaded: Jan 20 2022, 11:07

Last modified: Jan 20 2022, 11:12

Handy tool for working with bone constraints


Click to select a bone. With a bone selected, Shift+Click to set the Angle Control bone, Ctrl+Click to set the Scale Control bone, Alt+Click to set the Position Control bone.

The script also shows you the constraints as color-coded arrows. The green arrow is Angle, the red one is Scale, and the blue one is Position.
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: 1008