Hello @indexofrefraction,

Is this correct / covers all cases to get the targets position in local space?

There is no "correct" way. The way I showed you is a/the common approach to construct a frame from a vector. A vector in RÂ³ (opposed to a tuple of rotation values which might be stored in a type called Vector) only defines two out of the three degrees of freedom of a rotation in RÂ³. When you construct a frame manually, you can define that third degree of freedom with the up vector (or just right away construct the frame out of two meaningful vectors which are already orthogonal to each other). VectorToHPB() makes this decision for you, as it, quote, '[will always set] the bank [...] to 0.0' because a vector does not store three angles but two. I personally would never go over the Euler angles, as this seems unnecessarily complicated, but this is a question of personal preference and not right or wrong.

Is this correct / covers all cases to get the targets position in local space?

(~(op.GetUpMg() * op.GetFrozenMln())) * target.GetMg().off [- op->GetRelPos();]

What @s_bach did there was specific to that example which operates on Euler angles. I cannot explain all the math here, but in general, the position of an object B relative to an object A, i.e, the local offset of B within the coordinate system of A is just the delta of both offsets transformed by the coordinate system of A.

A: c4d.BaseObject
B: c4d.BaseObject
mgA: c4d.Matrix = A.GetMg()
mgB: c4d.Matrix = B.GetMg()
# This is the location of B in relation to A in world coordinates.
delta: c4d.Vector = mgB.off - mgA.off
# The same point but in the coordinate system of A. If B were parented to A, it would have
# this offset.
offBLocalToA: c4d.Vector = mgA * delta

I again would have personally done some things differently in the loot-at example, but the solution is just as good as others.

what is m = utils.MatrixMove(op.GetAbsPos()) * utils.HPBToMatrix(op.GetAbsRot()) * utils.MatrixScale(op.GetAbsScale()) in this context? (ps. GetAbsScale misses the brackets in the docs)

Please read the docs, I cannot explain here transforms from scratch again. Thanks for the hint for the missing parenthesis, I will fix that in an upcoming release. As a tip: Do not fixate too much on frozen transforms in our API, you can ignore them more or less, the relevant methods are GetMg and GetMl.

and... is this the real code of the Target Tag ?

I am not quite sure how you mean that? You mean if the LookAtCamera::Execute example is identical to what the ::Execute of Ttargetexpression does internally? No really, the expression ~(op.GetUpMg() * op.GetFrozenMln()) pops up there, but Ttargetexpression also constructs the frame manually with the cross product, but there are more steps involved than in my simple example. But again, there is no real right or wrong here, you can do things differently if you want to.

And before the question comes up, no, we unfortunately cannot share the code of the target expression. I would also point out again our Forum Rules, especially regarding the scope of support and the rules of conduct. We cannot teach you the math and you must implement your things yourself.

Cheers,

Ferdinand

PS: If you want to explore what the frozen transform means (it is mostly smoke and mirrors for the API perspective, unless you want to specifically deconstruct a transform), I would recommend adding a Python tag to objects, adding this code, and then play around with the freeze transform feature.

import c4d
op: c4d.BaseTag
def main() -> None:
"""
"""
def PrettyMatrixString(m: c4d.Matrix):
"""_summary_
"""
s: str = f"{m.__class__.__name__}("
l: int = len(s)
for i, v in enumerate((m.off, m.v1, m.v2, m.v3)):
s += f"{' ' * (l if i != 0 else 0)}({round(v.x, 3):>8}, {round(v.y, 3):>8}, {round(v.z, 3):>8}\n"
return s[:-1] + ")"
node: c4d.BaseObject = op.GetMain()
if not isinstance(node, c4d.BaseObject): # Should technically never happen
return
for line in (
f"GetMg():\n{PrettyMatrixString(node.GetMg())}",
f"GetMl():\n{PrettyMatrixString(node.GetMl())}",
f"GetFrozenMln():\n{PrettyMatrixString(node.GetFrozenMln())}"):
print (line)

09c7c8b7-63d3-4020-8ef3-2881ff262003-image.png