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

ScriptName = "AE_ResetLayerTransform"

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

AE_ResetLayerTransform = {}

function AE_ResetLayerTransform:Name()
	return "Reset Layer Transform"
end

function AE_ResetLayerTransform:Version()
	return "2.3"
end

function AE_ResetLayerTransform:UILabel()
	return "Reset Layer Transform"
end

function AE_ResetLayerTransform:Creator()
	return "Alexandra Evseeva"
end

function AE_ResetLayerTransform:Description()
	return "Set layer translation, scale and rotation Z to default values, saving vertices and child layers unmoved."
end




-- **************************************************
-- Recurring values
-- **************************************************

-- AE_ResetLayerTransform.value1 = false

-- **************************************************
-- Is Enabled
-- **************************************************

function AE_ResetLayerTransform:IsEnabled(moho)
	return true
end


-- **************************************************
-- The guts of this script
-- **************************************************

function AE_ResetLayerTransform:IsKeyframe(moho, frame, actionName)
	local skel = moho:Skeleton()
	for b = 0, skel:CountBones() - 1 do
		for i, j in pairs({'fAnimPos', 'fAnimAngle', 'fAnimScale'}) do
			local channel = skel:Bone(b)[j]
			if actionName then channel = channel:ActionByName(actionName) end
			if channel and channel:HasKey(frame) then
				return true
			end
		end
	end
	return false
end

function AE_ResetLayerTransform:NearestAngle(oldAngle, newAngle, toPrint)
	--if toPrint then print(oldAngle, " ", newAngle) end
	local dist = newAngle - oldAngle
	if math.abs(dist) < math.pi then return newAngle end
	--if toPrint then print(dist) end
	if math.abs(dist) >= (2 * math.pi) then dist = (dist % (2 * math.pi))*(dist/math.abs(dist)) end
	--if toPrint then print(dist) end	
	if math.abs(dist) > math.pi then
		local absDist = math.abs(dist) - (math.pi * 2)
		dist = absDist * (dist/math.abs(dist))
	end
	--if toPrint then print(dist) end	
	return (oldAngle + dist)
end

function AE_ResetLayerTransform:ApplyBoneTransform(moho, skel, boneID, mainMatrix, oldMatrixes, frame, actionName)
	-- apply to called bone 
	if not actionName then actionName = '' end
	local oldMatrix = oldMatrixes[boneID][actionName][frame]
	if not oldMatrix then 
		return
	end
	local tempMatrix = LM.Matrix:new_local()
	tempMatrix:Set(mainMatrix)
	tempMatrix:Multiply(oldMatrix)
	local newMatrix = LM.Matrix:new_local()
	newMatrix:Set(tempMatrix)
	local parentID = skel:Bone(boneID).fAnimParent:GetValue(0)
	if  parentID > -1 then
		local parentMatrix = AE_Utilities:GetGlobalBoneMatrix(moho, skel, skel:Bone(parentID), frame, actionName)
		tempMatrix:Set(parentMatrix)
		tempMatrix:Invert()
		tempMatrix:Multiply(newMatrix)
		newMatrix:Set(tempMatrix)
	end
	local p, r, s = AE_Utilities:Matrix2transform(newMatrix, false, true)
	-- apply p, r, s to the bone itself
	if frame == 0 then
		-- set p, r  and length
		skel:Bone(boneID).fAnimPos:SetValue(0, p)
		local oldAngle = skel:Bone(boneID).fAnimAngle:GetValue(0)
		-- get nearest angle
		r = self:NearestAngle(oldAngle, r)
		skel:Bone(boneID).fAnimAngle:SetValue(0, r)
		skel:Bone(boneID).fLength = skel:Bone(boneID).fLength * s.x
	else
		-- set p, r, s if channel has corresponding key in called frame
		local channel = skel:Bone(boneID).fAnimPos
		if actionName ~= '' then channel = channel:ActionByName(actionName) end
		if channel and channel:HasKey(frame) then
			channel = moho:ChannelAsAnimVec2(channel)
			channel:SetValue(frame, p)
		end
		local channel = skel:Bone(boneID).fAnimAngle		
		if actionName ~= '' then channel = channel:ActionByName(actionName) end
		if channel and channel:HasKey(frame) then
			channel = moho:ChannelAsAnimVal(channel)
			local oldAngle = channel:GetValue(frame)
			r = self:NearestAngle(oldAngle, r)
			channel:SetValue(frame, r)
		end	
		--  do nothing with scale
	end
	skel:UpdateBoneMatrix(boneID)
	-- and then apply recursive method to bones children
	for i = 0, skel:CountBones() - 1 do
		if skel:Bone(i).fAnimParent:GetValue(0) == boneID then
			self:ApplyBoneTransform(moho, skel, i, mainMatrix, oldMatrixes, frame, actionName)
		end
	end
end

function AE_ResetLayerTransform:Run(moho)

	moho.document:PrepUndo(moho.layer)
	moho.document:SetDirty()
	
	self:Eval(moho, moho.layer)

end
	
function AE_ResetLayerTransform:Eval(moho, mainLayer)	

	local printOutput = false --output calculated values for debug	
	local mainMatrix = LM.Matrix:new_local()
	mainLayer:GetLayerTransform(moho.layerFrame, mainMatrix, moho.document)

	if not mainLayer:Parent() then

		local cameraMatrix = LM.Matrix:new_local()
		moho.document:GetCameraMatrix(moho.frame, cameraMatrix)
		cameraMatrix:Invert()
		cameraMatrix:Multiply(mainMatrix)
		mainMatrix:Set(cameraMatrix)
		
		if printOutput then AE_Utilities:Matrix2transform(cameraMatrix,printOutput) end

	end
	
	if mainLayer:LayerType() == MOHO.LT_VECTOR then
		local mesh = moho:LayerAsVector(mainLayer):Mesh()
		for p = 0, mesh:CountPoints()-1 do
			local point = mesh:Point(p)
			local currentPos = point.fAnimPos:GetValue(moho.layerFrame)
			mainMatrix:Transform(currentPos)
			point.fAnimPos:SetValue(moho.layerFrame, currentPos)
			if mainLayer.fFlipH:GetValue(moho.layerFrame) or mainLayer.fFlipV:GetValue(moho.layerFrame) then
				for c = 0, point:CountCurves() - 1 do
					local curve, pointID = point:Curve(c)
					local inOffset = curve:GetOffset(pointID, moho.layerFrame, true)
					local outOffset = curve:GetOffset(pointID, moho.layerFrame, false)
					curve:SetOffset(pointID, -inOffset, moho.layerFrame, true)
					curve:SetOffset(pointID, -outOffset, moho.layerFrame, false)
				end
			end
			if moho.layerFrame == 0 then
				for k = 1, point.fAnimPos:CountKeys()-1 do
					currentPos = point.fAnimPos:GetValueByID(k)
					mainMatrix:Transform(currentPos)
					point.fAnimPos:SetValueByID(k, currentPos)					
					local layerFrame = point.fAnimPos:GetKeyWhen(k)
					if mainLayer.fFlipH:GetValue(0) or mainLayer.fFlipV:GetValue(0) then
						for c = 0, point:CountCurves() - 1 do
							local curve, pointID = point:Curve(c)
							local inOffset = curve:GetOffset(pointID, layerFrame, true)
							local outOffset = curve:GetOffset(pointID, layerFrame, false)
							curve:SetOffset(pointID, -inOffset, layerFrame, true)
							curve:SetOffset(pointID, -outOffset, layerFrame, false)
						end
					end
				end
				for a = 0, point.fAnimPos:CountActions() - 1 do
					local track = moho:ChannelAsAnimVec2(point.fAnimPos:Action(a))
					for k = 1, track:CountKeys()-1 do
						currentPos = track:GetValueByID(k)
						mainMatrix:Transform(currentPos)
						track:SetValueByID(k, currentPos)
					end
					--if layer was flipped need to invert offsets for all the actions too. But I am too lazy to do it. 
				end
			end
		end
	elseif mainLayer:IsGroupType() then
		local group = moho:LayerAsGroup(mainLayer)
		for ch = 0, group:CountLayers()-1 do
			local childLayer = group:Layer(ch)
			local childMatrix = LM.Matrix:new_local()
			childLayer:GetLayerTransform(moho.layerFrame, childMatrix, moho.document)
			local resultMatrix = LM.Matrix:new_local()
			resultMatrix:Set(mainMatrix)
			resultMatrix:Multiply(childMatrix)
			local translation, rotationZ, scale, flip = AE_Utilities:Matrix2transform(resultMatrix, printOutput)
			childLayer.fTranslation:SetValue(moho.layerFrame, translation)
			childLayer.fRotationZ:SetValue(moho.layerFrame, rotationZ)
			childLayer.fScale:SetValue(moho.layerFrame, scale)
			childLayer.fFlipH:SetValue(moho.layerFrame, flip)
		end
		if mainLayer:IsBoneType() and moho:Skeleton():CountBones() > 0 then
			local returnFrame = moho.frame
			local skel = moho:Skeleton()
			local oldMatrixes = {}
			-- here goes collecting of bone matrixes: from fMovedMatrix with mainline frames
			-- and from AE_Utilities:GetGlobalBoneMatrix with action timelines
			-- AE_Utilities:GetGlobalBoneMatrix does not work fine for now and may have to be replaced
			-- with AE_Utilities:GetGlobalBonePRS. But its return have to be converted into matrix anyway
			-- course all the matrixes are multiplied with mainMatrix, produced with layer transform
			-- so it would be better to update AE_Utilities:GetGlobalBoneMatrix
			-- making it work with AE_Utilities:GetGlobalBonePRS or fixing it any other way to produce correct results
			local rootBones = {}
			for i = 0, skel:CountBones() -1 do
				if skel:Bone(i).fAnimParent:GetValue(0) == -1 then table.insert(rootBones, skel:Bone(i)) end			
				oldMatrixes[i] = {}
				oldMatrixes[i][''] = {}
				for a = 0, mainLayer:CountActions()-1 do
					local actionName = mainLayer:ActionName(a)
					oldMatrixes[i][actionName] = {}
				end
			end

			for f = 0, moho.document:AnimDuration() do
				if f== 0 then 
					-- save rest matrix into table
					for b = 0, skel:CountBones()-1 do
						local tempMatrix = LM.Matrix:new_local()
						tempMatrix:Set(skel:Bone(b).fRestMatrix)
						oldMatrixes[b][''][0] = tempMatrix
					end

				elseif self:IsKeyframe(moho, f) then
					-- save moved matrix into table
					moho:SetCurFrame(f)				
					for b = 0, skel:CountBones()-1 do
						skel:UpdateBoneMatrix(b)
						local tempMatrix = LM.Matrix:new_local()
						tempMatrix:Set(skel:Bone(b).fMovedMatrix)
						oldMatrixes[b][''][f] = tempMatrix
					end				
				end
			end
			for a = 0, mainLayer:CountActions() - 1 do
				local actionName = mainLayer:ActionName(a)
				for f = 1, mainLayer:ActionDuration(actionName) do
					if self:IsKeyframe(moho, f, actionName) then
						-- save moved matrix into table
						for b = 0, skel:CountBones()-1 do
							--skel:UpdateBoneMatrix(b)
							local tempMatrix = LM.Matrix:new_local()
							--tempMatrix:Set(skel:Bone(b).fMovedMatrix)
							tempMatrix:Set(AE_Utilities:GetGlobalBoneMatrix(moho, skel, skel:Bone(b), f, actionName))
							oldMatrixes[b][actionName][f] = tempMatrix
						end					
					end
				end
			end
			-- iterate once again from root bones to their children		
			for f = 0, moho.document:AnimDuration() do
				if f== 0 then 
					for i, bone in pairs(rootBones) do
						-- call recursive bone method
						self:ApplyBoneTransform(moho, skel, skel:BoneID(bone), mainMatrix, oldMatrixes, f) 
					end
				else
					moho:SetCurFrame(f)				
					for i, bone in pairs(rootBones) do
						-- call recursive bone method
						self:ApplyBoneTransform(moho, skel, skel:BoneID(bone), mainMatrix, oldMatrixes, f)
					end			
				end
			end
			for a = 0, mainLayer:CountActions() - 1 do
				local actionName = mainLayer:ActionName(a)
				mainLayer:ActivateAction(actionName)
				for f = 1, mainLayer:ActionDuration(actionName) do
					--moho:SetCurFrame(f)
					for i, bone in pairs(rootBones) do
						-- call recursive bone method
						self:ApplyBoneTransform(moho, skel, skel:BoneID(bone), mainMatrix, oldMatrixes, f, actionName)
					end				
				end
			end
			mainLayer:ActivateAction(nil)
			moho:SetCurFrame(returnFrame)
		end	
	else return
	end

	local pos = LM.Vector3:new_local()
	mainLayer.fTranslation:SetValue(moho.layerFrame, pos)
	mainLayer.fRotationZ:SetValue(moho.layerFrame, 0)
	local scale = LM.Vector3:new_local()
	scale:Set(1,1,1)
	mainLayer.fScale:SetValue(moho.layerFrame, scale)
	mainLayer.fFlipH:SetValue(moho.layerFrame, false)
	mainLayer.fFlipV:SetValue(moho.layerFrame, false)
end





Reset layer transform
Listed

Script type: Button/Menu

Uploaded: Jan 18 2021, 01:15

Last modified: Feb 01 2022, 04:48

Resets transform moving it to direct child layers

Installation Options:

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: 1263