Group Details Private

Global Moderators

Forum wide moderators

  • RE: Automating Dynamic Place

    Hello @markeee,

    Welcome to the Maxon developers forum and its community, it is great to have you with us!

    Getting Started

    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.

    • Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
    • Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
    • Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

    It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions.

    About your First Question

    I really do not want to demotivate you in your first posting, but what you are trying is not trivial and this is one of the cases where when you have to ask, it is probably not for you. The Place tool is not exposed in the public API and so is not the general Rigid Body Dynamics API. Writing something like the place tool yourself is a very hard task.

    What is relatively easy, is just to create an RBD setup, and then animate that for X frames, in the hopes that it until then has settled.

    Cheers,
    Ferdinand

    Result

    b019ae64-720f-4829-aa17-cca3e764b54f-image.png

    """Creates a little RBD setup to place an object on top of another object.
    
    I am using here a plane as the object to settle on, but it could also be a non-planar object. Must
    be run as a Script Manager script and will place/create a Platonic, as if it had fallen on the world
    grid and settled on the origin of it.
    
    Since this must run a simulation, the script will run a while (and block the UI in the mean time).
    One could make this nicer with threading and statusbar spam, but I did not :)
    """
    
    import c4d
    import mxutils
    
    doc: c4d.documents.BaseDocument  # The currently active document.
    op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
    
    def main() -> None:
        """Called by Cinema 4D when the script is being executed.
        """
        # Generate a platonic object and a plane object, scale up the plane, move the platonic 500 units 
        # up on the y-axis, and finally create a little RBD setup.
        platonic: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Oplatonic))
        plane: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Oplane))
    
        plane[c4d.PRIM_PLANE_WIDTH] = 5000
        plane[c4d.PRIM_PLANE_HEIGHT] = 5000
        platonic.SetMg(c4d.Matrix(off=c4d.Vector(0, 500, 0)))
    
        mxutils.CheckType(plane.MakeTag(c4d.Tcollider))
        rbd: c4d.BaseTag = mxutils.CheckType(platonic.MakeTag(c4d.Trigidbody))
        rbd[c4d.RIGIDBODY_PBD_CUSTOM_INITIAL_VELOCITY] = True
        rbd[c4d.RIGIDBODY_PBD_CUSTOM_INITIAL_ANGULAR_VELOCITY] = True
        rbd[c4d.RIGIDBODY_PBD_INITIAL_LINEAR_VELOCITY] = c4d.Vector(-.1)
    
        # Create a dummy document, insert our little rig, and execute the passes for 100 frames, in the
        # hopes that the platonic has settled until then.
        temp: c4d.documents.BaseDocument = mxutils.CheckType(c4d.documents.BaseDocument())
        temp.InsertObject(plane)
        temp.InsertObject(platonic)
    
        fps: int = temp.GetFps()
        for i in range(100):
            temp.SetTime(c4d.BaseTime(i, fps))
            if not temp.ExecutePasses(None, True, True, True, c4d.BUILDFLAGS_NONE):
                raise RuntimeError(f"Failed to execute pass for {c4d.BaseTime(i, fps)} for {temp}.")
    
        # Get the matrix from the settled object. We can zero out the x/z pos, so that the objects sits
        # dead-center in the world grid.
        mg: c4d.Matrix = platonic.GetMg()
        mg.off = c4d.Vector(0, mg.off.y, 0)
    
        # Create a new platonic (with the same settings) and insert into the active document and set our
        # computed matrix.
        result: c4d.BaseObject = mxutils.CheckType(c4d.BaseObject(c4d.Oplatonic))
        result.SetMg(mg)
        doc.InsertObject(result)
    
        # Cinema 4D will garbage collect #temp and its content on its own, but we can call flush to make
        # it a bit cleaner.
        temp.Flush()
    
        # Push an update event.
        c4d.EventAdd()
    
    
    if __name__ == '__main__':
        main()
    
    posted in Cinema 4D SDK
  • RE: Get the random result of Cloner Object

    Hey @freeze,

    yes, clonerObj would be in your case the object which holds the generated MoGraph particle output in its cache. But generally speaking, you should not reach into caches. Sometimes it is necessary, but caches (be it generator or deform caches) are a dynamically generated part of the scene graph you usually should not interact with.

    Just getting the matrices of the elements in the cache is fine (to print them or do something similar harmless). Establishing pointers into caches or relying on the fact that there is an established cache is not fine (note that my code checks for the cache actually being populated).

    I still do not really understand what you want to do, but it strikes me as being on the 'you should really not do that' side. As I said in the beginning, MoGraph is a particle system and you are only supposed to interact with the abstract particle data.

    I have the feeling you want to interact with the MoGraph particles as if they were tangible objects in the scene graph. This is simply not supported/intended.

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK
  • RE: Get the random result of Cloner Object

    Hey @freeze,

    I am still not quite sure how you mean that. MoGraph is a particle system under the hood, i.e., you will not find the actual cloned objects in it unless you reach into the cache of the cloner. The particle arrays is all there exists, e.g., MODATA_MATRIX for the transform of the particles. When you want to retrieve the matrix of the input object, you must get that.

    Cheers,
    Ferdinand

    Result

    98fa49cd-5e64-4294-aaeb-030bf87a8317-image.png

    Code

    import c4d
    import mxutils
    
    doc: c4d.documents.BaseDocument  # The currently active document.
    op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
    
    def main() -> None:
        """Called by Cinema 4D when the script is being executed.
        """
        moData: c4d.modules.mograph.MoData | None = c4d.modules.mograph.GeGetMoData(op) if op else None
        if not moData:
            raise RuntimeError("Please select an object that holds MoGraph particle data.")
        
        print ("Particles:\n")
    
        # Iterate over the (local) particle matrices for this MoGraph data. Local means here in relation
        # to the MoGraph generator, i.e., cloner.
        for i, ml in enumerate(moData.GetArray(c4d.MODATA_MATRIX)):
            print(f"{i = }, {ml = }")
    
        print ("\nInputs:\n")
    
        # Iterate over the child objects of the cloner, i.e., the clone sources.
        for node in op.GetChildren():
            print (f"{node.GetName() = }, {node.GetMg() = }")
    
        print ("\nCache:\n")
    
        # Look into the cache of the cloner which might contain the flattened particle data (when in
        # Instance or Render-Instance mode). When the cloner is in Multi-Instance mode, the cache will
        # not be (fully) populated.
        cache: c4d.BaseObject | None = op.GetCache()
        if cache:
            for node in mxutils.IterateTree(cache):
                print (f"{node.GetName() = }, {node.GetMg() = }") 
    
    
    if __name__ == '__main__':
        main()
    
    posted in Cinema 4D SDK
  • RE: Get the random result of Cloner Object

    Hey @freeze,

    Thank you for reaching out to us. I do not understand your question, specifically this part:

    the matrixItemsCnt always be 60 ,full of the instances in this case ,same as the Matrix I got.Any way can I just get the clones shown as the random result?

    Could you please reiterate what you want to achieve or what you would consider incorrect/surprising about your results?

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK
  • RE: Cinema4D 2025 get user data value parameter not accessible?

    Good to hear!

    posted in Cinema 4D SDK
  • RE: Cinema4D 2025 get user data value parameter not accessible?

    Hey @BigRoy,

    Thank you for reaching out to us. What Python is trying to tell you, is that the data type at this parameter is not wrapped for the Python API. Not every data type known to the Cinema 4D API, and there are probably hundreds when you count plugins, is exposed to Python.

    The data types in the core Cinema API (i.e., things in what the Python API calls c4d) are mostly wrapped for Python (but there are also exceptions as for example ItemTreeData where the Python API has no clue what to do with such paramater). Redshift is for example a prime offender and has introduced many data types which are inaccessible in Python (at least as a whole).

    What you can however often do, when the author of the data type implemented it, is channel access. See here and here for examples. Since you do not show us what description_id is, I can only speculate here. My guess would be something from the "lower" section of the user data, as these types are all not wrapped (usually):

    d231792a-0098-406a-b502-192e32481efe-image.png

    I doubt that this is a regression, as this error is an intended feature of our API. It is more likely that you are now iterating over different user data than you did in 2023 and 2024. When you think differently, you would have to provide us a bit more information, specifically the data type and the scene file in which you are trying to iterate on some user data. I.e., just print out your description_id as this is a DescID, which will also contain type information.

    E.g.,

    for descid, _ in op.GetUserDataContainer():
       # You could also use C4Datom.GetParameter as this is a bit more elegant and does not need a try/catch:
       try:
          value = obj[descid]
       except:
          # Will print something like ((700, 5, 0), (1, 19, 0)) where the second triple is the actual parameter
          # (desc-level) and a desc level is composed as (ID, TYPE, CREATOR). I.e., the data type would be
          # 19 here, which is the value of `DTYPE_REAL`, i.e., a float parameter. When the data type integer
          # is a value in the millions, e.g., (1, 1234567, 0)), this is plugin data type from a third party. These
          # data types cannot be wrapped in Python (only component access works).
          print (descid) 
    

    So, long story short: The error is an intended feature. And when there would be a regression (which strikes me as quite unlikely), your code was always dagerous, as it assumes that you can read all parameter data types in Python (which you cannot). For details we would need the data type of the failing parameter and a scene file (when it is one of the native data types which are wrapped).

    Cheers,
    Ferdinand

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

    Hello @uogygiuol,

    Welcome to the Maxon developers forum and its community, it is great to have you with us!

    Getting Started

    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.

    • Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
    • Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
    • Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

    It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions.

    About your First Question

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

    doc: c4d.documents.BaseDocument = c4d.documents.GetActiveDocument()
    target: c4d.BaseObject | None = doc.SearchObject("Eberhardt")
    if target is None:
        raise RuntimeError("Could not find target.")
    

    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.

    doc: c4d.documents.BaseDocument = c4d.documents.GetActiveDocument()
    op: c4d.BaseObject = doc.GetFirstObject()
    
    # Walk the obejct tree and look for objects with a given name.
    for node in mxutils.IterateTree(op, True, True, True):
        if node.GetName() == "Eberhardt":
            pass
    
    # There is also abstract scene iteration now, here we look for any node named "Eberhardt" in #doc.
    for node in mxutils.RecurseGraph(doc, yieldBranches=True, yieldHierarchy=True):
        if node.GetName() == "Eberhardt":
            pass
    
    # Or for objects and tags named "Eberhardt". Check the docs on #RecurseGraph, there are a lot of 
    # options for finetuning the scene traversal.
    for node in mxutils.RecurseGraph(doc, yieldBranches=True, yieldHierarchy=True, nodeFilter=[c4d.Obase, c4d.Tbase]):
        if node.GetName() == "Eberhardt":
            pass
    

    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.

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK
  • RE: Creating a Playblast script falling at the hurdle.

    Hello @AG_Vivimagic,

    Welcome to the Maxon developers forum and its community, it is great to have you with us!

    Getting Started

    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.

    • Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
    • Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
    • Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

    It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions.

    About your First Question

    First of all, your script strikes me as sourced from or at least written with the help of a chat bot. Please disclose when you use AI, otherwise we might refuse to help you. Please also have a look at Support Procedures: Asking Questions, 'I am getting the render settings to align and execute however it is not updating the UI. It need to look like this !' is not a proper question.

    I am assuming that you want to have similar setup of video post effects in your render data, as if when you choose the Preview Hardware Renderer manually. To achieve that, you must manually curate the effects. You should also avoid using raw integer values when setting parameters, as this leads to confusing code and easily to errors. newRenderData.SetBit(8) #make it selected does for example not do what you think it does. The value 8 is BIT_ENABLEPAINT, but you probably mean here BIT_ACTIVE (2).

    Cheers,
    Ferdinand

    Result

    a0644cb2-627b-4f81-8205-799dcd76cd1c-image.png

    Code

    import c4d
    
    doc: c4d.documents.BaseDocument  # The currently active document.
    op: c4d.BaseObject | None  # The primary selected object in `doc`. Can be `None`.
    
    def main() -> None:
        """Called by Cinema 4D when the script is being executed.
        """
        # Set the document FPS.
        doc[c4d.DOCUMENT_FPS] = 25
    
        # Create a new render data instance with the values you wanted.
        rdata: c4d.documents.RenderData = c4d.documents.RenderData()
        rdata.SetName("Playblast")
        rdata[c4d.RDATA_RENDERENGINE] = c4d.RDATA_RENDERENGINE_PREVIEWHARDWARE
        rdata[c4d.RDATA_XRES_VIRTUAL] = 1920
        rdata[c4d.RDATA_YRES_VIRTUAL] = 1080
        rdata[c4d.RDATA_FRAMERATE] = 25 
        rdata[c4d.RDATA_FRAMESEQUENCE] = c4d.RDATA_FRAMESEQUENCE_ALLFRAMES
        rdata[c4d.RDATA_FORMAT] = c4d.FILTER_MOVIE
    
        # We must now curate the video post effects for this render data. This is probably a bit overkill,
        # we could also just delete all of them, since we know that the Preview Renderer only uses MBL which 
        # cannot be removed. But there could be a third party effect which supports the preview renderer 
        # and which is present by default, so we do it the proper way by checking each effect for being
        # compatible with the selected render engine.
        effect: c4d.documents.BaseVideoPost = rdata.GetFirstVideoPost()
        while effect:
            nxt: c4d.documents.BaseVideoPost = effect.GetNext()
            if not effect.RenderEngineCheck(c4d.RDATA_RENDERENGINE_PREVIEWHARDWARE):
                effect.Remove()
            effect = nxt
    
        # Add the native RDATA_RENDERENGINE_PREVIEWHARDWARE effect.
        previewEffect: c4d.documents.BaseVideoPost = c4d.documents.BaseVideoPost(
            c4d.RDATA_RENDERENGINE_PREVIEWHARDWARE)
        rdata.InsertVideoPostLast(previewEffect)
    
        # Insert the render data and do the other things you wanted to do.
        doc.InsertRenderDataLast(rdata)
        doc.SetActiveRenderData(rdata)
        rdata.SetBit(c4d.BIT_ACTIVE)
        c4d.CallCommand(12161)
    
    if __name__ == '__main__':
        main()
    
    posted in Cinema 4D SDK
  • RE: 2025 Python - No Plugin UI, can't find the reason

    Hi @derudo,

    Welcome to the Maxon developers forum and its community, it is great to have you with us!

    Getting Started

    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.

    • Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
    • Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
    • Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

    It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions.

    About your First Question

    There's no single known "thing" we're aware of that could lead to such behavior. In other words, it can be lots of different "things" that caused the symptoms you're describing. Hence, without any further details everything I'm pointing out here is highly speculative.

    I also don't think answering the question "What could have happened?" is by any means productive, so let's switch the point of view to "How one could diagnose it?".

    Since you haven't posted any console output in your question, I assume you haven't checked that. This would actually be the first thing to check. Please refer to our Python Console Manual and searching on the forum.

    Next, try to figure out if it's only UI that stopped appearing or your plugin isn't registered at all anymore. You can do this by checking (e.g. with some temporary print statements) if you plugin is actually functional.

    On the screenshot you've posted the structure is kind of strange, but we're not sure if it's just a visualization matter of your software. Namely, the plugin.pyp file is expected to reside in the root of the plugin folder. Essentially, the following hierarchy level is not supposed to be there:
    232c47cd-171e-4642-8c12-7661b51e6ce5-image.png
    Please refer to the article Plugin Structure Manual: Directory Structure and double check your plugin in this regard.

    If the points above don't lead to any result, try debugging it step-by-step. Namely, strip out everything except the essentials (like plugin registration) and continue adding things piece-by-piece until it starts failing. By the way, one can easily achieve this by using any version control system (e.g. git), as they typically provide a lossless way to manage your code (i.e. remove and add parts of code, without being worried to lose any of them). This approach could also have prevented your scenario in first place, when something stopped working and there're no clues about the change that has lead to it.

    If this still doesn't help, you can share your plugin here (or send us via contact form, when confidential information is involved). However, I must warn you that our Support Procedures still fully apply, namely:

    We cannot debug your code for you and instead provide answers to specific problems.

    Cheers,
    Ilia

    posted in Cinema 4D SDK
  • RE: color space of MODATA_COLOR

    Hey @BruceC,

    Thank you for the added information, but I will still need that step by step bug report. Without it, I will not touch a debugger or a scene file. There are a plethora of reasons why this could go wrong. I am still very much in the dark at what you are looking exactly (e.g., are you using our Picture Viewer to view render results, or do you use your render engines one. What are your rendering and how, etc., pp.).

    As I told you, applying a manual transform is not intended. It might be what you have to do as a work-around for older versions which we won't (hot)fix anymore, but there is no default answer here for you. But for all of that I first need a reliable bug/issue report which I can reproduce, and then other than you look at with a debug version of Cinema 4D. As I said, feel free to use your render engine, and please be precise in the reproduction steps. If you want to, you can also use our beta program bug tracker instead (since you are an MRD).

    Cheers,
    Ferdinand

    posted in Cinema 4D SDK