Left-Hand Local Coordinates to Right-Hand Local Coordinates?



  • Hi,

    I'm trying to export object an animated hierarchy of objects from Cinema 4D's left coordinates (z+ = forward) with HPB rotations to Three.js's right-hand coordinates (z+ = backward) with XYZ rotations.

    Unfortunately, I'm a bit beyond my depth with the matrix math and conversions involved. I'd like to take my C4D local coords write them out as local coords in this other system.

    Any tips on how to approach this?
    Thanks

    Donovan

    PS: Looks like we need an S22 tag in the tags option.



  • Thank you @zipit and @m_magalhaes for your replies! @zipit your response put me on the right track. The issue was that I was trying to do all of the conversions using C4D's left-handed coordinate matrices, and it was auto-fixing my "malformed" matrices.

    I ended up porting the Three.js Matrix4 and Euler classes from JS to python and using them in my script.

    So, the final code (leaving out the ported methods) looked something like:

            mg = self.op.GetMg()
            parent_mg = self.op.GetUpMg()
    
            c4d_to_three = c4d.Matrix(
                off=c4d.Vector(0),
                v1=c4d.Vector(1, 0, 0),
                v2=c4d.Vector(0, 1, 0),
                v3=c4d.Vector(0, 0, -1)
            )
    
            # Convert to new coordinate space
            # http://www.techart3d.com/2016/02/convert-left-handed-to-right-handed-coordinates/
    
            mg_three_coords = c4d_to_three * mg * c4d_to_three
            parent_mg_three_coords = c4d_to_three * parent_mg * c4d_to_three
    
            mg_mat4 = Matrix4(mg_three_coords)
            parent_mg_mat4 = Matrix4(parent_mg_three_coords)
    
            inv_parent_mg_mat4 = parent_mg_mat4.Clone()
            inv_parent_mg_mat4 = inv_parent_mg_mat4.Inverse()
    
            node_local = inv_parent_mg_mat4.Clone()
            node_local = node_local.MultiplyMatrices(inv_parent_mg_mat4, mg_mat4)
    
            position, scale, rotation = node_local.Decompose()
    
            if position != c4d.Vector(0):
                self.props["position"] = position
    
            if scale != c4d.Vector(1):
                self.props["scale"] = scale
    
            if rotation != c4d.Vector(0):
                self.props["rotation"] = rotation
    


  • Hi,

    I do not quite understand the question. You cannot express other frame orientations than Cinema's builtin frame orientation with Cinema's matrices. When you write to one component in such way, that it would produce a malformed matrix, Cinema will silently rectify that matrix. See this script for demonstration:

    import c4d
    from c4d import gui
    
    def main():
        """
        """
        if not op:
            return
    
        mg = op.GetMg()
        # Cinema will automatically rectify a matrix so that it does conform
        # to its world frame. Which is why this will flip also the x-axis, not just
        # the z-axis.
        mg.v3 *= -1
        op.SetMg(mg)
        c4d.EvenatAdd()
              
    if __name__=='__main__':
        main()
    

    I am not quite sure, what you are after. If you just want an axis tuple, then just grab it from the matrices and invert whatever you have to invert and construct the rest of the matrix with the cross product.

    Cheers,
    zipit



  • hi,

    sound like you just have to switch the Z axis by multiplying it by -1.

    Either you should go from local to global and back to local that's probably the problem, and with a hierarchy you will maybe hit some cases that i don't think right now.

    If you could come with one simple example. A c4d scene with a simple animation and what you expect for three.js

    (maybe the hierarchy isn't important there i don't know)

    Cheers,
    Manuel



  • Thank you @zipit and @m_magalhaes for your replies! @zipit your response put me on the right track. The issue was that I was trying to do all of the conversions using C4D's left-handed coordinate matrices, and it was auto-fixing my "malformed" matrices.

    I ended up porting the Three.js Matrix4 and Euler classes from JS to python and using them in my script.

    So, the final code (leaving out the ported methods) looked something like:

            mg = self.op.GetMg()
            parent_mg = self.op.GetUpMg()
    
            c4d_to_three = c4d.Matrix(
                off=c4d.Vector(0),
                v1=c4d.Vector(1, 0, 0),
                v2=c4d.Vector(0, 1, 0),
                v3=c4d.Vector(0, 0, -1)
            )
    
            # Convert to new coordinate space
            # http://www.techart3d.com/2016/02/convert-left-handed-to-right-handed-coordinates/
    
            mg_three_coords = c4d_to_three * mg * c4d_to_three
            parent_mg_three_coords = c4d_to_three * parent_mg * c4d_to_three
    
            mg_mat4 = Matrix4(mg_three_coords)
            parent_mg_mat4 = Matrix4(parent_mg_three_coords)
    
            inv_parent_mg_mat4 = parent_mg_mat4.Clone()
            inv_parent_mg_mat4 = inv_parent_mg_mat4.Inverse()
    
            node_local = inv_parent_mg_mat4.Clone()
            node_local = node_local.MultiplyMatrices(inv_parent_mg_mat4, mg_mat4)
    
            position, scale, rotation = node_local.Decompose()
    
            if position != c4d.Vector(0):
                self.props["position"] = position
    
            if scale != c4d.Vector(1):
                self.props["scale"] = scale
    
            if rotation != c4d.Vector(0):
                self.props["rotation"] = rotation
    

Log in to reply