how to import mesh animation from cinema4d into blender?

1

I need to import a mesh animation from Cinema4D into Blender.

I tried to do that using Collada.The Collada 1.3 importer doesn't seem to do anything, the Collada 1.4 importer seems to work, but the animation didn't get imported into Blender.

After reading this post, I tried modifying the animation nodes in the collada files, as explained in the post:

<library animation>
<animation>
<animation>
data
<animation>
<animation>
data
<animation>
<animation>
<library animation>

to this:

<library animation>
<animation>
data
<animation>
<animation>
data
<animation>
<library animation>

, but that doesn't work for me. I get an errors when the file is parsed.

Any hints on how to import a mesh animation from Cinema4D into Blender ?

George Profenza

Posted 2010-06-02T11:54:26.420

Reputation: 728

Answers

0

I ended up installing Py4D since I could barely found usable C.O.F.F.E.E. documentation.

I needed to export Point Level Animation and Morph Tag animation into Blender so I wrote a little script that handles that.

import c4d
from c4d import documents,UVWTag
from c4d.utils import Deg
from c4d import symbols as sy, plugins, utils, bitmaps, gui
import math


def BlenderExport():
    if not op: return
    if op.GetType() != 5100:
        print 'Selected Object is not an editable mesh'
        return
    unit = 0.001#for scale
    foffset = 1#for frames
    bd = doc.GetRenderBaseDraw()
    scr = bd.GetFrameScreen()
    rd = doc.GetActiveRenderData()
    sizeX = int(rd[sy.RDATA_XRES_VIRTUAL])
    sizeY = int(rd[sy.RDATA_YRES_VIRTUAL])
    name  = op.GetName()
    fps   = doc.GetFps()
    sFrame= doc.GetMinTime().GetFrame(fps)
    eFrame= doc.GetMaxTime().GetFrame(fps)
    code  = 'import Blender\nfrom Blender import *\nimport bpy\nfrom Blender.Mathutils import *\n\nscn = bpy.data.scenes.active\ncontext=scn.getRenderingContext()\ncontext.fps = '+str(fps)+'\ncontext.sFrame = '+str(sFrame)+'\ncontext.eFrame = '+str(eFrame)+'\ncontext.sizeX = '+str(sizeX)+'\ncontext.sizeY = ' + str(sizeY) + '\n'

    def GetMesh(code):
        # goto 0
        doc.SetTime(c4d.BaseTime(0, fps))
        c4d.DrawViews( c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_REDUCTION|c4d.DA_STATICBREAK )
        c4d.GeSyncMessage(c4d.EVMSG_TIMECHANGED)
        doc.SetTime(doc.GetTime())
        c4d.EventAdd(c4d.EVENT_ANIMATE)

        code      += 'editmode = Window.EditMode()\nif editmode:\tWindow.EditMode(0)\n'
        coords4D   = op.GetPointAll()
        coords     = 'coords = ['
        uvw        = 0
        uvs        = 'uvs = ['
        for tag in op.GetTags():
            if tag.GetName() == "UVW":
                uvw = tag
        for c in coords4D:
            coords += '['+str(c.x*unit)+','+str(c.z*unit)+','+str(c.y*unit)+'],'
        coords     = coords.rpartition(',')[0] + ']\n'
        faces4D    = op.GetAllPolygons()
        fcount     = 0
        faces      = 'faces = ['
        for f in faces4D:
            faces  += '['+str(f)+'],'
            uv = uvw.Get(fcount);
            uvs  += '[Vector('+str(uv[0].x)+','+str(1.0-uv[0].y)+'),Vector('+str(uv[1].x)+','+str(1.0-uv[1].y)+'),Vector('+str(uv[2].x)+','+str(1.0-uv[2].y)+')],'
            fcount += 1

        faces      = faces.rpartition(',')[0] + ']\n'
        uvs        = uvs.rpartition(',')[0] + ']\n'

        code       = code + coords + faces + uvs
        code      += "c4dmesh = bpy.data.meshes.new('"+name+"_mesh')\nc4dmesh.verts.extend(coords)\nc4dmesh.faces.extend(faces)\n\nob = scn.objects.new(c4dmesh,'"+name+"_obj')\nc4dmesh.flipNormals()\n\nif editmode:\tWindow.EditMode(1)\n\n"
        code      += "c4dmesh.quadToTriangle()\nc4dmesh.addUVLayer('c4duv')\n"
        code      += "for f in range(0,"+str(fcount)+"):\n\tc4dmesh.faces[f].uv = uvs[f]\n"

        return code

    def GetIPOKeys(code):
        # store properties for tracks
        tracks   = op.GetCTracks()
        # 0,1,2 = Position, 3,4,5 = Scale, 6,7,8 = Rotation, 9 = PLA
        # props = [[lx,f],[ly,f],[lz,f],[sx,f],[sy,f],[sz,f],[rx,f],[ry,f],[rz,f]]
        try:
            props = []
            trackIDs = [3,4,5,6,7,8,0,2,1]
            propVals = ['LocX','LocZ','LocY','SizeX','SizeY','SizeZ','RotZ','RotX','RotY']
            propIPOs = ['Ipo.OB_LOCX','Ipo.OB_LOCZ','Ipo.OB_LOCY','Ipo.OB_SCALEX','Ipo.OB_SCALEY','Ipo.OB_SCALEY','Ipo.OB_ROTZ','Ipo.OB_ROTX','Ipo.OB_ROTY']
            for t in range(0,9):
                props.append([[],[]])
                curve    = tracks[t].GetCurve()
                keyCount = curve.GetKeyCount()
                for k in range(0,keyCount):  
                        key   = curve.GetKey(k)
                        props[t][0].append(key.GetValue())
                        props[t][1].append(key.GetTime().GetFrame(fps))
            # find the max key
            maxProp = max(enumerate(props), key = lambda tup: len(tup[1]))[1][1]
            maxKeys = len(maxProp)
            # loop through tracks and keys
            for key in range(0,maxKeys):
                code += "Blender.Set('curframe',"+str(maxProp[key])+")\n"
                for track in trackIDs:
                    if(key < len(props[track][0])):
                        code += "ob."+propVals[track] + " = " + str(props[track][0][key]) + '\n'
                        code += 'key = ob.insertIpoKey(' + propIPOs[track] + ')\n'
        except:
            pass
        return code
    #     mesh/morph animation -> mesh always has the same number of verts
    def GetShapeKeys(code):
        track = 0;
        tracks = op.GetCTracks()
        for t in tracks:
            if(t.GetName() == 'PLA'):   track = t
        # track    = op.GetCTracks()[9]    
        if track != 0:
            curve    = track.GetCurve()
            keyCount = curve.GetKeyCount()
            verts    = []
            frames   = []
            vertsNum  = op.GetPointCount()
            ctime = doc.GetTime()

            for k in range(1,keyCount):
                key = curve.GetKey(k)
                frames.append(key.GetTime().GetFrame(fps))
                c4d.StatusSetBar(100*(k/keyCount))
                doc.SetTime(key.GetTime())
                c4d.DrawViews( c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_REDUCTION|c4d.DA_STATICBREAK )
                c4dvecs = op.GetPointAll();
                blendvecs = []
                for v in c4dvecs:
                    blendvecs.append([v.x*unit,v.z*unit,v.y*unit])
                verts.append(blendvecs)
                c4d.GeSyncMessage(c4d.EVMSG_TIMECHANGED)
            doc.SetTime(ctime)
            c4d.EventAdd(c4d.EVENT_ANIMATE)
            c4d.StatusClear()

            code += '\n\n# shape keys\nverts = ' + str(verts) + '\n'
            code += "if(ob.activeShape == 0):\n\tob.insertShapeKey()\n\n"
            for f in range(0,len(frames)):
                kNum = str(f+1)
                code += "if editmode:   Window.EditMode(0)\n"
                code += "for v in range(0,"+str(vertsNum)+"):\n\tc4dmesh.verts[v].co.x = verts["+str(f)+"][v][0]\n\tc4dmesh.verts[v].co.y = verts["+str(f)+"][v][1]\n\tc4dmesh.verts[v].co.z = verts["+str(f)+"][v][2]\n"
                code += "c4dmesh.calcNormals()\n"
                code += "ob.insertShapeKey()\n"
                code += "if editmode:   Window.EditMode(1)\n"
                code += "shapeKey = ob.getData().getKey()\n"
                code += "newIpo = Ipo.New('Key','newIpo')\n"
                code += "if(shapeKey.ipo == None):   shapeKey.ipo = newIpo\n"
                code += "if(shapeKey.ipo['Key "+kNum+"'] == None):   shapeKey.ipo.addCurve('Key "+kNum+"')\n"
                if(f == 0):  code += "shapeKey.ipo['Key "+kNum+"'].append(BezTriple.New(1.0,0.0,0.0))\n"
                if(f > 0):  code += "shapeKey.ipo['Key "+kNum+"'].append(BezTriple.New("+str(float(frames[f-1]))+",0.0,0.0))\n"
                code += "shapeKey.ipo['Key "+kNum+"'].append(BezTriple.New("+str(float(frames[f]))+",1.0,0.0))\n"
        else:
            #no PLA tracks, look for morph tag
            vertsNum  = op.GetPointCount()
            for tag in op.GetTags():
                if tag.GetType() == 1019633:
                    # print tag[sy.MORPHTAG_MORPHS]
                    '''
                    work around
                    1. store first key for each track curve
                    2. set the first key value to 1 for the 1st track and 0 for the others
                    3. store the mesh vertices -> track name verts = []
                    4. after all track verts are stored, restore the original values
                    5. write the the curve keys for blender shape keys
                    '''
                    code += "if(ob.activeShape == 0):\n\tob.insertShapeKey()\n\n"
                    tc = 0
                    tcs = str(tc+1)
                    for track in tag.GetCTracks():
                        curve = track.GetCurve()
                        value = curve.GetKey(0).GetValue()
                        curve.GetKey(0).SetValue(curve,1.0)
                        print track.GetName()
                        doc.SetTime(c4d.BaseTime(0, fps))
                        c4d.DrawViews( c4d.DA_ONLY_ACTIVE_VIEW|c4d.DA_NO_THREAD|c4d.DA_NO_REDUCTION|c4d.DA_STATICBREAK )
                        c4dvecs = op.GetPointAll();
                        blendverts = []
                        for v in c4dvecs:
                            blendverts.append([v.x*unit,v.z*unit,v.y*unit])
                        code += "Key"+tcs+"verts = " + str(blendverts)+"\n"
                        code += "if editmode:   Window.EditMode(0)\n"
                        code += "for v in range(0,"+str(vertsNum)+"):\n\tc4dmesh.verts[v].co.x = Key"+tcs+"verts[v][0]\n\tc4dmesh.verts[v].co.y = Key"+tcs+"verts[v][1]\n\tc4dmesh.verts[v].co.z = Key"+tcs+"verts[v][2]\n"
                        code += "c4dmesh.calcNormals()\n"
                        code += "ob.insertShapeKey()\n"
                        code += "if editmode:   Window.EditMode(1)\n"
                        code += "shapeKey = ob.getData().getKey()\n"
                        code += "newIpo = Ipo.New('Key','newIpo')\n"
                        code += "if(shapeKey.ipo == None):   shapeKey.ipo = newIpo\n"
                        code += "if(shapeKey.ipo['Key "+tcs+"'] == None):   shapeKey.ipo.addCurve('Key "+tcs+"')\n"
                        print op.GetPointAll()
                        c4d.GeSyncMessage(c4d.EVMSG_TIMECHANGED)
                        curve.GetKey(0).SetValue(curve,value)
                        keyCount = curve.GetKeyCount()
                        for k in range(0,keyCount):
                            key = curve.GetKey(k)
                            value = key.GetValue()
                            frame = key.GetTime().GetFrame(fps)
                            code += "shapeKey.ipo['Key "+tcs+"'].append(BezTriple.New("+str(float(frame))+","+str(value)+",0.0))\n"
                        tc += 1
                        tcs = str(tc+1)

                    c4d.EventAdd(c4d.EVENT_ANIMATE)
        return code

    def GetCamera(code):
        bd = doc.GetRenderBaseDraw()
        cp = bd.GetSceneCamera(doc)
        if cp is None: cp = bd.GetEditorCamera()
        fov = Deg(cp[sy.CAMERAOBJECT_FOV])
        pos = cp.GetPos()
        rot = cp.GetRot()
        code += "\nc4dCam = Camera.New('persp','c4d_"+cp.GetName()+"')\nc4dCam.drawPassepartout = True\nc4dCam.alpha = 0.5\nc4dCam.drawLimits = 1\nc4dCam.dofDist = 100.0\n"
        code += "c4dCam.angle = "+str(fov)+"\nc4dCamLens = c4dCam.lens\nc4dCam.lens = c4dCamLens\nWindow.RedrawAll()\nc4dCamObj = scn.objects.new(c4dCam)\n"
        code += "c4dCamObj.setLocation("+str([pos.x,pos.z,pos.y])+")\n"
        code += "c4dCamObj.setEuler("+str([rot.x+(math.pi*.5),rot.y,rot.z])+")\n"
        code += "scn.setCurrentCamera(c4dCamObj)\n"
        return code

    code = GetMesh(code)
    code = GetIPOKeys(code)
    code = GetShapeKeys(code)
    code = GetCamera(code)

    file = open(doc.GetDocumentPath()+'/'+op.GetName()+'_export.py','w')
    file.write(code)
    file.close()


BlenderExport()

Follow this and this for details.

George Profenza

Posted 2010-06-02T11:54:26.420

Reputation: 728

0

the answer here seems pretty clear even with my minor use of blender. The xml is invalid. This is probably what it should look like (below). I can see where using open tags instead of close tags would throw parsing errors. This will remove parsing errors, if library animation is in fact the root xml element.

<library animation>
<animation>
data
</animation>
<animation>
data
</animation>
</library animation>

ghostsource

Posted 2010-06-02T11:54:26.420

Reputation: 167

I posted the sample as it was on the cgsociety forum. I did indeed close the tags :) Still the import doesn't work in Blender 2.49 with the Collada 1.4.1 importer. Blender 2.50 imports collada with animation, but not all the animation properties(translation,rotation,scale) are properly imported. – George Profenza – 2010-07-06T07:44:10.180