-- **************************************************
-- 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.1"
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()
	
	local printOutput = false --output calculated values for debug
	
	local mainLayer = moho.layer
	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)
		end
	end
	if 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
	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

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





Reset layer transform
Listed

Script type: Button/Menu

Uploaded: Jan 18 2021, 01:15

Last modified: Mar 29 2021, 02:32

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