Hi @neon sorry for the delay, unfortunately, Cinema 4D is not designed this way.
If you think about it, there is no tag that works by hierarchy inheritance except the selection tag. Which work by naming a selection. So it's a very special case.
The main issue is Cinema 4D will, in any case, reset the data you define in the vertex map to the number of polygons. (and in this case, 0 since it's a generator).
So here a workaround, but it's very experimental and can be buggy. So please don't use it in production as he does some really cross-thread things that are not allowed and that could crash Cinema 4D. But at least it can give you some ideas.
pc_11963.c4d
And the python code of the python generator.
import c4d
def Bl2DIterator(obj):
"""
Iterates over any BaseList2D list
"""
while obj:
yield obj
for opChild in Bl2DIterator(obj.GetDown()):
yield opChild
obj = obj.GetNext()
def FindAllVetexShaderFromObj(obj, targetVertexMap):
"""
Retrieve from each material assigned to `obj` all vertexMap shader
where `targetVertexMap` is used.
"""
allVertexShader = []
for tag in obj.GetTags():
if not tag.IsInstanceOf(c4d.Ttexture):
continue
mat = tag[c4d.TEXTURETAG_MATERIAL]
if mat is None:
continue
for shader in Bl2DIterator(mat.GetFirstShader()):
if shader.IsInstanceOf(c4d.Xvertexmap):
vMap = shader[c4d.SLA_DIRTY_VMAP_OBJECT]
if vMap is not None and vMap == targetVertexMap:
allVertexShader.append(shader)
return allVertexShader
def main():
# Retrieve a copy of linked obj
polygonObj = op[c4d.ID_USERDATA,1]
if not isinstance(polygonObj, c4d.PolygonObject):
return
polygonObj = polygonObj.GetClone()
polygonObj.SetMl(op.GetMg())
# Retrieve vertex map from the copied object
vMap = polygonObj.GetTag(c4d.Tvertexmap)
if vMap is None:
return
# Subdivide the opbject
bc = c4d.BaseContainer()
bc[c4d.MDATA_SUBDIVIDE_SUB] = 1
res = c4d.utils.SendModelingCommand(
command=c4d.MCOMMAND_SUBDIVIDE,
list=[polygonObj],
mode=c4d.MODELINGCOMMANDMODE_POLYGONSELECTION,
bc=bc,
doc=polygonObj.GetDocument())
# Assign random values
weights = [float(n % 4 == 0) for n in range(vMap.GetDataCount())]
vMap.SetAllHighlevelData(weights)
# Retrieve existing vertexMap and shader from the applied material that use this vertex map
shaderUsingOldVertexMap = []
tMapOld = op.GetTag(c4d.Tvertexmap)
if tMapOld is not None:
shaderUsingOldVertexMap += FindAllVetexShaderFromObj(op, tMapOld)
tMapOld.Remove()
# Creates a new tag with the correct number of data and disable it so C4D don't overwrite it
# Cross-thread Operation, that could crash Cinema 4D
vMapGenerator = op.MakeVariableTag(c4d.Tvertexmap, polygonObj.GetPointCount())
vMapGenerator[c4d.EXPRESSION_ENABLE] = False
# Copy the data from the vertex map within the generator to the one exposed to the user
vMapGenerator.SetAllHighlevelData(vMap.GetAllHighlevelData())
# Remap all the vertex shader to use the new vertex map.
for shader in shaderUsingOldVertexMap:
shader[c4d.SLA_DIRTY_VMAP_OBJECT] = vMapGenerator
return polygonObj
Cheers,
Maxime.