Friday, February 17, 2012

C4D Python Matrix Basics & Helper Functions

I seem to forget the basics of working with matrices in C4D immediately after I use them. Here are some resources and helper functions:

Maxon's How to Use Matrices
C4D Python SDK Matrix Reference

Some PSR helper functions written by Maxon with additions for point manipulation by me
############## HIERARCHY HELPERS ######################
def GetGlobalPosition(obj):
    """
    Returns the global position of obj
    """
    return obj.GetMg().off
 
def GetGlobalRotation(obj):
    """
    Returns the global rotation of obj
    """
    return utils.MatrixToHPB(obj.GetMg())
 
def GetGlobalScale(obj):
    """
    Returns the global scale of obj
    """
    m = obj.GetMg()
    return c4d.Vector(  m.v1.GetLength(),
                        m.v2.GetLength(),
                        m.v3.GetLength())
 
def SetGlobalPosition(obj, pos):
    """
    Sets the global position of obj to pos
    """
    m = obj.GetMg()
    m.off = pos
    obj.SetMg(m)
 
def SetGlobalRotation(obj, rot):
    """
    Sets the global rotation of obj to rot
    Please remember, CINEMA 4D handles rotation in radians.
 
    Example for H=10, P=20, B=30:
 
    import c4d
    from c4d import utils
    #...
    hpb = c4d.Vector(utils.Rad(10), utils.Rad(20), utils.Rad(30))
    SetGlobalRotation(obj, hpb) #object's rotation is 10, 20, 30
    """
    m = obj.GetMg()
    pos = m.off
    scale = c4d.Vector( m.v1.GetLength(),
                        m.v2.GetLength(),
                        m.v3.GetLength())
 
    m = utils.HPBToMatrix(rot)
 
    m.off = pos
    m.v1 = m.v1.GetNormalized() * scale.x
    m.v2 = m.v2.GetNormalized() * scale.y
    m.v3 = m.v3.GetNormalized() * scale.z
 
    obj.SetMg(m)
 
def SetGlobalScale(obj, scale):
    """
    Sets the global scale of obj to scale
    """
    m = obj.GetMg()
 
    m.v1 = m.v1.GetNormalized() * scale.x
    m.v2 = m.v2.GetNormalized() * scale.y
    m.v3 = m.v3.GetNormalized() * scale.z
 
    obj.SetMg(m)

def LocalToGlobal(obj, local_pos):
    """
    Returns a point in local coordinate in global space.
    """
    obj_mg = obj.GetMg()
    return obj_mg * local_pos

def GlobalToLocal(obj, global_pos):
    """
    Returns a point in global coordinate in local space.
    """
    obj_mg = obj.GetMg()
    return ~obj_mg * global_pos

def SetPointGlobal(point_object, point_index, global_pos):
    """
    Sets the global position of point_object's point to global_pos
    """
    p_local_pos = GlobalToLocal(point_object, global_pos)

    #Set Point
    point_object.SetPoint(point_index, p_local_pos)

    #Tell C4D the spline has changed.
    point_object.Message(c4d.MSG_UPDATE)
    #Move this line to the end of your loop if you're call this command a lot.

def SetPointGlobalVirtual(point_object, parent, point_index, global_pos):
    """
    Sets the global position of a virtual point_object's point to global_pos
    Most useful when setting the points of a spline created in a Python Generator
""" p_local_pos = GlobalToLocal(parent, global_pos) #Set Point point_object.SetPoint(point_index, p_local_pos)

    #Tell C4D the spline has changed.
    point_object.Message(c4d.MSG_UPDATE) #Move this line to the end of your loop if you're call this command a lot.
def GetPointGlobal(point_object, point_index):
    """
    Return the position of a point in Global Space
    """
    ppos = point_object.GetPoint(point_index) #Get the point in local coords
    return LocalToGlobal(point_object, ppos) #Return the point in global space

#######################################################