Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Set Keyframes through a Python Tag

    Cinema 4D SDK
    r20 python
    2
    9
    2.3k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      bentraje
      last edited by

      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.

      1 Reply Last reply Reply Quote 0
      • M
        m_adam
        last edited by

        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.

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        1 Reply Last reply Reply Quote 3
        • B
          bentraje
          last edited by

          @m_adam

          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 the for loop in the def 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.

          1 Reply Last reply Reply Quote 0
          • M
            m_adam
            last edited by

            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.

            MAXON SDK Specialist

            Development Blog, MAXON Registered Developer

            1 Reply Last reply Reply Quote 1
            • B
              bentraje
              last edited by

              @m_adam

              Thanks for the response.
              I tried this one again at the end of the for loop in the def 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?

              1 Reply Last reply Reply Quote 0
              • M
                m_adam
                last edited by m_adam

                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

                MAXON SDK Specialist

                Development Blog, MAXON Registered Developer

                1 Reply Last reply Reply Quote 1
                • B
                  bentraje
                  last edited by

                  @m_adam

                  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 the SetTimeLeft() and SetTimeRight() 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.

                  1 Reply Last reply Reply Quote 0
                  • M
                    m_adam
                    last edited by

                    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.

                    MAXON SDK Specialist

                    Development Blog, MAXON Registered Developer

                    1 Reply Last reply Reply Quote 2
                    • B
                      bentraje
                      last edited by

                      @m_adam

                      Gotcha. Work as expected.
                      Thanks for the response.

                      Have a great day ahead!

                      1 Reply Last reply Reply Quote 0
                      • First post
                        Last post