The code entered in the Python emitter has no effect.
-
Hello, in theory, the Python code linked to the Python effector should randomly move the object in the cloner by 100 cm along the Y axis — why isn't it working
import c4d import random def main() -> bool: md = c4d.modules.mograph.GeGetMoData(op) if md is None: return True count = md.GetCount() matrices = md.GetArray(c4d.MODATA_MATRIX) # Inizializza la lista dei frame solo una volta if not hasattr(op, "frames"): random.seed(42) op.frames = [random.randint(0, 75) for _ in range(count)] fps = doc.GetFps() current_frame = doc.GetTime().GetFrame(fps) for i in range(count): if current_frame >= op.frames[i]: # Sposta il clone fuori scena (es. +100 cm su Y) m = matrices[i] m.off.y = 100 matrices[i] = m else: # Mantieni la posizione originale (nessuna modifica) pass md.SetArray(c4d.MODATA_MATRIX, matrices, True) return True
edit (@ferdinand): moved file link out of source code.
-
@Fabio-B Welcome to the Maxon developers forum and its 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 procedures. You did not do anything wrong, we point all new users to these rules.
- Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
- Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
- Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.
It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: How to Ask Questions.
About your First Question
Your code contains a syntax error:
op.frames = [random.randint(0, 75) for _ in range(count)]
op
is in this context aBaseObject
, more precisely the effector for which this code is running. Since this type (BaseObject
) has been implemented in C++, you cannot just put there an attribute namedframes
on it. That is simply not how it works. Did you write this code yourself or did you use an AI?When I check the
DOCUMENT_INFO_FILEVERSION
of the document you submitted, I get there'2025.2.1'
, i.e., the last public release, and not R25 (released in 2021). I will answer as if you are using Cinema 4D 2025. The code I show below will not run in R25.To set the height of each particle to a fixed position, while using full control mode, you can basically use the barely modified default code.
"""Realizes an effector that sets all particles to a y position of 25. """ 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 # Get the matrices of the particles. This is the array we will modify. matrices: list[c4d.Matrix] = data.GetArray(c4d.MODATA_MATRIX) # For each particle write the new position to the matrix array. for i in range(data.GetCount()): old: c4d.Vector = matrices[i].off matrices[i].off = c4d.Vector(old.x, 25, old.z) # Write the new data back. data.SetArray(c4d.MODATA_MATRIX, matrices, op[c4d.FIELDS].HasContent()) return True
When you want to give each particle a random height value, you could use mxutils.Random as it has been built for tasks exactly like this:
"""Realizes an effector that sets all particles to a y position of 25.. """ import c4d import mxutils 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 # Get the matrices of the particles. This is the array we will modify. matrices: list[c4d.Matrix] = data.GetArray(c4d.MODATA_MATRIX) # For each particle write a new persistent random height value, hashed over the index of the # particle. This will cause the height each time to be the same, as long as the index of the # particle does not change. One could also hash the position of the original particle to get a # height value that is not dependent on the index of the particle (e.g., when the user changes # the order of the particles in the Matrix object). for i in range(data.GetCount()): old: c4d.Vector = matrices[i].off matrices[i].off = c4d.Vector(old.x, mxutils.g_random.HashNumberToNumber(i) * 25.0, old.z) # Hash a height value over the position of the particle. # y: float = mxutils.g_random.HashVectorToNumber(matrices[i].off) * 25.0 # Write the new data back. data.SetArray(c4d.MODATA_MATRIX, matrices, op[c4d.FIELDS].HasContent()) return True
Result:
Cheers,
Ferdinand -
@ferdinand Thanks, Ferdinando. The code was written by the AI. Basically, I wanted a certain number of 2cm x 2cm planes to move randomly along the Y axis. My original grid contains 62,000 of them, but for convenience, the one I posted contains 150. Since my view is oriented in a certain way, as the clones move, they'll disappear from the scene, creating a sort of shimmering or swarming fade-out effect.
-
Hey @Fabio-B,
Please note that we cannot provide support for AI generated code. See Support Procedures: Scope of Support for details.
When you want the clones to move, or in other words to be animated over time, you will need a noise and cannot use hashes or random values, as they are not interpolated, i.e., continous.
"""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 import mxutils 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 # Get the matrices of the particles. This is the array we will modify. matrices: list[c4d.Matrix] = data.GetArray(c4d.MODATA_MATRIX) # For each particle write a new persistent random height value, hashed over the index of the # particle. This will cause the height each time to be the same, as long as the index of the # particle does not change. One could also hash the position of the original particle to get a # height value that is not dependent on the index of the particle (e.g., when the user changes # the order of the particles in the Matrix object). for i in range(data.GetCount()): pos: c4d.Vector = matrices[i].off y: float = c4d.utils.noise.Noise(matrices[i].off, doc.GetTime().Get()) * 25.0 matrices[i].off = c4d.Vector(pos.x, y, pos.z) # Hash a height value over the position of the particle. # y: float = mxutils.g_random.HashVectorToNumber(matrices[i].off) * 25.0 # Write the new data back. data.SetArray(c4d.MODATA_MATRIX, matrices, op[c4d.FIELDS].HasContent()) return True