Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware 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
    1. Maxon Developers Forum
    2. Gregor M
    G
    • Profile
    • Following 0
    • Followers 0
    • Topics 3
    • Posts 7
    • Best 0
    • Controversial 0
    • Groups 0

    Gregor M

    @Gregor M

    0
    Reputation
    5
    Profile views
    7
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    Gregor M Unfollow Follow

    Latest posts made by Gregor M

    • Tree view boolean column bug

      I have a problem with a tree view custom gui.
      When I toggle any boolean field other than the bottom one it also toggles the top most one by itself.

      import c4d
      import weakref
      
      # Control IDs
      ID_TREEVIEW          = 1000
      ID_BTN_NEW_FOLDER    = 1001
      ID_BTN_DELETE        = 1002
      ID_PATHFIELD         = 1003
      
      # Tree column IDs
      ID_CHECK = 1  # Checkbox column
      ID_NAME  = 2  # Name column
      
      #---------------------------------------------------------------------
      # Basic Entity
      #---------------------------------------------------------------------
      class Entity:
          def __init__(self, is_root=False, name="Folder"):
              self.is_root = is_root
              self.name = name if not is_root else "Root"
              self.checked = False
              self.opened = True
              self.selected = False
              self.parent = None
      
          def AddChild(self, child):
              child.parent = weakref.ref(self)
              self.children.append(child)
      
          def GetChildren(self):
              return self.children
      
          def GetParent(self):
              return self.parent() if self.parent else None
      
      #---------------------------------------------------------------------
      # TreeView Functions
      #---------------------------------------------------------------------
      class SimpleTreeFunctions(c4d.gui.TreeViewFunctions):
          def __init__(self, dlg):
              self._dlg = weakref.ref(dlg)
              # Create the global Root entity.
              self.root_entity = Entity(is_root=True)
              # Top-level entities: Root and any added Folders (as siblings).
              self.entities = [self.root_entity]
      
          def GetFirst(self, root, userdata):
              return self.entities[0] if self.entities else None
      
          def GetDown(self, root, userdata, obj):
              return obj.GetChildren()[0] if obj.GetChildren() else None
      
          def GetNext(self, root, userdata, obj):
              parent = obj.GetParent()
              siblings = parent.GetChildren() if parent else self.entities
              idx = siblings.index(obj) + 1
              return siblings[idx] if idx < len(siblings) else None
      
          def GetPred(self, root, userdata, obj):
              parent = obj.GetParent()
              siblings = parent.GetChildren() if parent else self.entities
              idx = siblings.index(obj) - 1
              return siblings[idx] if idx >= 0 else None
      
          def GetId(self, root, userdata, obj):
              return id(obj)
      
          def Select(self, root, userdata, obj, mode):
              # Clear all selections if a new selection is made.
              if mode == c4d.SELECTION_NEW:
                  for e in self._AllEntities():
                      e.selected = False
              if mode in [c4d.SELECTION_NEW, c4d.SELECTION_ADD]:
                  obj.selected = True
              elif mode == c4d.SELECTION_SUB:
                  obj.selected = False
              self._dlg().UpdatePathField()
      
          def IsSelected(self, root, userdata, obj):
              return obj.selected
      
          def IsOpened(self, root, userdata, obj):
              return obj.opened
      
          def Open(self, root, userdata, obj, onoff):
              obj.opened = onoff
      
          # Toggle checkboxes.
          def SetCheck(self, root, userdata, obj, column, checked, msg):
              if column == ID_CHECK:
                  # If the object is global Root, only change when directly clicked.
                  if obj.is_root:
                      obj.checked = bool(checked)
                  else:
                      # When toggling a Folder, ensure the Root's state is preserved.
                      global_root = self.root_entity
                      original = global_root.checked
                      obj.checked = bool(checked)
                      global_root.checked = original
              self._dlg()._treegui.Refresh()
      
          def IsChecked(self, root, userdata, obj, column):
              if obj.checked:
                  return c4d.LV_CHECKBOX_CHECKED | c4d.LV_CHECKBOX_ENABLED
              return c4d.LV_CHECKBOX_ENABLED
      
          def GetName(self, root, userdata, obj):
              return obj.name
      
          def SetName(self, root, userdata, obj, newname):
              obj.name = newname
              self._dlg().UpdatePathField()
              return True
      
          def _AllEntities(self):
              # Recursively iterate through all entities.
              def recurse(lst):
                  for ent in lst:
                      yield ent
                      yield from recurse(ent.GetChildren())
              return recurse(self.entities)
      
          def DeletePressed(self, root, userdata):
              # Delete selected entities, except the global Root.
              to_delete = [e for e in self._AllEntities() if e.selected and not e.is_root]
              for e in to_delete:
                  parent = e.GetParent()
                  if parent:
                      parent.GetChildren().remove(e)
                  else:
                      self.entities.remove(e)
              self._dlg().UpdatePathField()
              return True
      
      #---------------------------------------------------------------------
      # Main Dialog: Contains the tree view, add and delete buttons, and a text field.
      #---------------------------------------------------------------------
      class SimpleTreeDialog(c4d.gui.GeDialog):
          def __init__(self):
              self.treeData = None
              self._treegui = None
      
          def CreateLayout(self):
              self.SetTitle("Simple Tree (Folders as Siblings)")
              # Buttons: Add Folder and Delete Selected.
              self.GroupBegin(100, c4d.BFH_SCALEFIT, 2, 1)
              self.AddButton(ID_BTN_NEW_FOLDER, c4d.BFH_SCALEFIT, name="Add Folder")
              self.AddButton(ID_BTN_DELETE, c4d.BFH_SCALEFIT, name="Delete Selected")
              self.GroupEnd()
              # A text field to display a simple representation of the tree.
              self.AddEditText(ID_PATHFIELD, c4d.BFH_SCALEFIT)
              self.AddSeparatorH(0, c4d.BFH_SCALEFIT)
      
              # Create the TreeView.
              bc = c4d.BaseContainer()
              bc.SetBool(c4d.TREEVIEW_BORDER, True)
              self._treegui = self.AddCustomGui(ID_TREEVIEW, c4d.CUSTOMGUI_TREEVIEW, "",
                                                c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 400, 300, bc)
              if not self._treegui:
                  print("Error: Could not create TreeView")
                  return False
      
              # Set up the tree layout: a checkbox and name column.
              layout = c4d.BaseContainer()
              layout.SetLong(ID_CHECK, c4d.LV_CHECKBOX)
              layout.SetLong(ID_NAME, c4d.LV_TREE)
              self._treegui.SetLayout(2, layout)
              self._treegui.SetHeaderText(ID_CHECK, "Check")
              self._treegui.SetHeaderText(ID_NAME, "Name")
      
              # Initialize tree data: global Root is the first (and fixed) sibling.
              self.treeData = SimpleTreeFunctions(self)
              self._treegui.SetRoot(None, self.treeData, None)
              self._treegui.Refresh()
              self.UpdatePathField()
              return True
      
          def Command(self, id, msg):
              if id == ID_BTN_NEW_FOLDER:
                  self.AddFolder()
              elif id == ID_BTN_DELETE:
                  self.treeData.DeletePressed(None, None)
                  self._treegui.Refresh()
              return True
      
          def AddFolder(self):
              # Create a new Folder entity and add it as a sibling (top-level).
              new_entity = Entity(is_root=False, name="Folder")
              self.treeData.entities.append(new_entity)
              self._treegui.Refresh()
              self.UpdatePathField()
      
          def UpdatePathField(self):
              # Build a simple string showing the names of top-level entities.
              names = [ent.name for ent in self.treeData.entities]
              self.SetString(ID_PATHFIELD, " | ".join(names))
      
      if __name__=='__main__':
          dlg = SimpleTreeDialog()
          dlg.Open(c4d.DLG_TYPE_ASYNC, pluginid=0, defaultw=500, defaulth=400)
      
      posted in Cinema 4D SDK python windows
      G
      Gregor M
    • RE: RenderDocument produces different color

      Thank You for the answer Ferdinand.

      Unfortunately I'm sending those files to ComfyUI which has a problem interpreting color profile.
      For now I just use Change Render Space and change it to scene-linear and View Transform to Un-tone_mapped.
      I'm waiting patiently for this being listed in change log.
      Also I'm having problems setting bit depth for those files.

      posted in Bugs
      G
      Gregor M
    • RE: RenderDocument produces different color

      If you try to save this bitmap to .bmp it doesn't retain information about color profile. Is it possible to output the correct image that will open in other apps as it should using basebitmap.Save() function?

      import c4d
      
      doc: c4d.documents.BaseDocument
      
      def main():
      
          rd: c4d.BaseContainer = doc.GetActiveRenderData().GetClone().GetData()
          bmp: c4d.bitmaps.BaseBitmap = c4d.bitmaps.BaseBitmap()
          bmp.Init(int(rd[c4d.RDATA_XRES]), int(rd[c4d.RDATA_YRES]), 32)
          bmp.SetColorProfile(c4d.bitmaps.ColorProfile.GetDefaultLinearRGB())
          res: int = c4d.documents.RenderDocument(doc, rd, bmp, c4d.RENDERFLAGS_EXTERNAL)
          if res == c4d.RENDERRESULT_OK:
              c4d.bitmaps.ShowBitmap(bmp)
              path = "Path/To/Image.bmp"
              bmp.Save(path, c4d.FILTER_BMP, None,)
      
      if __name__ == '__main__':
          main()
      
      posted in Bugs
      G
      Gregor M
    • RE: Render depth map using python

      Thank you for the quick answer.
      Unfortunately this approach was quite destructive for my workflow, so i found a workaround using materials and 3d gradients. For anyone who want to render z-depth in python from c4d scene, this may be the approach. There may be some tweaks considering color space.
      It would be nice to get access to this kind of data inside cinema 4d's python without crazy workarounds.

      import c4d
      from c4d import gui, plugins, storage
      import os
      
      PLUGIN_ID = 1234567  # Replace this ID with your unique plugin ID from Maxon
      
      def GetFilterTypeFromFilename(filename):
          ext = os.path.splitext(filename)[1].lower()
          if ext == '.bmp':
              return c4d.FILTER_BMP
          elif ext == '.jpg' or ext == '.jpeg':
              return c4d.FILTER_JPG
          elif ext == '.png':
              return c4d.FILTER_PNG
          elif ext == '.tif' or ext == '.tiff':
              return c4d.FILTER_TIF
          elif ext == '.exr':
              return c4d.FILTER_EXR
          else:
              return c4d.FILTER_PNG  # Default to PNG if extension is unrecognized
      
      class RenderDialog(gui.GeDialog):
          DESTINATION_FILE = 1001
          BROWSE_BUTTON = 1002
          RENDER_BUTTON = 2000
      
          def CreateLayout(self):
              self.SetTitle("External Render Plugin")
      
              # Add Destination File Field
              self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT, cols=2)
              self.AddStaticText(id=0, flags=c4d.BFH_LEFT, name="Destination File:")
              self.AddEditText(id=self.DESTINATION_FILE, flags=c4d.BFH_SCALEFIT)
              self.GroupEnd()
      
              # Add Browse Button
              self.AddButton(id=self.BROWSE_BUTTON, flags=c4d.BFH_LEFT, name="Browse")
      
              # Add Render Button
              self.AddButton(id=self.RENDER_BUTTON, flags=c4d.BFH_CENTER, name="Render")
      
              return True
      
          def Command(self, id, msg):
              if id == self.BROWSE_BUTTON:
                  path = storage.SaveDialog(title="Select Destination File")
                  if path:
                      self.SetString(self.DESTINATION_FILE, path)
                  return True
      
              elif id == self.RENDER_BUTTON:
                  path = self.GetString(self.DESTINATION_FILE)
                  if not path:
                      gui.MessageDialog("Please specify a destination file.")
                      return True
      
                  # Get the active document
                  doc = c4d.documents.GetActiveDocument()
      
                  # Create a large sphere object
                  sphere = c4d.BaseObject(c4d.Osphere)
                  sphere[c4d.PRIM_SPHERE_RAD] = 10000000  # Set radius to 10,000,000 m
                  doc.InsertObject(sphere)
                  c4d.EventAdd()
      
                  # Check if a material named "LuminanceMaterial" already exists
                  material = doc.SearchMaterial("LuminanceMaterial")
                  if not material:
                      # Create new material and set its parameters
                      material = c4d.BaseMaterial(c4d.Mmaterial)
                      material.SetName("LuminanceMaterial")
                      material[c4d.MATERIAL_USE_COLOR] = False
                      material[c4d.MATERIAL_USE_REFLECTION] = False
                      material[c4d.MATERIAL_USE_LUMINANCE] = True
      
                      # Create gradient shader and set it as luminance
                      gradient_shader = c4d.BaseShader(c4d.Xgradient)
                      if gradient_shader:
                          gradient_shader[c4d.SLA_GRADIENT_TYPE] = c4d.SLA_GRADIENT_TYPE_3D_LINEAR  # 3D Linear Gradient
                          gradient_shader[c4d.SLA_GRADIENT_SPACE] = c4d.SLA_GRADIENT_SPACE_WORLD  # World space
                          gradient_shader[c4d.SLA_GRADIENT_CYCLE] = False
      
                          material[c4d.MATERIAL_LUMINANCE_SHADER] = gradient_shader
                          material.InsertShader(gradient_shader)
      
                      # Insert material into the document
                      doc.InsertMaterial(material)
      
                  # Update gradient start and end points for the current camera
                  gradient_shader = material[c4d.MATERIAL_LUMINANCE_SHADER]
                  if gradient_shader:
                      camera = doc.GetActiveObject()
                      if not camera or camera.GetType() != c4d.Ocamera:
                          camera = doc.GetRenderBaseDraw().GetSceneCamera(doc)
                      if not camera:
                          camera = doc.GetRenderBaseDraw().GetEditorCamera()
      
                      if camera:
                          start_position = camera.GetMg().off
                          focus_distance = camera[c4d.CAMERAOBJECT_TARGETDISTANCE]
                          end_position = start_position + (camera.GetMg().v3 * focus_distance)  # Use v3 for z-axis direction
                          gradient_shader[c4d.SLA_GRADIENT_START] = start_position
                          gradient_shader[c4d.SLA_GRADIENT_END] = end_position
      
                  # Enable material override in render settings
                  rd = doc.GetActiveRenderData()
                  rd[c4d.RDATA_MATERIAL_OVERRIDE] = True
                  rd[c4d.RDATA_MATERIAL_OVERRIDE_LINK] = material
      
                  # Set render settings
                  rdata = rd.GetDataInstance().GetClone(c4d.COPYFLAGS_NONE)
                  rdata[c4d.RDATA_PATH] = path
                  rdata[c4d.RDATA_RENDERENGINE] = c4d.RDATA_RENDERENGINE_STANDARD
      
                  # Create a bitmap to render into
                  width = int(rdata[c4d.RDATA_XRES])
                  height = int(rdata[c4d.RDATA_YRES])
                  bmp = c4d.bitmaps.BaseBitmap()
                  result = bmp.Init(width, height)
                  if result != c4d.IMAGERESULT_OK:
                      gui.MessageDialog("Failed to initialize bitmap.")
                      return True
      
                  # Trigger render
                  render_result = c4d.documents.RenderDocument(
                      doc,       # Document to render
                      rdata,     # Render settings
                      bmp,       # Bitmap to render into
                      c4d.RENDERFLAGS_EXTERNAL | c4d.RENDERFLAGS_DONTANIMATE  # Flags
                  )
      
                  if render_result != c4d.RENDERRESULT_OK:
                      gui.MessageDialog("Render failed.")
                  else:
                      # Determine the appropriate file format filter
                      filter_type = GetFilterTypeFromFilename(path)
                      # Save the rendered image
                      save_result = bmp.Save(path, filter_type, c4d.BaseContainer())
                      if save_result != c4d.IMAGERESULT_OK:
                          gui.MessageDialog("Failed to save image.")
                      else:
                          gui.MessageDialog("Render completed and saved.")
      
                  # Turn off material override after rendering
                  rd[c4d.RDATA_MATERIAL_OVERRIDE] = False
                  rd[c4d.RDATA_MATERIAL_OVERRIDE_LINK] = None
      
                  # Delete the large sphere after rendering
                  sphere.Remove()
                  c4d.EventAdd()
      
                  # Delete the material after rendering
                  if material:
                      material.Remove()
                      c4d.EventAdd()
      
                  # Refresh the document
                  c4d.EventAdd()
      
                  return True
      
              return False
      
      class ExternalRenderPlugin(plugins.CommandData):
          def __init__(self):
              self.dlg = None
      
          def Execute(self, doc):
              if not self.dlg:
                  self.dlg = RenderDialog()
              self.dlg.Open(c4d.DLG_TYPE_ASYNC, defaultw=400, defaulth=100)
              return True
      
      if __name__ == "__main__":
          plugins.RegisterCommandPlugin(
              id=PLUGIN_ID,
              str="External Render Plugin",
              info=0,
              icon=None,
              help="Render current frame to a specified file",
              dat=ExternalRenderPlugin()
          )
      
      posted in Cinema 4D SDK
      G
      Gregor M
    • Render depth map using python

      I'm creating a simple Python plugin and i need to render depth map using c4d.RENDERFLAGS_EXTERNAL. I'm not sure how to do this.

      import c4d
      from c4d import gui, plugins, storage
      import os
      
      PLUGIN_ID = 1234567  
      
      def GetFilterTypeFromFilename(filename):
          ext = os.path.splitext(filename)[1].lower()
          if ext == '.bmp':
              return c4d.FILTER_BMP
          elif ext == '.jpg' or ext == '.jpeg':
              return c4d.FILTER_JPG
          elif ext == '.png':
              return c4d.FILTER_PNG
          elif ext == '.tif' or ext == '.tiff':
              return c4d.FILTER_TIF
          elif ext == '.exr':
              return c4d.FILTER_EXR
          else:
              return c4d.FILTER_PNG  # Default to PNG if extension is unrecognized
      
      class RenderDialog(gui.GeDialog):
          DESTINATION_FILE = 1001
          BROWSE_BUTTON = 1002
          RENDER_BUTTON = 2000
      
          def CreateLayout(self):
              self.SetTitle("External Render Plugin")
      
              # Add Destination File Field
              self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT, cols=2)
              self.AddStaticText(id=0, flags=c4d.BFH_LEFT, name="Destination File:")
              self.AddEditText(id=self.DESTINATION_FILE, flags=c4d.BFH_SCALEFIT)
              self.GroupEnd()
      
              # Add Browse Button
              self.AddButton(id=self.BROWSE_BUTTON, flags=c4d.BFH_LEFT, name="Browse")
      
              # Add Render Button
              self.AddButton(id=self.RENDER_BUTTON, flags=c4d.BFH_CENTER, name="Render")
      
              return True
      
          def Command(self, id, msg):
              if id == self.BROWSE_BUTTON:
                  path = storage.SaveDialog(title="Select Destination File")
                  if path:
                      self.SetString(self.DESTINATION_FILE, path)
                  return True
      
              elif id == self.RENDER_BUTTON:
                  path = self.GetString(self.DESTINATION_FILE)
                  if not path:
                      gui.MessageDialog("Please specify a destination file.")
                      return True
      
                  # Get the active document and render settings
                  doc = c4d.documents.GetActiveDocument()
                  rd = doc.GetActiveRenderData()
                  rdata = rd.GetDataInstance().GetClone(c4d.COPYFLAGS_NONE)
      
                  # Set render settings
                  rdata[c4d.RDATA_PATH] = path
                  rdata[c4d.RDATA_RENDERENGINE] = c4d.RDATA_RENDERENGINE_STANDARD
      
                  # Create a bitmap to render into
                  width = int(rdata[c4d.RDATA_XRES])
                  height = int(rdata[c4d.RDATA_YRES])
                  bmp = c4d.bitmaps.BaseBitmap()
                  result = bmp.Init(width, height)
                  if result != c4d.IMAGERESULT_OK:
                      gui.MessageDialog("Failed to initialize bitmap.")
                      return True
      
                  # Trigger render
                  render_result = c4d.documents.RenderDocument(
                      doc,       # Document to render
                      rdata,     # Render settings
                      bmp,       # Bitmap to render into
                      c4d.RENDERFLAGS_EXTERNAL | c4d.RENDERFLAGS_DONTANIMATE  # Flags
                  )
      
                  if render_result != c4d.RENDERRESULT_OK:
                      gui.MessageDialog("Render failed.")
                  else:
                      # Determine the appropriate file format filter
                      filter_type = GetFilterTypeFromFilename(path)
                      # Save the rendered image
                      save_result = bmp.Save(path, filter_type, c4d.BaseContainer())
                      if save_result != c4d.IMAGERESULT_OK:
                          gui.MessageDialog("Failed to save image.")
                      else:
                          gui.MessageDialog("Render completed and saved.")
      
                  return True
      
              return False
      
      class ExternalRenderPlugin(plugins.CommandData):
          def __init__(self):
              self.dlg = None
      
          def Execute(self, doc):
              if not self.dlg:
                  self.dlg = RenderDialog()
              self.dlg.Open(c4d.DLG_TYPE_ASYNC, defaultw=400, defaulth=100)
              return True
      
      if __name__ == "__main__":
          plugins.RegisterCommandPlugin(
              id=PLUGIN_ID,
              str="External Render Plugin",
              info=0,
              icon=None,
              help="Render current frame to a specified file",
              dat=ExternalRenderPlugin()
          )
      
      posted in Cinema 4D SDK python
      G
      Gregor M
    • RE: Import NumPy?

      Hi, I'm also trying to install numpy, but after registering c4dpy I'm getting a syntax error after running "c4dpy -m ensurepip" command.

      c4dpy -m ensurepip
      (null) File "<stdin>", line 1
      c4dpy -m ensurepip
      ^^^^^^^^^
      (null)SyntaxError: invalid syntax

      posted in Cinema 4D SDK
      G
      Gregor M
    • Reading skeleton data from Character Definition tag

      I'm trying to create rig template with re-targeting functionality. Is there a way to access "MTCharacterBodyPart.GetParameters()" outside of main thread? I want to incorporate whole functionality without any scripts. Accessing this data using Python tag, Interaction tag or Python Generator crashes cinema.
      It would be very useful to mach joints using Character definition tag. The only other way would be to write equivalent in python.

      posted in Cinema 4D SDK 2024 python
      G
      Gregor M