I'm having a hard time wrapping my brain around this script I'm trying to write.

I want to rotate a cube along the floor in the direction that it's being animated. The problem I'm running into is that I need to be able to specify the rotation around the world axis (just like how the rotate tool does) so that when the cube is oriented in any direction, I can still rotate properly with the animation.

Here's some pseudo code and a screen grab. Any help would be greatly appreciated!

```
# Rolling
distTraveled = pos - PREV_POS
numRevs.x = (distTraveled.x / circumfrence.x)
numRevs.z = (distTraveled.z / circumfrence.z)
outRot = numRevs * c4d.utils.DegToRad(360.0)
objMx = rotObj.GetMl()
rotMx = c4d.utils.MatrixRotY(-outRot.z) * c4d.utils.MatrixRotZ(outRot.x)
rotObj.SetMl(objMx * rotMx)
```

This code almost works, but some of the time the cube rotates the wrong direction (although on the right axis).

]]>without any further questions, we will consider this topic as solved by Monday and flag it accordingly.

Thank you for your understanding,

Ferdinand

For anyone in the future looking for this solution here's what I needed:

```
# Rolling
distTraveled = pos - PREV_POS
numRevs.x = (distTraveled.x / circumfrence.x)
numRevs.z = (distTraveled.z / circumfrence.z)
outRot = numRevs * c4d.utils.DegToRad(360.0)
objMx = rotObj.GetMl()
worldXInLocal = ~objMx * c4d.Vector(1, 0, 0)
worldZInLocal = ~objMx * c4d.Vector(0, 0, 1)
xTrans = c4d.utils.RotAxisToMatrix(worldXInLocal, -outRot.z)
zTrans = c4d.utils.RotAxisToMatrix(worldZInLocal, outRot.x)
rotObj.SetMl(objMx * xTrans * zTrans)
```

I needed the cube to be able to roll the correct way regardless of orientation. Admittedly this was a simple matrix transform issue that anyone who actually understood graphics programming would've known. (LOL not me)

Here's the full scene for anyone interested. test_cube_roll.c4d

]]>thank you for reaching out to us. Your question is a bit hard to answer, given the abstract nature of the provided code and the absence of a specific setup/file. I would however point out that:

- This number of revisions expressed as a vector, i.e., separated onto axis, strikes me as a bit odd, since this is not how rotation works ^^
- Using
`BaseObject.GetMl()`

can make things harder to compute, depending on your setup. I would stay in world space. - Most importantly I would point that you do not seem to take order of rotation into account, i.e., that matrix multiplication is not commutative, i.e., M * N != N * M which might get in the way in your second to last line, as you do not make this dependent on the travel direction.

I personally would also take a more "transform" oriented approach. As it much easier to just rotate a vector than figuring out into which direction you are now traveling and what that means for constructing a transform in "the proper way". I have provided below a quick solution as Python scripting tag, which is more meant to line out the approach rather than being a full solution (which we cannot provide). My solution requires an "aligned-with-world-frame" orientation for the start of travel. It would not be too hard to fix this, you must account for that additional delta before applying the final transform. I am just running a bit of time here, especially since this question is a bit out of scope of support (as it is just a math question).

If you need further help, also with the "alignment" condition, just ask

Cheers,

Ferdinand

The result:

The file: rot_cube.c4d

The code:

```
import c4d
import math
# Global non-static variables are a really bad idea. Please replace this
# in a production environment with a more safe approach by for example
# storing this as a user-data parameter or just as an element in a
# BaseContainer of a node.
PREVIOUS_POSITION = None
NULL_VECTOR = c4d.Vector()
UP_VECTOR = c4d.Vector(0, 1, 0)
def main():
"""
"""
# Get out when the tag is not attached to a BaseObject
node = op.GetObject()
if node is None:
return
# Get out when the position cache, PREVIOUS_POSITION, has not been yet
# initialized.
global PREVIOUS_POSITION
if PREVIOUS_POSITION is None:
PREVIOUS_POSITION = node.GetMg().off
return
# Compute the position delta and get out when it is the null/zero vector,
# i.e., nothing happened.
nodeMg = node.GetMg()
currentPosition = nodeMg.off
positionDelta = currentPosition - PREVIOUS_POSITION
if positionDelta == NULL_VECTOR:
return
# Now we are going to compute the angle of rotation similarly to what you
# did as a ratio of arc length (of travel) to circumference.
# Compute the circumference of the traveling object as the maximum radius
# of its bounding box. This also could be done for a non spherical case,
# but would get quite a bit more complicated.
boundingBoxRadii = node.GetRad()
travelObjectCircumference = 2 * math.pi * max(boundingBoxRadii.x,
boundingBoxRadii.y,
boundingBoxRadii.z)
# The traveled distance since the last update, i.e., the arc-length of the
# angle of rotation.
travelDistance = positionDelta.GetLength()
# The angle of rotation, based on the arc-length to angle of rotation
# relation:
#
# arc_length theta
# --------------- = ---------
# circumference 2π
#
theta = travelDistance / travelObjectCircumference * 2 * math.pi
# Now we are going to construct a transform for that angle. First we are
# going to construct our axis rotation which is orthogonal to the travel
# vector and an arbitrary up-vector, i.e., we simply assume one degree or
# otherwise would have to also track the banking of the traveling object.
axisRot = ~positionDelta % UP_VECTOR
# Now we are just computing our final desired transform, we could do this,
# i.e., constructing a transform out of an axis and an angle, manually but
# since the Python SDK does offer RotAxisToMatrix, we are going to be lazy
# and just use that :)
transform = c4d.utils.RotAxisToMatrix(axisRot, theta)
# Now we are just going to write this into the object's transform in world
# space, i.e., what Cinema does call its global matrix.
mg = node.SetMg(nodeMg * transform)
# And we have to update our position cache at the end.
PREVIOUS_POSITION = currentPosition
```

]]>