access the layers in the shader layer
-
Hi,
Today I was trying to link or access the color within a sahder layer only with python, I know I can get it and change its parameter in the same sahder layer, but my question is more about how I can enter one of these and change its data , as in this case the color, or also the direction of a bitmap. -
Hi @JH23,
Thanks for reaching out to us. Please consider checking our Forum Guidelines about the question structure. I'm struggling from understanding your problem and would kindly ask you to elaborate on it.
In addition, Ferdinand shared an awesome example on the topic of shader layers earlier this week: Traversing a layer shader with python. You might be also interested in the How to change bitmap in layered shader? thread as it seems to directly answer your question.
Cheers,
Ilia -
Hi @i_mazlov ,
Excuse me for the lack of research, if I usually check if there were similar cases but I don't think I was able to understand it well, thank you very much for showing me these examples, they were really helpful.
the code you wanted:import c4d def ChangeTexturePathOfLayer(layer = c4d.LayerShaderLayer, Vector = c4d.Vector()): bmpShader = layer.GetParameter(c4d.LAYER_S_PARAM_SHADER_LINK) bmpShader[c4d.COLORSHADER_COLOR] = Vector def main(): mat = doc.GetFirstMaterial() if not mat: return shd = mat.GetFirstShader() if shd.CheckType(c4d.Xlayer): ChangeTexturePathOfLayer(shd.GetFirstLayer(), c4d.Vector(0.458823, 0.278431, 0.164705)) c4d.EventAdd() if __name__ == '__main__': main()
I still don't know what c4d.LAYER_S_PARAM_SHADER_LINK does specifically
Well, within the documentation it is only mentioned that int is allowed as a parameter.
Cheers,
James H. -
Hi James,
Thank you for your follow up message. The information about what you're trying to achieve is still missing or highly implicit in your reply (there is no question).
Assuming your goal is to adjust shader attributes (color value for color shader and bitmap path for the bitmap shader), the snippet on the thread that I pointed you out to shows up exactly this case (for the bitmap path): How to change bitmap in layered shader?. I've sketched up the corresponding part for the color shader for you (please find below).
The c4d.LAYER_S_PARAM_SHADER_LINK parameter basically points to the object that contains the shader. Please, refer to the C++ documentation in this regard: LAYER_S_PARAM_SHADER. Some parts of our API are better documented on the C++ side, so it is worth double checking the missing parts there.
Cheers,
IliaThe code snippet:
import c4d doc: c4d.documents.BaseDocument # The active document def RetrieveShader(layer: c4d.LayerShaderLayer): # Check if the layer is really a shader if not layer or layer.GetType() != c4d.TypeShader: raise ValueError("Layer is not a shader") # Retrieve the linked shader of this layer return layer.GetParameter(c4d.LAYER_S_PARAM_SHADER_LINK) def ChangeTexturePathOfLayer(layer: c4d.LayerShaderLayer, texturePath: str) -> None: """Change the texture path of an existing Bitmap Layer """ shader: c4d.C4DAtom = RetrieveShader(layer) # check if this is really a bitmap shader if not shader.CheckType(c4d.Xbitmap): raise ValueError("First layer is not a bitmap shader") # Update the texture path of the shader linked to this layer shader[c4d.BITMAPSHADER_FILENAME] = texturePath def ChangeColorShader(layer: c4d.LayerShaderLayer, color: c4d.Vector) -> None: """Change the color of and existing Color Shader """ shader: c4d.C4DAtom = RetrieveShader(layer) if not shader.CheckType(c4d.Xcolor): raise ValueError("First layer is not a color shader") shader[c4d.COLORSHADER_COLOR] = color def main() -> None: # Get the color channel shader for the first material in the scene. material: c4d.BaseMaterial | None = doc.GetFirstMaterial() if not material: raise RuntimeError("Please add at least one material to the document.") shader: c4d.BaseList2D | None = material.GetFirstShader() if not shader or not shader.CheckType(c4d.Xlayer): raise RuntimeError("First shader is not a layer shader") # Update an existing Bimtap Layer ChangeTexturePathOfLayer(shader.GetFirstLayer(), r"D:\temp\tex2.jpg") # Update an existing Color Layer ChangeColorShader(shader.GetFirstLayer().GetNext(), c4d.Vector(0., 1., 0.)) c4d.EventAdd() if __name__ == '__main__': main()
-
Hi @i_mazlov ,
I have another question and I want to take advantage of this situation to consult, I really also want to be able to change the float that measures the mixing force, (I also wanted to know how to access the rounding) and I could, but now my problem is that it really takes too long, because not to say that it does not react until I manually move this float.
Here is an example:
-
Currently my problem would only be the issue of the lack of updating, because now I know that I can change the boolean of the layer with LAYER_S_PARAM_ALL_ACTIVE , but the lack of updating persists, I really don't know what could be causing it is causing.
code example, using the booleans of the layer:import c4d def main(): doc = c4d.documents.GetActiveDocument() obj = op.GetObject() F = obj[c4d.ID_USERDATA,1] FM = doc.GetFirstMaterial() shd = FM.GetFirstShader() layer = shd.GetFirstLayer() i = 0 while True: if layer: if i == F: #layer.SetParameter(c4d.LAYER_S_PARAM_SHADER_BLEND,True) layer.SetParameter(c4d.LAYER_S_PARAM_ALL_ACTIVE,True) else: #layer.SetParameter(c4d.LAYER_S_PARAM_SHADER_BLEND,False) layer.SetParameter(c4d.LAYER_S_PARAM_ALL_ACTIVE,False) layer = layer.GetNext() elif layer == None: break i = i+1 c4d.EventAdd()
-
Hi @JH23,
Sorry for the delayed reply.
The issue you're struggling with is more the UI not being updated with the changed data. Normally, the SetParameter function also takes flags argument as a 3rd parameter, i.e. using
DESCFLAGS_SET_USERINTERACTION would do the trick. However, the LayerShader object is special in a way that it doesn't accept any flags argument. I'm not aware of a possible workaround for it.Let me know if you have any further questions.
Cheers,
Ilia -
Hola @i_mazlov ,
Yes, it is true, DESCFLAGS_SET_USERINTERACTION does not work with layers, any other contribution to the problem is appreciated, from this I have no other doubt related to this topic, I leave the file here as an example.
example.c4d
cheers,
James H. -
Hi @JH23,
We had an internal discussion about this issue. Sending the c4d.MSG_UPDATE message does trigger the necessary update. Please find the code snippet below.
Let me know if you have any further questions.
Cheers,
Iliaimport c4d doc: c4d.documents.BaseDocument # The active document def main(): material: c4d.BaseMaterial = doc.GetFirstMaterial() if not material: return shader: c4d.BaseShader = material[c4d.MATERIAL_COLOR_SHADER] if not shader or not shader.CheckType(c4d.Xlayer): print ("Color channel does not contain layer shader.") return layer: c4d.LayerShaderLayer = shader.GetFirstLayer() if not layer: return layer.SetParameter(c4d.LAYER_S_PARAM_SHADER_BLEND, 0.5) shader.Message(c4d.MSG_UPDATE) c4d.EventAdd() if __name__ == "__main__": main()
-
Hi @i_mazlov ,
This solves my problem, for now I don't think I have another question, and I could consider my problem solved, thanks.
cheers,
James H.