Notifications
Clear all

[Closed] Ignore empty frames

I’m triyng to write script what will be write for me information in max listener about quaternion rotation and position for animation.

on CopyBones pressed do
     	(
     		nframes = "sliderTime = "
     		rframes = "$.rotation = "
     		pframes = "$.pos = "
     		keystart = animationrange.start
     		keyend = animationrange.end-1
     	  
     		if selection.count == 1 then
     		(
     		
     		format nframes
     		sliderTime = 0f
     		print sliderTime
     		format rframes
     		print $.rotation
     		format pframes
     		print $.pos
     
     			for i = keystart to keyend do
     		(
     			sliderTime +=1
     			format nframes
     			print sliderTime
     			format rframes
     			print $.rotation
     			format pframes
     			print $.pos
     		)
     	)
     	else
     (
     	messagebox "You must select any bone first!"
     )
     )
Working good but information about rot and pos is write for all frames. I want to ignore frames what haven't keysframes.

For example

I have key in 1st then 5th and 10th, 12th frame.

In max listener I want to see something like that:
0f
5f
10f

12f

and not like now

0f
1f
2f
3f
4f
5f
6f
7f
8f
9f
10f
11f
12f

How I can do it?

18 Replies

You can check your controller keys array.

Try using :

$.position.controller.keys
$.rotation.controller.keys

Ok but can you (or someone else) explain me how I can check my controller keys array? My scripting level isn’t good I think this should be something with if.

For example this should like that:

sliderTime = 0f
$.rotation = (quat -0.0402838 -0.692195 0.0462476 -0.7191)
$.pos = [0.0814999,4.36233e-005,-0.00849035]
sliderTime = 1f
$.rotation = (quat -0.0398559 -0.692551 0.0462876 -0.718778)
$.pos = [0.0819329,0.000305913,-0.00848681]
sliderTime = 3f
$.rotation = (quat -0.0373623 -0.694563 0.0465611 -0.716951)
$.pos = [0.0844062,0.0018139,-0.00846642]
sliderTime = 5f
$.rotation = (quat -0.0348128 -0.696512 0.0469076 -0.715163)
$.pos = [0.0868516,0.00332114,-0.00844604]
sliderTime = 8f
$.rotation = (quat -0.0343639 -0.696845 0.0469752 -0.714856)
$.pos = [0.087274,0.00358315,-0.0084425]
sliderTime = 10f
$.rotation = (quat -0.0343639 -0.696845 0.0469752 -0.714856)
$.pos = [0.087274,0.00358315,-0.0084425]

The keyframes are in 0, 1, 3, 5, 8 and 10 frame. Empty frames are ignore.

Here is the main idea :

You are parsing all the frames between keystart and keyend.

We have the ability to know where keyframes have been set, using the code I gave you.

What you have to do now is :

  • Create a new empty array named keyframesArray, it will contain the frames where keyframes has been set
  • In this array, join the keyframes of the position controller
  • Repeat this for the rotation controller

At last, you won’t write :

for i = keystart to keyend do

But you’ll write :

for f in keyframesArray do
(
     sliderTimer = f
[...]
)

Give it a try, I’ve written in bold the words you can look for in the maxscript documentation. I’ll help you if you have further questions.

I’m was trying to do what you wrote but 3ds Max give me error

>> MAXScript Rollout Handler Exception: – Unable to convert: #keys(0f, 6f, 14f, 20f, 30f, 51f, 59f, 70f, 76f, 81f, 87f, 92f) to type: Time <<

The problem is with: sliderTime = f

If I understood correctly I must use for loop in for loop (two for loop; 1. for i = keystart to keyend do ; 2. for f in keyframesArray do) ?

I have this:

on CopyBones pressed do
 	(
 		keyframesArray = #()
 		join keyframesArray #($.rotation.controller.keys)
 		
 		nframes = "sliderTime = "
 		rframes = "$.rotation = "
 		keystart = animationrange.start
 		keyend = animationrange.end-1
 
 		
 		if selection.count == 1 then
 		(
 		
 		format nframes
 		sliderTime = 0f
 		print sliderTime
 		format rframes
 		print $.rotation
 
 			for i = keystart to keyend do
 			(
 				for f in keyframesArray do
 				(
 				sliderTime = f
 				format nframes
 				print sliderTime
 				format rframes
 				print $.rotation
 				)
 			
 
 			)
 		)
 	else
 	(
 	messagebox "You must select any bone first!"
 	)
 	)

Sorry but I’m lame in scripting 🙁

I was expecting you to write the error message, it means that you’re following the good way

The thing is, the values you are storing in the array are keyframes, try to write keyframesArray[1] once the values are gathered to see the result. This is an example of a keyframe, it can look like this :

#Bezier Float key(2 @ 50f)

Note that they’re two values : a controller value, and a frame time. What you want to do now, is to access the frame time. You can do it this way :

keyframe.time

Now, about the loops. You don’t have to (and you must not in your case) write a loop inside a loop.

Your first loop was saying :

  • Let’s parse all the frames of the animation range, and print their values

The second loop you wrote says :

  • We know where the keyframes are set, let’s parse those frames

If you put the two loops together you would have (in pseudo-code) :

At frame 0 :
     at frame 0
     at frame 6
     at frame 14
     ....
At frame 1 :
     at frame 0
     at frame 6
     at frame 14
     ....

You don’t need the first loop anymore. What you want your script to do is :

At frame 0 : print
At frame 6 : print
At frame 14 : print

Yes it is writing information about keyframes:

#Euler XYZ key(1 @ 0f)
#Euler XYZ key(2 @ 6f)
#Euler XYZ key(3 @ 14f)
#Euler XYZ key(4 @ 20f)
#Euler XYZ key(5 @ 30f)
#Euler XYZ key(6 @ 51f)
#Euler XYZ key(7 @ 59f)
#Euler XYZ key(8 @ 70f)
#Euler XYZ key(9 @ 76f)
#Euler XYZ key(10 @ 81f)
#Euler XYZ key(11 @ 87f)
#Euler XYZ key(12 @ 92f)

but I don’t get it. I’m trying to do it with keyframe.time but I’ve still the same error Unable to convert: to type: Time. I don’t know how I must use this keyframe.time. I found some things about it but I don’t get it 🙁
Maybe… Can you write how exactly look for loop or you can give me more instructions how I can write correctly it.

How do you write your for loop ?
I don’t need all the lines, just the beginning with the slidertime line.

Here it’s code.

on CopyBones pressed do
    	 (
    		 keyframesArray = #()
    		 join keyframesArray #($.rotation.controller.keys)
    		 
    		 nframes = "sliderTime = "
    		 rframes = "$.rotation = "
    		 keystart = animationrange.start
    		 keyend = animationrange.end-1
    
    		print keyframesArray[1] --for test
    		 
    		 if selection.count == 1 then
    		 (
    
    				 for f in keyframesArray[1] do
    				 (
    				 sliderTime = f --it give me error Unable to convert: to type: Time
    				 format nframes
    				 print sliderTime
    				 format rframes
    				 print $.rotation
    				 )
    		 )
    	 else
    	 (
    	 messagebox "You must select any bone first!"
    	 )
    	 )
sliderTime = f --it give me error Unable to convert: to type: Time

You exactly have spotted the error. You should be able to find the good syntax.
Remember :

  • sliderTime expects a value that looks like “10f”
  • f’s value is “(1 @ 10f)”

Your code is almost correct, and I gave you the value some lines ago, try again

Page 1 / 2