CTrack in a Stage Object
-
On 02/04/2014 at 14:45, xxxxxxxx wrote:
Thanks for the reply Scott.
The real issue I was having was cycling through the keys. Im not sure if I just needed a C4D reboot, or what the issue was, but yesterday the values I was getting when querying the key at a given frame were in the hundreds of millions and patternless. I restarted this morning, ran the same code and everything "magically" worked... I love when that happens
Was just coming back to post a small diagnostic trace that I put together from searching through the info available here to find the # of keyframes, the value of the key, and the frame of that keyframe. Nothing special, but I figure it might help someone like myself in the future. (When I was searching, I was unable to find anything in the boards about parsing the keyframes of stage object using python.)
If there's a better way to check if an object is a Stage Object and I missed, please let me know.
This will collect all objects, step through them until it finds a stage object that has a camera or base object in the link field, find the animation track, then print the number of keyframes and each keyframe with its value. Again, nothing special.
Thanks again for all the help gents!
import c4d doc = c4d.documents.GetActiveDocument() objects = doc.GetObjects() for i in objects: if i != None: if i[c4d.STAGEOBJECT_CLINK] and type(i[c4d.STAGEOBJECT_CLINK]) in [c4d.CameraObject, c4d.BaseObject]: track = i.GetFirstCTrack() fps = float(doc.GetFps()) while track: curve = track.GetCurve() frames = curve.GetKeyCount() print 'Total Keyframes: '+str(frames) for f in xrange(frames) : key = curve.GetKey(f) print str(f+1)+') '+str(key.GetGeData().GetName())+': '+str(key.GetTime().Get()*int(doc.GetFps())) track = track.GetNext()
-
On 02/04/2014 at 16:13, xxxxxxxx wrote:
This way is a little bit shorter: if type(i[c4d.STAGEOBJECT_CLINK]) == c4d.CameraObject:
-ScottA
-
On 02/04/2014 at 16:42, xxxxxxxx wrote:
Thanks again, Scott. Will it always be a Camera Object?
-
On 02/04/2014 at 18:37, xxxxxxxx wrote:
It should work the same way as your code works. Just tiny bit shorter.
It will return true and go to the next line of code if there is a camera type object in the link field.
If there's another kind of object in the link field. It will return false and skip any code under the If statement.
The code you posted was perfectly fine. But since you asked if there was another way to write it I just posted a different way to write it.If you wanted to check the type of object that's in the stage's link field.
You could write something like this:for i in objects: if i.GetType() == c4d.Ostage and i[c4d.STAGEOBJECT_CLINK] is not None: if i[c4d.STAGEOBJECT_CLINK].GetType() == c4d.Ocamera: print "camera" else: print i[c4d.STAGEOBJECT_CLINK].GetType()
Lots of way to skin a cat.
-ScottA
-
On 03/04/2014 at 09:56, xxxxxxxx wrote:
Awesome! Much appreciated
-
On 03/04/2014 at 12:58, xxxxxxxx wrote:
Hey Scott,
One more question if you dont mind.
How do I delete cameras with Python? I have my list of cameras that need to be deleted, but the cam.Remove() method I have been attempting isnt returning any results. So far I have been unable to find anything on it on the interwebs.
TIA
-
On 03/04/2014 at 14:05, xxxxxxxx wrote:
It sounds like you're doing correctly. But you're just missing c4d.EventAdd()
When using the ScriptManger. If you don't use that code. Then the task you did with your code is sitting in memory and often doesn't take effect until C4D gets updated. Like mouse clicking somewhere in it.
Sometimes you'll get lucky and it will update on it's own. But many times you have to send a message to C4D to tell it to update before you see your changes.import c4d def main() : obj = doc.SearchObject("Camera") obj.Remove() c4d.EventAdd() #<---Very important when using the script manager!! if __name__=='__main__': main()
-ScottA
-
On 03/04/2014 at 17:44, xxxxxxxx wrote:
Not working for me consistently... Unsure of why.
I have had multiple different results in output files after the save. The most common is that the cameras have been untouched. Second is that all cameras aside for a camera that is nested in a Null are deleted. And third is that only one or two cameras have been deleted.
I have tried rebooting, reinstalling, and moving to other machines, but nothing changes my outcome.
Am I missing somehting in here?
Thanks again
import c4d import time import os def buildRanges(doc, objs, fps) : for i in objs: if i != None: if type(i[c4d.STAGEOBJECT_CLINK]) == c4d.CameraObject: track = i.GetFirstCTrack() if track: tbl = {} curve = track.GetCurve() frames = curve.GetKeyCount() for f in xrange(frames) : key = curve.GetKey(f) tbl[f] = {} tbl[f]['cam'] = key.GetGeData() tbl[f]['strt'] = key.GetTime().Get()*int(fps) if f != 0: tbl[f-1]['end'] = int(tbl[f]['strt'])-1 if f == frames-1: tbl[f]['end'] = doc.GetMaxTime().GetFrame(int(fps)) return i, tbl return False #There has to be a better way than this def getCams(obj) : if obj is None: return if obj.GetTypeName() == 'Camera': cams[obj.GetName()] = obj if (obj.GetDown()) : getCams(obj.GetDown()) if (obj.GetNext()) : getCams(obj.GetNext()) doc = c4d.documents.GetActiveDocument() cur_name = doc.GetDocumentName() obj = doc.GetFirstObject() objs = doc.GetObjects() fps = float(doc.GetFps()) stage, f_tbl = buildRanges(doc, objs, fps) #build the camera list. Best method? global cams cams = {} getCams(obj) if f_tbl != False: for f in f_tbl: doc.StartUndo() for i in cams: if i != f_tbl[f]['cam'].GetName() : doc.AddUndo(c4d.UNDOTYPE_DELETE, cams[i]) cams[i].Remove() c4d.EventAdd() shot = 'sh'+str(f+1).zfill(3)+'0' name = cur_name.replace('testSplit', shot) new_scn_path = os.path.join(os.environ['HOME'], 'Desktop', name ) new_doc = c4d.documents.SaveDocument(doc, new_scn_path, c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, c4d.FORMAT_C4DEXPORT) doc.EndUndo() doc.DoUndo(multiple = True)
-
On 03/04/2014 at 18:28, xxxxxxxx wrote:
Here's how I would go about getting all of the cameras. And put them into a list.
import c4d #A list where we will store all of the cameras cams = [] def GetCameras(op) : while(op) : GetCameras(op.GetDown()) if op.GetType() == c4d.Ocamera: cams.append(op) op = op.GetNext() def main() : firstObj = doc.GetFirstObject() GetCameras(firstObj) print cams #Now lets delete all of the cameras that are in the cams list for i in cams: i.Remove() c4d.EventAdd() if __name__=='__main__': main()
-ScottA
-
On 03/04/2014 at 18:47, xxxxxxxx wrote:
Much better! I was pulling that function from another post and felt it was a bit convoluted.
So I only need a single EvenAdd() for all of the removals? I just left work, but Im starting up my VPN to check if this works in my setup.
-
On 04/04/2014 at 00:26, xxxxxxxx wrote:
I FOUND IT!!! (Im a bit excited)
When c4d gets to my for loop to cycle through the different keys on the stage object, the id for the cameras has changed.
When I set a fixed value for f and ran the script without the loop, everything worked fine. So I printed the object stored in cams _in the code above and compared it to a SearchObject on the name of the object stored in cams _and they were different. Changed the cams _to SearchObject and everything is working perfectly.
Thanks for all your help Scott!
This script will read the first available stage object, then separate the scene into as many shots as there are camera changes in the stage object. Inside the new shots will be only the camera in those keyframes and any objects that are visible at the beginning, middle, or end of the range for that particular stage range.
I just started writing this yesterday, so its still very much in test phase. As such, its dumping to my desktop right now, but anyone could easily change the path and filename subs to make it work for your needs.
Ill repost once I have it setting each shot and its animations back to 0 and closing the frame range, too.
import c4d import os def buildRanges(doc, objs, fps) : for i in objs: if i != None: if type(i[c4d.STAGEOBJECT_CLINK]) == c4d.CameraObject: track = i.GetFirstCTrack() if track: tbl = {} curve = track.GetCurve() frames = curve.GetKeyCount() for f in xrange(frames) : key = curve.GetKey(f) tbl[f] = {} tbl[f]['cam'] = key.GetGeData() tbl[f]['strt'] = key.GetTime().Get()*int(fps) if f != 0: tbl[f-1]['end'] = int(tbl[f]['strt'])-1 if f == frames-1: tbl[f]['end'] = doc.GetMaxTime().GetFrame(int(fps)) return i.GetName(), tbl return False, False def getActiveObjects(doc) : on = {} off = {} for i in doc.GetObjects() : if not i.GetName() in on: tag = i.GetTag(c4d.Tdisplay) if tag != None: if tag[c4d.DISPLAYTAG_VISIBILITY] > 0: on[i.GetName()] = i else: off[i.GetName()] = i return on, off def getCams(op) : #<--Thanks ScottA!! while(op) : getCams(op.GetDown()) if op.GetType() == c4d.Ocamera: cams[op.GetName()] = op op = op.GetNext() doc = c4d.documents.GetActiveDocument() cur_name = doc.GetDocumentName() objs = doc.GetObjects() fps = float(doc.GetFps()) stage, f_tbl = buildRanges(doc, objs, fps) cams = {} obj = doc.GetFirstObject() getCams(obj) if f_tbl != False: for f in f_tbl: doc.StartUndo() #calculate the middle frame of the frame section and build a list of the first, middle, and last mid_frame = (f_tbl[f]['end']-f_tbl[f]['strt'])+f_tbl[f]['strt'] frames = [f_tbl[f]['strt'], f_tbl[f]['end'], mid_frame] on_objs = {} off_objs = {} #for each of the first, middle, and last of the frame section for i in frames: #move to the frame doc.SetTime(c4d.BaseTime(i/int(fps))) #update C4D (this took a while to figure out and is a severe pain in the ass :D) c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW|c4d.DRAWFLAGS_NO_THREAD|c4d.DRAWFLAGS_NO_REDUCTION|c4d.DRAWFLAGS_STATICBREAK) on, off = getActiveObjects(doc) on_objs.update(on) off_objs.update(off) #Delete unused objects for i in off_objs: doc.AddUndo(c4d.UNDOTYPE_DELETE, off_objs[i]) off_objs[i].Remove() #Delete unused cameras for i in sorted(cams) : if i != f_tbl[f]['cam'].GetName() : doc.AddUndo(c4d.UNDOTYPE_DELETE, doc.SearchObject(i)) doc.SearchObject(i).Remove() #Delete stage object doc.AddUndo(c4d.UNDOTYPE_DELETE, doc.SearchObject(stage)) doc.SearchObject(stage).Remove() #update c4d.EventAdd() #Build a shot name and path shot = 'sh'+str(f+1).zfill(3)+'0' name = cur_name.replace('ryanSplit', shot) new_scn_path = os.path.join(os.environ['HOME'], 'Desktop', name) #Save the file new_doc = c4d.documents.SaveDocument(doc, new_scn_path, c4d.SAVEDOCUMENTFLAGS_DONTADDTORECENTLIST, c4d.FORMAT_C4DEXPORT) #Undo and start over doc.EndUndo() doc.DoUndo(multiple = True)
-
On 04/04/2014 at 14:38, xxxxxxxx wrote:
Copied over a mistake I made early last night.
mid_frame = (f_tbl[f]['end']-f_tbl[f]['strt'])+f_tbl[f]['strt']
should be:
mid_frame = ((f_tbl[f]['end']-f_tbl[f]['strt'])/2)+f_tbl[f]['strt']