fairs. I thought this was a normal forum for sharing ideas and solving problems/challenges.
Didn't really think about it being a support thing.
My bad
Posts made by PMenich
-
RE: Get MODATA_SIZE of Mograph Particles to Build Stacks of Geometry
-
RE: Get MODATA_SIZE of Mograph Particles to Build Stacks of Geometry
wow. smackdown.
Well, in the spirit of sharing, I managed to figure it out (with the help of AI) which I will attach here for any future users who might like to take a look.Pete
(C4D user since V6)
-
RE: Get MODATA_SIZE of Mograph Particles to Build Stacks of Geometry
Celebration was a bit premature. Doesn't work with text (MoText) - any ideas? Chat GTP seems flummoxed by this...
import c4d import math import typing from c4d.modules import mograph def get_clone_info(op, index: int) -> typing.Tuple[c4d.Vector, c4d.Vector]: """Gets the world coordinates and bounding box size of the specified clone index.""" moData: mograph.MoData = mograph.GeGetMoData(op) if moData is None: raise ValueError("MoData is None. Ensure this is a MoGraph object.") cloneMatrices: typing.List[c4d.Matrix] = moData.GetArray(c4d.MODATA_MATRIX) cloneOffsets: typing.List[float] = moData.GetArray(c4d.MODATA_CLONE) if len(cloneMatrices) != len(cloneOffsets): raise IndexError("Clone matrix and index arrays are not of equal length.") # Ensure the index is within the valid range if index < 0 or index >= len(cloneMatrices): raise IndexError(f"Index {index} is out of range for the number of clones {len(cloneMatrices)}.") cloneMatrix: c4d.Matrix = cloneMatrices[index] worldPosition: c4d.Vector = cloneMatrix.off # Get the bounding box size of the clone geometry boundingBoxSize: c4d.Vector = c4d.Vector(0, 0, 0) if op.GetTypeName() == "Text": # For Text objects, calculate the bounding box size of each letter textObject = op textObject.Update() bbox = textObject.GetBBox() if bbox: min_point = bbox["min"] max_point = bbox["max"] min_point = min_point * cloneMatrix max_point = max_point * cloneMatrix boundingBoxSize = max_point - min_point print(f"Index: {index}, World Position: {worldPosition}, Bounding Box Size: {boundingBoxSize}") return worldPosition, boundingBoxSize def main(): # Get the index from the user data slider index = op[c4d.ID_USERDATA, 1] # Adjust the ID to match your user data field try: worldPosition, boundingBoxSize = get_clone_info(op, index) # Store the results in user data fields or custom data fields op[c4d.ID_USERDATA, 2] = worldPosition # Adjust the ID to match your user data field for world position op[c4d.ID_USERDATA, 3] = boundingBoxSize # Adjust the ID to match your user data field for bounding box size except Exception as e: print(f"Error: {e}") op[c4d.ID_USERDATA, 2] = c4d.Vector(0, 0, 0) op[c4d.ID_USERDATA, 3] = c4d.Vector(0, 0, 0)
-
RE: Get MODATA_SIZE of Mograph Particles to Build Stacks of Geometry
Managed to get it working with the help of ChatGPT!
GetCloneSize.c4d -
RE: Get MODATA_SIZE of Mograph Particles to Build Stacks of Geometry
Hey,
I've been trying to unpick this project to achieve the result I need, but not getting anywhere.
I'm trying to get the x and y size of individual clones, specifically text objects, so I can create a rectangle spline that moves form letter to letter (or word to word) and draws a box around each letter or word. Driven by an index number slider in xpresso.
Any ideas? -
Drive smooth rotation
Hey, I've been trying to create a python node in xpresso to emulate this bit of code from the amazing Mr Ebberts...
http://motionscript.com/articles/speed-control.html
Here's the After Effects expression I'm trying to translate...
spd = effect("Slider Control")("Slider"); n = spd.numKeys; if (n > 0 && spd.key(1).time < time){ accum = spd.key(1).value*(spd.key(1).time - inPoint); for (i = 2; i <= n; i++){ if (spd.key(i).time > time) break; k1 = spd.key(i-1); k2 = spd.key(i); accum += (k1.value + k2.value)*(k2.time - k1.time)/2; } accum += (spd.value + spd.key(i-1).value)*(time - spd.key(i-1).time)/2; }else{ accum = spd.value*(time - inPoint); } value + accum
Here's where I'm at with my Python translation...
from typing import Optional import c4d op: c4d.modules.graphview.GvNode # The Xpresso node doc: c4d.documents.BaseDocument # The document evaluating this node tp: Optional[c4d.modules.thinkingparticles.TP_MasterSystem] # Particle system def main(): global Output1 #Grab the host-object to the xpresso Tag Rect = op.GetNodeMaster().GetOwner().GetObject() #Get the UserData spd = Rect[c4d.ID_USERDATA,1] # Get the first animation track of the object track = Rect.GetFirstCTrack() # Get the animation curve of the track curve = track.GetCurve() # Get the number of keyframes on the curve n = curve.GetKeyCount() fps = doc.GetFps() sFrame= doc.GetMinTime().GetFrame(fps) eFrame= doc.GetMaxTime().GetFrame(fps) name = op.GetName() key = curve.GetKey(1) keyValue = key.GetValue() keyFrame = key.GetTime().GetFrame(fps) currentFrame = doc.GetTime().GetFrame(doc.GetFps()) value = spd if n > 0 and curve.GetKey(1).GetTime().GetFrame(fps) < currentFrame: accum = curve.GetKey(1).GetValue() * (curve.GetKey(1).GetTime().Get() - sFrame) for i in range(2, n): if curve.GetKey(i).GetTime().Get() > currentFrame: break k1 = curve.GetKey(i-1) k2 = curve.GetKey(i) accum += (k1.GetValue() + k2.GetValue()) * (k2.GetTime().Get() - k1.GetTime().Get()) / 2 accum += (curve.GetValue(curve.GetKey(i-1).GetTime()) + curve.GetKey(i-1).GetValue()) * (currentFrame - curve.GetKey(i-1).GetTime().Get()) / 2 else: accum = Input1 * (currentFrame - sFrame) print(Input1 + accum) Output1 = value + accum
- There are loads of unnecessary variables in there btw - that was me just trying to figure this stuff out!
Basically trying to drive rotation without using time as my driver. Now, I'm no programmer (as you'll soon find out!), but the attached project does work, but doesn't do what I want it to! When the UsrData 'speed' gets to 0 it should stop. And the rotation is meant to be smooth ramp up and then smooth ramp down.
Any python geniuses out there got time to take a look and tell me where I'm going wrong?