Matrices / Rotations / Quaternions when transferring data.



  • Hey everyone,

    I'm currently working on a plugin to establish a neat connection between C4D and Houdini. ( https://twitter.com/lasse_lauch/status/1319296533016182787?s=20 )

    However, one thing that always drives me insane when transferring data between different apps is the matrix-rotation-euler-quaternion-endless-rabbit-hole when animation comes into play.

    Currently I'm using these functions from the documentation as a base...

    
        def GetGlobalPosition(obj):
            return obj.GetMg().off
    
        def GetGlobalRotation(obj):
            return c4d.utils.MatrixToHPB(obj.GetMg(), #order=c4d.ROTATIONORDER_XYZGLOBAL !? )
    
        def GetGlobalScale(obj):
            m = obj.GetMg()
            return c4d.Vector(  m.v1.GetLength(),
                                m.v2.GetLength(),
                                m.v3.GetLength())
    
    

    ... and write the components into a dict like:

    
        myDict[frame]['tx'] = pos.x
        myDict[frame]['ty'] = pos.y
        myDict[frame]['tz'] = pos.z
        myDict[frame]['sx'] = scale.x
        myDict[frame]['sy'] = scale.y
        myDict[frame]['sz'] = scale.z
        
        # getter in cinema4D (rotation in radians)
        myDict[frame]['rx'] = rot.x
        myDict[frame]['ry'] = rot.y
        myDict[frame]['rz'] = rot.z
    
        # setter in houdini (radians to degrees):
        hou.hmath.radToDeg(key['rx'])
    
    

    But I'm sure I somehow need to deconstruct the matrix and reconstruct in houdini.

    (BTW - For my AEC4DPRO plugin we've found a solution after working closely with @r_gigante in using the c4d.utils.GetOptimalAngle(hpb_old, hpb_new, rotation_order function as described -> here...

    Is this the way to go in general, or are there some other pointers to break this down to it's bare bones... I'm looking at you: @zipit … :D HELP!

    When it comes to Matrices and Rotations my brain sloooowly starts to melt……
    (…and yes, I've watched the 3Blue1Brown videos on quaternions... 😇 )

    Would love to provide further code details if needed.

    Thanks,
    Lasse



  • Hi,

    I am not sure if I am able to be of great help, because I do not know much about Houdini (cool project btw ;)).

    1. Quaternions only have been ported half the way in c4dpy. The implementation is missing the arithmetic operations, i.e. you can't transform directly with them. What you can do is create a quaternion from an axis of rotation and an angle, derive a rotation matrix from a quaternion and interpolate between two quaternions. Unless you want to do interpolations, i.e. animate some kind of rotation manually, then you probably won't need them.
    2. Euler angles are just another way to describe rotations. What rotation order you have to use depends on Houdini (its default rotation order seems to be XYZ), not on Cinema, since Houdini has to create from that the correct transforms. But I would be hesitant to use Euler angles as an export format, because of the ambiguity that comes with them.
    3. I would use linear transforms, i.e. "c4d.Matrix" in Cinema, as an export format, since they are quite straight forward. The only thing you have to worry about is the handedness [1] of the coordinate systems you are exporting from and to. With Houdini's hou.Quaternion [2] you can then convert these to anything you need in Houdini.

    Cheers,
    zipit

    [1] https://en.m.wikipedia.org/wiki/Orientation_(vector_space)
    [2] https://www.sidefx.com/docs/houdini/hom/hou/Quaternion.html



  • Hi @lasselauch , nice to see you again around.

    About your question on transferring object transformation to Houdini, given that I've no clue on the communication mechanism you've setup, I agree with @zipit that you should use transformation matrixes to transfer data from C4D to Houdini and pay attention to coordinate system handedness matching.

    A right handed coordinate system can be converted to a left handed coordination system (or vice-versa) by:

    • Inverting any one coordinate basis (such as replacing z with -z)
      or
    • swapping any two coordinate basis (such as x and y).

    Cheers, Riccardo



  • Hey guys,

    just wanted to let you know, that I've cracked the case in the meantime.

    Here are my findings:

    def convert_matrix_left_to_right(m):
        # http://www.techart3d.com/2016/02/convert-left-handed-to-right-handed-coordinates/
        # m = op.GetMg()
        new_m = c4d.Matrix(  m.off,
                            m.v1*-1,
                            m.v2,
                            m.v3)
        return new_m
    
    def rotate_y_axis_180():
        # Construct your own matrix based on rotation of axis
        # https://www.mathworks.com/help/phased/ref/roty.html
        x = c4d.Vector(-1, 0, 0)
        y = c4d.Vector(0, 1, 0)
        z = c4d.Vector(0, 0, -1)
        off = c4d.Vector(0, 0, 0)
        return c4d.Matrix(off, x, y, z)
    
    def GetGlobalRotation(obj):
        m = obj.GetMg()
        new_m = rotate_y_axis_180() * convert_matrix_left_to_right(m)
        return c4d.utils.MatrixToHPB(new_m, order=c4d.ROTATIONORDER_XYZGLOBAL)
    
    

    Indeed you have to convert from a left-handed (c4d) (hpb) to a right-handed (houdini) (xyz) coordinate system... plus I've found that you need to add 180° to the y axis, so I constructed a matrix in rotate_y_axis_180 that I can multiply to my converted matrix.

    Hope it helps someone...

    Thank you guys for your input! Have a great weekend and stay safe!

    Cheers,
    Lasse


Log in to reply