How to scale(/rotate/move) a parent object without affecting its children?
-
Hi everyone,
How can I set the scale of a parent object without affecting its children? I've tried using SetAbsScale() on the parent, but it also scaled all its children. I have seen a tutorial where you can press key '7' to do this interactively in the viewport, and I imagine there is a way to do this programmatically in python script?
Any insight would be appreciated! -
Hi @ops,
There's no built-in function, which does this for you, so you'd need to implement this on your own. Namely, you'd need to iterate through the object's children and adjust their transforms to the inverse change of the parents transform. Please check the code example below.
There're two important things to mention:
- The SetMl() function won't make any effect if the object has "Protection tag" (or other restricting means, e.g. "Constraint" tag etc). This will behave basically the same as if you were to use "7" shortcut. If you actually want to work around this, you'd need to disable the restriction before using SetMl() yourself.
- Generally speaking the GetMg()/SetMg() functions are inefficient to use (because it's value is calculated from the chain of local transformation matrices Ml). This is unlikely to be noticeable in python, because python api is pretty slow by itself. However, if you were to use Mg in C++ API (especially in some tight place like e.g. GetVirtualObjects()), it could negatively affect the performance. Hence, it's highly recommended to use GetMl()/SetMl() instead, if possible.
Cheers,
IliaThe code example:
import c4d op: c4d.BaseObject | None # The primary selected object in `doc`. Can be `None`. def SomehowMoveObject(obj: c4d.BaseObject) -> None: obj.SetAbsPos(obj.GetAbsPos() + c4d.Vector(100, 0, 0)) def main() -> None: opMlOriginal: c4d.Matrix = op.GetMl() # Keep the original matrix before moving the object SomehowMoveObject(op) # Somehow transform the parent object opMChangeInv: c4d.Matrix = opMlOriginal * ~op.GetMl() # Calculate the inverse matrix for the children for child in op.GetChildren(): child.SetMl(child.GetMl() * opMChangeInv) # Apply the inverse transform to the children if __name__ == '__main__': main() c4d.EventAdd()
-
Thanks Illia, for the exmple code!
Too bad that there's no built-in function for it, but I understand now that I'll have to inverse-matrix the children myself. -
And that's good to know about using GetMl() over Get Mg(), mainly for the performance reasons if I understood correctly.