Chaos Corona for Cinema 4D > [C4D] Corona Goodies - User Contributions
Material Switcher Python Tag, currently WIP
(1/1)
d4l1:
Hi!
I'm working on a Python Tag that I apply on a Null object in the scene, which then works as some kind of Material Switcher that stores multiple Materials that I can change through the selected Index. (instead of using Take Manager, or some other Layered Material stuff). I thought this could be helpful, because the Null object can be placed on top of the Outliner and it would be recognizable that there is something going on in that scene when it is reopened some months later. And because it is a nice thing to do these days, the code was 'mostly' written by ChatGPT - even though there were some inputs from my side. The script should replace materials in the applied Material Tags everywhere in the scene. It can't replace whole Material Tags, because there are some references from the top-most layer with Selection Tags. And these tags better stay where they are, which means I only want the linked Material to change. Now - this works fine and does its job, when the scene isn't rendering. If i keyframe the Index and let the frames render, the material won't change at all. It also doesnt work with Live Preview Rendering. And I believe it is because(!) I'm changing only the linked material and not the whole Material Tag. But it does work with the default C4D Render and RedShift. And that circumstances give me hope that I may be only missing some command that refreshes the Render Process - because it does change in Corona if I apply a Layered Material and change the Amount of Blending (even though I'm sure it isn't nearly the same process I was talking about before :) ).
Maybe someone else has some idea? Below is the script that sits in a Python Tag on a Null.
Edit: Forgot to add a scene with the existing Changer. There is some additional User Data stuff that needs to be recreated. And I called it Switcher instead of Changer. Both sound reasonable.
--- Code: ---import c4d
def get_all_objects_iterative(doc):
"""
Collects and returns a list of all objects in the document.
"""
result = []
op = doc.GetFirstObject()
while op:
result.append(op)
op = op.GetNext()
i = 0
while i < len(result):
current = result[i]
child = current.GetDown()
while child:
result.append(child)
child = child.GetNext()
i += 1
return result
# Global variable to store the last active index.
global g_lastActiveIndex
if 'g_lastActiveIndex' not in globals():
g_lastActiveIndex = None
def main():
# Get the active document.
doc = c4d.documents.GetActiveDocument()
if not doc:
print("No active document found.")
return
# New boolean user data to enable/disable the script (ID 12).
# When false, the script will exit immediately, allowing you to make changes without swapping.
enabled = op[c4d.ID_USERDATA, 12]
if not enabled:
print("Script disabled via user data parameter. No processing will be done.")
return
# Retrieve materials from custom user data.
# IDs: 1 = material0, 2 = material1, ..., 10 = material9.
mat0 = op[c4d.ID_USERDATA, 1]
mat1 = op[c4d.ID_USERDATA, 2]
mat2 = op[c4d.ID_USERDATA, 3]
mat3 = op[c4d.ID_USERDATA, 4]
mat4 = op[c4d.ID_USERDATA, 5]
mat5 = op[c4d.ID_USERDATA, 6]
mat6 = op[c4d.ID_USERDATA, 7]
mat7 = op[c4d.ID_USERDATA, 8]
mat8 = op[c4d.ID_USERDATA, 9]
mat9 = op[c4d.ID_USERDATA, 10]
# Active Index: keyframeable integer from 0 to 9 (ID 11).
activeIndex = op[c4d.ID_USERDATA, 11]
print("Current active index (new selection):", activeIndex)
# Build list of material options.
matOptions = [mat0, mat1, mat2, mat3, mat4, mat5, mat6, mat7, mat8, mat9]
# Validate activeIndex.
if activeIndex < 0 or activeIndex >= len(matOptions):
activeIndex = 0
# Get the new material from the active index.
newMat = matOptions[activeIndex]
if newMat and newMat.CheckType(c4d.Ttexture):
new_material_ref = newMat.GetMaterial()
else:
new_material_ref = newMat
print("New material reference (active):", new_material_ref)
# Use a global variable to know the previous selection.
global g_lastActiveIndex
if g_lastActiveIndex is None:
g_lastActiveIndex = activeIndex
print("Initializing g_lastActiveIndex to", activeIndex)
return # Nothing to swap on first run.
print("Previous active index (g_lastActiveIndex):", g_lastActiveIndex)
if activeIndex == g_lastActiveIndex:
print("Active index has not changed. Nothing to swap.")
return
# Get the previous material reference based on the previous active index.
oldMat = matOptions[g_lastActiveIndex]
if oldMat and oldMat.CheckType(c4d.Ttexture):
old_material_ref = oldMat.GetMaterial()
else:
old_material_ref = oldMat
print("Old material reference (previous active):", old_material_ref)
if new_material_ref is None:
print("New material reference is None. Aborting swap.")
return
# Get all objects from the scene.
objects = get_all_objects_iterative(doc)
objectCount = len(objects)
print("Total objects scanned:", objectCount)
swapCount = 0
# Iterate over the list of objects.
for obj in objects:
for tag in obj.GetTags():
if tag.CheckType(c4d.Ttexture):
currentMat = tag.GetMaterial()
# Compare by pointer equality OR by comparing material names.
if (currentMat == old_material_ref) or \
(currentMat and old_material_ref and currentMat.GetName() == old_material_ref.GetName()):
print("Swapping on object:", obj.GetName(),
"Tag:", tag.GetName(),
"\n from:", old_material_ref,
"\n to:", new_material_ref)
tag.SetMaterial(new_material_ref)
swapCount += 1
print("Finished swapping. Total tags swapped:", swapCount)
# Update the global variable with the new active index.
g_lastActiveIndex = activeIndex
c4d.EventAdd()
--- End code ---
Navigation
[0] Message Index
Go to full version