Hello @pchg,
Thank you for reaching out to us. Please note that we normally expect question to be accompanied by code. It is also still unanswered in which context you want to do this: As an effector, as a Script Manager script, etc.
Cheers,
Ferdinand
Result
347fc2f0-a0cd-4583-816b-b3e38fda2280-image.png
Code
"""Reads out the particle data of a MoGraph Cloner object.
Must be run as a Script Manager script in Cinema 4D with a MoGraph Cloner object selected.
"""
import c4d
doc: c4d.documents.BaseDocument # The currently active document.
op: c4d.BaseObject | None # The primary selected object in `doc`. Can be `None`.
def main() -> None:
"""Called by Cinema 4D when the script is being executed.
"""
if not op or not op.CheckType(c4d.Omgcloner):
raise ValueError("Please select a MoGraph Cloner object.")
# Get the particle data from the cloner object.
data: c4d.modules.mograph.MoData = c4d.modules.mograph.GeGetMoData(op)
if data is None:
return
# Get the transform and color data for the particles.
matrices: list[c4d.Matrix] = data.GetArray(c4d.MODATA_MATRIX)
colors: list[c4d.Vector] = data.GetArray(c4d.MODATA_COLOR)
# Iterate over all particle data and do something with it. If we were in an effector, we could
# also write back data. Technically, we could also write back data here, but it would be volatile.
for i in range(data.GetCount()):
matrix: c4d.Matrix = matrices[i]
color: c4d.Vector = colors[i]
print(f"Particle {i} at {matrix.off} with color {color}")
if __name__ == '__main__':
main()
And here is the 2024.0.0 effector full control mode default code which more or less is very similar but also writes data.
"""Realizes an effector that attracts MoGraph particles spherically around its origin.
Add the example to a Matrix object to understand its effect. In Full Control mode we can realize
a true attraction force as we have full control over the particle values. Compare this example to
Parameter Control mode to understand the difference.
"""
import c4d
op: c4d.BaseObject # The Python Effector object containing this code.
gen: c4d.BaseObject # The MoGraph Generator executing `op`.
doc: c4d.documents.BaseDocument # The document `op` and `gen`are contained in.
def main() -> bool:
"""Called by Cinema 4D to evaluate the effector.
"""
# Get the particle data for the effector #op. Get out when either the data cannot be retrieved.
data: c4d.modules.mograph.MoData = c4d.modules.mograph.GeGetMoData(op)
if data is None:
return 1.0
# The transform of both the generator and the effector, the transforms of all particles, and
# finally the position of the effector as if it would live in the coordinate system of the
# generator.
mgGen: c4d.Matrix = gen.GetMg()
mgEff: c4d.Matrix = op.GetMg()
matrices: list[c4d.Matrix] = data.GetArray(c4d.MODATA_MATRIX)
q: c4d.Vector = ~mgGen * mgEff.off
# For each particle compute a weight `w` for how much the particle should be attracted to the
# attraction point `q`, and then blend the particle position between the attraction point and
# its own position `p`.
for i in range(data.GetCount()) :
p: c4d.Vector = matrices[i].off
w: float = c4d.utils.RangeMap((mgGen * ~mgEff * p).GetLength(), 0., 100., 0., 1., True) ** 3.
matrices[i].off = c4d.utils.MixVec(q, p, w)
# Write the new data back.
data.SetArray(c4d.MODATA_MATRIX, matrices, op[c4d.FIELDS].HasContent())
return True