Unsolved instance objects onto points with arbitrary attributes (python)

I have a list of thousands of points where I'd like to add a brightness value to each of them to drive material emission and instance spheres onto the points. I've been reading posts like this and this--how would you approach this type of task in python?

I can setup a cloner object in multi instance mode but I'm not clear if it's possible to pass the brightness values to the (invisible) motagdata tag... Would a python generator be a better way to go?

Hello @tom_01,

Thank you for reaching out to us.

Would a python generator be a better way to go?

It depends a bit on how this question is meant. In general, it is not advisable to try to recreate a MoGraph cloner implementation from scratch in Python, as the result would likely not be very fast. But if you want to just write a thin wrapper, i.e., a generator which uses a MoGraph cloner in its output to simplify a specific setup, there is nothing which prevents you from doing this.

The rest of your question is unfortunately a bit ambiguous. It is unclear to me:

  1. If the 'add a brightness value to each [vertex]' part is already done. You should store that data in a vertex map and I will not consider the generation of that data of the problem.
  2. If 'to drive material emission' means driving the emission of a material assigned to the polygon object (you could just use the vertex map here).
  3. Or if 'to drive material emission' means the spheres you want to clone. I.e., that you want to assign a material with an emission equal to the brightness data attached to the vertex the sphere is being cloned onto.

If you want to go route 2, I do not really understand what the question is. If you want to go route 3, this can be almost entirely done with out of the box MoGraph.

  1. Create a MoGraph cloner called Cloner.
  2. Create a clone called Sphere and clone target called Target.
  3. Parent Sphere to Cloner
  4. In Cloner:
    a. Set Mode to Object.
    b. Set Object to Target.
    c. Set Distribution to Vertex.
  5. Create a material called Material.
  6. In Material:
    a. Disable all channels except Luminance.
    b. Add a MoGraph Color Shader to the Luminance texture channel.
    c. Set the the Color Shader to Channel: Color.

  1. Add a random effector called Random to the setup.
  2. In Random in the tab Parameter:
    a. Set Color Mode to Custom Color
    b. Enable Use Alpha/Strength.

Which will give you a set of Sphere clones cloned onto Target where the luminance of each clone is driven by the effector Random. You now just have to replace steps 7 and 8, the random effector, with a custom Python effector setup which sets the color of a clone depending on your data. Find an example which does that at the end of this posting.


The result:

The file: vertexmap_clones.c4d
The code:

"""Example for driving the color of clones with a vertex map.

import c4d

op: c4d.BaseObject # The python effector

def main() -> bool:
    """Executed by Cinema 4D to evaluate the clones of the cloner.

    This code assumes the Python effector to be in "Full Control" mode.
    # Get the MoData from the cloner and and the vertex map which has been linked in the user data
    # of the Python effector.
    moData: c4d.modules.mograph.MoData = c4d.modules.mograph.GeGetMoData(op)
    if moData is None:
        return False

    vertexMap: c4d.VariableTag = op[c4d.ID_USERDATA, 1]
    if not isinstance(vertexMap, c4d.VariableTag):
        return False

    # Get the data, the weights, from the vertex map and bail if they do not match the number of
    # clones.
    weights: list[float] = vertexMap.GetAllHighlevelData()
    if len(weights) != moData.GetCount():
        return False

    # We now simply write the weights as an array of vectors. This works because in this setup the
    # clones are cloned onto the same mesh for which the vertex map has been generated for. The
    # vertex map and clones therefore share an index order, i.e., both the n-th weight and clone
    # will have been constructed for the same vertex.
    # If necessary, this relation could also be given up (to for example use vertex maps/input data
    # which has not been generated for the same mesh), but then one would have to perform closest
    # element lookups which are quite expensive to do.
    colors: list[c4d.Vector] = [c4d.Vector(w, w, w) for w in weights]

    # Write the data as the color array into the clone data.
    moData.SetArray(c4d.MODATA_COLOR, colors, False)

    return True

MAXON SDK Specialist

Hi Ferdinand. Thank you for the thorough response. Apologies for the ambiguity on my part.

For a test project I wanted to fetch star coordinates (for ~100K–1M+ stars) and their brightness values. Then instance Redshift spheres onto them with a material where the brightness of each point is piped into the material's emission.

This was a test project to get started with python. I also wanted to see if c4d has a way of working with points and attributes. I don't think the real-world (galaxy?) data is available, but ideally each star would also have a radius, which would drive the sphere scales/sizes.

I'm familiar with cloner/effector/field setups, but I was looking for a programatic approach. I don't know how to pass specific values to each point (brightness in this case) and then to clones with effectors/fields.