Creating a Keyframe similar to Ctrl-Clicking the Curve



  • Hello,
    When in the Timeline, if I hold Ctrl/Cmd and click on the curve, Cinema 4D adds a keyframe that matches the contour of the curve perfectly.
    Curve2.jpg

    The tangents of the new key and neighboring keys are properly weighted.

    When I try to do this with the code below, I get a keyframe whose angles do not match the curve and where the Left & Right times of the neighboring keys are not adjusted.

    keyDict = keyCurve.AddKey(keyTime)
    keyIndex = keyDict["nidx"]
    key = keyDict["key"]
    key.SetValue(keyCurve,value)
    key[c4d.ID_CKEY_PRESET] = c4d.ID_CKEY_PRESET_NEWAUTOWEIGHTED
    

    Result:
    10972325-56f5-40c8-b50f-b32d3025c6bd-image.png

    The tangents of the key seem to be weighted properly using ID_CKEY_PRESET_NEWAUTOWEIGHTED, but how can I get the angle of the tangents to match the curve and the Left & Right Time of the neighboring keys to adjust so the curve's contour doesn't change as in the Ctrl-Click key creation scenario?

    Thank you!



  • Hi @blastframe,

    thank you for reaching out to us. One built in solution you could use is CCurve.AddKeyAdaptTangent() instead of CCurve.AddKey(). It will allow you to insert a smoothly interpolated key between two other keys and the result will look something like the attached image. I also attached a modified github ctrack_create_keys_r13.py example at the end. You only have to read the snip parts, everything else is unchanged.

    2798b905-ec91-4bc1-8363-ad0d65577044-image.png

    I hope this helps, if not, I would have to ask you to restate your goals.

    Cheers,
    Ferdinand

    """
    Copyright: MAXON Computer GmbH
    Author: Manuel MAGALHAES
    Description:
        - Creates position Y tracks.
        - Adds two keyframes.
        - Sets their value and interpolation.
    Class/method highlighted:
        - CKey.SetInterpolation()
        - CKey.SetKeyDefault()
    Compatible:
        - Win / Mac
        - R13, R14 R15, R16, R17, R18, R19, R20, R21, S22, R23
    """
    
    import c4d
    
    
    def CreateKey(curve, time, value, interpolation):
        """
        Creates a Key on the given curve at the given time with a given value and with the given interpolation.
        :param curve: The Curve where to add the keyframe.
        :type curve: c4d.CCurve
        :param time: The time of the keyframe.
        :type time: c4d.BaseTime
        :param value: The value of the keyframe.
        :type value: float
        :param interpolation: The interpolation of the key along the curve.
        :type interpolation: c4d.CINTERPOLATION_XXX
        :return: They key and the index of the key in the CCurve.
        :rtype: tuple(c4d.Ckey, int)
        :raise MemoryError: If for some reason, it was not possible to create the key.
        """
        # Adds the key
        keyDict = curve.AddKey(time)
    
        # Checks if the key have been added
        if keyDict is None:
            raise MemoryError("Failed to create a key")
    
        # Retrieves the inserted key
        key = keyDict["key"]
        keyIndex = keyDict["nidx"]
    
        # Sets the value of the key
        key.SetValue(curve, value)
    
        # Mandatory: Fill the key with default settings
        curve.SetKeyDefault(doc, keyIndex)
    
        # Changes it's interpolation
        key.SetInterpolation(curve, interpolation)
    
        return key, keyIndex
    
    
    def main():
        # Creates the object in memory
        obj = c4d.BaseObject(c4d.Ocube)
    
        # Creates the track in memory. Defined by it's DescID
        trackY = c4d.CTrack(obj, c4d.DescID(c4d.DescLevel(c4d.ID_BASEOBJECT_POSITION, c4d.DTYPE_VECTOR, 0),
                                            c4d.DescLevel(c4d.VECTOR_Y, c4d.DTYPE_REAL, 0)))
    
        # Gets curves for the track
        curveY = trackY.GetCurve()
    
        # Creates a key in the Y curve with value 0 at 0 frame with a spline interpolation
        keyA, keyAIndex = CreateKey(curveY, c4d.BaseTime(0), value=0, interpolation=c4d.CINTERPOLATION_SPLINE)
    
        # Retrieves time at frame 10
        keyBTime = c4d.BaseTime(10, doc.GetFps())
    
        # Creates another key in the Y curve with value 100 at 10 frame with a spline interpolation
        keyB, keyBIndex = CreateKey(curveY, keyBTime, value=100, interpolation=c4d.CINTERPOLATION_SPLINE)
        
        # --- snip ---
        
        # Add key in between the keys A and B.
        bt = c4d.BaseTime(5, doc.GetFps())
        curveY.AddKeyAdaptTangent(bt, True, True)
        
        # --- snip ---
    
        # Inserts the track containing the Y curve to the object
        obj.InsertTrackSorted(trackY)
    
        # Inserts the object in document
        doc.InsertObject(obj)
    
        # Pushes an update event to Cinema 4D
        c4d.EventAdd()
    
    
    # Execute main()
    if __name__ == '__main__':
        main()


  • Hi @blastframe,

    thank you for reaching out to us. One built in solution you could use is CCurve.AddKeyAdaptTangent() instead of CCurve.AddKey(). It will allow you to insert a smoothly interpolated key between two other keys and the result will look something like the attached image. I also attached a modified github ctrack_create_keys_r13.py example at the end. You only have to read the snip parts, everything else is unchanged.

    2798b905-ec91-4bc1-8363-ad0d65577044-image.png

    I hope this helps, if not, I would have to ask you to restate your goals.

    Cheers,
    Ferdinand

    """
    Copyright: MAXON Computer GmbH
    Author: Manuel MAGALHAES
    Description:
        - Creates position Y tracks.
        - Adds two keyframes.
        - Sets their value and interpolation.
    Class/method highlighted:
        - CKey.SetInterpolation()
        - CKey.SetKeyDefault()
    Compatible:
        - Win / Mac
        - R13, R14 R15, R16, R17, R18, R19, R20, R21, S22, R23
    """
    
    import c4d
    
    
    def CreateKey(curve, time, value, interpolation):
        """
        Creates a Key on the given curve at the given time with a given value and with the given interpolation.
        :param curve: The Curve where to add the keyframe.
        :type curve: c4d.CCurve
        :param time: The time of the keyframe.
        :type time: c4d.BaseTime
        :param value: The value of the keyframe.
        :type value: float
        :param interpolation: The interpolation of the key along the curve.
        :type interpolation: c4d.CINTERPOLATION_XXX
        :return: They key and the index of the key in the CCurve.
        :rtype: tuple(c4d.Ckey, int)
        :raise MemoryError: If for some reason, it was not possible to create the key.
        """
        # Adds the key
        keyDict = curve.AddKey(time)
    
        # Checks if the key have been added
        if keyDict is None:
            raise MemoryError("Failed to create a key")
    
        # Retrieves the inserted key
        key = keyDict["key"]
        keyIndex = keyDict["nidx"]
    
        # Sets the value of the key
        key.SetValue(curve, value)
    
        # Mandatory: Fill the key with default settings
        curve.SetKeyDefault(doc, keyIndex)
    
        # Changes it's interpolation
        key.SetInterpolation(curve, interpolation)
    
        return key, keyIndex
    
    
    def main():
        # Creates the object in memory
        obj = c4d.BaseObject(c4d.Ocube)
    
        # Creates the track in memory. Defined by it's DescID
        trackY = c4d.CTrack(obj, c4d.DescID(c4d.DescLevel(c4d.ID_BASEOBJECT_POSITION, c4d.DTYPE_VECTOR, 0),
                                            c4d.DescLevel(c4d.VECTOR_Y, c4d.DTYPE_REAL, 0)))
    
        # Gets curves for the track
        curveY = trackY.GetCurve()
    
        # Creates a key in the Y curve with value 0 at 0 frame with a spline interpolation
        keyA, keyAIndex = CreateKey(curveY, c4d.BaseTime(0), value=0, interpolation=c4d.CINTERPOLATION_SPLINE)
    
        # Retrieves time at frame 10
        keyBTime = c4d.BaseTime(10, doc.GetFps())
    
        # Creates another key in the Y curve with value 100 at 10 frame with a spline interpolation
        keyB, keyBIndex = CreateKey(curveY, keyBTime, value=100, interpolation=c4d.CINTERPOLATION_SPLINE)
        
        # --- snip ---
        
        # Add key in between the keys A and B.
        bt = c4d.BaseTime(5, doc.GetFps())
        curveY.AddKeyAdaptTangent(bt, True, True)
        
        # --- snip ---
    
        # Inserts the track containing the Y curve to the object
        obj.InsertTrackSorted(trackY)
    
        # Inserts the object in document
        doc.InsertObject(obj)
    
        # Pushes an update event to Cinema 4D
        c4d.EventAdd()
    
    
    # Execute main()
    if __name__ == '__main__':
        main()


  • @ferdinand That was exactly what I was seeking, thank you, Ferdinand! 😄