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

    Insert a shader into a shader hierarchy

    Cinema 4D SDK
    python
    4
    17
    2.5k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • indexofrefractionI
      indexofrefraction
      last edited by

      hm, actually i think the script does work correctly.

      i was additionally checking if the shader tree was correct
      and i was doing this using my own shader walker
      and it failed, it stopps walking after the Filter Shader

      if i use your PrintRelatedNodes() everything looks ok

      i will post a follow up question in the mentioned thread :
      https://developers.maxon.net/forum/topic/14056/copy-layershader-to-a-new-material/5

      1 Reply Last reply Reply Quote 0
      • indexofrefractionI
        indexofrefraction
        last edited by indexofrefraction

        ok, i think i figured out my issue mentioned above ..
        it would be nice if this could be confirmed:

        materials and shaders can only have shader type nodes,
        there must be a shader gelist head at the beginning and followed by normal nodes.
        i guess this is was InsertShader() actually does.

        now if you InsertShader again in the middle of a tree, you get a second shader gelist head
        and as expected this the point is where my simple shader traversing failed.
        but.. if you insert the filter shader manually in the material manager,
        there is no second shader gelist head, just the one at the beginning.

        so i guess that c4d accepts both ways,
        but the proper way would be already to use InsertUnder if we're already in a shader type node list (?)
        using InsertShader in the middle of a shader list is not necessary and bad practice (?)
        a list with multiple shader gelist heads could (should?) be pruned of excessive heads (?)

        ferdinandF 1 Reply Last reply Reply Quote 0
        • ferdinandF
          ferdinand @indexofrefraction
          last edited by ferdinand

          Hey @indexofrefraction,

          but the proper way would be already to use InsertUnder if we're already in a shader type node list (?) using InsertShader in the middle of a shader list is not necessary and bad practice (?) a list with multiple shader gelist heads could (should?) be pruned of excessive heads (?)

          Well, the answer to that all is sort of yesn't. I personally would for example consider the layer shader carrying its shader dependencies as direct children to be at least a regression of the classic API scene architecture, as the proper place would be the shader branch of the layer shader.

          The layer shader engineers might have (somewhat) rightfully thought that it does not really matter, or even had some technical reason to store the shaders as direct children. There is nothing special about branches, they are just contextualized hierarchies. For an object and its tags, they are necessary, because if we would also store tags as direct children of objects, it would become very cumbersome to sort out what is what when tags and child objects would be mixed. For shaders this is not the case, as there is nothing which is naturally a child of shaders as child objects are of objects. But in the end, the 'right' place to store shaders attached to a GeListNode is its shader branch. And other shader developers, both internal external, might have solved this differently and let their shaders store their shader dependencies in the 'Shader' branch of their shader. Which at end forces other developers to understand what each shader type does and imitate it when it must be handled in code.

          There is no 'satisfying' answer, when a shader type stores its shader dependencies as direct children, you must use InsertUnder, and when it does store its shader dependencies in the shader branch, you must use InsertShader (which is just a shortcut for calling InsertUnder on the shader branch GeListHead of that node).

          Cheers,
          Ferdinand

          MAXON SDK Specialist
          developers.maxon.net

          1 Reply Last reply Reply Quote 0
          • indexofrefractionI
            indexofrefraction
            last edited by indexofrefraction

            hi Ferdinand,

            i noticed that there is actually an issue with excessive gelist heads....
            if you have this :

            <c4d.BaseShader object called 'Filter/Filter' with ID 1011128 at 0x7fcebe74eeb0>
            + <c4d.GeListHead object at 0x7fcebe787a70> branch 'Shaders'
            + + <c4d.LayerShader object called 'Layer/Layer' with ID 1011123 at 0x7fcebe787ab0>
            + + + <c4d.BaseShader object called 'Noise/Noise' with ID 1011116 at 0x7fcebe787b90>
            

            GetUp() on the LayerShader seems to return None,
            which is a problem if - like in this case - you need to know if a shader is in the middle inside a shader tree,
            or if it is at the top / a direct child of the material

            this makes something like this necessary to properly "insert" a shader ....

            if isinstance(target, c4d.BaseShader): 
                shader.InsertUnder(target)
            else:
                target.InsertShader(shader)
            
            ferdinandF 1 Reply Last reply Reply Quote 0
            • ferdinandF
              ferdinand @indexofrefraction
              last edited by

              Hey @indexofrefraction,

              well, this is not surprising, as the LayerShader is not in a hierarchical relation with the GeListHead but a branch relation. You must call GetListHead on a GeListNode to retrieve its head, i.e., the branch which is containing the node.

              Cheers,
              Ferdinand

              MAXON SDK Specialist
              developers.maxon.net

              1 Reply Last reply Reply Quote 0
              • fwilleke80F
                fwilleke80
                last edited by

                I also stumbled on this just today, and had the suspicion that BaseList2D::InsertShader() isn't the right function for this. Thank you @ferdinand for verifying that.

                While it totally makes sense to use GeListNode::InsertUnder() when inserting shaders under shaders inside the shaders branch, I think it should totally be mentioned in the SDK docs. Ideally, as a big fat @note for the Doxygen description of BaseList2D::InsertShader(), as well as in the Shader section of the BaseList2D Manual.

                Cheers,
                Frank

                www.frankwilleke.de
                Only asking personal code questions here.

                ferdinandF 1 Reply Last reply Reply Quote 0
                • ferdinandF
                  ferdinand @fwilleke80
                  last edited by ferdinand

                  Hey @fwilleke80,

                  Thank you for reaching out to us. If I remember correctly, we briefly talked about this internally when this thread was created. The problem is, as lined out above, GeListNode::InsertUnder() is not the unambiguously correct function to insert a shader below a shader, and by convention BaseList2D::InsertShader() is neither. It depends on the implementation of the shader what is correct and what not.

                  So, flat out stating something like 'shaders which have other shaders as dependencies will carry them as direct children' as a warning in BaseList2D::InsertShader() can simply not be guaranteed to be correct. When the question was recent, I checked a couple of other shader types as the fusion shader, the filter shader, etc., and they all behaved the same as the layer shader, i.e., they carried their dependencies as direct children. But this only came by convention and not by definition, and there could certainly be shaders out there which handle this differently.

                  However, and long story short, I understand your concerns and will add a small note, although a bit more defensively stated. In the end you must check yourself what each shader type does.

                  Cheers,
                  Ferdinand

                  MAXON SDK Specialist
                  developers.maxon.net

                  1 Reply Last reply Reply Quote 1
                  • fwilleke80F
                    fwilleke80
                    last edited by fwilleke80

                    Then maybe it should be made an official guideline to insert shaders into materials with InsertShader(), and into a hierarchy of shaders with InsertUnder() 🙂

                    You're right, I think we did talk about this before. But I totally forgot, since it's not in the docs.

                    www.frankwilleke.de
                    Only asking personal code questions here.

                    1 Reply Last reply Reply Quote 0
                    • fwilleke80F
                      fwilleke80
                      last edited by

                      And, as a tip for other developers, I want to add that the "Active Object Dialog" example plugin from the C++ SDK does a fabulous job exposing things like this, and visualizing the document's node hierarchy.

                      Whoever wrote that back in the days still deserves a medal 🙂

                      cinema4dsdk_activeobjectdialog.jpg

                      www.frankwilleke.de
                      Only asking personal code questions here.

                      1 Reply Last reply Reply Quote 1
                      • indexofrefractionI
                        indexofrefraction
                        last edited by indexofrefraction

                        this "Active Object Dialog" plugin looks very interesting
                        if it would be understandably described how to compile it / the c++ sdk, we could check it out
                        but sadly this got so complicated that you need a degree in IT to do it. .-)

                        1 Reply Last reply Reply Quote 0
                        • kbarK
                          kbar
                          last edited by kbar

                          @indexofrefraction said in Insert a shader into a shader hierarchy:

                          this "Active Object Dialog" plugin looks very interesting
                          if it would be understandably described how to compile it / the c++ sdk, we could check it out
                          but sadly this got so complicated that you need a degree in IT to do it. .-)

                          The first video in my tutorial series shows you how to compile the SDK example plugins.

                          https://plugins4d.com/Dev/Tutorials

                          https://www.gamelogicdesign.com
                          https://www.plugins4d.com

                          1 Reply Last reply Reply Quote 1
                          • indexofrefractionI
                            indexofrefraction
                            last edited by indexofrefraction

                            Thanks a lot kbar.. i'll watch and learn!
                            still... the hurdles to compile a c++ plugin are extremely high nowadays. 😕
                            it would be great if the sdk plugins would be downloadable ready compiled as well

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post