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
    • Register
    • Login
    1. Maxon Developers Forum
    2. karthikbp
    K
    Offline
    • Profile
    • Following 0
    • Followers 0
    • Topics 3
    • Posts 15
    • Groups 0

    karthikbp

    @karthikbp

    0
    Reputation
    12
    Profile views
    15
    Posts
    0
    Followers
    0
    Following
    Joined
    Last Online

    karthikbp Unfollow Follow

    Latest posts made by karthikbp

    • RE: Tile rendering with Cinema 4D

      Thanks @ferdinand .

      I was about to add to this forum post that the rendered images are bit darker than actual.

      Thanks for the code link. Here's my updated script with changes for OCIO and I was able to get it rendering correctly at least locally.
      Anything to avoid or missed here?

      import c4d
      import os
      
      doc: c4d.documents.BaseDocument
      op: c4d.BaseObject | None
      
      
      def EnsureIsOcioDocument(doc: c4d.documents.BaseDocument) -> None:
          if doc[c4d.DOCUMENT_COLOR_MANAGEMENT] is not c4d.DOCUMENT_COLOR_MANAGEMENT_OCIO:
              doc[c4d.DOCUMENT_COLOR_MANAGEMENT] = c4d.DOCUMENT_COLOR_MANAGEMENT_OCIO
              doc.UpdateOcioColorSpaces()
              if c4d.threading.GeIsMainThreadAndNoDrawThread():
                  c4d.EventAdd()
      
      
      def main() -> None:
          """Renders the scene as a grid of tiles, then reassembles into the final image."""
          # --- Configure these ---
          tiles_x = 2
          tiles_y = 2
          output_dir = os.path.join(os.path.expanduser("~"), "Desktop", "tiles")
          final_path = os.path.join(output_dir, "final_assembled.png")
          # ------------------------
      
          os.makedirs(output_dir, exist_ok=True)
          EnsureIsOcioDocument(doc)
      
          if not doc.GetDocumentPath():
              c4d.gui.MessageDialog("Please save the document first.")
              return
      
          # Work directly on the document's render data, matching the reference pattern.
          renderData: c4d.documents.RenderData = doc.GetActiveRenderData()
          data: c4d.BaseContainer = renderData.GetDataInstance()
      
          requiresBaking: bool = data[c4d.RDATA_FORMATDEPTH] is c4d.RDATA_FORMATDEPTH_8
      
          xRes: int = int(data[c4d.RDATA_XRES_VIRTUAL] or data[c4d.RDATA_XRES])
          yRes: int = int(data[c4d.RDATA_YRES_VIRTUAL] or data[c4d.RDATA_YRES])
          tile_w = xRes // tiles_x
          tile_h = yRes // tiles_y
      
          # Determine save bit flags based on format depth
          if data[c4d.RDATA_FORMATDEPTH] is c4d.RDATA_FORMATDEPTH_16:
              save_bits = c4d.SAVEBIT_16BITCHANNELS
          elif data[c4d.RDATA_FORMATDEPTH] is c4d.RDATA_FORMATDEPTH_32:
              save_bits = c4d.SAVEBIT_32BITCHANNELS
          else:
              save_bits = c4d.SAVEBIT_NONE
      
          # Save original render region state to restore later
          orig_region = data[c4d.RDATA_RENDERREGION]
          orig_region_left = data[c4d.RDATA_RENDERREGION_LEFT]
          orig_region_top = data[c4d.RDATA_RENDERREGION_TOP]
          orig_region_right = data[c4d.RDATA_RENDERREGION_RIGHT]
          orig_region_bottom = data[c4d.RDATA_RENDERREGION_BOTTOM]
          orig_bake_flag = data.GetBool(c4d.RDATA_BAKE_OCIO_VIEW_TRANSFORM_RENDER)
      
          if requiresBaking:
              data[c4d.RDATA_BAKE_OCIO_VIEW_TRANSFORM_RENDER] = False
      
          tile_bmps = {}
          for ty in range(tiles_y):
              for tx in range(tiles_x):
                  left = tx * tile_w
                  top_ = ty * tile_h
                  right = left + tile_w
                  bottom = top_ + tile_h
      
                  data[c4d.RDATA_RENDERREGION] = True
                  # RDATA_RENDERREGION_* are offsets inward from each edge,
                  # not absolute pixel coordinates.
                  data[c4d.RDATA_RENDERREGION_LEFT] = left
                  data[c4d.RDATA_RENDERREGION_TOP] = top_
                  data[c4d.RDATA_RENDERREGION_RIGHT] = xRes - right
                  data[c4d.RDATA_RENDERREGION_BOTTOM] = yRes - bottom
      
                  # Always render as 32-bit float
                  bmp = c4d.bitmaps.MultipassBitmap(xRes, yRes, c4d.COLORMODE_RGBf)
                  bmp.AddChannel(True, True)
      
                  print(f"Rendering tile ({tx}, {ty}) region=({left},{top_})-({right},{bottom})")
                  result = c4d.documents.RenderDocument(
                      doc,
                      data,
                      bmp,
                      c4d.RENDERFLAGS_EXTERNAL,
                  )
      
                  if result != c4d.RENDERRESULT_OK:
                      print(f"Tile ({tx}, {ty}) failed with code: {result}")
                      # Restore original settings before returning
                      data[c4d.RDATA_RENDERREGION] = orig_region
                      data[c4d.RDATA_RENDERREGION_LEFT] = orig_region_left
                      data[c4d.RDATA_RENDERREGION_TOP] = orig_region_top
                      data[c4d.RDATA_RENDERREGION_RIGHT] = orig_region_right
                      data[c4d.RDATA_RENDERREGION_BOTTOM] = orig_region_bottom
                      data[c4d.RDATA_BAKE_OCIO_VIEW_TRANSFORM_RENDER] = orig_bake_flag
                      return
      
                  # Bake OCIO and null profiles — exactly as reference
                  if requiresBaking:
                      bmp = c4d.documents.BakeOcioViewToBitmap(bmp, data, c4d.SAVEBIT_NONE) or bmp
      
                  bmp.SetColorProfile(c4d.bitmaps.ColorProfile(), c4d.COLORPROFILE_INDEX_DISPLAYSPACE)
                  bmp.SetColorProfile(c4d.bitmaps.ColorProfile(), c4d.COLORPROFILE_INDEX_VIEW_TRANSFORM)
      
                  # Crop tile preserving bit depth
                  tile_bmp = bmp.GetClonePart(left, top_, tile_w, tile_h)
                  if tile_bmp is None:
                      print(f"Tile ({tx}, {ty}) crop failed")
                      continue
      
                  tile_path = os.path.join(output_dir, f"tile_{tx}_{ty}.png")
                  tile_bmp.Save(tile_path, c4d.FILTER_PNG, c4d.BaseContainer(), save_bits)
                  print(f"Saved {tile_path}")
                  tile_bmps[(tx, ty)] = tile_bmp
      
          # Restore original render data settings
          data[c4d.RDATA_RENDERREGION] = orig_region
          data[c4d.RDATA_RENDERREGION_LEFT] = orig_region_left
          data[c4d.RDATA_RENDERREGION_TOP] = orig_region_top
          data[c4d.RDATA_RENDERREGION_RIGHT] = orig_region_right
          data[c4d.RDATA_RENDERREGION_BOTTOM] = orig_region_bottom
          data[c4d.RDATA_BAKE_OCIO_VIEW_TRANSFORM_RENDER] = orig_bake_flag
      
          # --- Reassemble using GetPixelCnt/SetPixelCnt to preserve full bit depth ---
          print("Assembling final image...")
      
          # Get bit depth from the first tile
          first_tile = tile_bmps.get((0, 0))
          if first_tile is None:
              print("No tiles to assemble")
              return
      
          tile_bpp = first_tile.GetBt()
          bpc = tile_bpp // 3
          if bpc == 32:
              color_mode = c4d.COLORMODE_RGBf
              inc = 12
          elif bpc == 16:
              color_mode = c4d.COLORMODE_RGBw
              inc = 6
          else:
              color_mode = c4d.COLORMODE_RGB
              inc = 3
      
          final_bmp = c4d.bitmaps.BaseBitmap()
          final_bmp.Init(xRes, yRes, depth=tile_bpp)
      
          row_buffer = bytearray(tile_w * inc)
          row_view = memoryview(row_buffer)
      
          for ty in range(tiles_y):
              for tx in range(tiles_x):
                  if (tx, ty) not in tile_bmps:
                      continue
                  tile_bmp = tile_bmps[(tx, ty)]
                  dst_x = tx * tile_w
                  dst_y = ty * tile_h
                  for py in range(tile_h):
                      tile_bmp.GetPixelCnt(0, py, tile_w, row_view, inc, color_mode, c4d.PIXELCNT_0)
                      final_bmp.SetPixelCnt(dst_x, dst_y + py, tile_w, row_view, inc, color_mode, c4d.PIXELCNT_0)
      
          final_bmp.Save(final_path, c4d.FILTER_PNG, c4d.BaseContainer(), save_bits)
          print(f"Saved assembled image to {final_path}")
          c4d.bitmaps.ShowBitmap(final_bmp)
          c4d.gui.MessageDialog(f"Done! {tiles_x * tiles_y} tiles rendered and assembled.\n{final_path}")
      
      
      if __name__ == "__main__":
          main()
      
      
      
      posted in Cinema 4D SDK
      K
      karthikbp
    • RE: Tile rendering with Cinema 4D

      Hmm, I was able to reassemble the tiles within Cinema 4D as well. Here's the script with reassembly.

      Feel free to chime in if we should not be doing this (performance impact, does not work with different renderers etc)

      import c4d
      import os
      
      doc: c4d.documents.BaseDocument
      op: c4d.BaseObject | None
      
      
      def main() -> None:
          """Renders the scene as a grid of tiles, then reassembles into the final image."""
          # --- Configure these ---
          tiles_x = 2
          tiles_y = 2
          output_dir = os.path.join(os.path.expanduser("~"), "Desktop", "tiles")
          final_path = os.path.join(output_dir, "final_assembled.png")
          # ------------------------
      
          os.makedirs(output_dir, exist_ok=True)
      
          base_rd = doc.GetActiveRenderData()
          full_w = int(base_rd[c4d.RDATA_XRES])
          full_h = int(base_rd[c4d.RDATA_YRES])
          tile_w = full_w // tiles_x
          tile_h = full_h // tiles_y
      
          tile_bmps = {}
      
          for ty in range(tiles_y):
              for tx in range(tiles_x):
                  rd = base_rd.GetClone()
      
                  left = tx * tile_w
                  top_ = ty * tile_h
                  right = left + tile_w
                  bottom = top_ + tile_h
      
                  rd[c4d.RDATA_RENDERREGION] = True
                  rd[c4d.RDATA_RENDERREGION_LEFT] = left
                  rd[c4d.RDATA_RENDERREGION_TOP] = top_
                  rd[c4d.RDATA_RENDERREGION_RIGHT] = right
                  rd[c4d.RDATA_RENDERREGION_BOTTOM] = bottom
      
                  bmp = c4d.bitmaps.MultipassBitmap(full_w, full_h, c4d.COLORMODE_RGB)
                  bmp.AddChannel(True, True)
      
                  print(f"Rendering tile ({tx}, {ty}) region=({left},{top_})-({right},{bottom})")
                  result = c4d.documents.RenderDocument(
                      doc,
                      rd.GetData(),
                      bmp,
                      c4d.RENDERFLAGS_EXTERNAL | c4d.RENDERFLAGS_SHOWERRORS,
                  )
      
                  if result != c4d.RENDERRESULT_OK:
                      print(f"Tile ({tx}, {ty}) failed with code: {result}")
                      return
      
                  # Crop tile — use same coords as region
                  tile_bmp = c4d.bitmaps.BaseBitmap()
                  tile_bmp.Init(tile_w, tile_h)
                  for y in range(tile_h):
                      for x in range(tile_w):
                          r, g, b = bmp.GetPixel(left + x, top_ + y)
                          tile_bmp.SetPixel(x, y, r, g, b)
      
                  tile_path = os.path.join(output_dir, f"tile_{tx}_{ty}.png")
                  tile_bmp.Save(tile_path, c4d.FILTER_PNG)
                  print(f"Saved {tile_path}")
      
                  tile_bmps[(tx, ty)] = tile_bmp
      
          # --- Reassemble: place each tile at its matching position, no flip ---
          print("Assembling final image...")
          final_bmp = c4d.bitmaps.BaseBitmap()
          final_bmp.Init(full_w, full_h)
      
          for ty in range(tiles_y):
              for tx in range(tiles_x):
                  tile_bmp = tile_bmps[(tx, ty)]
                  dst_x = tx * tile_w
                  dst_y = ty * tile_h
                  for y in range(tile_h):
                      for x in range(tile_w):
                          r, g, b = tile_bmp.GetPixel(x, y)
                          final_bmp.SetPixel(dst_x + x, dst_y + y, r, g, b)
      
          final_bmp.Save(final_path, c4d.FILTER_PNG)
          print(f"Saved assembled image to {final_path}")
          c4d.bitmaps.ShowBitmap(final_bmp)
      
          c4d.gui.MessageDialog(
              f"Done! {tiles_x * tiles_y} tiles rendered and assembled.\n{final_path}"
          )
      
      
      if __name__ == "__main__":
          main()
      
      
      posted in Cinema 4D SDK
      K
      karthikbp
    • RE: Tile rendering with Cinema 4D

      I was able to get tile rendering done by running a script like this:

      import c4d
      import os
      
      doc: c4d.documents.BaseDocument
      op: c4d.BaseObject | None
      
      
      def main() -> None:
          # --- Configure these ---
          tiles_x = 2  # columns
          tiles_y = 2  # rows
          output_dir = os.path.join(os.path.expanduser("~"), "Desktop", "tiles")
          # ------------------------
      
          os.makedirs(output_dir, exist_ok=True)
      
          base_rd = doc.GetActiveRenderData()
          full_w = int(base_rd[c4d.RDATA_XRES])
          full_h = int(base_rd[c4d.RDATA_YRES])
          tile_w = full_w // tiles_x
          tile_h = full_h // tiles_y
      
          for ty in range(tiles_y):
              for tx in range(tiles_x):
                  rd = base_rd.GetClone()
      
                  left = tx * tile_w
                  top = ty * tile_h
                  right = left + tile_w
                  bottom = top + tile_h
      
                  # Region at full resolution
                  rd[c4d.RDATA_RENDERREGION] = True
                  rd[c4d.RDATA_RENDERREGION_LEFT] = left
                  rd[c4d.RDATA_RENDERREGION_TOP] = top
                  rd[c4d.RDATA_RENDERREGION_RIGHT] = right
                  rd[c4d.RDATA_RENDERREGION_BOTTOM] = bottom
      
                  # Full-res bitmap — C4D renders region into this
                  bmp = c4d.bitmaps.MultipassBitmap(full_w, full_h, c4d.COLORMODE_RGB)
                  bmp.AddChannel(True, True)
      
                  result = c4d.documents.RenderDocument(
                      doc,
                      rd.GetData(),
                      bmp,
                      c4d.RENDERFLAGS_EXTERNAL | c4d.RENDERFLAGS_SHOWERRORS,
                  )
      
                  if result != c4d.RENDERRESULT_OK:
                      print(f"Tile ({tx}, {ty}) failed with code: {result}")
                      continue
      
                  # Crop the tile region out of the full bitmap
                  tile_bmp = c4d.bitmaps.BaseBitmap()
                  tile_bmp.Init(tile_w, tile_h)
                  for y in range(tile_h):
                      for x in range(tile_w):
                          r, g, b = bmp.GetPixel(left + x, top + y)
                          tile_bmp.SetPixel(x, y, r, g, b)
      
                  path = os.path.join(output_dir, f"tile_{tx}_{ty}.png")
                  tile_bmp.Save(path, c4d.FILTER_PNG)
                  print(f"Saved {path}")
      
          c4d.gui.MessageDialog(
              f"Done! {tiles_x * tiles_y} tiles saved to:\n{output_dir}"
          )
      
      
      if __name__ == "__main__":
          main()
      
      
      posted in Cinema 4D SDK
      K
      karthikbp
    • Tile rendering with Cinema 4D

      Dear community,

      Is there a recommended way to do tile rendering—dividing a large image into smaller pieces that can be rendered quickly and then reassembled into one final image?

      Current Approach:

      We currently use the "Render Tiles" camera to divide an image into smaller pieces, then assemble them using software like FFmpeg or OpenImageIO.
      Here's our detailed step-by-step procedure: https://github.com/aws-deadline/deadline-cloud-for-cinema-4d/blob/mainline/docs/tile_rendering/tile_rendering.md based on this old article.

      Alternative approach:

      But while going over some of the render settings, I stumbled on "RDATA_RENDERREGION_LEFT" (similarly for left, top and bottom).
      Could we use this approach instead—rendering specific regions of the image separately and then assembling them into the final image?

      Has anyone implemented a similar solution or can provide guidance on whether this approach is feasible?

      Thank you for your assistance.

      posted in Cinema 4D SDK python 2026
      K
      karthikbp
    • RE: Bundle fonts with Cinema 4D submissions

      Hey @ferdinand ,

      Sorry for the late replies.

      You can only answer these with end user support and the beta community.

      I will do that. Although I haven't used the beta community yet, I'll post the same question there to better understand what the recommended workflows are right now.

      you would either have to limit the feature to 2024+ clients

      That's good enough for us. Our plugin officially supports only the latest versions of 2024 and 2025.

      posted in Cinema 4D SDK
      K
      karthikbp
    • RE: Bundle fonts with Cinema 4D submissions

      Hi @ferdinand ,

      Thanks for your support so far. I should be able to go forward from here.

      I do have a question though. Is there a reason why the flag "ASSETDATA_FLAG_WITHFONTS" does not appear in the docs? https://developers.maxon.net/docs/py/2025_3_1/modules/c4d.documents/index.html#c4d.documents.GetAllAssetsNew

      The users of our plugin generally have Cinema 4D 2024 and 2025 installed. Will there be any issues using this flag? I tried running the script that you shared above on 2024 and that seemed to work as well so I assume there are no issues on that front.

      Thanks,
      Karthik

      posted in Cinema 4D SDK
      K
      karthikbp
    • RE: Bundle fonts with Cinema 4D submissions

      Hi @ferdinand,

      Thanks so much for your responses and sharing the code above. I really appreciate it! But our plugin users still want to have completed renders.

      Which leads me to wonder if we can convert all the text objects into editable before submission through code? I was thinking of something like this:

      • check if there is a custom font in the scene (this should be possible with the code that you just shared)
      • find all the text objects in the scene
      • convert it to the editable state just before submitting to the render farm (similar to what happens when we select the Text and press 'C')

      Is this approach feasible? Are there downsides for it, would animations stop working with this approach when the object turns into several different objects?

      The article mentioned that if we need to keep the text objects "procedural" we need to install the fonts.

      What does "procedural" mean in this context?

      Thanks again

      posted in Cinema 4D SDK
      K
      karthikbp
    • Bundle fonts with Cinema 4D submissions

      Dear community,

      I'm facing an issue with custom fonts when rendering on a render farm. Is there a way to bundle fonts with a scene so that Cinema 4D automatically uses these bundled fonts when rendering on a render farm?

      I have already reviewed the official documentation: https://support.maxon.net/hc/en-us/articles/1500006439721-Why-don-t-fonts-look-correct-on-machines-rendered-with-Team-Render-but-appear-correct-when-rendered-locally. However, making the text editable (as suggested in the article) is not an acceptable solution for our plugin users.

      Is the following approach possible through the Cinema 4D SDK?

      • Get the location of the fonts used in the scene (Could c4d.documents.GetAllAssetsNew() help with this?)
      • Bundle these fonts with the scene file
      • And then we could:
        • Get Cinema 4D to recognize and use the bundled font while rendering?
        • Or at least install the now bundled font on the render node and then uninstall the font once it's done rendering?

      Has anyone implemented a similar solution or can provide guidance on whether this approach is feasible?

      Thank you for your assistance.

      posted in Cinema 4D SDK python 2025 2024
      K
      karthikbp
    • RE: Path mapping in Cinema 4D using Redshift does not work

      Hi @ferdinand ,

      We are starting to run here in circles. Please consider applying for MRD as lined out here and via chat.

      I think that makes sense. I'll apply for MRD right away.

      posted in Cinema 4D SDK
      K
      karthikbp
    • RE: Path mapping in Cinema 4D using Redshift does not work

      Hi @ferdinand ,

      when for a pyro sim we render the first frame isolated on a node, then it is black unless we do this

      Yup. We only saw an improvement for Pyro scenes at our end. Other scenes work correctly even without adding the doc.ExecutePasses line.

      posted in Cinema 4D SDK
      K
      karthikbp