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. uogygiuol
    3. Posts
    • Profile
    • Following 0
    • Followers 0
    • Topics 2
    • Posts 6
    • Best 0
    • Controversial 0
    • Groups 0

    Posts made by uogygiuol

    • RE: How to modify parameters of individual clones of Cloner in Python SDK

      This is fantastic, thank you so much!

      This works beautifully.

      I see your confusion with the "offset". This is absolutely my fault in formulating the question. Sorry about that. I also wanted the clones to follow a spline with an individual offset, but then thought to remove this part to not overcomplicate the question and accidentally left some traces. However, in your video you gave me valuable insight in how to achieve this as well. I already have a working sketch where I'm daisy chaining your script with a Spline Effector in the right order.

      Giving these thoughtful answers is incredibly valuable, you can't believe how motivating this is to go further.

      posted in Cinema 4D SDK
      uogygiuolU
      uogygiuol
    • RE: How to modify parameters of individual clones of Cloner in Python SDK

      Sidenote while researching my answer:
      Something I found confusing in the Set MoData Selection Example is that it's not clear what to do with the selection.

      Wouldn't it make sense to add a op.MakeTag(c4d.Tmgselection) before calling GeSetMoDataSelection?

      This way, also the Get MoData Selection Example works with it in a tandem.

      Do you agree?
      If not I'd be curious why.
      If you do agree, please check this PR
      Thanks!

      posted in Cinema 4D SDK
      uogygiuolU
      uogygiuol
    • How to modify parameters of individual clones of Cloner in Python SDK

      Hi,

      I would like to access the parameters of individual clones of the Cloner object in Python.

      Particularly I would like to modify the offset of each clone individually. I am pretty sure this should be possible, however I can't think of a way that does not include some complicated procedure of using the MoGraph Selection Tool. I do have a hunch that using this tool is the way to go, but I have a feeling it should be easier.

      My rather complicated guess is:

      1. create MoGraph selection per individual clone (don't know how yet)
      2. create equal amount of Plain Effectors
      3. connect selections with effectors
      4. modify effectors parameters

      As a bonus, I would like to be able to specify the reference object for each individual clone.
      So, if I have two reference objects A & B, and I want a cloned linear pattern of AAABBBABAAAABBBABBABBABBBBAAAABBABABAA.
      My current approach is to keep A and B in a separate place and put instances of them as children under the cloner following the pattern. It works, but I am not sure if this is bad practice. After all, Cloner will create then Multiinstances referencing Instances. However, my hunch is that a custom cloning pattern is not possible.
      (I thought to combine both questions in one post, as they both refer to modifying individual clones, and possibly have a very similar solution. If this is not true, I am happy to remove this second question for the sake of clarity.)

      The example code is a minified version of the starting situation, with some hallucinated pseudo code at the last lines. In the end I want to use it in the GetVirtualObjects function of an ObjectData plugin.

      # get the obligatory active document to attach our objects to
      doc = c4d.documents.GetActiveDocument()
      
      # construct a cloner object
      cloner = c4d.BaseObject(c4d.Omgcloner)
      # use linear mode, so we can better see if it works
      cloner[c4d.ID_MG_MOTIONGENERATOR_MODE] = c4d.ID_MG_MOTIONGENERATOR_MODE_LINEAR
      # also here, iterating through the children sounds the most intuitive
      cloner[c4d.MGCLONER_MODE] = c4d.MGCLONER_MODE_ITERATE
      # always use 42, as you might accidentally solve all problems of the world
      cloner[c4d.MG_LINEAR_COUNT] = 42
      # might not really matter for this example
      # but in my particular use case I use multiinstance rendering,
      # defining it therefore just in case there are side effects when accessing
      # individual clones
      cloner[c4d.MGCLONER_VOLUMEINSTANCES_MODE] = (
      	c4d.MGCLONER_VOLUMEINSTANCES_MODE_RENDERMULTIINSTANCE
      )
      # okay, now we're ready to throw the fish in the water!
      doc.InsertObject(cloner)
      # give it some children
      A =  c4d.BaseObject(c4d.Ocube)
      A.InsertUnderLast(cloner)
      B = c4d.BaseObject(c4d.Osphere)
      B.InsertUnderLast(cloner)
      
      # now let's do some wishful thinking
      # to demonstrate in pseudocode what I tried to describe in words
      pattern = "AAABBBABAAAABBBABBABBABBBBAAAABBABABAA"
      for i in range(0, len(pattern)):
      	# adjust offset by some arbitrary value
      	cloner.GetCloneByIndex(index).SetOffset(i * 0.2)
      	# move relative to current position along some vector
      	cloner.GetCloneByIndex(index).SetRelPos(c4d.Vector(i))
      	# bonus: set reference object
      	cloner.GetCloneByIndex(index).SetReferenceObject(A if pattern[i] == "A" else B)
      

      Obviously, the last part will throw errors.

      Thank you already for reading this! I am thankful for any hint towards the right direction.

      posted in Cinema 4D SDK python 2025
      uogygiuolU
      uogygiuol
    • RE: Find objects within GLTF-file by name and attach them to the scene.

      @ferdinand said in Find objects within GLTF-file by name and attach them to the scene.:

      Sorry, I did overlook the 'without having to load the complete gltf in memory' part of your initial question.

      No worries πŸ™‚ I also understand that Cinema4D cannot implement a mechanism as I describe for all possible file formats.

      What you could do, given your GLTF file is in JSON format, is mangle it into place, given that Python has very nice JSON support. But making sure that this file stays valid, when you remove elements from it, might be not so trivial. I am also not sure if you will ever come out here with a net-win where mangling the file in Python first and then loading it outpaces just loading the full file.

      I have to look into that. Given that loading the whole file can easily take 5 minutes, even an approach like this might be a winner. However, you're absolutely right about introducing quite some potential instability when mangling with the file. Also, I did write GLTF everywhere, but there may be also GLB files, which should be treated the same way.

      Could you shed some light on where this becomes relevant? Are your files so large that loading is a bottleneck? I struggle to see a bit where this could become a scenario with GLTF.

      In the end this is all a bit hypothetical. You do not disclose if there are material, animations, etc., and most importantly how the scene hierarchy is, e.g., could an Eberhardt{n} hold descendant nodes that must be preserved, e.g., Ebertraudt is the first child of Eberhardt42. This would of course make this all much more complicated.

      Of course! I'm happy to share, I just didn't want to blast too many details in this post to avoid distraction from the main question. In the end this will be a basic plugin for placing 3D text along curves.

      Imagine a font with 3D letters. This font is saved in a single GLTF file. Each character is a node with a single mesh. No materials, no animations, no nested meshes.* The nodes are not nested, Eberhardt cannot be a child of Ebertraut. I do already have a couple of these files and also an already working plugin for Blender. In Blender, I copied the internal function to load gltf's and interjected some code between indexing and loading the file. When the index is created, I reiterate over it and build a new scene tree with only the matching objects, and then continue the normal loading process with the new scene tree. So this is very similar to your file-mangling approach, and it's super fast. I could take this function and plug it in, but I'd need to disentangle it from the internal Blender specific dependencies which I assume to be a significant effort.

      The reason why I don't want to load the whole file into memory is because these files can be a gigabyte or even more. If the whole file is loaded into RAM, then it occupies a lot of space there. However, we may write just a couple of letters, so the most of the occupied RAM could be free. It does need to be in the file though! Also, loading a file like this may take 5 literal Minutes, which is - combined with the loss of RAM - an inconvenience I'd love to avoid. What is important, is that the user will have their own project to work with, and whatever this plugin is doing is running on the side. This is why I want to occupy the least amount of RAM possible.

      *At least for now a simple mesh per character is fine. In a happy future it would be great to add support for materials, animations, etc - but this seems already complicated enough to get working.

      When you want to also support 2024, I would suggest that you just monkey patch mxutils.IterateTree (as this seems to be all you need). I have dumped the implementation of it at the end. Doing it like that, would have the benefit that you would native code for 2025.

      Beautiful, thank you!


      I hope that this cleared up some question marks. I get the feeling that I won't get around writing a custom gltf/glb loader. As you said, I can't expect that c4d already provides me with the functions I need, but I still wanted to ask just in case I am overlooking something.

      posted in Cinema 4D SDK
      uogygiuolU
      uogygiuol
    • RE: Find objects within GLTF-file by name and attach them to the scene.

      Dear Ferdinand,

      thank you so much for your quick and helpful reply! Amazing how fast, super impressive and it really motivated me to keep going. I needed a bit more time to reply and verify I am not writing stupid things. I can't promise that there is nothing stupid left, but I did my best :)

      Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.

      This makes a lot of sense. I checked out the links you posted and found already the one or other thing I want to do better.

      To clarify, this is my main question:
      How can I search in a GLTF-file for specific objects, and load them selectively in the scene - without loading the whole file in memory?

      I have a gltf-file with hundreds of shapes, possibly gigabytes. They are structured like a flat database. Imagine it like a 3D font, with many, many individual letters. I don't want the whole character set for all languages and variations to be loaded, just because the user wants to write "hello world". It is by the way, exactly what this is going to be used for and will become relevant when we think about identifiers.

      Maybe it is best to give an example of what I want to do:

      1. parse the nodes-index of the gltf-file
      2. find an object by name
      3. load this particular object in memory
      4. instantiate object in the scene

      1) parse the nodes-index of the gltf-file

      Consider this gltf-file, which holds various objects:

      {
        "meshes": [ ... ],
        ...,
        "nodes": [
          {
            "mesh": 0,
            "name": "Eberhardt"
          },
          {
            "mesh": 1,
            "name": "Edeltraudt"
          },
          {
            "mesh": 2,
            "name": "Ebertraudt"
          },
          ...,
      
          {
            "mesh": 65535,
            "name": "Eberhardt42"
          },
        ]
      }
      

      So here I want to parse "nodes", check the names and only load the meshes of the nodes that start with "Eberhardt".

      2) find an object by name

      I agree that names are usually not a good identifier. However, in this case it does make sense to me, because the individual nodes are characters for a 3D font. The first character of the string refers to the character the shape represents. "A_1", "A_2", "Γ„_42", "δΊΊ_1" or "𒀇_9" can all be represented in json/gltf strings, which makes the name easy and straightforward to use. It doesn't matter if a character has the name "A_1.001" or "A_1"

      About your First Question

      You can search for objects with c4d.documents.BaseDocument.SearchObject.

      Maybe this is due to my limited understanding, but I couldn't manage yet to use it without loading the whole document in memory. Also, as described above I need to allow partial matches and it looks as if SearchObject only searches for exact matches. I realize that I didn't mention this limitation in my initial question...

      Apart from the fact that names are a poor way to identify objects, you can also not find multiple objects with the same name in this manner. With release 2025 we added abstracted scene iteration.

      The abstracted scene iteration looks great! However, I need to stay compatible with 2024.x.x.

      Last but not least, what you are doing in your example code, recursion (at least unbound recursion) should be avoided, as this can quite easily lead to stack overflows. See this thread for how to do scene traversal manually.

      Noted and agreed. Thank you for your attentiveness! Also, a wonderfully helpful post in that thread. Isn't this a perfect 2024.x.x replacement for what I'd use mxutils.RecurseGraph in 2025.x.x for?

      such as:

      for n in GetAllNodesIteratively(node):
          if n.GetName().startswith("Eberhardt"):
              pass
      

      I guess the only real downside is that mxutils.RecurseGraph would be implemented in c++ and way more performant on large node graphs.

      3) load this particular object in memory

      Ideally we have identified the matching nodes, without loading the whole gltf into memory. But we do need to load the matches selectively. I do not know yet how to do that, or if this is even possible with out-of-the-box functions. If we can manage to do 1) and 2), then this should be possible somehow. In any case I'd love to use existing functions and avoid custom acrobatics wherever possible.

      4) instantiate object in the scene

      I realize also this may be a follow up question, but I guess it will lead me to c4d.InstanceObject and should be trivial in comparison.


      I hope that my question makes sense, and thank you so much already for your help.

      posted in Cinema 4D SDK
      uogygiuolU
      uogygiuol
    • Find objects within GLTF-file by name and attach them to the scene.

      Hi!

      For a python plugin I need to use some GLTF files as "asset library" files. For example, I have a gltf with hundreds of meshes in it. Ideally I would be able to scan the gltf for specific meshes by name and attach these to the scene without having to load the complete gltf in memory.

      Coming mostly from Blender plugin development, this is my first C4D plugin, so please forgive me that I am not quite fluent in C4D python yet and may have some stupid assumptions.

      As far as I can see I need to use c4d.documents.LoadDocument and made some quick tests. I didn't run into anything major as far as I can tell, but I am not sure if I will run into a dead end with this approach.

      Here, the first quick tryout:

      import c4d
      
      
      def findChildByName(mom, name, recursive = True):
          """Naive function to find a child object by name. Can produce only one child and is therefore not very sexy."""
          if hasattr(mom, 'GetObjects'):
              for child in mom.GetObjects():
                  if child.GetName() == name:
                      return child
                  elif recursive:
                      c = findChildByName(child, name)
                      if c:
                          return c
          if hasattr(mom, 'GetChildren'):
              for child in mom.GetChildren():
                  if child.GetName() == name:
                      return child
                  elif recursive:
                      c = findChildByName(child, name)
                      if c:
                          return c
          return None
      
      
      filepath = "C:/path/to/file.glb"
      f = c4d.documents.LoadDocument(filepath, c4d.SCENEFILTER_OBJECTS)
      
      doc = c4d.documents.GetActiveDocument()
      
      eberhardt = findChildByName(f, "Eberhardt")
      if eberhardt != None:
          doc.InsertObject(eberhardt.GetClone(c4d.COPYFLAGS_0))
      

      Of course the whole glb file is loaded into memory, but otherwise it works. How would I go about without loading the whole file into memory? Do I need to adjust the gltf importer settings similar to the obj importer example somehow? I saw the c4d.SCENEFILTER_IDENTIFY_ONLY flag... is this one leading to the road of glory?

      Is it even possible to load files only partially, or do I need to write my own gltf importer?

      I'd be super happy if someone could point me in the right direction!

      posted in Cinema 4D SDK python 2024 2025 windows macos linux
      uogygiuolU
      uogygiuol