Creating shaders from PSD files



  • 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.



  • 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.



  • 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()
    
    


  • 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.



  • 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.


Log in to reply