Copy the texture in the Reflection channel to the Color channel
-
As the title suggests, I'm trying to bulk copy the layer texture in the Reflection channel to the Color channel in all the selected materials, then enabling the Color channel and disabling the Reflection channel. Here's my script:
import c4d from c4d import gui def main(): mat = doc.GetActiveMaterials() if len(mat) == 0: return for i, m in enumerate(mat): try: layerIndex = m.GetReflectionLayerIndex(0).GetDataID() reftex = m[layerIndex + c4d.REFLECTION_LAYER_COLOR_TEXTURE] m[c4d.MATERIAL_USE_COLOR] = True colt = c4d.BaseList2D(c4d.Xbitmap) colt[c4d.BITMAPSHADER_FILENAME] = reftex m.InsertShader(colt) m[c4d.MATERIAL_COLOR_SHADER] = colt m[c4d.MATERIAL_USE_REFLECTION] = False m.Message(c4d.MSG_UPDATE) except: pass c4d.EventAdd() if __name__=='__main__': main()
The layer can be the first one so that's not a problem, the script doesn't need to parse all the reflection layers, but somehow this doesn't work. I have no issues copying the texture shader from different channels but not from the Reflection channel. It's probably because Reflection channel can have many layers. But it seems I'm making a simple mistake somewhere.
Thanks in advance.
-
Hello @tankun,
Welcome to the Plugin Café forum and the Cinema 4D development community, it is great to have you with us!
Getting Started
Before creating your next postings, we would recommend making yourself accustomed with our Forum and Support Guidelines, as they line out details about the Maxon SDK Group support procedures. Of special importance are:
- Support Procedures: Scope of Support: Lines out the things we will do and what we will not do.
- Support Procedures: Confidential Data: Most questions should be accompanied by code but code cannot always be shared publicly. This section explains how to share code confidentially with Maxon.
- Forum Structure and Features: Lines out how the forum works.
- Structure of a Question: Lines out how to ask a good technical question. It is not mandatory to follow this exactly, but you should follow the idea of keeping things short and mentioning your primary question in a clear manner.
About your First Question
You got it almost right, good job for your first question on the tricky subject of reflection layers! Your main fault was that you treated your variable
reftex
as if it were astr
ormaxon.Url
, although it is in reality aBaseShader
orNone
. There were also some minor bits and bobs, but they are not so important. Find an example for how I would write such thing below.Cheers,
FerdinandResult:
Before:
After:
Code:
"""Demonstrates how to move the color shader of the first reflection layer which has such shader to the color channel of the material. """ import c4d doc: c4d.documents.BaseDocument def main(): """Runs the example. """ # For every material in the document, ... for material in doc.GetMaterials(): # but skip over everything that does not have reflectance channels, ... if not material.CheckType(c4d.Mmaterial): continue # iterate over all reflection layers to find the first layer that has a color shader. i: int = 0 layer: c4d.ReflectionLayer | None = material.GetReflectionLayerIndex(i) while(layer): # Get the ID of the reflection layer color shader and retrieve the shader. pid: int = layer.GetDataID() + c4d.REFLECTION_LAYER_COLOR_TEXTURE colorShader: c4d.BaseShader | None = material[pid] # Increment our counter and get the next layer. i += 1 layer = material.GetReflectionLayerIndex(i) # When the last layer did not have color shader, continue the inner iteration. if not colorShader: continue # One of the flaws of your code was that you were reallocating a shader and also # were trying to treat your #reftex like a str/Url, although it was of type # c4d.BaseShader or None. But we can also just reuse the existing shader, no reallocation # required. When you want to explicitly reallocate the shader, you should also remove # the old shader, i.e., call #colorShader.Remove() in this case. # Toggle the channels and move the shader reference. Also wrap the whole operation into # an undo step. If you want the whole material conversion to be one undo, you would # have to move the #StartUndo and #EndUndo outside of the outmost loop. doc.StartUndo() doc.AddUndo(c4d.UNDO_CHANGE, material) material[c4d.MATERIAL_USE_COLOR] = True material[c4d.MATERIAL_USE_REFLECTION] = False material[pid] = None # This is important, a shader can only be refed once. material[c4d.MATERIAL_COLOR_SHADER] = colorShader doc.EndUndo() # Break the inner iteration since we have set/found a color shader. break # Push an update event to Cinema 4D so that our changes are reflected in the UI. c4d.EventAdd() if __name__=='__main__': main()
-
Yes, thank you so much. This works perfectly. And thanks a million for the in depth explanation.
-