Camera animation to Text file?



  • I'm trying to find a way to export moving camera data (rotation and position) from cinema 4d to a csv file.
    I have found a python script on how to get this on ONE single frame. I'll insert the code I found bellow.
    This code outputs position (x, y and z) and rotation degrees (x, y and z) on one row in different columns, which is perfect.

    My question is how to expand the code to make the script look through each frame in the timeline and not only one frame,
    giving each frame it's own row in the csv doc.

    My lack of python knowledge hinders me from getting closer to my goals. All help is appreciated!

    import c4d
    #Welcome to the world of Python
     
    def Walker(obj):
        if not obj: return
     
        elif obj.GetDown():
            return obj.GetDown()
        while obj.GetUp() and not obj.GetNext():
            obj = obj.GetUp()
        return obj.GetNext()
     
    def main():
        file = c4d.storage.SaveDialog(c4d.FILESELECTTYPE_ANYTHING, title='Save csv file as', force_suffix='csv')
        csv_file = open(file, 'w')
        obj = doc.GetFirstObject()
        while obj:
            if obj.GetType() == 5103:
                name = obj.GetName()
                obj_matrix = obj.GetMg()
                position = obj_matrix.off
                rotation_rad = c4d.utils.MatrixToHPB(obj_matrix,c4d.ROTATIONORDER_XYZGLOBAL)
                rotation_deg = c4d.Vector(c4d.utils.Deg(rotation_rad.x), c4d.utils.Deg(rotation_rad.y), c4d.utils.Deg(rotation_rad.z))
                line = '%s, %s, %s, %s, %s, %s'%(position.x,
                                                     position.y,
                                                     position.z,
                                                     rotation_deg.x,
                                                     rotation_deg.y,
                                                     rotation_deg.z)
                csv_file.write(line + '\n')
            obj = Walker(obj)
        csv_file.close()
     
     
    if __name__=='__main__':
        main()
    


  • Hello and thanks for the question,

    First, for your next threads, please help us keeping things organised and clean. It really simplify our work here.

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

    About your question :

    you need to update the document's time and use ExecutesPasses, you can have more information on this manual

    You can also add some variable to have the beginning and the end of the animation range

    I've updated your script but you should considered doing something better.
    Depending on how many camera you need to export and how your scene update of course.
    You should update each frame, collect all the data than go to the next frame. And organize it on your csv file.

    import c4d
    #Welcome to the world of Python
     
    def Walker(obj):
        if not obj: return
     
        elif obj.GetDown():
            return obj.GetDown()
        while obj.GetUp() and not obj.GetNext():
            obj = obj.GetUp()
        return obj.GetNext()
     
    def main():
        if doc is None:
            raise ValueError("there's no document")
        # Animation Range and save the actual time of the document
        startingFrame = 0
        endFrame = 30
        savedTime = doc.GetTime()
        docFPS = doc.GetFps()
        
        # Changes the document's time to the start of the animation
        currentTime = c4d.BaseTime(startingFrame, docFPS)
        doc.SetTime(currentTime)
        # ExecutePasses to update the whole scene
        doc.ExecutePasses(None, True, True, True, c4d.BUILDFLAGS_NONE)
    
        file = c4d.storage.SaveDialog(c4d.FILESELECTTYPE_ANYTHING, title='Save csv file as', force_suffix='csv')
        csv_file = open(file, 'w')
        obj = doc.GetFirstObject()
        while obj:
            if obj.GetType() == 5103:
                while startingFrame < endFrame:
                    name = obj.GetName()
                    obj_matrix = obj.GetMg()
                    position = obj_matrix.off
                    rotation_rad = c4d.utils.MatrixToHPB(obj_matrix,c4d.ROTATIONORDER_XYZGLOBAL)
                    rotation_deg = c4d.Vector(c4d.utils.Deg(rotation_rad.x), c4d.utils.Deg(rotation_rad.y), c4d.utils.Deg(rotation_rad.z))
                    line = '%s, %s, %s, %s, %s, %s'%(position.x,
                                                     position.y,
                                                     position.z,
                                                     rotation_deg.x,
                                                     rotation_deg.y,
                                                     rotation_deg.z)
                    csv_file.write(line + '\n')
                    # updates the document's time and the scene
                    startingFrame += 1
                    currentTime = c4d.BaseTime(startingFrame, docFPS)
                    doc.SetTime(currentTime)
                    doc.ExecutePasses(None,True, True, True, c4d.BUILDFLAGS_NONE)
            obj = Walker(obj)
        csv_file.close()
        
        # Restores the time 
        doc.SetTime(savedTime)
     
    if __name__=='__main__':
        main()
    

    If your camera is animated with only key frames (tracks) you can retrieves those value with CCurve.GetValue(time, fps).

        # tracks to export
        trackListToExport = [c4d.ID_BASEOBJECT_POSITION, c4d.ID_BASEOBJECT_ROTATION, c4d.ID_BASEOBJECT_SCALE]
        
        # Gets all tracks
        tracks = op.GetCTracks()
        if not tracks:
            raise ValueError("Failed to retrieved animated tracks information for obj1.")
        
        for track in tracks:
            # Retrieves the full parameter ID (DescID) describing a parameter.
            did = track.GetDescriptionID()
    
            # If the Parameter ID of the current CTracks is not on the trackListToExport we go to the next one.
            if not did[0].id in trackListToExport:
                continue
    
            # Finds the track
            foundTrack = op.FindCTrack(did)
            if foundTrack:
                # Gets the curve of that track
                cc = foundTrack.GetCurve()
                if cc is None:
                    raise ValueError("no curve retrieved")
                
                t = doc.GetTime()
                print cc.GetValue(t, doc.GetFps())
    

    Cheers,
    Manuel



  • This is a great start - will defiantly be using this to get closer to the desired end result :)
    Thanks so much Manuel for your help!


Log in to reply