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

    How can I add an offset to the global matrix of an object that is rotated?

    Cinema 4D SDK
    python sdk s26
    2
    4
    667
    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.
    • H
      HerrMay
      last edited by

      Hi guys,

      as the title already suggests I wonder how I can add an arbitrary offset value to the global matrix of an object that is rotated. In that way that the object moves along that angled position plus the given offset?

      I tried adding the offset to the z axis of the 'off' component of the objects global matrix. But without any luck. The object is then of course moving along the world axis by the amount of the offset.

      I hope someone can help me here with these dreadful matrices. 😄

      Cheers,
      Sebastian

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

        Hello @HerrMay,

        Thank you for reaching out to us. Yeah, transforms can be a tricky subject, I would recommend having a look at the Matrix Manual as it does explain some fundamentals.

        Your question was quite clear, but there is always some ambiguity with transform questions unless one uses a super mathematical language. But I think I got what you meant and have provided an example below.

        Cheers,
        Ferdinand

        Result:

        e177a34a-97fc-4b85-aa47-5219dc4cbb95-image.png
        The input object is selected, in blue an object translated by (0, 500, 0) units in the local coordinate system of the selected object.

        Code:

        """Demonstrates translating an object in its own local coordinate system.
        
        Must be run as a Script Manager script with an object selected.
        
        Related:
            https://developers.maxon.net/docs/py/2023_2/manuals/data_algorithms/classic_api/matrix.html
        """
        
        import c4d
        import typing
        
        doc: c4d.documents.BaseDocument  # The active document
        op: typing.Optional[c4d.BaseObject]  # The active object, None if unselected
        
        def main() -> None:
            """
            """
            if not op:
                raise RuntimeError("Please select an object.")
        
            # Clone the selected object and insert the clone into the document, so that we have this out of 
            # the way.
            clone: c4d.BaseObject = op.GetClone(c4d.COPYFLAGS_NO_HIERARCHY)
            if not clone:
                raise MemoryError("Could not clone object.")
        
            clone.SetName(f"{op.GetName()} (Clone)")
            clone[c4d.ID_BASEOBJECT_USECOLOR] = c4d.ID_BASEOBJECT_USECOLOR_ALWAYS
            clone[c4d.ID_BASEOBJECT_COLOR] = c4d.Vector(0, 0, 1)
            doc.InsertObject(clone)
        
            # The vector with which we want to translate something.
            p: c4d.Vector = c4d.Vector(0, 500, 0)
        
            # Translate an object inside its own local coordinate system.
            #
            # Doing this means simply multiplying our translation vector #p with the global matrix of the 
            # object and setting the result as the new offset of the global matrix. Remember, multiplying a 
            # point #p with the matrix #M will yield a global point #q that is in the same relation to #M as
            # #p is to the global frame. I.e., in this case it will yield a vector #q that is in the same 
            # relation with #mg as the vector (0, 500, 0) is with the world frame.
            mg: c4d.Matrix = op.GetMg()
            mg.off = mg * p
            clone.SetMg(mg)
        
            c4d.EventAdd()
        
        if __name__ == '__main__':
            main()
        

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • H
          HerrMay
          last edited by

          Hello @ferdinand,

          sorry for being a bit nebulous. I wasn't sure how I should explain what I mean in a way that would illustrate it a bit better. 😄

          Actually I hab a look at the matrix manual. But as someone who had no matrix calculation lessons in school, it's a bit overwhelming at first glance. 😄 😄 😄

          Yes, you guessed correctly. That is exactly what I wanted. Thank you once again. 🤗

          Is the multiplication of a matrix with a vector (mg.off = mg * p) essentially the same what mg * c4d.utils.MatrixMove(vec) does?

          Cheers,
          Sebastian

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

            Hello @HerrMay,

            Is the multiplication of a matrix with a vector (mg.off = mg * p) essentially the same what mg * c4d.utils.MatrixMove(vec) does?

            No, mg * p multiplies a matrix by a vector which will yield the transformed vector p'. mg * c4d.utils.MatrixMove(vec) on the other hand multiplies two matrices, yielding the combined transform of them, a new matrix.

            What would be equivalent to mg * p is mg * c4d.utils.MatrixMove(p) * c4d.Vetcor(0, 0, 0). Please note that the whole subject is also out of scope of support as declared in the forum guidelines. I understand that the subject is a common barrier for the more on the artist-sided leaning users of ours, and I help where I can, but we cannot teach you vector math, linear algebra, or however you want to label this subject.

            Find below a short code example.

            Cheers,
            Ferdinand

            Output:

            M = Matrix(v1: (1, 0, 0); 
                       v2: (0, 1, 0); 
                       v3: (0, 0, 1); 
                       off: (0, 100, 0))
            p = Vector(100, 0, 0)
            
            M * p = Vector(100, 100, 0)
            M * c4d.utils.MatrixMove(c4d.Vector(100, 0, 0)) = Matrix(v1: (1, 0, 0); 
                                                                     v2: (0, 1, 0); 
                                                                     v3: (0, 0, 1); 
                                                                     off: (100, 100, 0))
            M * c4d.Vector(100, 0, 0) = Vector(100, 100, 0)
            N * c4d.Vector(  0, 0, 0) = Vector(100, 100, 0)
            M * c4d.utils.MatrixMove(p) * c4d.Vector(0, 0, 0) = Vector(100, 100, 0)
            

            Code:

            import c4d
            
            # Let us assume #M to be the global matrix/transform of some object #op. View it as a tool to 
            # transform a point in global space into the local coordinate system of #op.
            M: c4d.Matrix = c4d.Matrix(off=c4d.Vector(0, 100, 0))
            
            # The matrix #M now has this form:
            #
            #   | v1     1    0    0 |   # The "x-axis" of the coordinate system defined by #M.
            #   | v2     0    1    0 |   # The "y-axis" of the coordinate system defined by #M.
            #   | v3     0    0    1 |   # The "z-axis" of the coordinate system defined by #M.
            #   ---------------------- 
            #   | off    0  100    0 |   # The origin of the coordinate system defined by #M.
            #
            # I.e., #M has the standard orientation and scale and only translates all things by 100 units
            # on the y-axis. So, the object #op would have the Euler angles (0°, 0°, 0°), the scale (1, 1, 1) 
            # and the position (0, 100, 0) in world coordinates.
            
            # Define a vector #p to transform and print both #M and #p.
            p: c4d.Vector = c4d.Vector(100, 0, 0)
            print(f"{M = }")
            print(f"{p = }")
            
            # Transforming a point #p by a matrix #M will yield a point #q that is in the same relation to #M
            # as #p is to the global frame.
            q: c4d.Vector = M * p
            
            # #q will be the vector (100, 100, 0) because , (100, 100, 0) and #M are the same relation as #p
            # and the identity matrix are, a.k.a., the world frame. In a less technical way, (0, 100, 0) is the
            # origin of the coordinate system defined by #M. And to express #p in a manner as if #M would be
            # its coordinate system, we have to add (0, 100, 0), because that is the new origin. For orientation
            # and scale it works more or less the same, I would recommend having a look at the Matrix manual or
            # Wikipedia article on the subject.
            print (f"{M * p = }")
            
            # We can construct new transforms in many ways (again, Matrix Manual :)), one of them is by 
            # combining multiple transforms via matrix multiplication.
            
            # We "add" the translation transform (100, 0, 0) to #M. Note that matrix multiplication is not 
            # commutative, i.e., "M * N = N * M" does not always hold true. In this case it would because only
            # translations are involved.
            N: c4d.Matrix = M * c4d.utils.MatrixMove(c4d.Vector(100, 0, 0))
            print(f"{M * c4d.utils.MatrixMove(c4d.Vector(100, 0, 0)) = }")
            
            # To get the same point as #q when multiplying a point #r with #N, we must pick the null-vector
            # because the origin of #N is already at where M * (100, 0, 0) is.
            print (f"{M * c4d.Vector(100, 0, 0) = }")
            print (f"{N * c4d.Vector(  0, 0, 0) = }")
            
            # We can also do it in one operation:
            print (f"{M * c4d.utils.MatrixMove(p) * c4d.Vector(0, 0, 0) = }")
            

            MAXON SDK Specialist
            developers.maxon.net

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