Two scripts for you: "Maintain pose" and "Toggle visibility"

Moho allows users to write new tools and plugins. Discuss scripting ideas and problems here.

Moderators: Víctor Paredes, Belgarath, slowtiger

lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by lehtiniemi »

synthsin75 wrote:Here's code that gets both next and last keyframe (point motion here), whether the current frame is keyed or not:

Code: Select all

	local pos = 1
	local neg = -1
	local frame = moho.frame
	local ch = moho.layer:Channel(2, 1, moho.document)

	if (ch:GetKeyWhen(ch:GetClosestKeyID(frame)) ~= frame) then
		neg = 0
	end
	
	local nextKeyframe = ch:GetKeyWhen(ch:GetClosestKeyID(frame)+pos)
	local lastKeyframe = ch:GetKeyWhen(ch:GetClosestKeyID(frame)+neg)
	print("nextKeyframe = "..nextKeyframe.."\n".."lastKeyframe = "..lastKeyframe)
Wow, thanks! I'll check this out when I get home.
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by lehtiniemi »

I can't get this to work. Despite what I give as pos/neg, it always returns the closest previous key, never the next. I can't control the direction... What could it be?
User avatar
hayasidist
Posts: 3492
Joined: Wed Feb 16, 2011 8:12 pm
Location: Kent, England

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by hayasidist »

How I'd go about this:

idOfKey = AnimChannel:GetClosestKeyID(when) -- the id of the key at or before "when"

later = idOfKey + 1 -- the id of the key later than "when"

frameOfKey = AnimChannel:GetKeyWhen(id)

use the above to get the key ids at the start and end of the frame range you want

e.g. between frames 15 and 25:
AnimChannel:GetClosestKeyID(15) will give you a key at or before 15 -- get its frame - if it's at 15 you have it; if not add one to keyId - make sure it's a valid keyId- get that id's frame, check it's not more than 25 - and that's the "earliest in timeline in range"
AnimChannel:GetClosestKeyID(25) will give you a key at or before 25 -- get its frame - if it's at 25 you have it; if not, check it's not less than 15 and that's the "latest in timeline in range"

there might not be a key in range; or earliest and latest may well be the same key of course!


for the whole timeline:
latest in range is the id of the key at AnimChannel:Duration() (should be AnimChannel:CountKeys()-1)
earliest in range is the id of the key at frame 0 (should be 0)

if there's only one key then it'll be at frame 0.



to go backwards between two key ids start at "latest in range" and subtract 1 from that until you get to "earliest in range"
to go forwards between two key ids start at "earliest in range" and add 1 to that until you get to until you get to "latest in range"

using AnimChannel:GetKeyWhen(keyId) as you go to find the key's frame

(and I'm sure I don't actually need to say this, but take care if you're moving keys as you go ... :wink: )
User avatar
synthsin75
Posts: 9935
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by synthsin75 »

lehtiniemi wrote:I can't get this to work. Despite what I give as pos/neg, it always returns the closest previous key, never the next. I can't control the direction... What could it be?
You shouldn't have to change the pos/neg values. Just use the one you need to get the direction you want.

Previous keyframe:

Code: Select all

       local neg = -1
       local frame = moho.frame
       local ch = moho.layer:Channel(2, 1, moho.document)

       if (ch:GetKeyWhen(ch:GetClosestKeyID(frame)) ~= frame) then
          neg = 0
       end

       local lastKeyframe = ch:GetKeyWhen(ch:GetClosestKeyID(frame)+neg)
       print("lastKeyframe = "..lastKeyframe)
Next keyframe:

Code: Select all

       local pos = 1
       local frame = moho.frame
       local ch = moho.layer:Channel(2, 1, moho.document)
       
       local nextKeyframe = ch:GetKeyWhen(ch:GetClosestKeyID(frame)+pos)
       print("nextKeyframe = "..nextKeyframe)

The only thing you may need to change is the frame value, if you are evaluating it from somewhere other than the current frame.
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by lehtiniemi »

synthsin75 wrote:
lehtiniemi wrote:I can't get this to work. Despite what I give as pos/neg, it always returns the closest previous key, never the next. I can't control the direction... What could it be?
You shouldn't have to change the pos/neg values. Just use the one you need to get the direction you want.

Previous keyframe:

Code: Select all

       local neg = -1
       local frame = moho.frame
       local ch = moho.layer:Channel(2, 1, moho.document)

       if (ch:GetKeyWhen(ch:GetClosestKeyID(frame)) ~= frame) then
          neg = 0
       end

       local lastKeyframe = ch:GetKeyWhen(ch:GetClosestKeyID(frame)+neg)
       print("lastKeyframe = "..lastKeyframe)
Next keyframe:

Code: Select all

       local pos = 1
       local frame = moho.frame
       local ch = moho.layer:Channel(2, 1, moho.document)
       
       local nextKeyframe = ch:GetKeyWhen(ch:GetClosestKeyID(frame)+pos)
       print("nextKeyframe = "..nextKeyframe)

The only thing you may need to change is the frame value, if you are evaluating it from somewhere other than the current frame.
Ah sorry I wrote unclearly. But to me it seems that GetClosestKeyID only looks for current frame and before it. It doesn't seem to look forwards in timeline, always backwards. At least I couldn't make it do so.
User avatar
synthsin75
Posts: 9935
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by synthsin75 »

lehtiniemi wrote:Ah sorry I wrote unclearly. But to me it seems that GetClosestKeyID only looks for current frame and before it. It doesn't seem to look forwards in timeline, always backwards. At least I couldn't make it do so.
GetClosestKeyID does only get either the current frame, if keyed, or the last. But it returns an ID. Keyframe IDs are chronological, so if the current frame ID is 16, the next later keyframe ID is 17. My code uses the pos/neg to determine the direction we're looking by ID. Only after getting the next or last keyframe ID do we give that to GetKeyWhen to get the frame. Does it help to write it like this:

Code: Select all

	local pos = 1
	local frame = moho.frame
	local ch = moho.layer:Channel(2, 1, moho.document)
	
	local nextKeyID = ch:GetClosestKeyID(frame)+pos
	local nextKeyedFrame = ch:GetKeyWhen(nextKeyID)
	print("nextKeyedFrame = "..nextKeyedFrame)
Last edited by synthsin75 on Wed Mar 23, 2016 11:17 pm, edited 1 time in total.
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by lehtiniemi »

synthsin75 wrote:
lehtiniemi wrote:Ah sorry I wrote unclearly. But to me it seems that GetClosestKeyID only looks for current frame and before it. It doesn't seem to look forwards in timeline, always backwards. At least I couldn't make it do so.
GetClosestKeyID does only get either the current frame, if keyed, or the last. But it returns an ID. Keyframe IDs are chronological, so if the current frame ID is 16, the next later keyframe ID is 17. My code uses the pos/neg to determine the direction we're looking by ID. Only after getting the next or last keyframe do we give that to GetKeyWhen to get the frame. Does it help to write it like this:

Code: Select all

	local pos = 1
	local frame = moho.frame
	local ch = moho.layer:Channel(2, 1, moho.document)
	
	local nextKeyID = ch:GetClosestKeyID(frame)+pos
	local nextKeyedFrame = ch:GetKeyWhen(nextKeyID)
	print("nextKeyedFrame = "..nextKeyedFrame)
Oh, now I get it! Genious! Thank you! In addition, there probably has to be a check that the ID isn't bigger than the amount of keyframes?
User avatar
synthsin75
Posts: 9935
Joined: Mon Jan 14, 2008 11:20 pm
Location: Oklahoma
Contact:

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by synthsin75 »

lehtiniemi wrote:Oh, now I get it! Genious! Thank you! In addition, there probably has to be a check that the ID isn't bigger than the amount of keyframes?
Yeah, off-hand, I'd assume a HasKey(when) check would work.

if (ch:HasKey(frame+pos)) then
Last edited by synthsin75 on Wed Mar 23, 2016 11:20 pm, edited 1 time in total.
lehtiniemi
Posts: 107
Joined: Mon Jan 14, 2013 3:18 pm

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by lehtiniemi »

synthsin75 wrote:
lehtiniemi wrote:Oh, now I get it! Genious! Thank you! In addition, there probably has to be a check that the ID isn't bigger than the amount of keyframes?
Yeah, off-hand, I'd assume a HasKey(when) check would work.
Thank you so much again. I know I ask alot, I'm really greatful for your help...!
HardikLakhalani
Posts: 19
Joined: Mon Jan 18, 2016 9:32 am

Re: Two scripts for you: "Maintain pose" and "Toggle visibil

Post by HardikLakhalani »

lehtiniemi wrote: TOGGLE VISIBILITY
The script toggles the current visibility state for the layer: if it's visible, it becomes hidden and vice versa. "Automated layer effects" is automatically enabled for the selected layer. If the new visibility state is the same as in previous frame (=layer visibility state doesn't change), the keyframe is automatically removed.

Makes animating visibility a LOT faster than with the built-in functions (unless there's something I've missed), especially when the "Automated layer effects" isn't enabled and you animate visibility for the first time in the project.

Installation
Copy both .lua and .png files to the tool-folder.
The buttons appear in "Other"-group after restart.

Download both here:
http://www.juhanalehtiniemi.com/tmp/JL_ ... cripts.zip
I'm that someone you helped. But Its not working with multiple layers, When selecting 2 or more layers, It applies only on first selected layer. Can you update this script to v1.1 ?
Post Reply