Set Keyframes through a Python Tag
-
Hi,
I need to set a keyframe through a python tag. This means if I change something a frame and a value in the code, it updates in the affected object.
I watched this
. It also uses a python tag but unfortunately, once you set the keyframe, you have to modify it on the timeline rather than within the code.Here is my code so far, assuming a simple primitive cube in the scene:
import c4d def set_keyframe(obj, objParameter, frameList, valueList): old_tracks = obj.FindCTrack(objParameter) # Remove existing track and create a new one. This ensures that the only track available in the object is within the code if old_tracks: old_tracks.Remove() new_track = c4d.CTrack(objParameter) obj.InsertTrackSorted(new_track) curve = atrck.GetCurve() # This is the part that I don't know what I'm doing. for (frame,value) in zip(frameList,valueList): curve.AddKey (c4d.BaseTime(frame, 24)) atrck.FillKey(doc, obj, value ) set_keyframe( obj = doc.SearchObject("Cube"), objParameter = c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y, # Assuming the selected object is frameList = [0,30,45], valueList = [100,-250,20] )
Is there a way around this?
Thank you for looking at the problem.
-
Hi @bentraje.
First of all, I would like to remind you a Python Tag is executed at every scene execution. And modify the current scene representation (aka adding a keyframe, changing object data) while the scene execution may lead to some change not being correctly synchronized.
Moreover, this means for each frame you will modify this, so there is probably a better way for doing it, depending on your need. Maybe through a button user data? That can be caught in the Message methods.
Regarding how to creates keyframe take a look at the next example. Written for the script manager.
import c4d def set_keyframe(obj, objParameter, frameList, valueList): # Searches if there is already an existing Track for this parameter. track = obj.FindCTrack(objParameter) # Removes the track if it's already here. if track is not None: track.Remove() # Creates a new track for this parameter. track = c4d.CTrack(obj, objParameter) # Inserts the track into the object obj.InsertTrackSorted(track) # Retrieves the curve representation of this track curve = track.GetCurve() # Iterates over the frame list and the valueList (count have to be the same) for (frame, value) in zip(frameList, valueList): # Calculates the equivalent of a BaseTime for a given frame time = c4d.BaseTime(frame, obj.GetDocument().GetFps()) # Creates a keyframe in the memory key = c4d.CKey() # Fills the key with the default data track.FillKey(doc, obj, key) # Defines the y value key.SetValue(curve, value) # Defines the time value key.SetTime(curve, time) # Adds a key on the curve for the given frame curve.InsertKey(key) # Main function def main(): set_keyframe(obj = doc.SearchObject("Cube"), objParameter = c4d.DescID(c4d.DescLevel(c4d.ID_BASEOBJECT_REL_POSITION), c4d.DescLevel(c4d.VECTOR_Y)), frameList = [0,30,45], valueList = [100,-250,20]) c4d.EventAdd() # Execute main() if __name__=='__main__': main()
If you have any question, please let me know.
Cheers,
Maxime. -
Thanks for the response! You are right, I guess a normal script should do the job.
Quick question:
How do I set the interpolation to spline? I tried the following code at the end of thefor loop
in thedef set_keyframes
:key.SetInterpolation(curve, 2)
Interestingly. There is no error in the Python Console but it is still on a linear interpolation.
Thank you for looking at the problem.
-
Try to use another value since symbols c4d.CINTERPOLATION_LINEAR is equal to 2 so it's normal if the interpolation is defined to linear.
Take a look at the CKey.SetInterpolation methods to know which symbols are expected.Cheers,
Maxime. -
Thanks for the response.
I tried this one again at the end of thefor loop
in thedef set_keyframes
:key.SetInterpolation(curve, c4d.CINTERPOLATION_SPLINE)
It doesn't error out but it's also not in the spline interpolation.
Am I missing something?
-
Which version are you? Here is working nicely
# Adds a key on the curve for the given frame curve.InsertKey(key) key.SetInterpolation(curve, c4d.CINTERPOLATION_SPLINE)
Cheers,
Maxime -
I'm using R20.059. Looking at it now, it seems like, yes, it is on spline interpolation.
The problem is the "Ease In/Ease Out" is not enabled.
I can set it using theSetTimeLeft()
andSetTimeRight()
but this would mean hardcoding a value. I can't hard code it since the Ease In/Ease Out depends on how far the next and previous frames are.Is there a command that set that values automatically? The same where you click the "Ease In/Ease Out" command in timeline editor.
-
Unfortunately, this is not possible. EaseIn/Out commands are not exposed.
But you could define the key as auto tangents, clamp and remove overshooting, which make the same result here.
# Adds a key on the curve for the given frame curve.InsertKey(key) key.SetInterpolation(curve, c4d.CINTERPOLATION_SPLINE) key.ChangeNBit(c4d.NBIT_CKEY_AUTO, c4d.NBITCONTROL_SET) key.ChangeNBit(c4d.NBIT_CKEY_REMOVEOVERSHOOT, c4d.NBITCONTROL_SET) key.ChangeNBit(c4d.NBIT_CKEY_CLAMP, c4d.NBITCONTROL_SET)
Otherwise, you have to calculate and define the correct value using SetTimeLeft/Right.
Cheers,
Maxime. -