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
    • Unread
    • Recent
    • Tags
    • Users
    • Login
    1. Maxon Developers Forum
    2. Dunhou
    • Profile
    • Following 2
    • Followers 4
    • Topics 52
    • Posts 259
    • Best 52
    • Controversial 0
    • Groups 0

    Dunhou

    @Dunhou

    81
    Reputation
    117
    Profile views
    259
    Posts
    4
    Followers
    2
    Following
    Joined Last Online
    Website www.boghma.com Location China

    Dunhou Unfollow Follow

    Best posts made by Dunhou

    • Open source wrapper for Octane/Redshift/Arnold/Vray/Corona in Cinema 4D.

      Hi community!

      Older version called renderEngine had been move to versions folder, if you are still interested.
      

      Renderer is a wrapper class for the maxon and c4d api of popular render engine for Cinema 4D.

      Intended for more user-friendly manipulation of node materials with the new maxon.GraphNode model. And also with Octane Material.

      Provide helper class for convenient access AOV , Material , Scene Object(Object/Tag/Light/...) in Cinema 4D popular renderer.

      I try to keep it as same as possible, but each renderer has their own logic, so there are some compromises.

      Happy Rendering and Scpriting!😊

      Cheers~
      DunHou


      Renderer

      This is a custom wrapper for most popular render engine like Octane\Redshift\Arnold\Corona\VRay in Cinema 4D, which is also contains in boghma library.

      All the boghma plugins and boghma library is FREE.
      

      Supported Renderer

      • Octane
      • Corona
      • Node Materials with the new GraphNode model
      • Redshift ( Only Node Material for Material Helper)
      • Arnold ( Only Node Material for Material Helper)
      • Vray ( Only Node Material for Material Helper)

      Installation

      1. (Recommend) Download Boghma Plugin Manager and install any plugin, the boghma lib will auto installed or updated.
      2. Download the source code and import it to your Cinema 4D.

      Quick Intro

      
      import c4d
      import maxon
      from Renderer import Redshift, EasyTransaction, TextureHelper
      from pprint import pprint
      
      # Create a TextureHelper instance
      # 创建一个 TextureHelper 实例
      tex_helper: TextureHelper = TextureHelper()
      
      # Get the url with given asset id
      # 获取给定资产ID的URL
      # "si-v1_fingerprints_02_15cm.png" with AssetId : file_fa9c42774dd05049
      disp: maxon.Url = tex_helper.GetAssetUrl("file_fa9c42774dd05049")
      
      def HowToUse():
          """
          How to reate a redshift material and modify the gragh with EasyTransaction.
          """
      
          # Create Redshift Node Material instance, if no material filled, we create a new STD material
          # 创建一个Redshift节点材质实例,如果没有材质传入,创建新的STD材质
          material: c4d.BaseMaterial = Redshift.Material("MyMaterial")
      
          # Use EasyTransaction to modify the graph
          # 使用EasyTransaction来修改材质
          with EasyTransaction(material) as tr:
          
              # the attribute #tr is the instance of Redshift.MaterialHelper, 
              # we got it with just apply to the #material to the EasyTransaction
              # it will inherit from NodeGraghHelper class
              # 属性tr是Redshift.MaterialHelper的实例,通过将材质赋予EasyTransaction获得,继承自NodeGraghHelper
      
              # Use Redshift.MaterialHelper methods : add a texture + displacement to the Output node
              # 使用Redshift.MaterialHelper中的方法: 添加图片+置换节点到Output节点
              tr.AddDisplacementTree(filepath = disp, shadername = "DISP")
      
              # Use NodeGraghHelper methods: get the Output(endNode)
              # 使用NodeGraghHelper中的方法: 获取输出节点
              output = tr.GetOutput()
              print(f"{output = }")
      
              # Insert the material to the document
              # 导入材质(来自Redshift MaterialHelper)
              tr.InsertMaterial()
      
          # Auto apply GraphTransaction.Commit() to the graph
          # 退出with后, 自动执行GraphTransaction.Commit()
      
      

      Limit

      • For some reasons, AddShader-like methods(maxon.GraphModelInterface.AddChild) will add the node in the center of the graph, if we call those methods on exsited material, it will return a mess graph, you can call Renderer.ArrangeAll() after.
      • Material(except Octane) helper only support material with the new GraphNode model(Node Material after R26)
      • Due to Octane use his Custom UserArea UI base on old layer system, and didn't support python, we can only modify Octane materials in material level, but can not interactive with selections in octane node editor.
      • Also Octane materials didn't have a "port" or "wire" context, we can not use all those methods as same as NodeGraghHelper.
      • Arnold mask tag SetPrameter has a refresh bug.

      Examples

      • Material Example
      • AOV Example
      • Scene Example

      Class Presentation and Highlights

      Renderer

      • NodeGraghHelper
      • TextureHelper
      • EasyTransaction
      • Redshift
        • AOV
        • Material
        • Scene
      • Octane
        • AOV
        • Material
        • Scene
      • Arnold
        • AOV
        • Material
        • Scene
      • Vray
        • AOV
        • Material
      • Corona
        • AOV
        • Material
      • utils
        • NodeGraghHelper
        • TextureHelper
        • EasyTransaction
      • constants

      Version & Updates

      • Change Log
      posted in General Talk programming learning-resource
      DunhouD
      Dunhou
    • RE: UserArea drag and drop example?

      Hi @m_adam ,

      Thanks for your reply! After some research, I had expanded the code for this case to adapt to the requirements I mentioned earlier:

      • we can drag c4d.BaseObject , c4d.BaseMaterial or Image into UA, create their icon.
      • we can drag the UA item(Object) back to OM, and drag the UA item(Material) into Material Manager or OM(on the selected object), or drag the UA item(ImageRef) into a shader link.

      The UserArea Accept:

      • c4d.BaseObject
      • c4d.BaseMaterial
      • Image file outside Cinema 4D.

      Here is the code in case anyone is interested in this topic in the future.Hope it can be helpful.

      Cheers~
      DunHou

      Animation.gif

      import c4d
      from c4d import Vector
      from c4d.gui import GeUserArea, GeDialog
      
      GADGET_ID_GEUSERAREA = 10000
      
      class DropArea(GeUserArea):
      
          def __init__(self):
              # data host
              self.receivedObject: list[c4d.BaseList2D, str] = []
              # bg color of the pen
              self.color: Vector = self._get_color()
      
          def _get_color(self, colorId: int = c4d.COLOR_BG) -> Vector:
              """
              Get a rgb color from c4d color id
              """
              color = self.GetColorRGB(colorId)
              r = color['r']/255
              g = color['g']/255
              b = color['b']/255
              return c4d.Vector(r,g,b)
      
          def DrawMsg(self, x1, y1, x2, y2, msg):
              """This Method is called automatically when Cinema 4D Draw the Gadget.
      
              Args:
                  x1 (int): The upper left x coordinate.
                  y1 (int): The upper left y coordinate.
                  x2 (int): The lower right x coordinate.
                  y2 (int): The lower right y coordinate.
                  msg (c4d.BaseContainer): The original message container.
              """
      
              # Initializes draw region
              self.OffScreenOn()
              self.SetClippingRegion(x1, y1, x2, y2)
      
              # Defines the color used in draw operation, use c4d backgroud color here.
              self.DrawSetPen(self.color)
      
              # Draws a rectangle filling the whole UI
              self.DrawRectangle(x1, y1, x2, y2)
      
              # Draw a Icon with the drop object, only consider c4d.BaseList2D and ImageRef here
              if msg.GetInt32(c4d.BFM_DRAG_FINISHED) == 1:
                              
                  # If drag info recive a image, draw a icon of image
                  if isinstance(self.receivedObject, str):
                      icon = c4d.bitmaps.InitResourceBitmap(1050500)
                      self.DrawBitmap(icon, x1, y1, x2, y2, 0, 0, icon.GetBw(), icon.GetBh(), mode= c4d.BMP_ALLOWALPHA)
      
                  # If drag info recive a list of BaseList2D, draw a icon of first one.
                  else:
                      if self.receivedObject:
                          # Draw the first drop object's Icon, 
                          # for BaseMaterial, we can get the preview image.
                          # for BaseObject, we can get the icon.
                          if isinstance(self.receivedObject[0], c4d.BaseList2D):
                              icon = self.receivedObject[0].GetIcon()
                              self.DrawBitmap(icon['bmp'], x1, y1, x2, y2, icon['x'], icon['y'], icon['w'], icon['h'],mode= c4d.BMP_ALLOWALPHA)
      
          def GetMinSize(self):
              # do a calculation here, min size.
              return 200, 200
      
          def Message(self, msg, result) :
              if msg.GetId()==c4d.BFM_DRAGRECEIVE:
                  # Discard if lost drag or if it has been escaped
                  if msg.GetInt32(c4d.BFM_DRAG_LOST) or msg.GetInt32(c4d.BFM_DRAG_ESC):
                      return self.SetDragDestination(c4d.MOUSE_FORBIDDEN)
                  
                  if not self.CheckDropArea(msg, True, True):
                      return self.SetDragDestination(c4d.MOUSE_FORBIDDEN)
                                          
                  # Check if drag is finished (=drop)
                  if msg.GetInt32(c4d.BFM_DRAG_FINISHED) == 1:
                      # Get drag object type and data
                      dragInfo = self.GetDragObject(msg)
      
                      # Redraw the GeUserArea (will call DrawMsg)
                      self.Redraw()
      
                      #print(type(dragInfo['object']))
                      self.receivedObject = dragInfo['object']
                      print(f"Dropped: {self.receivedObject}")
                      return True
                  
                  # Return current mouse cursor for valid drag operation
                  return self.SetDragDestination(c4d.MOUSE_MOVE)
              
              # Call GeUserAre.Message() implementation so that it can handle all the other messages
              return c4d.gui.GeUserArea.Message(self, msg, result)
      
          def InputEvent(self, msg):
              """Called by Cinema 4D when a click occurs"""
              
              # If the #self.receivedObject host the file path of the image, we generate the file path.
              # this means we can drag it into a image link like a shader link.
              if isinstance(self.receivedObject, str):
                  self.HandleMouseDrag(msg, c4d.DRAGTYPE_FILENAME_IMAGE, self.receivedObject, 0)
      
              else:
                  # Create a list of C4DAtom and pass that to the HandleMouseDrag function that will generate all the drag information
                  self.HandleMouseDrag(msg, c4d.DRAGTYPE_ATOMARRAY, self.receivedObject, 0)        
      
              return True
          
      class ExampleDialog(GeDialog):
          # The GeUserArea need to be stored somewhere, we will need this instance to be attached to the current Layout
          geUserArea = DropArea()
      
          def CreateLayout(self):
              """This Method is called automatically when Cinema 4D Create the Layout (display) of the Dialog."""
              
              self.SetTitle("Drag Area")
      
              if self.GroupBegin(0,  c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, cols=1, rows=0, title="", groupflags=0, initw=100, inith=100):
                  
                  self.GroupBorderSpace(8,8,8,8)
                  self.GroupSpace(2, 2)
                  
                  # Adds a Gadget that will host a GeUserArea
                  self.AddUserArea(GADGET_ID_GEUSERAREA, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 200, 200)
          
                  # Attaches the stored GeUserArea to the Gadget previously created
                  self.AttachUserArea(self.geUserArea, GADGET_ID_GEUSERAREA)
                  
              self.GroupEnd()
              
              return True
      
      
      if __name__ == "__main__":
          global dlg
          dlg = ExampleDialog()
          dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC, defaultw=200, defaulth=200)
      
      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • Free plugin : Octane Light Manager

      A free plugin for manage octane lights in the active document.

      Here is the dialog looks like, hope it can help you😊

      🤡 Octane verison : oc-light-manager v1.0.2.zip
      🤡 Redshift verison : rs-light-manager v1.0.1.zip

      preview.png


      Cinema 4D Octane Light Manager

      🔒:Cinema 4D R2023.2.0 above

      Online Help

      Standalone Download

      • Boghma Community(Chinese Language)

      • Gitee(Chinese Language)

      • Github( .pypv)

      Plugin Manager Download

      • Boghma Plugin Manager (Beta)

      Function Highlights

      • track document Octane lights and get/set some key parameter
      • Drag to set Light ID
      • Quickly set Texture or Distribution slot with RGB or Texture
      • Solo / Enable / As Camera for Octane Light
      • And so on, please check document

      Cheers~
      DunHou

      posted in General Talk
      DunhouD
      Dunhou
    • Free plugins all in one : Boghma HUB

      Hi community!

      Here is a new plugin to manage all my(boghma) plugins and some open source librarys like ualib and renderEngine for Cinema 4D.

      All the boghma plugin is 100% Free
      

      About boghma: boghma is the pronounce of python in Uighur, It is a free community for Cinema 4D and operated by me and my two friends.If you want to share your plugins for free and put it into the manager, please contact me👍

      Hope it can help you.

      Cheers~
      DunHou


      Boghma-Plugin-HUB

      This plugin manage all the boghma plugin, and install/update/uninstall them.

      Install

      1. Download boghma hub and unzip it.

      2. Put boghma hub folder to your ssd disk,Like:D:/boghma hub

      3. Start Cinema 4D,Preference - Plugins - Add Folder,Add the boghma hub folder and keep active,like:D:/boghma hub

      4. Restart Cinema,find boghma menu and enjoy
        15633e63-cbd0-4294-9452-a003199b1088-image.png

      Do not change the folder structure of boghma hub
      

      How to use

      53c621b5-1b83-4e0e-b0a8-ab68115b9811-image.png

      • Install
      • Update
      • Unstall
      posted in General Talk
      DunhouD
      Dunhou
    • RE: Open source wrapper for Octane/Redshift/Arnold/Vray/Corona in Cinema 4D.

      Hi community!

      Since my last post, I had some updates and fix to this library.

      And the following picture shows the new node functions added to my Render Flow plugin based on the use of this library within few lines( just the node context ).

      Have fun with it.

      Cheers~
      DunHou

      all.gif

      posted in General Talk
      DunhouD
      Dunhou
    • Cinema 4D plugin market and tons of free plugins!

      Hi community!

      It is a great honor to introduce new Boghma and core products : Boghma Plugins Manager

      We try to provide free plugins market for users and developers :

      As User:
      • Just install the manager, you already get tons of plugins and growing plugin numbers!
      • You can download any plugin you want and get the newest update all in manager.
      • All the plugins are free, even needn't have to login.
      As Developer:
      • Deliver your plugins and updates directly to users with no fees.
      • Emphasize the developers themselves, uploading your plugins here will not weaken your personal brand. On the contrary, we encourage self promotion.
      • Intuitively obtaining your plugin popularity, investing more energy into user favorite plugins, and achieving a great sense of accomplishment

      So far, we have above 30 plugins and keeping going on, over a month of internal testing inside China, there have been over 9000 downloads, hoping to attract more developers to release their free plugins here.

      And as always, if you have any good ideas, please let me know, or you can join our discord channel in the website and get real-time updates and feedback .

      Cheers~
      DunHou

      posted in General Talk plugin-information chit-chat
      DunhouD
      Dunhou
    • RE: Get the Name of the Node?

      @bentraje

      I think name atttribute is not easy as old c4d SDK to use . It cann't print in console .

      I use this to get Name , and Set Name .
      some codes in python sdk didn't work and return None .Maxon SDK has a example to get info form node retrieve_information_r26.py

          # 获取名称 : 
          def GetNodeName(self, node, display=False):
              """
              Retrieve the displayed name of a node.
              
              Parameters
              ----------        
              Args:
                  node: (maxon.GraphNode): The node to retrieve the name from.
                  display: print info when display is True
              Returns:
                  Optional[str]: The node name, or None if the Node name can't be retrieved.
              """
              if node is None:
                  return None
      
              nodeName = node.GetValue(maxon.NODE.BASE.NAME)
      
              if nodeName is None:
                  nodeName = node.GetValue(maxon.EffectiveName)
      
              if nodeName is None:
                  nodeName = str(node)
              if display ==True :
                  print(nodeName)
              return nodeName   
      
      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • RE: Open source wrapper for Octane/Redshift/Arnold/Vray/Corona in Cinema 4D.

      Hi community!

      the renderEngine helper is beta now, I set version number to 1.0.0, it contains three renderer now:

      • Octane
      • Arnold ( MaterialHelper only support NodeGragh )
      • Redshift ( MaterialHelper only support NodeGragh )

      I personally not use Vray and Corona quite often, if anyone is a pro user of these , very welcome to add them to renderEngine

      You can modify the aovs/materials with renderEngine quickly and easliy . See the examples above this topic.

      Hope you can have fun with it, and any improvement and fix is very appreciated.

      Cheers~
      DunHou

      posted in General Talk
      DunhouD
      Dunhou
    • RE: Running Automatic UV for all objects

      @BineeMan here is my unwrap script, but I didn't find how to change to cubic or angle mode, there seems not a symbol in the .h file.

      import c4d
      
      MCOMMAND_AUTOMATICUV = 1053624
      
      def unwrap(node: c4d.BaseObject):
          doc = node.GetDocument()
          if isinstance(node, c4d.PolygonObject) and node.GetTag(c4d.Tuvw) is not None:
              pass
          elif isinstance(node, c4d.PolygonObject) and node.GetTag(c4d.Tuvw) is None:
              doc.AddUndo(c4d.UNDOTYPE_CHANGE, node)
              settings = c4d.BaseContainer()
              settings[c4d.MDATA_AUTOMATICUV_TAGINDEX] = 0
              settings[c4d.MDATA_AUTOMATICUV_FORCESEAMS] = False
              settings[c4d.MDATA_AUTOMATICUV_OVERLAPMIRRORED] = False
              settings[c4d.MDATA_AUTOMATICUV_OVERLAPIDENTICAL] = False
              settings[c4d.MDATA_AUTOMATICUV_SPACING] = 0.01
              settings[c4d.MDATA_AUTOMATICUV_USENORMALS] = True
              settings[c4d.MDATA_AUTOMATICUV_SPACINGASPECT] = 1.0
              c4d.utils.SendModelingCommand(command = MCOMMAND_AUTOMATICUV,
                                          list=[node],
                                          mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
                                          bc=settings,
                                          doc=doc)
      
      def do_it():
          doc = c4d.documents.GetActiveDocument()
          for node in doc.GetActiveObjects(0):
              unwrap(node)
          c4d.EventAdd()
      
      if __name__ == '__main__':
          do_it()
      
      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • RE: Open source wrapper for Octane/Redshift/Arnold/Vray/Corona in Cinema 4D.

      Hi community!

      Th renderEngine library has been updated to the 1.0.4 version, there are some re-write functions and may not incompatible with older versions,see the main changes as follows:

      • rename all node & material functions to Capitalize style.
      • remove transaction in node_helper, use it in the final scripts.
      • organize the functions in node_helper with comments ( node\port\wire\util )
      • add some functions to check node or port info, like if it is connected , see the README.
      • add a InserShader function to create a shader into a wire.
      • re-write RemoveConnection in node_helper and support one argument(port) to remove connection.
      • see the Version & Updates

      Cheers~
      DunHou

      posted in General Talk
      DunhouD
      Dunhou

    Latest posts made by Dunhou

    • RE: How to implement an image control that can receive and generate image data drag events

      Hey @m_adam ,

      Yes , I had a look at this example, but I'm confusing to understand how it can apply to my case, sorry for my foolish brain.

      If I keep InputEvent as @ferdinand did in the example, HandleMouseDrag will return True if I have a little move, I try to stop this,
      so I want to execute HandleDragEvent only when mouse "obvious interaction outside the ua",to avoid the accompanying effect of dragging when lightly clicked (download) .

          def InputEvent(self, msg: c4d.BaseContainer) -> bool:
              """Called by Cinema 4D when the user area receives input events.
      
              Here we implement creating drag events when the user drags from this user area. The type of
              drag event which is initiated is determined by the drag type selected in the combo box
              of the dialog.
              """
              # When this is not a left mouse button event on this user area, we just get out without
              # consuming the event (by returning False).
              if (msg.GetInt32(c4d.BFM_INPUT_DEVICE) != c4d.BFM_INPUT_MOUSE or
                      msg.GetInt32(c4d.BFM_INPUT_CHANNEL) != c4d.BFM_INPUT_MOUSELEFT):
                  return False
      
              # Get the type of drag event that should be generated, and handle it.
              dragType: int = self._host.GetInt32(self._host.ID_DRAG_TYPE)
              return self.HandleDragEvent(msg, dragType)
      

      my code did stop the HandleDragEvent execute if I didn't want to.

      but in this situation, even if I print and execute HandleDragEvent successfully, C4D does not accept drag events, which means the material cannot be assigned to the object. I don't know what is preventing this.

          def InputEvent(self, msg: c4d.BaseContainer) -> bool:
              """Called by Cinema 4D when the user area receives input events.
      
              Here we implement creating drag events when the user drags from this user area. The type of
              drag event which is initiated is determined by the drag type selected in the combo box
              of the dialog.
              """
              # When this is not a left mouse button event on this user area, we just get out without
              # consuming the event (by returning False).
              if msg[c4d.BFM_INPUT_DEVICE] != c4d.BFM_INPUT_MOUSE and msg[c4d.BFM_INPUT_CHANNEL] != c4d.BFM_INPUT_MOUSELEFT:
                  return False
              
              dragType: int = self._host.GetInt32(self._host.ID_DRAG_TYPE)
              
              if msg.GetBool(c4d.BFM_INPUT_DOUBLECLICK):
                  print("Double click detected, generating drag event")
                  return True
         
              mx = int(msg[c4d.BFM_INPUT_X])
              my = int(msg[c4d.BFM_INPUT_Y])
              mx -= self.Local2Global()["x"]
              my -= self.Local2Global()["y"]
              # print(f"Start mouse: {mx}, {my}")
      
              state = c4d.BaseContainer()
      
              self.MouseDragStart(c4d.BFM_INPUT_MOUSELEFT,mx,my,c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE|c4d.MOUSEDRAGFLAGS_NOMOVE)
              isFirstTick = True
              s = 0
              dua = 0
              
              while True:
                  res, dx, dy, channels = self.MouseDrag()
                  if res != c4d.MOUSEDRAGRESULT_CONTINUE:
                      break  
      
                  mx -= dx
                  my -= dy
                  
                  self.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, state)
                  
                  # mouse released, this can triggered by a click or a drag end
                  if state[c4d.BFM_INPUT_VALUE] == 0:
                      dua = time.perf_counter() - s
                      print (f"Released Mouse in {dua:.4f} seconds")
                      
                      # drag too short, not starting drag event
                      if dua < 0.15:
                          return False
                      break                
      
                  if isFirstTick:
                      isFirstTick = False
                      s = time.perf_counter()
                      print(f"\t-- first click : {mx}, {my}")
                      continue
      
              endState = self.MouseDragEnd()
              if endState == c4d.MOUSEDRAGRESULT_FINISHED:
                  print(f"\t-- drag finished : {mx}, {my}")
                  
                  # drag end inside ua, not generating drag event
                  if (0 <= mx <= 0 + self.width and 0 <= my <= 0 + self.height): 
                      return False
      
              print('Now ,try to start drag event')        
              return self.HandleDragEvent(msg, dragType)
      

      Cheers~
      DunHou

      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • RE: How to implement an image control that can receive and generate image data drag events

      Hey @ferdinand ,

      Sorry for silence, quite busy last days, anyway, back to the question.

      It should be noted that from the results, I have found an alternative way to implement it as mentioned above. I just want to review the diagram to understand the logic of the input event
      I'm not questioning the rationality of this setting, I just want to know if there's a way to control it more finely

      A more precise question may be control over clicking and dragging, e.g. :

      • Assume Cinema consider a click down and release under 0.1sencond and mouse position didn't change more than 2 pixels as a BFM_INPUT_MOUSELEFT, and hold on more than 0.1s and mouse move as HandleMouseDrag.
      • Under this premise, if the user accidentally touches and causes the mouse to quickly click and the cursor to move some distance, this behavior will be considered as dragging.
      • I hope this behavior is seen as a click (I know this is a bit strange, I just want to try and see if it can be achieved)
      • I tried to use c4d.BFM-INPUT_LUE to retrieve mouse release, but as far as I know, this needs to be executed in a while loop.
      • When there is a loop in InputEvent, the conditions I set are judged correctly, but the drag time is masked, which means that the drag behavior cannot be triggered(e.g., no plus under the cursor, and no material created).

      like our asset browser, click or drag between the green arrow will not trigger the download progress. only click download/double click/drag outside will download and assign the asset.

      88e2f25a-efa8-40a8-8a48-8cef92778f32-image.png

      Cheers~
      DunHou

      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • RE: ImportSymbols with single file didn't return as expect.

      Hey @ferdinand,

      Is there any deficiency in pathlib ? I just think its writing style is more convenient and it produces less code. Lazy me🤡

      @ferdinand said in ImportSymbols with single file didn't return as expect.:

      does not support passing a file as an input but only directories

      I'm a bit confused, does this mean that ImportSymbols only support directories, but the documentation says that files can be passed for parsing, or did I misunderstand again...
      9164e957-59e9-4433-b901-f7298d92fed5-PixPin_2025-06-12_10-39-10.png
      Cheers~
      DunHou

      posted in Bugs
      DunhouD
      Dunhou
    • RE: How to implement an image control that can receive and generate image data drag events

      Hey @ferdinand ,

      An extension issue, which is actually the original intention of this issue, I followed your suggestion and implemented "user seamless interaction" using a timer, but there is still one issue that troubles me.

      How to exclude mouse clicks before dragging event.

      • The reason I need to do this is that before clicking, there may not be any data on the hard drive to generate the material. After dragging and dropping, I want to perform a data check, but I don't want to trigger a download task every time I click
      • I tried using MouseDragStart polling to determine the position of the mouse when it is released, in order to determine whether the action should be considered a click, but at this point, the print ('try to start drag event ') did trigger, but there was no HandleMouseDrag action, and there was no interaction when the mouse moved over the object.
      • I followed the suggestion here and tried using GetInputState to determine mouse release, but I couldn't get rid of this limitation

      Uncertain alternative methods require testing

      • Generate empty material, if it is a valid dragging, check data and replace materials after successful execution, which may be feasible but requires a lot of additional code.
      • Generate an empty material, but download the address in the texture path after success, and then refresh the material.

      These methods certainly cannot separate clicking and dragging intuitively. Is it possible to achieve this?

      get idea from https://developers.maxon.net/forum/topic/16267/marquee-selection-of-items-in-geuserarea

      Cheers~
      DunHou

          def InputEvent(self, msg: c4d.BaseContainer) -> bool:
      
              
              mx = int(msg[c4d.BFM_INPUT_X])
              my = int(msg[c4d.BFM_INPUT_Y])
              gx,gy = mx,my
              mx -= self.Local2Global()["x"]
              my -= self.Local2Global()["y"]
      
              channel = msg[c4d.BFM_INPUT_CHANNEL]
              state = c4d.BaseContainer()
              mousex = mx
              mousey = my
      
              if channel == c4d.BFM_INPUT_MOUSELEFT:
                  # res, dx, dy, channels = self.MouseDrag()
                  # print(res, dx, dy, channels)
                  self.MouseDragStart(
                      c4d.BFM_INPUT_MOUSELEFT,
                      mx,
                      my,
                      c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE,
                  )
                  while True:
                      res, dx, dy, channels = self.MouseDrag()
                      
                      if res == c4d.MOUSEDRAGRESULT_ESCAPE:
                          self._drag_enabled = False
                          break                
                      elif res == c4d.MOUSEDRAGRESULT_CONTINUE:
                          mx -= dx
                          my -= dy
                          
                      if not self.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, state):
                          break
                      
                      if state[c4d.BFM_INPUT_VALUE] == 0:
                          print ("Released Left Mouse")
                          break
      
                      if dx == 0 and dy == 0:
                          continue
                  
                      mousex += dx
                      mousey += dy
                      print("Mouse Dragging at position [%f,%f]" % (mousex, mousey))
                      
                      if res == c4d.MOUSEDRAGRESULT_FINISHED:
                          print("dra finished")
                          # print(mx,my)
                          # print(f"inside: {self.is_inside(mx, my)}")
                          if self.is_inside(mx, my):
                              print("end inside")
                              if min(abs(gx-mx), abs(gy-my)) < 20:
                                  print("move little, treat as click")
                                  self._drag_enabled = False
                                  return True
                              break
                          else:
                              self._drag_enabled = True
                              print("end outside, drag enabled")
                              break
      
                  self.MouseDragEnd()
      
              if self._drag_enabled:
                  print('try to start drag event')
                  dragType: int = self._host.GetInt32(self._host.ID_DRAG_TYPE)
                  return self.HandleDragEvent(msg, dragType)
              return True
      
      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • RE: How to Get and Set Specific Node Attributes in Maxon Graph API?

      Hey @Amazing_iKe,

      As I know Graph Description used to modify graphs but have no methods to get port values.

      You should use maxon.GraphNode, like GetPortValue(), or just use GetValue(''value).

      Cheers~
      DunHou

      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • ImportSymbols with single file didn't return as expect.

      Hi community,

      I found the mxutils.ImportSymbols can not work with single file. Is this is a bug?

      win 11 + 2025.2

      Cheers~
      DunHou

      import c4d
      from pathlib import Path
      from mxutils import ImportSymbols
      from pprint import pp
      
      doc: c4d.documents.BaseDocument  # The currently active document.
      op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
      
      # replace a file path
      c4d_symbol = r".....c4d_symbols.h"
      
      def main() -> None:
      
          # the file is true exists
          print(Path(c4d_symbol).exists())
          
          symbols_A = ImportSymbols(str(c4d_symbol), output=dict)
          pp(symbols_A) # return {}
      
          symbols_B = ImportSymbols(str(Path(c4d_symbol).parent), output=dict)
          pp(symbols_B) # return a dict with symbols
      
          symbols_C = ImportSymbols(str(Path(c4d_symbol).parent))
          pp(symbols_C) # return None
      
      if __name__ == '__main__':
          main()
      
      posted in Bugs windows python 2025
      DunhouD
      Dunhou
    • RE: How to implement an image control that can receive and generate image data drag events

      What a detailed explanation! Love these technical videos!

      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • RE: Link StoreColorToAOV to Existing AOV (Python)

      hey @itstanthony ,

      I don't quite understand what you're saying about “find one named “BaseColor” for example, and set it as the value for the “AOV Name 0” parameter in a Store Color To AOV node.”

      I assume you want to find an AOV named BaseColor in the AOV Manager and change its settings? I'm not sure if this is what you want.

      relevant Maxon IDs or documentation to manipulate these parameters - you should look at redshift resource folder, but if you only need some id about rs aov, you can also check redshift_id.py

      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • RE: Link StoreColorToAOV to Existing AOV (Python)

      Hi @itstanthony ,

      To add AOV to Redshift, you need use redshift.RendererSetAOVs to add a c4d.redshift.RSAOV object to your RS videopost.

      But I think the Redshift module has never been released and is not supported. I used this module to make a very clumsy wrapper( Renderer ), although not very elegant, it works.

      Hope the Redshift team can release the API as soon as possible.

      Cheers~
      DunHou

      posted in Cinema 4D SDK
      DunhouD
      Dunhou
    • RE: Load presets args in python?

      It sounds worth a try, but there may be latency issues when it comes to changes, or data changes can be manually processed during the changes

      Perhaps for my needs, I can force the database to be use GetSceneRepository, anyway, it's worth a try. Thank you for your guidance 😊

      posted in Bugs
      DunhouD
      Dunhou