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

    Copy the texture in the Reflection channel to the Color channel

    Bugs
    python 2023
    2
    3
    886
    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.
    • T
      tankun
      last edited by

      As the title suggests, I'm trying to bulk copy the layer texture in the Reflection channel to the Color channel in all the selected materials, then enabling the Color channel and disabling the Reflection channel. Here's my script:

      import c4d
      from c4d import gui
      
      
      def main():
          mat = doc.GetActiveMaterials()
          if len(mat) == 0: return
      
          for i, m in enumerate(mat):
              try:
                  layerIndex = m.GetReflectionLayerIndex(0).GetDataID()
      
                  reftex = m[layerIndex + c4d.REFLECTION_LAYER_COLOR_TEXTURE]
                  m[c4d.MATERIAL_USE_COLOR] = True
      
                  colt = c4d.BaseList2D(c4d.Xbitmap)
                  colt[c4d.BITMAPSHADER_FILENAME] = reftex
                  m.InsertShader(colt)
                  m[c4d.MATERIAL_COLOR_SHADER]  = colt
      
                  m[c4d.MATERIAL_USE_REFLECTION] = False
      
                  m.Message(c4d.MSG_UPDATE)
      
              except:
                  pass
      
      
          c4d.EventAdd()
      
      if __name__=='__main__':
          main()
      

      The layer can be the first one so that's not a problem, the script doesn't need to parse all the reflection layers, but somehow this doesn't work. I have no issues copying the texture shader from different channels but not from the Reflection channel. It's probably because Reflection channel can have many layers. But it seems I'm making a simple mistake somewhere.

      Thanks in advance.

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

        Hello @tankun,

        Welcome to the Plugin Café forum and the Cinema 4D development 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 Guidelines, as they line out details about the Maxon SDK Group support procedures. Of special importance are:

        • Support Procedures: Scope of Support: Lines out the things we will do and what we will not do.
        • Support Procedures: Confidential Data: Most questions should be accompanied by code but code cannot always be shared publicly. This section explains how to share code confidentially with Maxon.
        • Forum Structure and Features: Lines out how the forum works.
        • Structure of a Question: Lines out how to ask a good technical question. It is not mandatory to follow this exactly, but you should follow the idea of keeping things short and mentioning your primary question in a clear manner.

        About your First Question

        You got it almost right, good job for your first question on the tricky subject of reflection layers! Your main fault was that you treated your variable reftex as if it were a str or maxon.Url, although it is in reality a BaseShader or None. There were also some minor bits and bobs, but they are not so important. Find an example for how I would write such thing below.

        Cheers,
        Ferdinand

        Result:
        Before:
        e6dc1bea-efd8-4450-8e52-8a870db3354c-image.png
        After:
        09984c18-40e9-43e4-a781-49875356bc01-image.png

        Code:

        """Demonstrates how to move the color shader of the first reflection layer 
        which has such shader to the color channel of the material. 
        """
        
        import c4d
        
        doc: c4d.documents.BaseDocument
        
        def main():
            """Runs the example.
            """
            # For every material in the document, ...
            for material in doc.GetMaterials():
                # but skip over everything that does not have reflectance channels, ...
                if not material.CheckType(c4d.Mmaterial):
                    continue
        
                # iterate over all reflection layers to find the first layer that has a color shader.
                i: int = 0
                layer: c4d.ReflectionLayer | None = material.GetReflectionLayerIndex(i)
                while(layer):
                    # Get the ID of the reflection layer color shader and retrieve the shader.
                    pid: int = layer.GetDataID() + c4d.REFLECTION_LAYER_COLOR_TEXTURE
                    colorShader: c4d.BaseShader | None = material[pid]
        
                    # Increment our counter and get the next layer.
                    i += 1
                    layer = material.GetReflectionLayerIndex(i)
        
                    # When the last layer did not have color shader, continue the inner iteration.
                    if not colorShader:
                        continue
                    
                    # One of the flaws of your code was that you were reallocating a shader and also
                    # were trying to treat your #reftex like a str/Url, although it was of type 
                    # c4d.BaseShader or None. But we can also just reuse the existing shader, no reallocation
                    # required. When you want to explicitly reallocate the shader, you should also remove
                    # the old shader, i.e., call #colorShader.Remove() in this case.
        
                    # Toggle the channels and move the shader reference. Also wrap the whole operation into
                    # an undo step. If you want the whole material conversion to be one undo, you would
                    # have to move the #StartUndo and #EndUndo outside of the outmost loop.
                    doc.StartUndo()
                    doc.AddUndo(c4d.UNDO_CHANGE, material)
        
                    material[c4d.MATERIAL_USE_COLOR] = True
                    material[c4d.MATERIAL_USE_REFLECTION] = False
                    material[pid] = None # This is important, a shader can only be refed once.
                    material[c4d.MATERIAL_COLOR_SHADER] = colorShader
        
                    doc.EndUndo()
        
                    # Break the inner iteration since we have set/found a color shader.
                    break
            
            # Push an update event to Cinema 4D so that our changes are reflected in the UI.
            c4d.EventAdd()
        
        if __name__=='__main__':
            main()
        

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • T
          tankun
          last edited by

          Yes, thank you so much. This works perfectly. And thanks a million for the in depth explanation.

          1 Reply Last reply Reply Quote 0
          • maxonM maxon moved this topic from Cinema 4D SDK on
          • First post
            Last post