[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?
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