问题
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:
Problem solved!
In case anyone comes in here looking for the answer, I spoke to Otomo via email and he kindly explained that the problem lies in the .dae file being exported incorrectly from C4D.
I hope Otomo doesn't mind me quoting his email, I just don't want other people to waste the time I did on such a stupid problem.
Open up the .dae in a text editor and change:
data data
to this:
data data
The fps must also be the same in both c4d and blender.
I tried that, but I get an error:
FEEDBACK: Illusoft Collada 1.4 Plugin v0.3.162 started
The minor version of the file you are using is newer then the plug-in, so errors may occur.
image not found: None
Traceback (most recent call last):
File "/Applications/blender/blender.app/Contents/MacOS/.blender/scripts/bpymodules/colladaImEx/cstartup.py", line 681, in ButtonEvent
onlyMainScene, applyModifiers)
File "/Applications/blender/blender.app/Contents/MacOS/.blender/scripts/bpymodules/colladaImEx/translator.py", line 120, in __init__
self.__Import(fileName)
File "/Applications/blender/blender.app/Contents/MacOS/.blender/scripts/bpymodules/colladaImEx/translator.py", line 127, in __Import
documentTranslator.Import(fileName)
File "/Applications/blender/blender.app/Contents/MacOS/.blender/scripts/bpymodules/colladaImEx/translator.py", line 333, in Import
self.sceneGraph.LoadFromCollada(self.colladaDocument.visualScenesLibrary.items, self.colladaDocument.scene)
File "/Applications/blender/blender.app/Contents/MacOS/.blender/scripts/bpymodules/colladaImEx/translator.py", line 550, in LoadFromCollada
ob = sceneNode.ObjectFromDae(daeNode)
File "/Applications/blender/blender.app/Contents/MacOS/.blender/scripts/bpymodules/colladaImEx/translator.py", line 2079, in ObjectFromDae
a.LoadFromDae(daeAnimation, daeNode, newObject)
File "/Applications/blender/blender.app/Contents/MacOS/.blender/scripts/bpymodules/colladaImEx/translator.py", line 1254, in LoadFromDae
interpolationsSource = daeAnimation.GetSource(interpolations.source)
AttributeError: 'NoneType' object has no attribute 'source'
Has anyone come across this issue ? Where can I find a newer Collada importer ? Any hints on modifying the importer ?
Note: Blender 2.5a2 imports collada animations, but the coordinate system is different and not all animation makes it through. For example, when I animate a box from 0,0,0 to 100,100,100, rotate it on x,y,z and scale it on x,y,z, in Blender I get: translation on 1 axis(x which originally is y in cinema 4d), rotation is fine, scale is ignored.
回答1:
I ended up writing a script.
I barely found usable C.O.F.F.E.E. documentation so went ahead and installed py4D.
The documentation is pretty good and the support on the forum is amazing.
Here's the current script:
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()
It supports ipo keys(position,rotation,scale). Point Level Animation gets converted to multiple shape keys. Morph Tag animation preserves nicely.
来源:https://stackoverflow.com/questions/2957310/3d-animation-from-cinema4d-to-blender