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
    • Register
    • Register
    • Login

    Creating shaders from PSD files

    Cinema 4D SDK
    python
    6
    11
    2.0k
    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.
    • M
      m_adam
      last edited by

      First of all welcome in the plugincafe community 😉

      May I ask you for a psd file because here I don't have any issue with a file I made so maybe there is something wrong.
      Does the issue also appear if you setup manually the file? If it's the case it's most likely a limitation of Cinema 4D viewport.

      And if it's not the case please share your code.
      Cheers,
      Maxime.

      MAXON SDK Specialist

      Development Blog, MAXON Registered Developer

      1 Reply Last reply Reply Quote 0
      • Y
        yanmasterson
        last edited by

        Hi Maxime,

        The PSD file is just a test file, so at the moment it's a very simple layered file. Four layers, everything completely rasterised, no text or effects or anything special. Here's the code I'm using - you'll need to replace "/MyPath/test.psd" with a path to your PSD image.

        Than you so much for helping!

        import c4d
        from c4d import bitmaps
        
        def CreateMaterial(matName, fileName, layerName, i):
            # Create a new material from scratch
            mat = c4d.Material()
            mat.SetName(matName)
            doc = c4d.documents.GetActiveDocument()
            doc.InsertMaterial(mat)
        
            # create a texture shader and assign it to the color channel
            
            # enable the color channel
            mat[c4d.MATERIAL_USE_COLOR] = True
            # create a bitmap shader
            texshader = c4d.BaseShader(c4d.Xbitmap)
            texshader[c4d.BITMAPSHADER_FILENAME] = fileName
            # provide the layer set information
            layerSet = c4d.LayerSet()
            layerSet.SetMode(c4d.LAYERSETMODE_LAYERS)
            layerSet.AddLayer(layerName)
            texshader[c4d.BITMAPSHADER_LAYERSET] = layerSet
            # insert the bitmap shader into the material
            mat.InsertShader(texshader)
            # assign the bitmap shader to the color channel
            mat[c4d.MATERIAL_COLOR_SHADER] = texshader
            
            # enable the alpha channel
            mat[c4d.MATERIAL_USE_ALPHA] = True
            # create a bitmap shader
            texshader = c4d.BaseShader(c4d.Xbitmap)
            texshader[c4d.BITMAPSHADER_FILENAME] = fileName
            # provide the layer set information
            layerSet = c4d.LayerSet()
            layerSet.SetMode(c4d.LAYERSETMODE_LAYERALPHA)
            layerSet.AddLayer(layerName)
            texshader[c4d.BITMAPSHADER_LAYERSET] = layerSet
            layerSet.SetPreviewMode(0)
            # insert the bitmap shader into the material
            mat.InsertShader(texshader)
            # assign the bitmap shader to the color channel
            mat[c4d.MATERIAL_ALPHA_SHADER] = texshader
            
            # by default the reflectance channel is enabled,
            # let's disable it
            mat[c4d.MATERIAL_USE_REFLECTION] = False
           
           
            # Create a new null and plane from scratch
            nl = c4d.BaseObject(c4d.Onull)
            nl.SetName(matName)
            nl.SetRelScale(c4d.Vector(i,i,i))
            doc.InsertObject(nl)
            pl = c4d.BaseObject(c4d.Oplane)
            pl.SetName(matName)
            pl[c4d.PRIM_PLANE_WIDTH] = 192
            pl[c4d.PRIM_PLANE_HEIGHT] = 108
            pl[c4d.PRIM_PLANE_SUBW] = 1
            pl[c4d.PRIM_PLANE_SUBH] = 1
            pl[c4d.PRIM_AXIS] = 5
            pl.SetRelPos(c4d.Vector(0,0, 200))
            doc.InsertObject(pl,nl)
            
            
            # Add a texture tag to the plane
            tt = c4d.TextureTag()
            tt.SetName(matName)
            tt.SetMaterial(mat)
            
            pl.InsertTag(tt)
             
            return
        
        
        
        
        def main():
        
            # load a multi layer psd file
            path = "/MyPath/test2.psd"
        
            bc = c4d.BaseContainer()
            bc.SetFilename(c4d.LOADTEXTURE_FILENAME, path.encode('utf-8'))
            tex = c4d.modules.bodypaint.SendPainterCommand(c4d.PAINTER_LOADTEXTURE, doc=doc, tex=None, bc=bc)
            if tex is None:
                print "Failed loading file"
                return
            
            # iterate over the layers and create the materials
            layer = tex.GetFirstLayer()
            i = 0
            while layer:
                i += 1
                layerName = layer.GetName()
                materialName = layerName
                CreateMaterial(materialName, path, layerName, i)
                
                # up to the next layer in the PSD
                layer = layer.GetNext()
            
                c4d.EventAdd()
              
            
        
        if __name__=='__main__':
            main()
        
        
        1 Reply Last reply Reply Quote 0
        • M
          m_adam
          last edited by m_adam

          Hi, @yanmasterson I'm afraid there is currently a bug in PAINTER_LOADTEXTURE, which change the OpenGL cache of the picture, and there is actually no way to properly set it back once PAINTER_LOADTEXTURE have screwed it for a given Bitmap, you can't restore it and you have to close Cinema 4D.

          So as a workaround you can use external libraries to read layer name of your psd file
          And then use the next stuff.

              # load a multi layer psd file
              path = r"C:\Users\graphos\Desktop\test.psd"
          
              # Data retrieved from the psd file.
              layerData = {"Layer2":1, "Layer4":2, "Layer3":3, "Layer1":4}
          
              for layerName, i in layerData.iteritems():
                  materialName = layerName
                  CreateMaterial(materialName, path, layerName, i)
          
              c4d.EventAdd()
          

          While I know this workaround is not perfect I still investigate the bug.
          Cheers,
          Maxime.

          MAXON SDK Specialist

          Development Blog, MAXON Registered Developer

          1 Reply Last reply Reply Quote 0
          • Y
            yanmasterson
            last edited by

            Thanks Maxime! I'm relieved it's a bug, I was looking everywhere for functions to manually fix the OpenGL preview. I will try with this approach.

            Y.

            1 Reply Last reply Reply Quote 0
            • G
              glasses
              last edited by glasses

              Gah, this bug has me hung up too. I'll attempt to implement the external library approach. @yanmasterson @m_adam did you find a workaround that doesn't use an external library?

              Also, is there any other way to get the layers from a photoshop file other than using:

              c4d.modules.bodypaint.SendPainterCommand(c4d.PAINTER_LOADTEXTURE, doc=doc, tex=None, bc=bc)
              
              1 Reply Last reply Reply Quote 0
              • S
                s_bach
                last edited by

                Hello,

                the C++ API includes the MultipassBitmap class, that allows to handle multi-layer images. While this class is also available in Python, the Python version is somewhat limited. So might have to switch to C++.

                best wishes,
                Sebastian

                MAXON SDK Specialist

                Development Blog, MAXON Registered Developer

                1 Reply Last reply Reply Quote 0
                • G
                  glasses
                  last edited by glasses

                  Here is a thread having similar issues. https://developers.maxon.net/forum/topic/3209/2592_parsing-psd-layers-in-multipassbitmap/11

                  Looks like Pythons MultiPassBitmap class is not working at all for loading bitmaps from layered PSD files. I get a layer count of 0 and no other data from the PSD file. I can't write C++ so I think I'll have to live with the openGL bug.

                  Screen Shot 2019-11-20 at 2.45.24 PM.png
                  image above is editor view vs standard renderer picture view.

                  I want to be able to just select these layers here somehow without using SendPainterCommand:
                  Screen Shot 2019-11-20 at 8.15.30 PM.png

                  1 Reply Last reply Reply Quote 0
                  • G
                    glasses
                    last edited by glasses

                    You can use LayerSet.AddLayer('myPSD_LayerName') which will select the layer of the layerSet. It works, However, you can't retrieve the name of the PSD layers using LayerSet so I'm still stuck with the SendPainterCommand openGL bug and MultiPassBitmap not functioning with Python. 😕

                    1 Reply Last reply Reply Quote 0
                    • M
                      masterofthejack
                      last edited by

                      Hi Been a few years now, any changes on this, I would love a script that iterated through a PSD file, create a material for each layer and set the Alphas for each layer

                      1 Reply Last reply Reply Quote 0
                      • N
                        Nilupul Perera
                        last edited by

                        This post is deleted!
                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post