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.
    • Y
      yanmasterson
      last edited by

      Hi,

      Newbie here so forgive any breach of protocol etc!

      I'm trying to use python to assign PSD layers to individual materials, then apply these materials to a texture tag on individual planes (this can be used to create a pop-up book effect for example). The material previews look fine in the material window, and perfect when rendered with the standard renderer, but in the C4d view panel they all appear as the PSD layers all merged together (see pic attached of viewport vs rendered, with the material previews below). I suspect I'm missing a command to create a specific viewport or OpenGL texture from the material, or from the shader... Does anyone have any obvious suggestions or pointers?

      opengl texture is merged layers.jpg

      Thanks, Yan.

      1 Reply Last reply Reply Quote 0
      • 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