-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "MR_KeyMotion" -- ************************************************** -- General information about this script -- ************************************************** MR_KeyMotion = {} function MR_KeyMotion:Name() return self:Localize('UILabel') end function MR_KeyMotion:Version() return '1.0' end function MR_KeyMotion:UILabel() return self:Localize('UILabel') end function MR_KeyMotion:Creator() return 'Eugene Babich' end function MR_KeyMotion:Description() return self:Localize('Description') end -- ************************************************** -- Recurring Values -- ************************************************** MR_KeyMotion.smooth = true MR_KeyMotion.pull = false MR_KeyMotion.scale = false MR_KeyMotion.flip = false MR_KeyMotion.centerTop = true MR_KeyMotion.centerMid = false MR_KeyMotion.centerDown = false MR_KeyMotion.scaleIn = true MR_KeyMotion.useChannelX = true MR_KeyMotion.useChannelY = true MR_KeyMotion.useChannelZ = true MR_KeyMotion.scaleValue = 10 MR_KeyMotion.smoothFrameOffset = 4 MR_KeyMotion.smoothStepValue = 4 MR_KeyMotion.smoothThresholdValue = 4 MR_KeyMotion.allowDifference = 0.005 MR_KeyMotion.pullFrameOffset = 2 MR_KeyMotion.pullStepValue = 8 -- ************************************************** -- Prefs -- ************************************************** function MR_KeyMotion:LoadPrefs(prefs) self.smooth = prefs:GetBool("MR_KeyMotion.smooth", true) self.pull = prefs:GetBool("MR_KeyMotion.pull", false) self.scale = prefs:GetBool("MR_KeyMotion.scale", false) self.flip = prefs:GetBool("MR_KeyMotion.flip", false) self.centerTop = prefs:GetBool("MR_KeyMotion.centerTop", true) self.centerMid = prefs:GetBool("MR_KeyMotion.centerMid", false) self.centerDown = prefs:GetBool("MR_KeyMotion.centerDown", false) self.scaleIn = prefs:GetBool("MR_KeyMotion.scaleIn", true) self.scaleOut = prefs:GetBool("MR_KeyMotion.scaleOut", false) self.useChannelX = prefs:GetBool("MR_KeyMotion.useChannelX", true) self.useChannelY = prefs:GetBool("MR_KeyMotion.useChannelY", true) self.useChannelZ = prefs:GetBool("MR_KeyMotion.useChannelZ", true) self.scaleValue = prefs:GetInt("MR_KeyMotion.scaleValue", 10) self.smoothStepValue = prefs:GetInt("MR_KeyMotion.smoothStepValue", 4) self.pullStepValue = prefs:GetInt("MR_KeyMotion.pullStepValue", 8) end function MR_KeyMotion:SavePrefs(prefs) prefs:SetBool("MR_KeyMotion.smooth", self.smooth) prefs:SetBool("MR_KeyMotion.pull", self.pull) prefs:SetBool("MR_KeyMotion.scale", self.scale) prefs:SetBool("MR_KeyMotion.flip", self.flip) prefs:SetBool("MR_KeyMotion.centerTop", self.centerTop) prefs:SetBool("MR_KeyMotion.centerMid", self.centerMid) prefs:SetBool("MR_KeyMotion.centerDown", self.centerDown) prefs:SetBool("MR_KeyMotion.scaleIn", self.scaleIn) prefs:SetBool("MR_KeyMotion.scaleOut", self.scaleOut) prefs:SetBool("MR_KeyMotion.useChannelX", self.useChannelX) prefs:SetBool("MR_KeyMotion.useChannelY", self.useChannelY) prefs:SetBool("MR_KeyMotion.useChannelZ", self.useChannelZ) prefs:SetInt("MR_KeyMotion.scaleValue", self.scaleValue) prefs:SetInt("MR_KeyMotion.scaleValue", self.smoothStepValue) prefs:SetInt("MR_KeyMotion.pullStepValue", self.pullStepValue) end function MR_KeyMotion:ResetPrefs() MR_KeyMotion.smooth = true MR_KeyMotion.pull = false MR_KeyMotion.scale = false MR_KeyMotion.flip = false MR_KeyMotion.centerTop = true MR_KeyMotion.centerMid = false MR_KeyMotion.centerDown = false MR_KeyMotion.scaleIn = true MR_KeyMotion.scaleOut = false MR_KeyMotion.useChannelX = true MR_KeyMotion.useChannelY = true MR_KeyMotion.useChannelZ = true MR_KeyMotion.scaleValue = 10 MR_KeyMotion.smoothStepValue = 4 MR_KeyMotion.pullStepValue = 8 end -- ************************************************** -- MR_KeyMotionDialog -- ************************************************** local MR_KeyMotionDialog = {} MR_KeyMotionDialog.SMOOTH = MOHO.MSG_BASE MR_KeyMotionDialog.PULL = MOHO.MSG_BASE + 1 MR_KeyMotionDialog.SCALE = MOHO.MSG_BASE + 2 MR_KeyMotionDialog.FLIP = MOHO.MSG_BASE + 3 MR_KeyMotionDialog.CENTER_TOP_BUTTON = MOHO.MSG_BASE + 4 MR_KeyMotionDialog.CENTER_MID_BUTTON = MOHO.MSG_BASE + 5 MR_KeyMotionDialog.CENTER_DOWN_BUTTON = MOHO.MSG_BASE + 6 MR_KeyMotionDialog.SCALE_IN_BUTTON = MOHO.MSG_BASE + 7 MR_KeyMotionDialog.SCALE_OUT_BUTTON = MOHO.MSG_BASE + 8 MR_KeyMotionDialog.USE_CHANNEL_X = MOHO.MSG_BASE + 9 MR_KeyMotionDialog.USE_CHANNEL_Y = MOHO.MSG_BASE + 10 MR_KeyMotionDialog.USE_CHANNEL_Z = MOHO.MSG_BASE + 11 MR_KeyMotionDialog.SCALE_PERCENTAGE = MOHO.MSG_BASE + 12 MR_KeyMotionDialog.SMOOTH_PERCENTAGE = MOHO.MSG_BASE + 13 MR_KeyMotionDialog.PULL_PERCENTAGE = MOHO.MSG_BASE + 14 function MR_KeyMotionDialog:new() local d = LM.GUI.SimpleDialog(MR_KeyMotion:Localize('UILabel'), MR_KeyMotionDialog) local l = d:GetLayout() l:PushH() d.smoothRadioButton = LM.GUI.RadioButton(MR_KeyMotion:Localize('Smooth'), d.SMOOTH) l:AddChild(d.smoothRadioButton, LM.GUI.ALIGN_LEFT, 0) l:AddPadding(-5) l:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) l:AddPadding(-5) d.pullRadioButton = LM.GUI.RadioButton(MR_KeyMotion:Localize('Pull'), d.PULL) l:AddChild(d.pullRadioButton, LM.GUI.ALIGN_LEFT, 0) l:AddPadding(-5) l:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) l:AddPadding(-5) d.scaleRadioButton = LM.GUI.RadioButton(MR_KeyMotion:Localize('Scale'), d.SCALE) l:AddChild(d.scaleRadioButton, LM.GUI.ALIGN_LEFT, 0) l:AddPadding(-5) l:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) l:AddPadding(-5) d.flipRadioButton = LM.GUI.RadioButton(MR_KeyMotion:Localize('Flip'), d.FLIP) l:AddChild(d.flipRadioButton, LM.GUI.ALIGN_LEFT, 0) l:Pop() l:PushH() d.smoothPercentageInput = LM.GUI.TextControl(84, '10', d.SMOOTH_PERCENTAGE, LM.GUI.FIELD_INT, MR_KeyMotion:Localize('Smooth Percentage')) l:AddChild(d.smoothPercentageInput, LM.GUI.ALIGN_LEFT, 0) d.pullPercentageInput = LM.GUI.TextControl(84, '10', d.PULL_PERCENTAGE, LM.GUI.FIELD_INT, MR_KeyMotion:Localize('Pull Percentage')) l:AddChild(d.pullPercentageInput, LM.GUI.ALIGN_LEFT, 0) d.scalePercentageInput = LM.GUI.TextControl(84, '10', d.SCALE_PERCENTAGE, LM.GUI.FIELD_INT, MR_KeyMotion:Localize('Scale Percentage')) l:AddChild(d.scalePercentageInput, LM.GUI.ALIGN_LEFT, 0) l:Pop() l:AddChild(LM.GUI.Divider(false), LM.GUI.ALIGN_FILL) l:PushH() d.useChanneXButton = LM.GUI.ImageButton('ScriptResources/mr_key_motion/mr_transform_x', MR_KeyMotion:Localize('Transform X'), true, d.USE_CHANNEL_X, false) l:AddChild(d.useChanneXButton, LM.GUI.ALIGN_LEFT, 0) d.useChanneYButton = LM.GUI.ImageButton('ScriptResources/mr_key_motion/mr_transform_y', MR_KeyMotion:Localize('Transform Y'), true, d.USE_CHANNEL_Y, false) l:AddChild(d.useChanneYButton, LM.GUI.ALIGN_LEFT, 0) d.useChanneZButton = LM.GUI.ImageButton('ScriptResources/mr_key_motion/mr_transform_z', MR_KeyMotion:Localize('Transform Z'), true, d.USE_CHANNEL_Z, false) l:AddChild(d.useChanneZButton, LM.GUI.ALIGN_LEFT, 0) l:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) d.centerTopButton = LM.GUI.ImageButton('ScriptResources/mr_key_motion/mr_center_top', MR_KeyMotion:Localize('Transform Top'), true, d.CENTER_TOP_BUTTON, false) l:AddChild(d.centerTopButton, LM.GUI.ALIGN_LEFT, 0) d.centerMidButton = LM.GUI.ImageButton('ScriptResources/mr_key_motion/mr_center_mid', MR_KeyMotion:Localize('Transform Mid'), true, d.CENTER_MID_BUTTON, false) l:AddChild(d.centerMidButton, LM.GUI.ALIGN_LEFT, 0) d.centerDownButton = LM.GUI.ImageButton('ScriptResources/mr_key_motion/mr_center_down', MR_KeyMotion:Localize('Transform Down'), true, d.CENTER_DOWN_BUTTON, false) l:AddChild(d.centerDownButton, LM.GUI.ALIGN_LEFT, 0) l:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL) d.scaleInButton = LM.GUI.ImageButton('ScriptResources/mr_key_motion/mr_scale_in', MR_KeyMotion:Localize('Scale In'), true, d.SCALE_IN_BUTTON, false) l:AddChild(d.scaleInButton, LM.GUI.ALIGN_LEFT, 0) d.scaleOutButton = LM.GUI.ImageButton('ScriptResources/mr_key_motion/mr_scale_out', MR_KeyMotion:Localize('Scale Out'), true, d.SCALE_OUT_BUTTON, false) l:AddChild(d.scaleOutButton, LM.GUI.ALIGN_LEFT, 0) l:Pop() return d end function MR_KeyMotionDialog:UpdateWidgets(moho) self.smoothRadioButton:SetValue(MR_KeyMotion.smooth) self.pullRadioButton:SetValue(MR_KeyMotion.pull) self.scaleRadioButton:SetValue(MR_KeyMotion.scale) self.flipRadioButton:SetValue(MR_KeyMotion.flip) self.centerTopButton:SetValue(MR_KeyMotion.centerTop) self.centerMidButton:SetValue(MR_KeyMotion.centerMid) self.centerDownButton:SetValue(MR_KeyMotion.centerDown) self.scaleInButton:SetValue(MR_KeyMotion.scaleIn) self.scaleOutButton:SetValue(MR_KeyMotion.scaleOut) self.useChanneXButton:SetValue(MR_KeyMotion.useChannelX) self.useChanneYButton:SetValue(MR_KeyMotion.useChannelY) self.useChanneZButton:SetValue(MR_KeyMotion.useChannelZ) self.smoothPercentageInput:SetValue(MR_KeyMotion.smoothStepValue) self.pullPercentageInput:SetValue(MR_KeyMotion.pullStepValue) self.scalePercentageInput:SetValue(MR_KeyMotion.scaleValue) self.centerTopButton:Enable(not MR_KeyMotion.smooth and not MR_KeyMotion.pull) self.centerMidButton:Enable(not MR_KeyMotion.smooth and not MR_KeyMotion.pull) self.centerDownButton:Enable(not MR_KeyMotion.smooth and not MR_KeyMotion.pull) self.scaleInButton:Enable(MR_KeyMotion.scale) self.scaleOutButton:Enable(MR_KeyMotion.scale) self.smoothPercentageInput:Enable(MR_KeyMotion.smooth) self.pullPercentageInput:Enable(MR_KeyMotion.pull) self.scalePercentageInput:Enable(MR_KeyMotion.scale) end function MR_KeyMotionDialog:OnOK(moho) MR_KeyMotion.smooth = self.smoothRadioButton:Value() MR_KeyMotion.pull = self.pullRadioButton:Value() MR_KeyMotion.scale = self.scaleRadioButton:Value() MR_KeyMotion.flip = self.flipRadioButton:Value() MR_KeyMotion.centerTop = self.centerTopButton:Value() MR_KeyMotion.centerMid = self.centerMidButton:Value() MR_KeyMotion.centerDown = self.centerDownButton:Value() MR_KeyMotion.scaleIn = self.scaleInButton:Value() MR_KeyMotion.scaleOut = self.scaleOutButton:Value() MR_KeyMotion.useChannelX = self.useChanneXButton:Value() MR_KeyMotion.useChannelY = self.useChanneYButton:Value() MR_KeyMotion.useChannelZ = self.useChanneZButton:Value() MR_KeyMotion.smoothStepValue = self.smoothPercentageInput:IntValue() MR_KeyMotion.pullStepValue = self.pullPercentageInput:IntValue() MR_KeyMotion.scaleValue = self.scalePercentageInput:IntValue() end function MR_KeyMotionDialog:HandleMessage(msg) if msg == self.SMOOTH then self.centerTopButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.centerMidButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.centerDownButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.scaleInButton:Enable(self.scaleRadioButton:Value()) self.scaleOutButton:Enable(self.scaleRadioButton:Value()) self.smoothPercentageInput:Enable(self.smoothRadioButton:Value()) self.pullPercentageInput:Enable(self.pullRadioButton:Value()) self.scalePercentageInput:Enable(self.scaleRadioButton:Value()) elseif msg == self.PULL then self.centerTopButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.centerMidButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.centerDownButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.scaleInButton:Enable(self.scaleRadioButton:Value()) self.scaleOutButton:Enable(self.scaleRadioButton:Value()) self.smoothPercentageInput:Enable(self.smoothRadioButton:Value()) self.pullPercentageInput:Enable(self.pullRadioButton:Value()) self.scalePercentageInput:Enable(self.scaleRadioButton:Value()) elseif msg == self.SCALE then self.centerTopButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.centerMidButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.centerDownButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.scaleInButton:Enable(self.scaleRadioButton:Value()) self.scaleOutButton:Enable(self.scaleRadioButton:Value()) self.smoothPercentageInput:Enable(self.smoothRadioButton:Value()) self.pullPercentageInput:Enable(self.pullRadioButton:Value()) self.scalePercentageInput:Enable(self.scaleRadioButton:Value()) elseif msg == self.FLIP then self.centerTopButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.centerMidButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.centerDownButton:Enable(not self.smoothRadioButton:Value() and not self.pullRadioButton:Value()) self.scaleInButton:Enable(self.scaleRadioButton:Value()) self.scaleOutButton:Enable(self.scaleRadioButton:Value()) self.smoothPercentageInput:Enable(self.smoothRadioButton:Value()) self.pullPercentageInput:Enable(self.pullRadioButton:Value()) self.scalePercentageInput:Enable(self.scaleRadioButton:Value()) elseif msg == self.CENTER_TOP_BUTTON then self.centerTopButton:SetValue(true) self.centerMidButton:SetValue(false) self.centerDownButton:SetValue(false) elseif msg == self.CENTER_MID_BUTTON then self.centerTopButton:SetValue(false) self.centerMidButton:SetValue(true) self.centerDownButton:SetValue(false) elseif msg == self.CENTER_DOWN_BUTTON then self.centerTopButton:SetValue(false) self.centerMidButton:SetValue(false) self.centerDownButton:SetValue(true) elseif msg == self.SCALE_IN_BUTTON then self.scaleInButton:SetValue(true) self.scaleOutButton:SetValue(false) elseif msg == self.SCALE_OUT_BUTTON then self.scaleInButton:SetValue(false) self.scaleOutButton:SetValue(true) elseif msg == self.USE_CHANNEL_X then if not self.useChanneXButton:Value() then if self.useChanneYButton:Value() or self.useChanneZButton:Value() then self.useChanneXButton:SetValue(self.useChanneXButton:Value()) else self.useChanneXButton:SetValue(true) end else self.useChanneXButton:SetValue(self.useChanneXButton:Value()) end elseif msg == self.USE_CHANNEL_Y then if not self.useChanneYButton:Value() then if self.useChanneXButton:Value() or self.useChanneZButton:Value() then self.useChanneYButton:SetValue(self.useChanneYButton:Value()) else self.useChanneYButton:SetValue(true) end else self.useChanneYButton:SetValue(self.useChanneYButton:Value()) end elseif msg == self.USE_CHANNEL_Z then if not self.useChanneZButton:Value() then if self.useChanneXButton:Value() or self.useChanneYButton:Value() then self.useChanneZButton:SetValue(self.useChanneZButton:Value()) else self.useChanneZButton:SetValue(true) end else self.useChanneZButton:SetValue(self.useChanneZButton:Value()) end elseif msg == self.SMOOTH_PERCENTAGE then self.smoothPercentageInput:SetValue(LM.Clamp(self.smoothPercentageInput:Value(), 1, 100)) elseif msg == self.PULL_PERCENTAGE then self.pullPercentageInput:SetValue(LM.Clamp(self.pullPercentageInput:Value(), 1, 100)) elseif msg == self.SCALE_PERCENTAGE then self.scalePercentageInput:SetValue(LM.Clamp(self.scalePercentageInput:Value(), 1, 100)) end end -- ************************************************** -- Is Relevant / Is Enabled -- ************************************************** function MR_KeyMotion:IsRelevant(moho) return true end function MR_KeyMotion:IsEnabled(moho) return true end -- ************************************************** -- The guts of this script -- ************************************************** function MR_KeyMotion:Run(moho) local skel = moho:Skeleton() local mesh = moho:Mesh() self.isUndoPrepared = false self.isKeysSelected = false if skel then for i = 0, skel:CountBones() - 1 do local bone = skel:Bone(i) if bone.fSelected then if MR_KeyMotion.smooth then self:AnalizeAndSmoothChanelVal(moho, bone.fAnimAngle) self:AnalizeAndSmoothChanelVal(moho, bone.fAnimScale) self:AnalizeAndSmoothChanelVec(moho, bone.fAnimPos) elseif MR_KeyMotion.pull then self:AnalizeAndPullChanelVal(moho, bone.fAnimAngle) self:AnalizeAndPullChanelVal(moho, bone.fAnimScale) self:AnalizeAndPullChanelVec(moho, bone.fAnimPos) elseif MR_KeyMotion.scale then local boneAngleChannel = bone.fAnimAngle local boneScaleChannel = bone.fAnimScale self:ScaleChannel(moho, boneAngleChannel, false, false) self:ScaleChannel(moho, boneScaleChannel, false, false) if bone.fAnimPos:AreDimensionsSplit() then local boneTranslationChannel1 = bone.fAnimPos:DimensionChannel(0) local boneTranslationChannel2 = bone.fAnimPos:DimensionChannel(1) self:ScaleChannel(moho, boneTranslationChannel1, false, false) self:ScaleChannel(moho, boneTranslationChannel2, false, false) else local boneTranslationChannel1 = bone.fAnimPos self:ScaleChannel(moho, boneTranslationChannel1, true, false) end elseif MR_KeyMotion.flip then local boneAngleChannel = bone.fAnimAngle local boneScaleChannel = bone.fAnimScale self:ScaleChannel(moho, boneAngleChannel, false, true) self:ScaleChannel(moho, boneScaleChannel, false, true) if bone.fAnimPos:AreDimensionsSplit() then local boneTranslationChannel1 = bone.fAnimPos:DimensionChannel(0) local boneTranslationChannel2 = bone.fAnimPos:DimensionChannel(1) self:ScaleChannel(moho, boneTranslationChannel1, false, true) self:ScaleChannel(moho, boneTranslationChannel2, false, true) else local boneTranslationChannel1 = bone.fAnimPos self:ScaleChannel(moho, boneTranslationChannel1, true, true) end end end end elseif mesh then for i = 0, mesh:CountPoints() - 1 do local point = mesh:Point(i) if point.fSelected then if MR_KeyMotion.smooth then self:AnalizeAndSmoothChanelVec(moho, point.fAnimPos) self:AnalizeAndSmoothChanelVal(moho, point.fWidth) for c = 0, point:CountCurves() - 1 do local myCurve, where = point:Curve(c) local curvatureChannel = myCurve:Curvature(where) self:AnalizeAndSmoothChanelVal(moho, curvatureChannel) if AE_Utilities then local curvatureOffsetChannel1 = AE_Utilities:GetOffsetChannel(moho, moho.layer, myCurve, where, false) local curvatureOffsetChannel2 = AE_Utilities:GetOffsetChannel(moho, moho.layer, myCurve, where, true) local curvatureWeightChannel1 = AE_Utilities:GetWeightChannel(moho, moho.layer, myCurve, where, false) local curvatureWeightChannel2 = AE_Utilities:GetWeightChannel(moho, moho.layer, myCurve, where, true) self:AnalizeAndSmoothChanelVal(moho, curvatureOffsetChannel1) self:AnalizeAndSmoothChanelVal(moho, curvatureOffsetChannel2) self:AnalizeAndSmoothChanelVal(moho, curvatureWeightChannel1) self:AnalizeAndSmoothChanelVal(moho, curvatureWeightChannel2) end end elseif MR_KeyMotion.pull then self:AnalizeAndPullChanelVec(moho, point.fAnimPos) self:AnalizeAndPullChanelVal(moho, point.fWidth) for c = 0, point:CountCurves() - 1 do local myCurve, where = point:Curve(c) local curvatureChannel = myCurve:Curvature(where) self:AnalizeAndPullChanelVal(moho, curvatureChannel) if AE_Utilities then local curvatureOffsetChannel1 = AE_Utilities:GetOffsetChannel(moho, moho.layer, myCurve, where, false) local curvatureOffsetChannel2 = AE_Utilities:GetOffsetChannel(moho, moho.layer, myCurve, where, true) local curvatureWeightChannel1 = AE_Utilities:GetWeightChannel(moho, moho.layer, myCurve, where, false) local curvatureWeightChannel2 = AE_Utilities:GetWeightChannel(moho, moho.layer, myCurve, where, true) self:AnalizeAndPullChanelVal(moho, curvatureOffsetChannel1) self:AnalizeAndPullChanelVal(moho, curvatureOffsetChannel2) self:AnalizeAndPullChanelVal(moho, curvatureWeightChannel1) self:AnalizeAndPullChanelVal(moho, curvatureWeightChannel2) end end elseif MR_KeyMotion.scale then if point.fAnimPos:AreDimensionsSplit() then local pointTranslationChannel1 = point.fAnimPos:DimensionChannel(0) local pointTranslationChannel2 = point.fAnimPos:DimensionChannel(1) self:ScaleChannel(moho, pointTranslationChannel1, false, false) self:ScaleChannel(moho, pointTranslationChannel2, false, false) else local pointTranslationChannel = point.fAnimPos self:ScaleChannel(moho, pointTranslationChannel, true, false) end self:ScaleChannel(moho, point.fWidth, false, false) for c = 0, point:CountCurves() - 1 do local myCurve, where = point:Curve(c) local curvatureChannel = myCurve:Curvature(where) local curvatureOffsetChannel1 = AE_Utilities:GetOffsetChannel(moho, moho.layer, myCurve, where, false) local curvatureOffsetChannel2 = AE_Utilities:GetOffsetChannel(moho, moho.layer, myCurve, where, true) local curvatureWeightChannel1 = AE_Utilities:GetWeightChannel(moho, moho.layer, myCurve, where, false) local curvatureWeightChannel2 = AE_Utilities:GetWeightChannel(moho, moho.layer, myCurve, where, true) self:ScaleChannel(moho, curvatureChannel) self:ScaleChannel(moho, curvatureOffsetChannel1, false, false) self:ScaleChannel(moho, curvatureOffsetChannel2, false, false) self:ScaleChannel(moho, curvatureWeightChannel1, false, false) self:ScaleChannel(moho, curvatureWeightChannel2, false, false) end elseif MR_KeyMotion.flip then if point.fAnimPos:AreDimensionsSplit() then local pointTranslationChannel1 = point.fAnimPos:DimensionChannel(0) local pointTranslationChannel2 = point.fAnimPos:DimensionChannel(1) self:ScaleChannel(moho, pointTranslationChannel1, false, true) self:ScaleChannel(moho, pointTranslationChannel2, false, true) else local pointTranslationChannel = point.fAnimPos self:ScaleChannel(moho, pointTranslationChannel, true, true) end self:ScaleChannel(moho, point.fWidth, false, true) for c = 0, point:CountCurves() - 1 do local myCurve, where = point:Curve(c) local curvatureChannel = myCurve:Curvature(where) local curvatureOffsetChannel1 = AE_Utilities:GetOffsetChannel(moho, moho.layer, myCurve, where, false) local curvatureOffsetChannel2 = AE_Utilities:GetOffsetChannel(moho, moho.layer, myCurve, where, true) local curvatureWeightChannel1 = AE_Utilities:GetWeightChannel(moho, moho.layer, myCurve, where, false) local curvatureWeightChannel2 = AE_Utilities:GetWeightChannel(moho, moho.layer, myCurve, where, true) self:ScaleChannel(moho, curvatureChannel) self:ScaleChannel(moho, curvatureOffsetChannel1, false, true) self:ScaleChannel(moho, curvatureOffsetChannel2, false, true) self:ScaleChannel(moho, curvatureWeightChannel1, false, true) self:ScaleChannel(moho, curvatureWeightChannel2, false, true) end end end end end local layer = moho.layer self:TransformChannelVal(moho, layer.fAlpha) self:TransformChannelVal(moho, layer.fBlur) self:TransformChannelVal(moho, layer.fFollowing) self:TransformChannelVec(moho, layer.fTranslation) self:TransformChannelVal(moho, layer.fRotationX) self:TransformChannelVal(moho, layer.fRotationY) self:TransformChannelVal(moho, layer.fRotationZ) self:TransformChannelVec(moho, layer.fScale) self:TransformChannelVec(moho, layer.fShear) self:TransformChannelVec(moho, moho.document.fCameraTrack) self:TransformChannelVec(moho, moho.document.fCameraPanTilt) self:TransformChannelVal(moho, moho.document.fCameraZoom) self:TransformChannelVal(moho, moho.document.fCameraRoll) if not self.isKeysSelected then local dlog = MR_KeyMotionDialog:new(moho) if (dlog:DoModal() == LM.GUI.MSG_CANCEL) then return end end moho:UpdateSelectedChannels() moho.layer:UpdateCurFrame() moho:UpdateUI() end function MR_KeyMotion:ScaleChannel(moho, channel, isSubChannels, flip) local maxVal1 = -10000000 local minVal1 = 10000000 local maxVal2 = -10000000 local minVal2 = 10000000 local maxVal3 = -10000000 local minVal3 = 10000000 local scaleCenter1 = 0 local scaleCenter2 = 0 local scaleCenter3 = 0 local vec3 = false if isSubChannels then if moho:ChannelAsAnimVec3(channel) then vec3 = true end end for keyID = 0, channel:CountKeys() - 1 do local keyFrame = channel:GetKeyWhen(keyID) if (keyFrame > 0 and channel:IsKeySelectedByID(keyID)) then self.isKeysSelected = true self:PrepUndo(moho) if isSubChannels then local channelValue = channel:GetValue(keyFrame) if channelValue.x > maxVal1 then maxVal1 = channelValue.x end if channelValue.x < minVal1 then minVal1 = channelValue.x end if channelValue.y > maxVal2 then maxVal2 = channelValue.y end if channelValue.y < minVal2 then minVal2 = channelValue.y end if vec3 then if channelValue.z > maxVal3 then maxVal3 = channelValue.z end if channelValue.z < minVal3 then minVal3 = channelValue.z end end else local channelValue = channel:GetValue(keyFrame) if channelValue > maxVal1 then maxVal1 = channelValue end if channelValue < minVal1 then minVal1 = channelValue end end end end if isSubChannels then if MR_KeyMotion.centerTop then scaleCenter1 = maxVal1 scaleCenter2 = maxVal2 if vec3 then scaleCenter3 = maxVal3 end elseif MR_KeyMotion.centerMid then scaleCenter1 = maxVal1 - ((maxVal1 - minVal1) / 2) scaleCenter2 = maxVal2 - ((maxVal2 - minVal2) / 2) if vec3 then scaleCenter3 = maxVal3 - ((maxVal3 - minVal3) / 2) end elseif MR_KeyMotion.centerDown then scaleCenter1 = minVal1 scaleCenter2 = minVal2 if vec3 then scaleCenter3 = minVal3 end end else if MR_KeyMotion.centerTop then scaleCenter1 = maxVal1 elseif MR_KeyMotion.centerMid then scaleCenter1 = maxVal1 - ((maxVal1 - minVal1) / 2) elseif MR_KeyMotion.centerDown then scaleCenter1 = minVal1 end end for keyID = 0, channel:CountKeys() - 1 do local keyFrame = channel:GetKeyWhen(keyID) if (keyFrame > 0 and channel:IsKeySelectedByID(keyID)) then self.isKeysSelected = true self:PrepUndo(moho) local channelValue = channel:GetValue(keyFrame) local scaleValue = MR_KeyMotion.scaleValue scaleValue = 1 - (scaleValue / 100) if MR_KeyMotion.scaleOut then scaleValue = 1 + (1 - scaleValue) end if isSubChannels then if not MR_KeyMotion.useChannelX and not MR_KeyMotion.useChannelY and not MR_KeyMotion.useChannelZ then return end local dif1 = channelValue.x - scaleCenter1 local dif2 = channelValue.y - scaleCenter2 local dif3 if vec3 then dif3 = channelValue.z - scaleCenter3 end local newValue1 local newValue2 local newValue3 if flip then newValue1 = scaleCenter1 - dif1 newValue2 = scaleCenter2 - dif2 if vec3 then newValue3 = scaleCenter3 - dif3 end else newValue1 = (dif1 * scaleValue) + scaleCenter1 newValue2 = (dif2 * scaleValue) + scaleCenter2 if vec3 then newValue3 = (dif3 * scaleValue) + scaleCenter3 end end if vec3 then local newVec = LM.Vector3:new_local() if MR_KeyMotion.useChannelX and MR_KeyMotion.useChannelY and MR_KeyMotion.useChannelZ then -- X Y Z newVec:Set(newValue1, newValue2, newValue3) elseif MR_KeyMotion.useChannelX and MR_KeyMotion.useChannelY and not MR_KeyMotion.useChannelZ then -- X Y newVec:Set(newValue1, newValue2, channelValue.z) elseif MR_KeyMotion.useChannelX and not MR_KeyMotion.useChannelY and MR_KeyMotion.useChannelZ then -- X Z newVec:Set(newValue1, channelValue.y, newValue3) elseif MR_KeyMotion.useChannelX and not MR_KeyMotion.useChannelY and not MR_KeyMotion.useChannelZ then -- X newVec:Set(newValue1, channelValue.y, channelValue.z) elseif not MR_KeyMotion.useChannelX and MR_KeyMotion.useChannelY and MR_KeyMotion.useChannelZ then -- Y Z newVec:Set(channelValue.x, newValue2, newValue3) elseif not MR_KeyMotion.useChannelX and MR_KeyMotion.useChannelY and not MR_KeyMotion.useChannelZ then -- Y newVec:Set(channelValue.x, newValue2, channelValue.z) elseif not MR_KeyMotion.useChannelX and not MR_KeyMotion.useChannelY and MR_KeyMotion.useChannelZ then -- Z newVec:Set(channelValue.x, channelValue.y, newValue3) end channel:SetValue(keyFrame, newVec) else local newVec = LM.Vector2:new_local() if MR_KeyMotion.useChannelX and MR_KeyMotion.useChannelY then newVec:Set(newValue1, newValue2) elseif MR_KeyMotion.useChannelX and not MR_KeyMotion.useChannelY then newVec:Set(newValue1, channelValue.y) elseif not MR_KeyMotion.useChannelX and MR_KeyMotion.useChannelY then newVec:Set(channelValue.x, newValue2) end if MR_KeyMotion.useChannelX or MR_KeyMotion.useChannelY then channel:SetValue(keyFrame, newVec) end end else local dif1 = channelValue - scaleCenter1 local newValue1 if flip then newValue1 = scaleCenter1 - dif1 else newValue1 = (dif1 * scaleValue) + scaleCenter1 end channel:SetValue(keyFrame, newValue1) end end end end function MR_KeyMotion:SmoothChannel(moho, channel, listLeft, listRight) local boneChannel = channel for i, a in pairs(listLeft) do local isOk = false local dubFound = false for k, b in pairs(listRight) do if a.frame == b.frame then if math.abs(a.difValue) > math.abs(b.difValue) then isOk = true end dubFound = true end end if not dubFound then isOk = true end if isOk then boneChannel:SetValue(a.extraFrame, boneChannel:GetValue(a.extraFrame)) boneChannel:SetValue(a.frame, a.keyValue) end end for n, r in pairs(listRight) do local isOk = false local dubFound = false for k, b in pairs(listLeft) do if r.frame == b.frame then if math.abs(r.difValue) > math.abs(b.difValue) then isOk = true end dubFound = true end end if not dubFound then isOk = true end if isOk then boneChannel:SetValue(r.extraFrame, boneChannel:GetValue(r.extraFrame)) boneChannel:SetValue(r.frame, r.keyValue) end end end function MR_KeyMotion:AnalizeAndSmoothChanelVal(moho, channel) local keysAngleChangesLeft = {} local keysAngleChangesRight = {} self:AnalizeChannel(moho, channel, keysAngleChangesLeft, keysAngleChangesRight) self:SmoothChannel(moho, channel, keysAngleChangesLeft, keysAngleChangesRight) end function MR_KeyMotion:AnalizeAndSmoothChanelVec(moho, channel) local vec3 = false if channel:ChannelType() == MOHO.CHANNEL_VEC3 then vec3 = true end local keysPosChangesLeft = {} local keysPosChangesRight = {} local keysPosChangesLeftX = {} local keysPosChangesRightX = {} local keysPosChangesLeftY = {} local keysPosChangesRightY = {} local keysPosChangesLeftZ = {} local keysPosChangesRightZ = {} local boneChannelX = nil local boneChannelY = nil local boneChannelZ = nil if channel:AreDimensionsSplit() then if vec3 then boneChannelX = channel:DimensionChannel(0) boneChannelY = channel:DimensionChannel(1) boneChannelZ = channel:DimensionChannel(2) self:AnalizeChannel(moho, boneChannelX, keysPosChangesLeftX, keysPosChangesRightX) self:AnalizeChannel(moho, boneChannelY, keysPosChangesLeftY, keysPosChangesRightY) self:AnalizeChannel(moho, boneChannelZ, keysPosChangesLeftZ, keysPosChangesRightZ) else boneChannelX = channel:DimensionChannel(0) boneChannelY = channel:DimensionChannel(1) self:AnalizeChannel(moho, boneChannelX, keysPosChangesLeftX, keysPosChangesRightX) self:AnalizeChannel(moho, boneChannelY, keysPosChangesLeftY, keysPosChangesRightY) end else for keyID = 0, channel:CountKeys() - 1 do local keyFrame = channel:GetKeyWhen(keyID) if (keyFrame > 0 and channel:IsKeySelectedByID(keyID)) then self.isKeysSelected = true self:PrepUndo(moho) -- LEFT if keyFrame - self.smoothFrameOffset > 0 and channel:CountKeys() > keyID + 1 then local isOk = false local targetFrame = keyFrame - self.smoothFrameOffset local closestKey = channel:GetKeyWhen(keyID - 1) local nextFrame = channel:GetKeyWhen(keyID + 1) if closestKey > 0 and closestKey > targetFrame then targetFrame = closestKey end local nextKeyValue local targetKeyValue local prevKeyValue if vec3 then nextKeyValue = LM.Vector3:new_local() targetKeyValue = LM.Vector3:new_local() prevKeyValue = LM.Vector3:new_local() else nextKeyValue = LM.Vector2:new_local() targetKeyValue = LM.Vector2:new_local() prevKeyValue = LM.Vector2:new_local() end targetKeyValue = channel:GetValue(keyFrame) nextKeyValue:Set(channel:GetValue(channel:GetKeyWhen(keyID + 1))) prevKeyValue = channel:GetValue(channel:GetKeyWhen(keyID - 1)) if not channel:HasKey(targetFrame) then if vec3 then local dif = LM.Vector3:new_local() dif:Set(channel:GetValue(closestKey) - targetKeyValue) if math.abs(self:Round(dif.x, 4)) < self.allowDifference or math.abs(self:Round(dif.y, 4)) < self.allowDifference or math.abs(self:Round(dif.z, 4)) < self.allowDifference then isOk = true end else local dif = LM.Vector2:new_local() dif:Set(channel:GetValue(closestKey) - targetKeyValue) if math.abs(self:Round(dif.x, 4)) < self.allowDifference or math.abs(self:Round(dif.y, 4)) < self.allowDifference then isOk = true end end else isOk = true end if targetKeyValue ~= nextKeyValue and nextKeyValue ~= nil and isOk then local difValue = LM.Vector2:new_local() local newValue = LM.Vector2:new_local() if vec3 then difValue = LM.Vector3:new_local() newValue = LM.Vector3:new_local() end local newValueX local newValueY local newValueZ difValue:Set(nextKeyValue - targetKeyValue) if vec3 then newValue:Set(targetKeyValue.x + ((difValue.x / 100) * self.smoothStepValue), targetKeyValue.y + ((difValue.y / 100) * self.smoothStepValue), targetKeyValue.z + ((difValue.z / 100) * self.smoothStepValue)) if self.useChannelX and self.useChannelY and self.useChannelZ then -- X Y Z newValueX = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, closestKey, nextFrame) newValueY = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, closestKey, nextFrame) newValueZ = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.z, prevKeyValue.z, nextKeyValue.z, closestKey, targetFrame, closestKey, nextFrame) elseif self.useChannelX and self.useChannelY and not self.useChannelZ then -- X Y newValueX = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, closestKey, nextFrame) newValueY = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, closestKey, nextFrame) newValueZ = targetKeyValue.z elseif not self.useChannelX and self.useChannelY and not self.useChannelZ then -- Y newValueX = targetKeyValue.x newValueY = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, closestKey, nextFrame) newValueZ = targetKeyValue.z elseif not self.useChannelX and self.useChannelY and self.useChannelZ then -- Y Z newValueX = targetKeyValue.x newValueY = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, closestKey, nextFrame) newValueZ = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.z, prevKeyValue.z, nextKeyValue.z, closestKey, targetFrame, closestKey, nextFrame) elseif self.useChannelX and not self.useChannelY and not self.useChannelZ then -- X newValueX = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, closestKey, nextFrame) newValueY = targetKeyValue.y newValueZ = targetKeyValue.z elseif self.useChannelX and not self.useChannelY and self.useChannelZ then -- X Z newValueX = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, closestKey, nextFrame) newValueY = targetKeyValue.y newValueZ = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.z, prevKeyValue.z, nextKeyValue.z, closestKey, targetFrame, closestKey, nextFrame) elseif not self.useChannelX and not self.useChannelY and self.useChannelZ then -- Z newValueX = targetKeyValue.x newValueY = targetKeyValue.y newValueZ = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.z, prevKeyValue.z, nextKeyValue.z, closestKey, targetFrame, closestKey, nextFrame) end newValue:Set(newValueX, newValueY, newValueZ) else newValue:Set(targetKeyValue.x + ((difValue.x / 100) * self.smoothStepValue), targetKeyValue.y + ((difValue.y / 100) * self.smoothStepValue)) if self.useChannelX and self.useChannelY then -- X Y Z newValueX = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, closestKey, nextFrame) newValueY = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, closestKey, nextFrame) elseif self.useChannelX and self.useChannelY and not self.useChannelZ then -- X Y newValueX = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, closestKey, nextFrame) newValueY = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, closestKey, nextFrame) elseif not self.useChannelX and self.useChannelY and not self.useChannelZ then -- Y newValueX = targetKeyValue.x newValueY = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, closestKey, nextFrame) elseif not self.useChannelX and self.useChannelY and self.useChannelZ then -- Y Z newValueX = targetKeyValue.x newValueY = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, closestKey, nextFrame) elseif self.useChannelX and not self.useChannelY and not self.useChannelZ then -- X newValueX = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, closestKey, nextFrame) newValueY = targetKeyValue.y elseif self.useChannelX and not self.useChannelY and self.useChannelZ then -- X Z newValueX = self:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, closestKey, nextFrame) newValueY = targetKeyValue.y elseif not self.useChannelX and not self.useChannelY and self.useChannelZ then -- Z newValueX = targetKeyValue.x newValueY = targetKeyValue.y end if self.useChannelX or self.useChannelY then newValue:Set(newValueX, newValueY) end end local keyData = {} keyData.frame = keyFrame keyData.extraFrame = targetFrame keyData.keyValue = newValue keyData.difValue = difValue table.insert(keysPosChangesLeft, keyData) end end -- RIGHT local isOk = false local targetFrame = keyFrame + self.smoothFrameOffset local closestKey = keyFrame local prewFrame = channel:GetKeyWhen(keyID - 1) local prevKeyValue local targetKeyValue local nextKeyValue if vec3 then prevKeyValue = LM.Vector3:new_local() targetKeyValue = LM.Vector3:new_local() nextKeyValue = LM.Vector3:new_local() else prevKeyValue = LM.Vector2:new_local() targetKeyValue = LM.Vector2:new_local() nextKeyValue = LM.Vector2:new_local() end prevKeyValue:Set(channel:GetValue(channel:GetKeyWhen(keyID - 1))) targetKeyValue:Set(channel:GetValue(keyFrame)) nextKeyValue:Set(channel:GetValue(keyFrame)) if channel:CountKeys() > keyID + 1 then closestKey = channel:GetKeyWhen(keyID + 1) nextKeyValue = channel:GetValue(channel:GetKeyWhen(keyID + 1)) end if closestKey ~= keyFrame and closestKey < targetFrame then targetFrame = closestKey end if not channel:HasKey(targetFrame) then if vec3 then local dif = LM.Vector3:new_local() dif:Set(channel:GetValue(closestKey) - targetKeyValue) if math.abs(self:Round(dif.x, 4)) < self.allowDifference or math.abs(self:Round(dif.y, 4)) < self.allowDifference or math.abs(self:Round(dif.x, 4)) < self.allowDifference then isOk = true end else local dif = LM.Vector2:new_local() dif:Set(channel:GetValue(closestKey) - targetKeyValue) if math.abs(self:Round(dif.x, 4)) < self.allowDifference or math.abs(self:Round(dif.y, 4)) < self.allowDifference then isOk = true end end else isOk = true end if targetKeyValue ~= prevKeyValue and prevKeyValue ~= nil and isOk then local difValue = prevKeyValue - targetKeyValue local newValue = LM.Vector2:new_local() local newValueX local newValueY local newValueZ if vec3 then newValue = LM.Vector3:new_local() newValue:Set(targetKeyValue.x + ((difValue.x / 100) * self.smoothStepValue), targetKeyValue.y + ((difValue.y / 100) * self.smoothStepValue), targetKeyValue.z + ((difValue.z / 100) * self.smoothStepValue)) if self.useChannelX and self.useChannelY and self.useChannelZ then -- X Y Z newValueX = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, prewFrame, closestKey) newValueY = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, prewFrame, closestKey) newValueZ = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.z, prevKeyValue.z, nextKeyValue.z, closestKey, targetFrame, prewFrame, closestKey) elseif self.useChannelX and self.useChannelY and not self.useChannelZ then -- X Y newValueX = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, prewFrame, closestKey) newValueY = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, prewFrame, closestKey) newValueZ = targetKeyValue.z elseif not self.useChannelX and self.useChannelY and not self.useChannelZ then -- Y newValueX = targetKeyValue.x newValueY = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, prewFrame, closestKey) newValueZ = targetKeyValue.z elseif not self.useChannelX and self.useChannelY and self.useChannelZ then -- Y Z newValueX = targetKeyValue.x newValueY = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, prewFrame, closestKey) newValueZ = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.z, prevKeyValue.z, nextKeyValue.z, closestKey, targetFrame, prewFrame, closestKey) elseif self.useChannelX and not self.useChannelY and not self.useChannelZ then -- X newValueX = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, prewFrame, closestKey) newValueY = targetKeyValue.y newValueZ = targetKeyValue.z elseif self.useChannelX and not self.useChannelY and self.useChannelZ then -- X Z newValueX = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, prewFrame, closestKey) newValueY = targetKeyValue.y newValueZ = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.z, prevKeyValue.z, nextKeyValue.z, closestKey, targetFrame, prewFrame, closestKey) elseif not self.useChannelX and not self.useChannelY and self.useChannelZ then -- Z newValueX = targetKeyValue.x newValueY = targetKeyValue.y newValueZ = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.z, prevKeyValue.z, nextKeyValue.z, closestKey, targetFrame, prewFrame, closestKey) end newValue:Set(newValueX, newValueY, newValueZ) else newValue:Set(targetKeyValue.x + ((difValue.x / 100) * self.smoothStepValue), targetKeyValue.y + ((difValue.y / 100) * self.smoothStepValue)) if self.useChannelX and self.useChannelY and self.useChannelZ then -- X Y Z newValueX = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, prewFrame, closestKey) newValueY = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, prewFrame, closestKey) elseif self.useChannelX and self.useChannelY and not self.useChannelZ then -- X Y newValueX = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, prewFrame, closestKey) newValueY = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, prewFrame, closestKey) elseif not self.useChannelX and self.useChannelY and not self.useChannelZ then -- Y newValueX = targetKeyValue.x newValueY = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, prewFrame, closestKey) elseif not self.useChannelX and self.useChannelY and self.useChannelZ then -- Y Z newValueX = targetKeyValue.x newValueY = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.y, prevKeyValue.y, nextKeyValue.y, closestKey, targetFrame, prewFrame, closestKey) elseif self.useChannelX and not self.useChannelY and not self.useChannelZ then -- X newValueX = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, prewFrame, closestKey) newValueY = targetKeyValue.y elseif self.useChannelX and not self.useChannelY and self.useChannelZ then -- X Z newValueX = self:AnalizeAdjactedPosKeysRight(moho, targetKeyValue.x, prevKeyValue.x, nextKeyValue.x, closestKey, targetFrame, prewFrame, closestKey) newValueY = targetKeyValue.y elseif not self.useChannelX and not self.useChannelY and self.useChannelZ then -- Z newValueX = targetKeyValue.x newValueY = targetKeyValue.y end if self.useChannelX or self.useChannelY then newValue:Set(newValueX, newValueY) end end local keyData = {} keyData.frame = keyFrame keyData.extraFrame = targetFrame keyData.keyValue = newValue keyData.difValue = difValue table.insert(keysPosChangesRight, keyData) end end end end if channel:AreDimensionsSplit() then if vec3 then self:SmoothChannel(moho, boneChannelX, keysPosChangesLeftX, keysPosChangesRightX) self:SmoothChannel(moho, boneChannelY, keysPosChangesLeftY, keysPosChangesRightY) self:SmoothChannel(moho, boneChannelZ, keysPosChangesLeftZ, keysPosChangesRightZ) else self:SmoothChannel(moho, boneChannelX, keysPosChangesLeftX, keysPosChangesRightX) self:SmoothChannel(moho, boneChannelY, keysPosChangesLeftY, keysPosChangesRightY) end else for i, a in pairs(keysPosChangesLeft) do local isOkX = false local isOkY = false local isOkZ = false local dubFound = false for k, b in pairs(keysPosChangesRight) do if a.frame == b.frame then if math.abs(a.difValue.x) > math.abs(b.difValue.x) then isOkX = true end if math.abs(a.difValue.y) > math.abs(b.difValue.y) then isOkY = true end if vec3 then if math.abs(a.difValue.z) > math.abs(b.difValue.z) then isOkZ = true end end dubFound = true end end if not dubFound then isOkX = true isOkY = true if vec3 then isOkZ = true end end if isOkX then if vec3 then local xValue = LM.Vector3:new_local() xValue:Set(a.keyValue.x, channel:GetValue(a.frame).y, channel:GetValue(a.frame).z) channel:SetValue(a.extraFrame, channel:GetValue(a.extraFrame)) channel:SetValue(a.frame, xValue) else if self.useChannelX or self.useChannelY then local xValue = LM.Vector2:new_local() xValue:Set(a.keyValue.x, channel:GetValue(a.frame).y) channel:SetValue(a.extraFrame, channel:GetValue(a.extraFrame)) channel:SetValue(a.frame, xValue) end end end if isOkY then if vec3 then local yValue = LM.Vector3:new_local() yValue:Set(channel:GetValue(a.frame).x, a.keyValue.y, channel:GetValue(a.frame).z) channel:SetValue(a.extraFrame, channel:GetValue(a.extraFrame)) channel:SetValue(a.frame, yValue) else if self.useChannelX or self.useChannelY then local yValue = LM.Vector2:new_local() yValue:Set(channel:GetValue(a.frame).x, a.keyValue.y) channel:SetValue(a.extraFrame, channel:GetValue(a.extraFrame)) channel:SetValue(a.frame, yValue) end end end if isOkZ and vec3 then local zValue = LM.Vector3:new_local() zValue:Set(channel:GetValue(a.frame).x, channel:GetValue(a.frame).y, a.keyValue.z) channel:SetValue(a.extraFrame, channel:GetValue(a.extraFrame)) channel:SetValue(a.frame, zValue) end end for n, r in pairs(keysPosChangesRight) do local isOkX = false local isOkY = false local isOkZ = false local dubFound = false for k, b in pairs(keysPosChangesLeft) do if r.frame == b.frame then if math.abs(r.difValue.x) > math.abs(b.difValue.x) then isOkX = true end if math.abs(r.difValue.y) > math.abs(b.difValue.y) then isOkY = true end if vec3 then if math.abs(r.difValue.z) > math.abs(b.difValue.z) then isOkZ = true end end dubFound = true end end if not dubFound then isOkX = true isOkY = true if vec3 then isOkZ = true end end if isOkX then if vec3 then local xValue = LM.Vector3:new_local() xValue:Set(r.keyValue.x, channel:GetValue(r.frame).y, channel:GetValue(r.frame).z) channel:SetValue(r.extraFrame, channel:GetValue(r.extraFrame)) channel:SetValue(r.frame, xValue) else if self.useChannelX or self.useChannelY then local xValue = LM.Vector2:new_local() xValue:Set(r.keyValue.x, channel:GetValue(r.frame).y) channel:SetValue(r.extraFrame, channel:GetValue(r.extraFrame)) channel:SetValue(r.frame, xValue) end end end if isOkY then if vec3 then local yValue = LM.Vector3:new_local() yValue:Set(channel:GetValue(r.frame).x, r.keyValue.y, channel:GetValue(r.frame).z) channel:SetValue(r.extraFrame, channel:GetValue(r.extraFrame)) channel:SetValue(r.frame, yValue) else if self.useChannelX or self.useChannelY then local yValue = LM.Vector2:new_local() yValue:Set(channel:GetValue(r.frame).x, r.keyValue.y) channel:SetValue(r.extraFrame, channel:GetValue(r.extraFrame)) channel:SetValue(r.frame, yValue) end end end if isOkZ and vec3 then local zValue = LM.Vector3:new_local() zValue:Set(channel:GetValue(r.frame).x, channel:GetValue(r.frame).y, r.keyValue.z) channel:SetValue(r.extraFrame, channel:GetValue(r.extraFrame)) channel:SetValue(r.frame, zValue) end end end end function MR_KeyMotion:AnalizeChannel(moho, channel, listLeft, listRight) local boneChannel = channel for keyID = 0, boneChannel:CountKeys() - 1 do local keyFrame = boneChannel:GetKeyWhen(keyID) if (keyFrame > 0 and boneChannel:IsKeySelectedByID(keyID)) then self.isKeysSelected = true self:PrepUndo(moho) -- LEFT if keyFrame - self.smoothFrameOffset > 0 and boneChannel:CountKeys() > keyID + 1 then local isOk = true local targetFrame = keyFrame - self.smoothFrameOffset local closestKey = boneChannel:GetKeyWhen(keyID - 1) local nextKey = boneChannel:GetValue(keyFrame) if closestKey > 0 and closestKey > targetFrame then targetFrame = closestKey end local targetKeyValue = boneChannel:GetValue(keyFrame) local nextKeyValue = targetKeyValue if boneChannel:CountKeys() > keyID + 1 then nextKeyValue = boneChannel:GetValue(boneChannel:GetKeyWhen(keyID + 1)) nextKey = boneChannel:GetKeyWhen(keyID + 1) end if not boneChannel:HasKey(targetFrame) then local dif = self:Round(boneChannel:GetValue(closestKey) - targetKeyValue, 4) if math.abs(dif) > self.allowDifference then isOk = false end end if targetKeyValue ~= nextKeyValue and nextKeyValue ~= nil and isOk then local smoothThresholdValue = self.smoothThresholdValue smoothThresholdValue = smoothThresholdValue / math.abs(((boneChannel:GetKeyWhen(keyID - 1) - nextKey) / 50)) local prevKeyValue = boneChannel:GetValue(boneChannel:GetKeyWhen(keyID - 1)) local difAdjactedPrcntValue = ((prevKeyValue - nextKeyValue) / 100) * smoothThresholdValue local difValue = nextKeyValue - targetKeyValue local newValue = targetKeyValue + ((difValue / 100) * self.smoothStepValue) if closestKey >= targetFrame then if prevKeyValue > nextKeyValue then if targetKeyValue < nextKeyValue then difValue = -difValue end if prevKeyValue - difAdjactedPrcntValue > targetKeyValue then newValue = targetKeyValue - ((difValue / 100) * self.smoothStepValue) if prevKeyValue - difAdjactedPrcntValue < newValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = prevKeyValue - difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until prevKeyValue - difAdjactedPrcntValue > targetKeyValue - tempValue newValue = targetKeyValue - tempValue end end if prevKeyValue - difAdjactedPrcntValue > newValue and prevKeyValue - difAdjactedPrcntValue < targetKeyValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = prevKeyValue - difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until prevKeyValue - difAdjactedPrcntValue < targetKeyValue + tempValue newValue = targetKeyValue + tempValue end else if targetKeyValue > nextKeyValue then difValue = -difValue end if prevKeyValue - difAdjactedPrcntValue < targetKeyValue then newValue = targetKeyValue - ((difValue / 100) * self.smoothStepValue) if prevKeyValue - difAdjactedPrcntValue > newValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = prevKeyValue - difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until prevKeyValue - difAdjactedPrcntValue < targetKeyValue - tempValue newValue = targetKeyValue - tempValue end end if prevKeyValue - difAdjactedPrcntValue < newValue and prevKeyValue - difAdjactedPrcntValue > targetKeyValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = prevKeyValue - difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until prevKeyValue - difAdjactedPrcntValue > targetKeyValue + tempValue newValue = targetKeyValue + tempValue end end end local keyData = {} keyData.frame = keyFrame keyData.extraFrame = targetFrame keyData.keyValue = newValue keyData.difValue = difValue table.insert(listLeft, keyData) end end -- RIGHT local isOkR = true local targetFrame = keyFrame + self.smoothFrameOffset local closestKey = keyFrame local nextKeyValue = boneChannel:GetValue(keyFrame) local nextKey = boneChannel:GetValue(keyFrame) if boneChannel:CountKeys() - 1 > keyID + 1 then closestKey = boneChannel:GetKeyWhen(keyID + 1) nextKeyValue = boneChannel:GetValue(boneChannel:GetKeyWhen(keyID + 1)) nextKey = boneChannel:GetKeyWhen(keyID + 1) end if closestKey ~= keyFrame and closestKey < targetFrame then targetFrame = closestKey end local prevKeyValue = boneChannel:GetValue(boneChannel:GetKeyWhen(keyID - 1)) local targetKeyValue = boneChannel:GetValue(keyFrame) if not boneChannel:HasKey(targetFrame) then local dif = self:Round(boneChannel:GetValue(closestKey) - targetKeyValue, 4) if math.abs(dif) > self.allowDifference then isOkR = false end end if targetKeyValue ~= prevKeyValue and prevKeyValue ~= nil and isOkR then local smoothThresholdValue = self.smoothThresholdValue smoothThresholdValue = smoothThresholdValue / math.abs(((boneChannel:GetKeyWhen(keyID - 1) - closestKey) / 50)) local difAdjactedPrcntValue = ((prevKeyValue - nextKeyValue) / 100) * smoothThresholdValue local difValue = prevKeyValue - targetKeyValue local newValue = targetKeyValue + ((difValue / 100) * self.smoothStepValue) if closestKey >= targetFrame then if prevKeyValue < nextKeyValue then if targetKeyValue < prevKeyValue then difValue = -difValue end if nextKeyValue + difAdjactedPrcntValue > targetKeyValue then newValue = targetKeyValue - ((difValue / 100) * self.smoothStepValue) if nextKeyValue + difAdjactedPrcntValue < newValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = newValue + difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until nextKeyValue + difAdjactedPrcntValue > targetKeyValue - tempValue newValue = targetKeyValue - tempValue end end if nextKeyValue + difAdjactedPrcntValue > newValue and nextKeyValue + difAdjactedPrcntValue < targetKeyValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = newValue + difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until nextKeyValue + difAdjactedPrcntValue < targetKeyValue + tempValue newValue = targetKeyValue + tempValue end else if targetKeyValue > prevKeyValue then difValue = -difValue end if nextKeyValue + difAdjactedPrcntValue < targetKeyValue then newValue = targetKeyValue - ((difValue / 100) * self.smoothStepValue) if nextKeyValue + difAdjactedPrcntValue > newValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = newValue + difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until nextKeyValue + difAdjactedPrcntValue < targetKeyValue - tempValue newValue = targetKeyValue - tempValue end end if nextKeyValue + difAdjactedPrcntValue < newValue and nextKeyValue + difAdjactedPrcntValue > targetKeyValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = newValue + difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until nextKeyValue + difAdjactedPrcntValue > targetKeyValue + tempValue newValue = targetKeyValue + tempValue end end end local keyData = {} keyData.frame = keyFrame keyData.extraFrame = targetFrame keyData.keyValue = newValue keyData.difValue = difValue table.insert(listRight, keyData) end end end end function MR_KeyMotion:AnalizeAdjactedPosKeysLeft(moho, targetKeyValue, prevKeyValue, nextKeyValue, closestKey, targetFrame, prewFrame, nextFreme) local smoothThresholdValue = self.smoothThresholdValue smoothThresholdValue = smoothThresholdValue / math.abs(((prewFrame - nextFreme) / 50)) local difAdjactedPrcntValue = ((prevKeyValue - nextKeyValue) / 100) * smoothThresholdValue local difValue = nextKeyValue - targetKeyValue local newValue = targetKeyValue + ((difValue / 100) * self.smoothStepValue) if closestKey >= targetFrame then if prevKeyValue > nextKeyValue then if targetKeyValue < nextKeyValue then difValue = -difValue end if prevKeyValue - difAdjactedPrcntValue > targetKeyValue then newValue = targetKeyValue - ((difValue / 100) * self.smoothStepValue) if prevKeyValue - difAdjactedPrcntValue < newValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = prevKeyValue - difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until prevKeyValue - difAdjactedPrcntValue > targetKeyValue - tempValue newValue = targetKeyValue - tempValue end end if prevKeyValue - difAdjactedPrcntValue > newValue and prevKeyValue - difAdjactedPrcntValue < targetKeyValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = prevKeyValue - difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until prevKeyValue - difAdjactedPrcntValue < targetKeyValue + tempValue newValue = targetKeyValue + tempValue end else if targetKeyValue > nextKeyValue then difValue = -difValue end if prevKeyValue - difAdjactedPrcntValue < targetKeyValue then newValue = targetKeyValue - ((difValue / 100) * self.smoothStepValue) if prevKeyValue - difAdjactedPrcntValue > newValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = prevKeyValue - difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until prevKeyValue - difAdjactedPrcntValue < targetKeyValue - tempValue newValue = targetKeyValue - tempValue end end if prevKeyValue - difAdjactedPrcntValue < newValue and prevKeyValue - difAdjactedPrcntValue > targetKeyValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = prevKeyValue - difAdjactedPrcntValue break end tempValue = tempValue * 0.75 steps = steps + 1 until prevKeyValue - difAdjactedPrcntValue > targetKeyValue + tempValue newValue = targetKeyValue + tempValue end end end return newValue end function MR_KeyMotion:AnalizeAdjactedPosKeysRight(moho, targetKeyValue, prevKeyValue, nextKeyValue, closestKey, targetFrame, prewFrame, nextFreme) local smoothThresholdValue = self.smoothThresholdValue smoothThresholdValue = smoothThresholdValue / math.abs(((prewFrame - nextFreme) / 50)) local difAdjactedPrcntValue = ((prevKeyValue - nextKeyValue) / 100) * smoothThresholdValue local difValue = prevKeyValue - targetKeyValue local newValue = targetKeyValue + ((difValue / 100) * self.smoothStepValue) if closestKey >= targetFrame then if prevKeyValue < nextKeyValue then if targetKeyValue < prevKeyValue then difValue = -difValue end if nextKeyValue + difAdjactedPrcntValue > targetKeyValue then newValue = targetKeyValue - ((difValue / 100) * self.smoothStepValue) if nextKeyValue + difAdjactedPrcntValue < newValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = nextKeyValue + difAdjactedPrcntValue break end tempValue = tempValue * 0.6 steps = steps + 1 until nextKeyValue + difAdjactedPrcntValue > targetKeyValue - tempValue newValue = targetKeyValue - tempValue end end if nextKeyValue + difAdjactedPrcntValue > newValue and nextKeyValue + difAdjactedPrcntValue < targetKeyValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = nextKeyValue + difAdjactedPrcntValue break end tempValue = tempValue * 0.6 steps = steps + 1 until nextKeyValue + difAdjactedPrcntValue < targetKeyValue + tempValue newValue = targetKeyValue + tempValue end else if targetKeyValue > prevKeyValue then difValue = -difValue end if nextKeyValue + difAdjactedPrcntValue < targetKeyValue then newValue = targetKeyValue - ((difValue / 100) * self.smoothStepValue) if nextKeyValue + difAdjactedPrcntValue > newValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = nextKeyValue + difAdjactedPrcntValue break end tempValue = tempValue * 0.6 steps = steps + 1 until nextKeyValue + difAdjactedPrcntValue < targetKeyValue - tempValue newValue = targetKeyValue - tempValue end end if nextKeyValue + difAdjactedPrcntValue < newValue and nextKeyValue + difAdjactedPrcntValue > targetKeyValue then local tempValue = ((difValue / 100) * self.smoothStepValue) local maxSteps = 10 local steps = 0 repeat if steps > maxSteps then newValue = nextKeyValue + difAdjactedPrcntValue break end tempValue = tempValue * 0.6 steps = steps + 1 until nextKeyValue + difAdjactedPrcntValue > targetKeyValue + tempValue newValue = targetKeyValue + tempValue end end end return newValue end function MR_KeyMotion:AnalizeAndPullChanelVal(moho, channel) local keysAngleChanges = {} self:AnalizeChannelForPull(moho, channel, keysAngleChanges) self:PullChannel(moho, channel, keysAngleChanges) end function MR_KeyMotion:AnalizeAndPullChanelVec(moho, channel) local keysPosChanges = {} local keysPosChangesX = {} local keysPosChangesY = {} local keysPosChangesZ = {} local channelX local channelY local channelZ local vec3 = false if moho:ChannelAsAnimVec3(channel) then vec3 = true end if channel:AreDimensionsSplit() then channelX = channel:DimensionChannel(0) channelY = channel:DimensionChannel(1) self:AnalizeChannelForPull(moho, channelX, keysPosChangesX) self:AnalizeChannelForPull(moho, channelY, keysPosChangesY) if vec3 then channelZ = channel:DimensionChannel(2) self:AnalizeChannelForPull(moho, channelZ, keysPosChangesZ) end else for keyID = 0, channel:CountKeys() - 1 do local keyFrame = channel:GetKeyWhen(keyID) if (keyFrame - self.pullFrameOffset > 0 and channel:IsKeySelectedByID(keyID)) then self.isKeysSelected = true self:PrepUndo(moho) local keyData = {} keyData.frame = keyFrame table.insert(keysPosChanges, keyData) end end end if channel:AreDimensionsSplit() then self:PullChannel(moho, channelX, keysPosChangesX) self:PullChannel(moho, channelY, keysPosChangesY) if vec3 then self:PullChannel(moho, channelZ, keysPosChangesZ) end else for i, a in pairs(keysPosChanges) do local prevKey = a.frame - self.pullFrameOffset local nextKey = a.frame + self.pullFrameOffset local closestPrevKey = channel:GetKeyWhen(channel:GetClosestKeyID(a.frame - 1)) local closestNextKey = nextKey if channel:CountKeys() > channel:GetClosestKeyID(a.frame) + 1 then closestNextKey = channel:GetKeyWhen(channel:GetClosestKeyID(a.frame) + 1) end if closestPrevKey < a.frame and closestPrevKey > prevKey then prevKey = closestPrevKey end if closestNextKey > a.frame and closestNextKey < nextKey then nextKey = closestNextKey end local targetKeyVal = LM.Vector2:new_local() targetKeyVal:Set(channel:GetValue(a.frame)) local val1 local dif1 local newValue1 local val2 local dif2 local newValue2 local dif3 local newValue3 if vec3 then targetKeyVal = LM.Vector3:new_local() targetKeyVal:Set(channel:GetValue(a.frame)) val1 = LM.Vector3:new_local() dif1 = LM.Vector3:new_local() newValue1 = LM.Vector3:new_local() val1:Set(channel:GetValue(prevKey)) dif1:Set(val1 - targetKeyVal) newValue1:Set(val1.x - (dif1.x / 100) * self.pullStepValue, val1.y - (dif1.y / 100) * self.pullStepValue, val1.z - (dif1.z / 100) * self.pullStepValue) val2 = LM.Vector3:new_local() dif2 = LM.Vector3:new_local() newValue2 = LM.Vector3:new_local() val2:Set(channel:GetValue(nextKey)) dif2:Set(val2 - targetKeyVal) newValue2:Set(val2.x - (dif2.x / 100) * self.pullStepValue, val2.y - (dif2.y / 100) * self.pullStepValue, val2.z - (dif2.z / 100) * self.pullStepValue) else val1 = LM.Vector2:new_local() dif1 = LM.Vector2:new_local() newValue1 = LM.Vector2:new_local() val1:Set(channel:GetValue(prevKey)) dif1:Set(val1 - targetKeyVal) newValue1:Set(val1.x - (dif1.x / 100) * self.pullStepValue, val1.y - (dif1.y / 100) * self.pullStepValue) val2 = LM.Vector2:new_local() dif2 = LM.Vector2:new_local() newValue2 = LM.Vector2:new_local() val2:Set(channel:GetValue(nextKey)) dif2:Set(val2 - targetKeyVal) newValue2:Set(val2.x - (dif2.x / 100) * self.pullStepValue, val2.y - (dif2.y / 100) * self.pullStepValue) end if vec3 then if val1.x > targetKeyVal.x and val2.x > targetKeyVal.x or val1.x < targetKeyVal.x and val2.x < targetKeyVal.x then local newValueX1 = LM.Vector3:new_local() local newValueX2 = LM.Vector3:new_local() if self.useChannelX then newValueX1:Set(newValue1.x, val1.y, val1.z) newValueX2:Set(newValue2.x, val2.y, val1.z) else newValueX1:Set(val1.x, val1.y, val1.z) newValueX2:Set(val1.x, val2.y, val1.z) end channel:SetValue(prevKey, newValueX1) channel:SetValue(nextKey, newValueX2) end if val1.y > targetKeyVal.y and val2.y > targetKeyVal.y or val1.y < targetKeyVal.y and val2.y < targetKeyVal.y then val1:Set(channel:GetValue(prevKey)) val2:Set(channel:GetValue(nextKey)) local newValueY1 = LM.Vector3:new_local() local newValueY2 = LM.Vector3:new_local() if self.useChannelY then newValueY1:Set(val1.x, newValue1.y, val1.z) newValueY2:Set(val2.x, newValue2.y, val1.z) else newValueY1:Set(val1.x, val1.y, val1.z) newValueY2:Set(val2.x, val1.y, val1.z) end channel:SetValue(prevKey, newValueY1) channel:SetValue(nextKey, newValueY2) end if val1.z > targetKeyVal.z and val2.z > targetKeyVal.z or val1.z < targetKeyVal.z and val2.z < targetKeyVal.z then val1:Set(channel:GetValue(prevKey)) val2:Set(channel:GetValue(nextKey)) local newValueY1 = LM.Vector3:new_local() local newValueY2 = LM.Vector3:new_local() if self.useChannelZ then newValueY1:Set(val1.x, val1.y, newValue1.z) newValueY2:Set(val2.x, val1.y, newValue2.z) else newValueY1:Set(val1.x, val1.y, val1.z) newValueY2:Set(val2.x, val1.y, val1.z) end channel:SetValue(prevKey, newValueY1) channel:SetValue(nextKey, newValueY2) end else if val1.x > targetKeyVal.x and val2.x > targetKeyVal.x or val1.x < targetKeyVal.x and val2.x < targetKeyVal.x then local newValueX1 = LM.Vector2:new_local() local newValueX2 = LM.Vector2:new_local() if self.useChannelX then newValueX1:Set(newValue1.x, val1.y) newValueX2:Set(newValue2.x, val2.y) else newValueX1:Set(val1.x, val1.y) newValueX2:Set(val1.x, val2.y) end if self.useChannelX or self.useChannelY then channel:SetValue(prevKey, newValueX1) channel:SetValue(nextKey, newValueX2) end end if val1.y > targetKeyVal.y and val2.y > targetKeyVal.y or val1.y < targetKeyVal.y and val2.y < targetKeyVal.y then val1:Set(channel:GetValue(prevKey)) val2:Set(channel:GetValue(nextKey)) local newValueY1 = LM.Vector2:new_local() local newValueY2 = LM.Vector2:new_local() if self.useChannelY then newValueY1:Set(val1.x, newValue1.y) newValueY2:Set(val2.x, newValue2.y) else newValueY1:Set(val1.x, val1.y) newValueY2:Set(val2.x, val1.y) end if self.useChannelX or self.useChannelY then channel:SetValue(prevKey, newValueY1) channel:SetValue(nextKey, newValueY2) end end end end end end function MR_KeyMotion:AnalizeChannelForPull(moho, channel, keyList) local boneChannel = channel for keyID = 0, boneChannel:CountKeys() - 1 do local keyFrame = boneChannel:GetKeyWhen(keyID) if (keyFrame - self.pullFrameOffset > 0 and boneChannel:IsKeySelectedByID(keyID)) then self.isKeysSelected = true self:PrepUndo(moho) local keyData = {} keyData.frame = keyFrame table.insert(keyList, keyData) end end end function MR_KeyMotion:PullChannel(moho, channel, keyList) for i, a in pairs(keyList) do local val1 = channel:GetValue(a.frame - self.pullFrameOffset) local dif1 = val1 - channel:GetValue(a.frame) local newValue1 = val1 - (dif1 / 100) * self.pullStepValue channel:SetValue(a.frame - self.pullFrameOffset, newValue1) local val2 = channel:GetValue(a.frame + self.pullFrameOffset) local dif2 = val2 - channel:GetValue(a.frame) local newValue2 = val2 - (dif2 / 100) * self.pullStepValue channel:SetValue(a.frame + self.pullFrameOffset, newValue2) end end function MR_KeyMotion:Round(x,n) n = math.pow(10, n or 4) 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_KeyMotion:PrepUndo(moho) if not self.isUndoPrepared then moho.document:SetDirty() moho.document:PrepUndo(moho.layer, true) self.isUndoPrepared = true end end function MR_KeyMotion:TransformChannelVal(moho, channel) for keyID = 0, channel:CountKeys() - 1 do local keyFrame = channel:GetKeyWhen(keyID) if (keyFrame > 0 and channel:IsKeySelectedByID(keyID)) then self.isKeysSelected = true if MR_KeyMotion.smooth then self:AnalizeAndSmoothChanelVal(moho, channel) elseif MR_KeyMotion.pull then self:AnalizeAndPullChanelVal(moho, channel) elseif MR_KeyMotion.scale then self:ScaleChannel(moho, channel, false, false) end break end end end function MR_KeyMotion:TransformChannelVec(moho, channel) if channel:AreDimensionsSplit() then for i=0, 2 do local subChannel = channel:DimensionChannel(i) for keyID = 0, subChannel:CountKeys() - 1 do local keyFrame = subChannel:GetKeyWhen(keyID) if (keyFrame > 0 and subChannel:IsKeySelectedByID(keyID)) then self.isKeysSelected = true if MR_KeyMotion.smooth then self:AnalizeAndSmoothChanelVec(moho, channel) elseif MR_KeyMotion.pull then self:AnalizeAndPullChanelVec(moho, channel) elseif MR_KeyMotion.scale then self:ScaleChannel(moho, subChannel, false, false) elseif MR_KeyMotion.flip then self:ScaleChannel(moho, subChannel, false, true) end break end end end else for keyID = 0, channel:CountKeys() - 1 do local keyFrame = channel:GetKeyWhen(keyID) if (keyFrame > 0 and channel:IsKeySelectedByID(keyID)) then self.isKeysSelected = true if MR_KeyMotion.smooth then self:AnalizeAndSmoothChanelVec(moho, channel) elseif MR_KeyMotion.pull then self:AnalizeAndPullChanelVec(moho, channel) elseif MR_KeyMotion.scale then self:ScaleChannel(moho, channel, true, false) elseif MR_KeyMotion.flip then self:ScaleChannel(moho, channel, true, true) end break end end end end -- ************************************************** -- Localization -- ************************************************** function MR_KeyMotion:Localize(text) local phrase = {} phrase['Description'] = 'Smooth, pull, scale and flip keys motion' phrase['UILabel'] = 'Key Motion' phrase['Smooth'] = 'Smooth' phrase['Pull'] = 'Pull' phrase['Scale'] = 'Scale' phrase['Flip'] = 'Flip' phrase['Transform Top'] = 'Transform From Top' phrase['Transform Mid'] = 'Transform From Center' phrase['Transform Down'] = 'Transform From Down' phrase['Scale In'] = 'Scale In' phrase['Scale Out'] = 'Scale Out' phrase['Transform X'] = 'Transform X Channel' phrase['Transform Y'] = 'Transform Y Channel' phrase['Smooth Percentage'] = '' phrase['Scale Percentage'] = '' phrase['Pull Percentage'] = '' return phrase[text] end
MR Key Motion
Listed
Author: eugenebabich
View Script
Script type: Button/Menu
Uploaded: Feb 25 2023, 19:21
This script helps you to smooth your animation in a fast and convenient way.
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: 359

MR Key Motion
Listed
Author: eugenebabich
View Script
Script type: Button/Menu
Uploaded: Feb 25 2023, 19:21
This script helps you to smooth your animation in a fast and convenient way.
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: 359