"History" xpresso node python analogue?



  • Hi,

    For your next threads, please help us keeping things organised and clean. I know it's not your priority but it really simplify our work here.

    I've added the tags and marked this thread as a question so when you considered it as solved, please change the state :)

    This is some kind of problem that cinema 4D have. Depending on what you want to retrieve as information you can be stucked.

    Let's say you want to have a position of an object at frame X.
    Dynamics need the information of frame X-1 to calculate the frame X. So when you read the timeline, you can store information from the past, but not the futur ones.
    If you have a track you can retrieve the value of that track an any point in time.
    If the object is moving based on the time of the document, you can change the time document and ExecutePasses to update the scene at that time and retrieve the information you need.

    You can store your data in a global variable, of course if it's consuming too much memory you have to bake to a file.

    Solution can also be different if you are on a script or a tag, a plugin, a node etc.

    what are you trying to achieve ? Maybe just adding a "bake" function could be one solution.

    Cheers,
    Manuel



  • @zipit it's looking great, thank you for such a snippet. But the thing is there may be no keyframes on the object, but I must retrieve the changes in it's properties anyway..

    @m_magalhaes said in "History" xpresso node python analogue?:

    For your next threads, please help us keeping things organised and clean

    Ok, sorry. I've been on the old Cafe, but it's the first time after the move, I will try to follow new guides

    @m_magalhaes said in "History" xpresso node python analogue?:

    what are you trying to achieve ?

    Actually, I need to calculate the velocityes of the animated parameters of the object from the deformer (ObjectData plugin, not Python deformer) and trigger an action when it overcomes a threshold. So I need to check the values at least a frame back from the current time



  • hi,

    in that case, you should try to change the document time, ExecutePasses to update the scene and retrieve the information. It could be enough.

    If you are inside a deformer you should probably need to clone the document and work on the cloned. But, if the animation is based on some random, that could maybe change your animation. (something you have to keep in mind somewhere)

    Cheers,
    Manuel



  • @m_magalhaes said in "History" xpresso node python analogue?:

    you should try to change the document time

    But how would it affect the speed/scene handling? I'm afraid it will be too cycle/memory hungry.
    Actually, I see Delay and Jiggle use some way of retrieving the time-dependant values, and actually the result of their work is incorrect if some frames are dropped.
    Can't you give a clue please, how is it done in Jiggle? I start to suspect it simply stores previous frame value as a global variable and rewrites it every frame, no matter if some are dropped. Right guess?



  • Here is an example which shows different approaches. Memory consumption should not be your biggest issue.

    Cheers,
    zipit

    # -*- coding: utf-8 -*-
    
    """ This script expects you to have an object selected which has a position
    animation. Also the active document is excpected to be at least 1s long and
    the current time should be larger than .1 seconds.
    """
    
    import c4d
    
    def main():
        """
        """
        if op is None:
            return
    
        # the time the active document is currently at
        current_time = doc.GetTime()
    
        # print out the position at time of the selected object
        print "current postion:", op[c4d.ID_BASEOBJECT_REL_POSITION]
        print "current time:", current_time.Get()
    
        # construct a time value that was 100ms before the current time,
        # but does not go below frame 0 (assuming that is what you want)
        lookback_time = c4d.BaseTime(max(0., current_time.Get() - .1))
    
        # set the document time to the time you want to poll
        doc.SetTime(lookback_time)
        # let the cinema update the document, you should lookup that method
        # and tailor the call to your needs. This will
        doc.ExecutePasses(None,
                          animation=True,
                          expressions=True,
                          caches=True,
                          flags=c4d.BUILDFLAGS_NONE)
    
        # print out the position at time of the selected object
        print "lookback postion:", op[c4d.ID_BASEOBJECT_REL_POSITION]
        print "lookback time:", lookback_time.Get()
    
        # set the document back to the original time
        doc.SetTime(current_time)
        doc.ExecutePasses(None,
                          animation=True,
                          expressions=True,
                          caches=True,
                          flags=c4d.BUILDFLAGS_NONE)
    
        # Everything should be where it has been before.
        print "postion after lookback:", op[c4d.ID_BASEOBJECT_REL_POSITION]
    
        # But this all could mess with the current state of your document.
        # To circumvent this, you could just clone the document and do the
        # lookups in the clone.
    
        lookup_doc = doc.GetClone(0)
        lookup_doc.SetTime(lookback_time)
    
        lookup_doc.ExecutePasses(None,
                                 animation=True,
                                 expressions=True,
                                 caches=True,
                                 flags=c4d.BUILDFLAGS_NONE)
    
        obj = lookup_doc.GetActiveObject()
        pos = obj[c4d.ID_BASEOBJECT_REL_POSITION]
        print "pos of the selected object in the lookup doc:", pos
    
        # Make life a bit easier for Python's GC
        lookup_doc.Flush()
    
        # But if you have some sort of seld-dependent animation in your document,
        # particles for example, this will not work, just as timeline scrubbing
        # won't work for these animations.
    
        # The only solution then is to cache your data:
    
        cache_doc = doc.GetClone()
        obj = cache_doc.GetActiveObject()
    
        # let's say we want to cache the first second of the document with
        # a stride of 100ms.
        min_time = 0.
        max_time = 1.
        stride = .1
        steps = int((max_time - min_time) / stride) + 1
    
        cache = {}
    
        for i in range(steps):
            t = i * stride
            bt = c4d.BaseTime(t)
            cache_doc.SetTime(bt)
            cache_doc.ExecutePasses(None,
                                    animation=True,
                                    expressions=True,
                                    caches=True,
                                    flags=c4d.BUILDFLAGS_NONE)
            # For some data types, like for example SplineData you will have
            # to clone the data, as we otherwise will only store a reference to
            # the data, i.e. the same object over and over again.
            cache[t] = obj[c4d.ID_BASEOBJECT_REL_POSITION]
    
        cache_doc.Flush()
    
        print "cached data for 0 <= t <= 1 of the position animation:", cache
    
    if __name__ == '__main__':
        main()
    
    


  • @intenditore said in "History" xpresso node python analogue?:

    Can't you give a clue please, how is it done in Jiggle?

    it store the actual value of the point in a "particle" kind of data type.
    When it update, it check the length of that stored point with the actual one and act accordingly.
    That's why the jiggle deformer works even if you play the animation backwards. But the result is not the same when you play foward.

    Cheers,
    Manuel



  • Wow, seems it's the best dev support forum I ever visited 😃
    Thank you much! Seems I get the idea

    @zipit said in "History" xpresso node python analogue?:

    Here is an example which shows different approaches

    Many thanks! Where do you get those snippets from?



  • @intenditore said in "History" xpresso node python analogue?:

    Many thanks! Where do you get those snippets from?

    I wrote them ;)

    Cheers,
    zipit



  • @zipit oh! That's a huge effort! I do appreciate it :)



  • hi,

    can we considered this thread as solved ? (at least we answered your question)
    Without further feedback i'll set it to solved tomorrow.

    Cheers,
    Manuel