Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Matrices / Rotations / Quaternions when transferring data.

    General Talk
    3
    4
    805
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • lasselauchL
      lasselauch
      last edited by

      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 … 😄 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

      1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand
        last edited by

        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

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • r_giganteR
          r_gigante
          last edited by

          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

          1 Reply Last reply Reply Quote 0
          • lasselauchL
            lasselauch
            last edited by

            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

            1 Reply Last reply Reply Quote 0
            • First post
              Last post