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
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Animated Tiled Camera

    Scheduled Pinned Locked Moved PYTHON Development
    3 Posts 0 Posters 340 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 25/10/2016 at 08:31, xxxxxxxx wrote:

      Hello,

      Got a little project I'm working on.
      Basically I'm trying to make a script that will create a tiled camera for every frame in a user defined range, then save a new file with the frame number as a suffix after setting the tile camera to the scene camera for that frame.

      We start with one animated camera

      I've identified the following main tasks:

      1. From the animated camera, create one static camera for each frame of animation in the user defined range.
      2. Name the cameras with the frame of creation.
      3. Create tiled camera (from c4d content library) and assign the static camera as reference camera.
      4. Set number of tiles per axis.
      5. Enable use tiling.
      6. Set tiled camera as scene camera.
      7. Save file as "documentname_TileFrame####.c4d"

      The settings on the tiled camera:

      The code I've got so far is:

      import c4d  
      from c4d import gui  
      import os  
        
      # Returns a BaseDraw instance  
      bd = doc.GetActiveBaseDraw()  
        
      def set_render_cam() :  
        """  
        Sets the currently selected camera to the active render camera  
        """  
        # Get the selected camera  
        cam = doc.GetActiveObject()  
        # Set the active camera  
        bd.SetSceneCamera(cam)  
        # Re-draws the view  
        c4d.DrawViews()  
        # Adds event  
        c4d.EventAdd()  
        
      def camera_setup() :  
        # Get int of current frame  
        current_frame = doc.GetTime().GetFrame(doc.GetFps())  
         
        # Create null for camera group and set name  
        camgroup = c4d.BaseObject(c4d.Onull)  
        camgroup.InsertBefore(doc.GetFirstObject())  
        camgroup.SetName('CamGroup Frame' + str(current_frame))  
        # Create new cam in null and set name  
        newcam = c4d.BaseObject(c4d.Ocamera)  
        doc.InsertObject(newcam, parent=camgroup)  
        newcam.SetName('Frame ' + str(current_frame))  
         
        # Gets scene cam data and copies to new cam  
        scene_cam = bd.GetSceneCamera(doc)  
        newcam.SetData(scene_cam.GetData())  
        newcam.SetMg(scene_cam.GetMln())    
         
        # Clones Tiled Camera Base  
        tilecambase = doc.SearchObject("Tiled Camera Base")  
        tilecamclone = tilecambase.GetClone()  
        doc.InsertObject(tilecamclone, parent=camgroup)  
        tilecamclone.SetName('Tiled Cam - Frame ' + str(current_frame))  
         
        # Sets 'tiles per axis', 'reference camera' and 'use tiling'  
        tilecamclone[c4d.ID_USERDATA,3] = 5  
        tilecamclone[c4d.ID_USERDATA,4] = doc.SearchObject('Frame ' + str(current_frame))  
        tilecamclone[c4d.ID_USERDATA,1] = 1  
         
        # Set the scene camera to tiled camera  
        ##bd.SetSceneCamera(tilecamclone)  
         
        c4d.EventAdd()  
        c4d.DrawViews()  
         
        
      def cam_range(start, end) :  
        for f in range(start, end + 1) :  
            doc.SetTime(c4d.BaseTime(f, doc.GetFps()))  
            camera_setup()  
         
        c4d.DrawViews()  
        c4d.EventAdd()  
        
        
      def main() :  
        cam_range(91, 100)  
         
        
      if __name__=='__main__':  
        main()  
        
      
      

      When I run it, it creates the cameras for each frame in the range and names them accordingly.
      However, it fails to copy the coordinates (Matrix?) across every frame from the animated camera to each static camera.

      Any ideas on how to achieve this?
      I've tried the usual googling, but come up dry.

      Thanks in advance

      Tom

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

        On 26/10/2016 at 02:31, xxxxxxxx wrote:

        I've managed to get it working!

        In case anyone else is having a similar problem looping through frames and copying values, here is my solution:

        In the loop section of my code:

          
        def cam_range(start, end) :  
          for f in range(start, end + 1) :  
              doc.SetTime(c4d.BaseTime(f, doc.GetFps()))  
              camera_setup()          
              c4d.DrawViews()  
              c4d.EventAdd()  
        

        I needed to add a [

        doc.ExecutePasses(None, True, True, True, 0)
        

        ](https://developers.maxon.net/docs/py/2023_2/modules/c4d.documents/BaseDocument/index.html?highlight=execute#BaseDocument.ExecutePasses)
        This gets it to evaluate every frame. Not sure what else it does, but my script is now working.

        So this is what my loop code looks like now:

          
        def cam_range(start, end) :  
          for f in range(start, end + 1) :  
              doc.SetTime(c4d.BaseTime(f, doc.GetFps()))  
              doc.ExecutePasses(None, True, True, True, 0)  
              camera_setup()          
              c4d.DrawViews()  
              c4d.EventAdd()  
        

        Cheers!

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

          On 26/10/2016 at 06:26, xxxxxxxx wrote:

          Hi Tom,

          welcome to the Plugin Café forums 🙂

          Before suggesting another approach, I'd like to mention a few things in your current code:
          - You are using doc.SetTime(), which is probably not enough for what you want. Additionally you will need to "animate" the document to the given time using ExecutePasses().
          - Then there's an excessive use of EventAdd() and DrawViews() calls. I don't think you need DrawViews() at all in your situation. And EventAdd() is enough to call once after you did a change to the scene. Probably these are just signs of desperation 😉
          - In order to transfer the animation from one object to another, you'd normally copy the CTrack(s).

          Now, just by accident I did a script for the tiled camera some time ago. The idea was to script the functionality of the Tiled Camera, so that Xpresso wasn't needed and I could add a command line option for tiled rendering.
          Here's some of the code, it's just ripped from the middle, but I'm sure you get the point:

          	bd = doc.GetRenderBaseDraw()
          	if bd is None:
          		return
            
          	# Get the active camera
          	cam = bd.GetSceneCamera(doc)
          	if cam is None:
          		return
            
          	# Get the active render settings and output path
          	rd = doc.GetActiveRenderData()
          	filepath, filename = ntpath.split(rd[c4d.RDATA_PATH])
            
          	for tileIdx in range(tileIdxMin, tileIdxMax) :
          		# Prefix the output filename with tile index
          		outputPath = filepath + "/" + str(tileIdx) + "_" + filename
          		rd[c4d.RDATA_PATH] = outputPath
            
          		# Create a new camera and configure it for tiled render
          		camOffset = c4d.BaseObject(c4d.Ocamera)
          		camOffset.SetMg(cam.GetMg())
          		camOffset[c4d.CAMERA_PROJECTION] = cam[c4d.CAMERA_PROJECTION]
          		camOffset[c4d.CAMERAOBJECT_APERTURE] = cam[c4d.CAMERAOBJECT_APERTURE]
          		camOffset[c4d.CAMERAOBJECT_SHOW] = cam[c4d.CAMERAOBJECT_SHOW]
          		camOffset[c4d.CAMERA_FOCUS] = cam[c4d.CAMERA_FOCUS] * fNumTiles
          		camOffset[c4d.CAMERA_ZOOM] = cam[c4d.CAMERA_ZOOM] * fNumTiles
            
          		biasX = math.fmod(float(tileIdx), fNumTiles) - (fNumTiles - 1.0) * 0.5
          		biasY = float(tileIdx / numTiles) - (fNumTiles - 1.0) * 0.5
            
          		camOffset[c4d.CAMERAOBJECT_FILM_OFFSET_X] = fNumTiles * cam[c4d.CAMERAOBJECT_FILM_OFFSET_X] + biasX
          		camOffset[c4d.CAMERAOBJECT_FILM_OFFSET_Y] = fNumTiles * cam[c4d.CAMERAOBJECT_FILM_OFFSET_Y] + biasY
            
          		# Insert the new camera into the scene and set it for rendering
          		doc.InsertObject(camOffset)
          		bd.SetSceneCamera(camOffset)
            
          		# Initialize a bitmap with the result size (must match output size of render settings)
          		# ...
          		# Render the file (and assure saving of rendered image)
          		# ...
          

          So, why am I posting this code? Well, basically with this, you can have a tiled camera, which is independent of animation (opposed to the one in Content Browser). And you don't need to set up one per frame. Instead you can have just one tiled camera (or maybe number of tiles tiled cameras), which you could simply make child of your animated camera. And without copying any animation, you could just render these cameras over the desired frame range. Just an idea.

          1 Reply Last reply Reply Quote 0
          • First post
            Last post