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?
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.
-
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)
-
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 -
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.
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:
-
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.
-
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
-
This post is deleted!