Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Recent
    • Tags
    • Users
    • Login

    CTrack in a Stage Object

    Scheduled Pinned Locked Moved PYTHON Development
    14 Posts 0 Posters 1.2k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      On 02/04/2014 at 16:42, xxxxxxxx wrote:

      Thanks again, Scott. Will it always be a Camera Object?

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        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

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          On 03/04/2014 at 09:56, xxxxxxxx wrote:

          Awesome! Much appreciated

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            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

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              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

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                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)
                
                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  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

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    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.

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      Helper
                      last edited by

                      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)
                      
                      1 Reply Last reply Reply Quote 0
                      • H Offline
                        Helper
                        last edited by

                        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']
                        
                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post