SOLVED SetTimeRight fail!

Hi, when the value I set is very small, such as BaseTime.get() is 0.001, by using SetTimeRight(), but when I access this value again by script, the result is BaseTime.get() is 0. but SetTimeLeft() can Successfully set, such as BaseTime.get() is -0.001 !
Thanks for any help!

        key.SetInterpolation(curve,c4d.CINTERPOLATION_SPLINE)
        

        key.SetTimeLeft(curve,L_time_v)
        key.SetValueLeft(curve,TL_vector[1])
        key.SetTimeRight(curve, R_time_v)
        key.SetValueRight(curve, TR_vector[1])

        key[c4d.ID_CKEY_PRESET] = c4d.ID_CKEY_PRESET__CUSTOM
        key.ChangeNBit(c4d.NBIT_CKEY_AUTO, c4d.NBITCONTROL_CLEAR)
        key.ChangeNBit(c4d.NBIT_CKEY_BREAK, c4d.NBITCONTROL_SET)
        key.ChangeNBit(c4d.NBIT_CKEY_KEEPVISUALANGLE, c4d.NBITCONTROL_SET)

Hello @chuanzhen,

thank you for reaching out to us. There is some truncating going on when setting the time component of a key to a value which is within the sub-second range. But I cannot reproduce any differences between the left and right tangent and also not than a tangent is zero when it should not be zero. within a second.

I would declare this an acceptable limitation of the Cinema 4D; since animation definitions below the millisecond range do not seem particularly useful for most users. If you can reproduce differences for setting the left and right time value of a key, I would ask you to provide an example file and/or executable code. But even then, chances are good that we will declare this an acceptable limitation.

Cheers,
Ferdinand

The output of the example code below:

doc.GetFps()=300


 Key Index|                Set Value|            GetTimeLeft()|           GetTimeRight()
----------------------------------------------------------------------------------------
         0|                   0.0125|                    0.013|                    0.013
         1|                    0.012|                    0.012|                    0.012
         2|                   0.0115|                    0.012|                    0.012
         3|                    0.011|                    0.011|                    0.011
         4|                   0.0105|                    0.011|                    0.011
         5|                     0.01|                     0.01|                     0.01
         6|                   0.0095|                     0.01|                     0.01
         7|     0.009000000000000001|                    0.009|                    0.009
         8|                   0.0085|                    0.009|                    0.009
         9|                    0.008|                    0.008|                    0.008
        10|                   0.0075|                    0.008|                    0.008
        11|                    0.007|                    0.007|                    0.007
        12|     0.006500000000000001|                    0.007|                    0.007
        13|                    0.006|                    0.006|                    0.006
        14|                   0.0055|                    0.006|                    0.006
        15|                    0.005|                    0.005|                    0.005
        16|    0.0045000000000000005|                    0.005|                    0.005
        17|                    0.004|                    0.004|                    0.004
        18|                   0.0035|                    0.004|                    0.004
        19|                    0.003|                    0.003|                    0.003
        20|                   0.0025|                    0.003|                    0.003
        21|                    0.002|                    0.002|                    0.002
        22|                   0.0015|                    0.002|                    0.002
        23|                    0.001|                    0.001|                    0.001
        24|                   0.0005|                    0.001|                    0.001

The code:

"""Provides an example for setting the time component of key-tangents to very
low values.

Creates a cube object with tweenty-five keys in a position-x track. Then loops
over the time component of the key-tangents of these keys, sets them to
increasingly smaller values and prints out the time values before and after
the changes, as well as the true value of the time t.
"""
import c4d


def main():
    """Runs the example.
    """
    # Creates a cube with a postion-x animation with 25 keys.
    cube = c4d.BaseList2D(c4d.Ocube)
    if cube is None:
        raise MemoryError("Could not allocate object.")

    descID = c4d.DescID (c4d.DescLevel(c4d.ID_BASEOBJECT_REL_POSITION),
                         c4d.DescLevel(c4d.VECTOR_X))
    track = c4d.CTrack(cube, descID)
    if track is None:
        raise MemoryError("Could not allocate track.")
    cube.InsertTrackSorted(track)
    curve = track.GetCurve()
    count = 25

    for t in range(count):
        result = curve.AddKey(c4d.BaseTime(t))
        if result is None:
            raise MemoryError("Could not allocate key.")
        result["key"].SetValue(curve, t ** 1.5)
        result["key"].SetInterpolation(curve, c4d.CINTERPOLATION_SPLINE)

    doc.InsertObject(cube)
    c4d.EventAdd()

    # Loop over the created key and print out their time-tagent values while
    # attempting to set them to incerasingly smaller values.
    print (f"{doc.GetFps()=}\n\n")
    print (f"{'Key Index':>10}|{'Set Value':>25}|{'GetTimeLeft()':>25}|"
           f"{'GetTimeRight()':>25}")
    line = "{:>10}|{:>25}|{:>25}|{:>25}"
    print ("-"*88)

    for i in range(curve.GetKeyCount()):
        ckey = curve.GetKey(i)
        t = (count - i) * 0.0005
        ckey.SetTimeLeft(curve, c4d.BaseTime(t))
        ckey.SetTimeRight(curve, c4d.BaseTime(t))
        print (line.format(
            i, t, ckey.GetTimeLeft().Get(), ckey.GetTimeRight().Get()))
    c4d.EventAdd()


if __name__ == '__main__':
    main()

Please use the curve->SetTangents(index, &curveTleftX, &curveTRightX, &curveTleftY, &curveTRightY); .
Detailed see:
https://plugincafe.maxon.net/topic/13352/ccurve-gettangents-broken
https://plugincafe.maxon.net/topic/13344/ckey-auto-tangents

Hello @chuanzhen,

thank you for reaching out to us. There is some truncating going on when setting the time component of a key to a value which is within the sub-second range. But I cannot reproduce any differences between the left and right tangent and also not than a tangent is zero when it should not be zero. within a second.

I would declare this an acceptable limitation of the Cinema 4D; since animation definitions below the millisecond range do not seem particularly useful for most users. If you can reproduce differences for setting the left and right time value of a key, I would ask you to provide an example file and/or executable code. But even then, chances are good that we will declare this an acceptable limitation.

Cheers,
Ferdinand

The output of the example code below:

doc.GetFps()=300


 Key Index|                Set Value|            GetTimeLeft()|           GetTimeRight()
----------------------------------------------------------------------------------------
         0|                   0.0125|                    0.013|                    0.013
         1|                    0.012|                    0.012|                    0.012
         2|                   0.0115|                    0.012|                    0.012
         3|                    0.011|                    0.011|                    0.011
         4|                   0.0105|                    0.011|                    0.011
         5|                     0.01|                     0.01|                     0.01
         6|                   0.0095|                     0.01|                     0.01
         7|     0.009000000000000001|                    0.009|                    0.009
         8|                   0.0085|                    0.009|                    0.009
         9|                    0.008|                    0.008|                    0.008
        10|                   0.0075|                    0.008|                    0.008
        11|                    0.007|                    0.007|                    0.007
        12|     0.006500000000000001|                    0.007|                    0.007
        13|                    0.006|                    0.006|                    0.006
        14|                   0.0055|                    0.006|                    0.006
        15|                    0.005|                    0.005|                    0.005
        16|    0.0045000000000000005|                    0.005|                    0.005
        17|                    0.004|                    0.004|                    0.004
        18|                   0.0035|                    0.004|                    0.004
        19|                    0.003|                    0.003|                    0.003
        20|                   0.0025|                    0.003|                    0.003
        21|                    0.002|                    0.002|                    0.002
        22|                   0.0015|                    0.002|                    0.002
        23|                    0.001|                    0.001|                    0.001
        24|                   0.0005|                    0.001|                    0.001

The code:

"""Provides an example for setting the time component of key-tangents to very
low values.

Creates a cube object with tweenty-five keys in a position-x track. Then loops
over the time component of the key-tangents of these keys, sets them to
increasingly smaller values and prints out the time values before and after
the changes, as well as the true value of the time t.
"""
import c4d


def main():
    """Runs the example.
    """
    # Creates a cube with a postion-x animation with 25 keys.
    cube = c4d.BaseList2D(c4d.Ocube)
    if cube is None:
        raise MemoryError("Could not allocate object.")

    descID = c4d.DescID (c4d.DescLevel(c4d.ID_BASEOBJECT_REL_POSITION),
                         c4d.DescLevel(c4d.VECTOR_X))
    track = c4d.CTrack(cube, descID)
    if track is None:
        raise MemoryError("Could not allocate track.")
    cube.InsertTrackSorted(track)
    curve = track.GetCurve()
    count = 25

    for t in range(count):
        result = curve.AddKey(c4d.BaseTime(t))
        if result is None:
            raise MemoryError("Could not allocate key.")
        result["key"].SetValue(curve, t ** 1.5)
        result["key"].SetInterpolation(curve, c4d.CINTERPOLATION_SPLINE)

    doc.InsertObject(cube)
    c4d.EventAdd()

    # Loop over the created key and print out their time-tagent values while
    # attempting to set them to incerasingly smaller values.
    print (f"{doc.GetFps()=}\n\n")
    print (f"{'Key Index':>10}|{'Set Value':>25}|{'GetTimeLeft()':>25}|"
           f"{'GetTimeRight()':>25}")
    line = "{:>10}|{:>25}|{:>25}|{:>25}"
    print ("-"*88)

    for i in range(curve.GetKeyCount()):
        ckey = curve.GetKey(i)
        t = (count - i) * 0.0005
        ckey.SetTimeLeft(curve, c4d.BaseTime(t))
        ckey.SetTimeRight(curve, c4d.BaseTime(t))
        print (line.format(
            i, t, ckey.GetTimeLeft().Get(), ckey.GetTimeRight().Get()))
    c4d.EventAdd()


if __name__ == '__main__':
    main()

@aimidi said in SetTimeRight fail!:

SetTangents

Thanks for your help,but not find SetTangents() in python sdk

Hello @chuanzhen,

SetTangent() is a member of CCurve and you must use it when you want to access tangents of keys with a non-custom interpolation. CKey.Get/SetTimeLeft/Right on the other hand always accesses the raw underlying tangent data. So, even when key[c4d.ID_CKEY_PRESET] != c4d.ID_CKEY_PRESET__CUSTOM, CKey.Get/SetTimeLeft/Right will always retrieve the then for the user invisible custom tangents.

Long story short: using CCurve.Get\SetTangent() should not make a difference for you in this case. At least I do not see how it should. But you can of course try.

Cheers,
Ferdinand

@ferdinand Thanks for your help!
I have been looking for the source of the problem. After seeing your answer, I should have looked in the wrong direction (I always thought that SetTimeLeft() could not accurately transmit the value I calculated). Below I uploaded a GIF to show the problem I encountered more accurately.
1: I use Add key slider to dynamically add functions. It will call my autoweight function by default. It can be seen that in the process of dynamic addition, the error of RightTime == 0 of some key frames appears
2: When I dynamically use EasyInOut slider to perform the smoothing process, it also calls the autoweight function, and it still does not correct the wrong situation
3: When I use c4d's default auto tangent classic for these key frames, then use EasyInOut again to perform the smoothing process, the autoweight function will work normally.
So I don’t know why this happens, because the above code is used to set the key in the autoweight function

It seems that can't see the gif in full,i upload a file ,can be download. easyinout2.gif

easyinout2.gif

Hello @chuanzhen,

thank you for your detailed explanation, but I unfortunately still struggle a bit with the details. I will answer as best as I can from what I do understand.

I assume your major problem are the kinks that are introduced into your spline by incorrect tangents.

  1. Cinema 4D has multiple tangent modes which partially or fully take away the control from the user how the tangents between keys are set. So, when you are in another mode than ID_CKEY_PRESET__CUSTOM or have any of the automatisms enabled in ID_CKEY_PRESET__CUSTOM, then setting the raw tangents with CKey won't help you, as they always set the raw tangents. As lined out before, when you want to set tangents with the automatisms enabled, you must must use the tangent methods attached to CCurve.
  2. When you just want to ensure the smoothness/continuity of your curve, you can also use CCurve.SetTimeLeftAdjustValue and its counter part for the right tangent.
  3. Finally, when you want to construct a smooth spline from a to b with all automatisms turned of, you will have to get your hands dirty yourself. I once posted this example, but this is more complicated than your case, since this was for 3D.
  4. When you just want to subdivide a curve without changing its curvature, we cannot give you any detailed instructions on how the curve interpolation of ours works, but you should get pretty close with the common cubic-bezier curves.

If there are remaining questions, I would propose that you follow the recommended pattern of posting executable example code and line out what you would expect to happen and what happens instead.

Cheers,
Ferdinand

@ferdinand Thank you for your detailed answer!
In my autoweight function, there is no error in the calculation result of the tangent, but when setting the CKey, there is a problem. It seems that there are too many parameters set, which causes the left and right time values of the key frame to be set according to the calculation results. Then an unknown change was made, causing the final value to not match the calculated value. Although I still don't know why those settings will cause the value to go wrong.

wrong code:

    key.SetInterpolation(curve,c4d.CINTERPOLATION_SPLINE)

    key.SetTimeLeft(curve,L_time_v)
    key.SetValueLeft(curve,TL_vector[1])
    key.SetTimeRight(curve, R_time_v)
    key.SetValueRight(curve, TR_vector[1])

    key[c4d.ID_CKEY_PRESET] = c4d.ID_CKEY_PRESET__CUSTOM
    key.ChangeNBit(c4d.NBIT_CKEY_AUTO, c4d.NBITCONTROL_CLEAR)
    key.ChangeNBit(c4d.NBIT_CKEY_BREAK, c4d.NBITCONTROL_SET)
    key.ChangeNBit(c4d.NBIT_CKEY_KEEPVISUALANGLE, c4d.NBITCONTROL_SET)

current code:

    key.SetInterpolation(curve,c4d.CINTERPOLATION_SPLINE)
    key.SetTimeLeft(curve,L_time_v)
    key.SetValueLeft(curve,TL_vector[1])
    key.SetTimeRight(curve, R_time_v)
    key.SetValueRight(curve, TR_vector[1])
    key.ChangeNBit(c4d.NBIT_CKEY_AUTO, c4d.NBITCONTROL_CLEAR)

Using the current code, the left and right time values of CKey, the calculated result matches the final result.
this is an print example:

    Calculate_RTime: 0.0301874202486 After_Set_Get_from_Key_RTime 0.03

gif also shows that it is working fine now.

easyinout_end.gif

Hey @chuanzhen,

great to hear that you found your solution! Also: I have not missed that you reported problems with your GIFs. We have discussed this problem internally before (it was then me having a problem) but then moved on. I will reraise the topic and we will see what we can do. The problem is a bit weird; I cannot guarantee that we will fix it. I think it has something to do with standard conformance of file types. ScreenToGif, the tool I am using, seems to produce files that deviate from some sort of core standard. But in other cases, the same files load fine. As I said, it is a bit weird, but we will see if we can squeeze in some time for looking at it.

Cheers,
Ferdinand

@ferdinand I also use ScreenToGif to make pictures!