예제 #1
0
 def get_original_rotations(self, rt_rot=None):
     if rt_rot is None:
         rt_rot = self.rt_rot
     yaxis_rotations = Quaternions(np.array(Pivots(rt_rot).quaternions()))
     rt_rotations = Quaternions(self.rotations[:, :1])  # [T, 1, 4]
     rt_rotations = np.array(yaxis_rotations * rt_rotations)
     rt_rotations /= np.sqrt((rt_rotations ** 2).sum(axis=-1))[..., np.newaxis]
     return np.concatenate((rt_rotations, self.rotations[:, 1:]), axis=1)  # [T, J, 4]
예제 #2
0
 def unravel(clas, anim, shape, parents):
     nf, nj = shape
     rotations = anim[nf * nj * 0:nf * nj * 3]
     positions = anim[nf * nj * 3:nf * nj * 6]
     orients = anim[nf * nj * 6 + nj * 0:nf * nj * 6 + nj * 3]
     offsets = anim[nf * nj * 6 + nj * 3:nf * nj * 6 + nj * 6]
     return cls(Quaternions.exp(rotations), positions,
                Quaternions.exp(orients), offsets, parents.copy())
예제 #3
0
    def __call__(self):

        children = AnimationStructure.children_list(self.animation.parents)

        for i in range(self.iterations):

            for j in AnimationStructure.joints(self.animation.parents):

                c = np.array(children[j])
                if len(c) == 0: continue

                anim_transforms = Animation.transforms_global(self.animation)
                anim_positions = anim_transforms[:, :, :3, 3]
                anim_rotations = Quaternions.from_transforms(anim_transforms)

                jdirs = anim_positions[:, c] - anim_positions[:, np.newaxis, j]
                ddirs = self.positions[:, c] - anim_positions[:, np.newaxis, j]

                jsums = np.sqrt(np.sum(jdirs**2.0, axis=-1)) + 1e-10
                dsums = np.sqrt(np.sum(ddirs**2.0, axis=-1)) + 1e-10

                jdirs = jdirs / jsums[:, :, np.newaxis]
                ddirs = ddirs / dsums[:, :, np.newaxis]

                angles = np.arccos(np.sum(jdirs * ddirs, axis=2).clip(-1, 1))
                axises = np.cross(jdirs, ddirs)
                axises = -anim_rotations[:, j, np.newaxis] * axises

                rotations = Quaternions.from_angle_axis(angles, axises)

                if rotations.shape[1] == 1:
                    averages = rotations[:, 0]
                else:
                    averages = Quaternions.exp(rotations.log().mean(axis=-2))

                self.animation.rotations[:,
                                         j] = self.animation.rotations[:,
                                                                       j] * averages

            if not self.silent:
                anim_positions = Animation.positions_global(self.animation)
                error = np.mean(np.sum((anim_positions - self.positions)**2.0,
                                       axis=-1)**0.5,
                                axis=-1)
                print('[BasicInverseKinematics] Iteration %i Error: %f' %
                      (i + 1, error))

        return self.animation
예제 #4
0
def rotations_global(anim):
    """
    Global Animation Rotations
    
    This relies on joint ordering
    being incremental. That means a joint
    J1 must not be a ancestor of J0 if
    J0 appears before J1 in the joint
    ordering.
    
    Parameters
    ----------
    
    anim : Animation
        Input animation
        
    Returns
    -------
    
    points : (F, J) Quaternions
        global rotations for every frame F 
        and joint J
    """

    joints = np.arange(anim.shape[1])
    parents = np.arange(anim.shape[1])
    locals = anim.rotations
    globals = Quaternions.id(anim.shape)

    globals[:, 0] = locals[:, 0]

    for i in range(1, anim.shape[1]):
        globals[:, i] = globals[:, anim.parents[i]] * locals[:, i]

    return globals
예제 #5
0
def forward_rotations(skel, rotations, rtpos=None, trim=True, panda=False):
    """
    input: rotations [T, J, 4], rtpos [T, 3]
    output: positions [T, J, 3]
    """
    transforms = Quaternions(rotations).transforms()  # [..., J, 3, 3]
    glb = np.zeros(rotations.shape[:-1] + (3, ))  # [T, J, 3]
    if rtpos is not None:
        glb[..., 0, :] = rtpos

    if panda:
        # CHANGED: Removed the first bone as it is not recorded in the animation
        topology = skel.topology[1:]
    else:
        topology = skel.topology

    for i, pi in enumerate(topology):
        if pi == -1:
            continue
        glb[..., i, :] = np.matmul(transforms[..., pi, :, :], skel.offset[i])
        glb[..., i, :] += glb[..., pi, :]
        transforms[..., i, :, :] = np.matmul(transforms[..., pi, :, :],
                                             transforms[..., i, :, :])
    if not panda and trim:
        glb = glb[..., skel.chosen_joints, :]
    return glb
예제 #6
0
    def jacobian(self, x, fp, fr, goal, weights, des_r, des_t):
        """ Find parent rotations """
        prs = fr[:, self.animation.parents]
        prs[:, 0] = Quaternions.id((1))
        """ Get partial rotations """
        qys = Quaternions.from_angle_axis(x[:, 1:prs.shape[1] * 3:3],
                                          np.array([[[0, 1, 0]]]))
        qzs = Quaternions.from_angle_axis(x[:, 2:prs.shape[1] * 3:3],
                                          np.array([[[0, 0, 1]]]))
        """ Find axis of rotations """
        es = np.empty((len(x), fr.shape[1] * 3, 3))
        es[:, 0::3] = ((prs * qzs) * qys) * np.array([[[1, 0, 0]]])
        es[:, 1::3] = ((prs * qzs) * np.array([[[0, 1, 0]]]))
        es[:, 2::3] = ((prs * np.array([[[0, 0, 1]]])))
        """ Construct Jacobian """
        j = fp.repeat(3, axis=1)
        j = des_r[np.newaxis, :, :, :,
                  np.newaxis] * (goal[:, np.newaxis, :, np.newaxis] -
                                 j[:, :, np.newaxis, np.newaxis])
        j = np.sum(j * weights[np.newaxis, np.newaxis, :, :, np.newaxis], 3)
        j = self.cross(es[:, :, np.newaxis, :], j)
        j = np.swapaxes(
            j.reshape((len(x), fr.shape[1] * 3, goal.shape[1] * 3)), 1, 2)

        if self.translate:

            es = np.empty((len(x), fr.shape[1] * 3, 3))
            es[:, 0::3] = prs * np.array([[[1, 0, 0]]])
            es[:, 1::3] = prs * np.array([[[0, 1, 0]]])
            es[:, 2::3] = prs * np.array([[[0, 0, 1]]])

            jt = des_t[np.newaxis, :, :, :,
                       np.newaxis] * es[:, :, np.newaxis,
                                        np.newaxis, :].repeat(goal.shape[1],
                                                              axis=2)
            jt = np.sum(jt * weights[np.newaxis, np.newaxis, :, :, np.newaxis],
                        3)
            jt = np.swapaxes(
                jt.reshape((len(x), fr.shape[1] * 3, goal.shape[1] * 3)), 1, 2)

            j = np.concatenate([j, jt], axis=-1)

        return j
예제 #7
0
    def jacobian(self, x, fp, fr, ts, dsc, tdsc):
        """ Find parent rotations """
        prs = fr[:, self.animation.parents]
        prs[:, 0] = Quaternions.id((1))
        """ Find global positions of target joints """
        tps = fp[:, np.array(list(ts.keys()))]
        """ Get partial rotations """
        qys = Quaternions.from_angle_axis(x[:, 1:prs.shape[1] * 3:3],
                                          np.array([[[0, 1, 0]]]))
        qzs = Quaternions.from_angle_axis(x[:, 2:prs.shape[1] * 3:3],
                                          np.array([[[0, 0, 1]]]))
        """ Find axis of rotations """
        es = np.empty((len(x), fr.shape[1] * 3, 3))
        es[:, 0::3] = ((prs * qzs) * qys) * np.array([[[1, 0, 0]]])
        es[:, 1::3] = ((prs * qzs) * np.array([[[0, 1, 0]]]))
        es[:, 2::3] = ((prs * np.array([[[0, 0, 1]]])))
        """ Construct Jacobian """
        j = fp.repeat(3, axis=1)
        j = dsc[np.newaxis, :, :,
                np.newaxis] * (tps[:, np.newaxis, :] - j[:, :, np.newaxis])
        j = self.cross(es[:, :, np.newaxis, :], j)
        j = np.swapaxes(j.reshape((len(x), fr.shape[1] * 3, len(ts) * 3)), 1,
                        2)

        if self.translate:

            es = np.empty((len(x), fr.shape[1] * 3, 3))
            es[:, 0::3] = prs * np.array([[[1, 0, 0]]])
            es[:, 1::3] = prs * np.array([[[0, 1, 0]]])
            es[:, 2::3] = prs * np.array([[[0, 0, 1]]])

            jt = tdsc[np.newaxis, :, :,
                      np.newaxis] * es[:, :, np.newaxis, :].repeat(
                          tps.shape[1], axis=2)
            jt = np.swapaxes(
                jt.reshape((len(x), fr.shape[1] * 3, len(ts) * 3)), 1, 2)

            j = np.concatenate([j, jt], axis=-1)

        return j
예제 #8
0
def orients_global(anim):

    joints = np.arange(anim.shape[1])
    parents = np.arange(anim.shape[1])
    locals = anim.orients
    globals = Quaternions.id(anim.shape[1])

    globals[:, 0] = locals[:, 0]

    for i in range(1, anim.shape[1]):
        globals[:, i] = globals[:, anim.parents[i]] * locals[:, i]

    return globals
예제 #9
0
def y_rotation_from_positions(positions, hips=(2, 6), sdrs=(14, 18)):
    """
    input: positions [T, J, 3]
    output: quaters: [T, 1, 4], quaternions that rotate the character around the y-axis to face [0, 0, 1]
            pivots: [T, 1] in [0, 2pi], the angle from [0, 0, 1] to the current facing direction
    """
    across = across_from_glb(positions, hips=hips, sdrs=sdrs)
    direction_filterwidth = 20
    forward = np.cross(across, np.array([[0, 1, 0]]))
    forward = filters.gaussian_filter1d(forward, direction_filterwidth, axis=0, mode='nearest')
    forward = forward / np.sqrt((forward ** 2).sum(axis=-1))[..., np.newaxis]

    target = np.tile(np.array([0, 0, 1]), forward.shape[:-1] + (1, ))
    quaters = Quaternions.between(forward, target)[..., np.newaxis, :]  # [T, 4] -> [T, 1, 4]
    pivots = Pivots.from_quaternions(-quaters).ps  # from "target"[0, 0, 1] to current facing direction "forward"
    return quaters, pivots
예제 #10
0
def forward_rotations(skel, rotations, rtpos=None, trim=True):  #$$
    """
    input: rotations [T, J, 4], rtpos [T, 3]
    output: positions [T, J, 3]
    """
    transforms = Quaternions(rotations).transforms()  # [..., J, 3, 3]
    glb = np.zeros(rotations.shape[:-1] + (3, ))  # [T, J, 3]
    if rtpos is not None:
        glb[..., 0, :] = rtpos
    for i, pi in enumerate(skel.topology):
        if pi == -1:
            continue
        glb[..., i, :] = np.matmul(transforms[..., pi, :, :], skel.offset[i])
        glb[..., i, :] += glb[..., pi, :]
        transforms[..., i, :, :] = np.matmul(transforms[..., pi, :, :],
                                             transforms[..., i, :, :])
    if trim:
        glb = glb[..., skel.chosen_joints, :]
    return glb
예제 #11
0
    def from_rotations_and_root_positions(cls, rotations, root_positions, skel=None, frametime=1/30):
        """
        rotations: [T, J, 4]
        root_positions: [T, 3]
        """
        if skel is None:
            skel = Skel()

        rotations /= np.sqrt(np.sum(rotations ** 2, axis=-1))[..., np.newaxis]
        global_positions = forward_rotations(skel, rotations, root_positions, trim=True)
        foot_contact = foot_contact_from_positions(global_positions, fid_l=skel.fid_l, fid_r=skel.fid_r)
        quaters, pivots = y_rotation_from_positions(global_positions, hips=skel.hips, sdrs=skel.sdrs)

        root_rotations = Quaternions(rotations[:, 0:1, :].copy())  # [T, 1, 4]
        root_rotations = quaters * root_rotations  # facing [0, 0, 1]
        root_rotations = np.array(root_rotations).reshape((-1, 1, 4))  # [T, 1, 4]
        rotations[:, 0:1, :] = root_rotations

        full = np.concatenate([rotations.reshape((len(rotations), -1)), root_positions, pivots, foot_contact], axis=-1)
        return cls(full, skel, frametime)
예제 #12
0
def load_from_maya(root, start, end):
    """
    Load Animation Object from Maya Joint Skeleton    
    
    Parameters
    ----------
    
    root : PyNode
        Root Joint of Maya Skeleton
        
    start, end : int, int
        Start and End frame index of Maya Animation
    
    Returns
    -------
    
    animation : Animation
        Loaded animation from maya
        
    names : [str]
        Joint names from maya   
    """

    import pymel.core as pm

    original_time = pm.currentTime(q=True)
    pm.currentTime(start)
    """ Build Structure """

    names, parents = AnimationStructure.load_from_maya(root)
    descendants = AnimationStructure.descendants_list(parents)
    orients = Quaternions.id(len(names))
    offsets = np.array([pm.xform(j, q=True, translation=True) for j in names])

    for j, name in enumerate(names):
        scale = pm.xform(pm.PyNode(name), q=True, scale=True, relative=True)
        if len(descendants[j]) == 0: continue
        offsets[descendants[j]] *= scale
    """ Load Animation """

    eulers = np.zeros((end - start, len(names), 3))
    positions = np.zeros((end - start, len(names), 3))
    rotations = Quaternions.id((end - start, len(names)))

    for i in range(end - start):

        pm.currentTime(start + i + 1, u=True)

        scales = {}

        for j, name, parent in zip(range(len(names)), names, parents):

            node = pm.PyNode(name)

            if i == 0 and pm.hasAttr(node, 'jointOrient'):
                ort = node.getOrientation()
                orients[j] = Quaternions(
                    np.array([ort[3], ort[0], ort[1], ort[2]]))

            if pm.hasAttr(node, 'rotate'):
                eulers[i, j] = np.radians(pm.xform(node, q=True,
                                                   rotation=True))
            if pm.hasAttr(node, 'translate'):
                positions[i, j] = pm.xform(node, q=True, translation=True)
            if pm.hasAttr(node, 'scale'):
                scales[j] = pm.xform(node, q=True, scale=True, relative=True)

        for j in scales:
            if len(descendants[j]) == 0: continue
            positions[i, descendants[j]] *= scales[j]

        positions[i, 0] = pm.xform(root,
                                   q=True,
                                   translation=True,
                                   worldSpace=True)

    rotations = orients[np.newaxis] * Quaternions.from_euler(
        eulers, order='xyz', world=True)
    """ Done """

    pm.currentTime(original_time)

    return Animation(rotations, positions, orients, offsets, parents), names
예제 #13
0
def load_to_maya(anim, names=None, radius=0.5):
    """
    Load Animation Object into Maya as Joint Skeleton
    loads each frame as a new keyfame in maya.
    
    If the animation is too slow or too fast perhaps
    the framerate needs adjusting before being loaded
    such that it matches the maya scene framerate.
    
    
    Parameters
    ----------
    
    anim : Animation
        Animation to load into Scene
        
    names : [str]
        Optional list of Joint names for Skeleton
    
    Returns
    -------
    
    List of Maya Joint Nodes loaded into scene
    """

    import pymel.core as pm

    joints = []
    frames = range(1, len(anim) + 1)

    if names is None:
        names = ["joint_" + str(i) for i in range(len(anim.parents))]

    for i, offset, orient, parent, name in zip(range(len(anim.offsets)),
                                               anim.offsets, anim.orients,
                                               anim.parents, names):

        if parent < 0:
            pm.select(d=True)
        else:
            pm.select(joints[parent])

        joint = pm.joint(n=name, p=offset, relative=True, radius=radius)
        joint.setOrientation([orient[1], orient[2], orient[3], orient[0]])

        curvex = pm.nodetypes.AnimCurveTA(n=name + "_rotateX")
        curvey = pm.nodetypes.AnimCurveTA(n=name + "_rotateY")
        curvez = pm.nodetypes.AnimCurveTA(n=name + "_rotateZ")

        jrotations = (-Quaternions(orient[np.newaxis]) *
                      anim.rotations[:, i]).euler()
        curvex.addKeys(frames, jrotations[:, 0])
        curvey.addKeys(frames, jrotations[:, 1])
        curvez.addKeys(frames, jrotations[:, 2])

        pm.connectAttr(curvex.output, joint.rotateX)
        pm.connectAttr(curvey.output, joint.rotateY)
        pm.connectAttr(curvez.output, joint.rotateZ)

        offsetx = pm.nodetypes.AnimCurveTU(n=name + "_translateX")
        offsety = pm.nodetypes.AnimCurveTU(n=name + "_translateY")
        offsetz = pm.nodetypes.AnimCurveTU(n=name + "_translateZ")

        offsetx.addKeys(frames, anim.positions[:, i, 0])
        offsety.addKeys(frames, anim.positions[:, i, 1])
        offsetz.addKeys(frames, anim.positions[:, i, 2])

        pm.connectAttr(offsetx.output, joint.translateX)
        pm.connectAttr(offsety.output, joint.translateY)
        pm.connectAttr(offsetz.output, joint.translateZ)

        joints.append(joint)

    return joints
예제 #14
0
def load(filename, start=None, end=None, order=None, world=False):
    """
    Reads a BVH file and constructs an animation
    
    Parameters
    ----------
    filename: str
        File to be opened
        
    start : int
        Optional Starting Frame
        
    end : int
        Optional Ending Frame
    
    order : str
        Optional Specifier for joint order.
        Given as string E.G 'xyz', 'zxy'
        
    world : bool
        If set to true euler angles are applied
        together in world space rather than local
        space

    Returns
    -------
    
    (animation, joint_names, frametime)
        Tuple of loaded animation and joint names
    """

    f = open(filename, "r")

    i = 0
    active = -1
    end_site = False

    names = []
    orients = Quaternions.id(0)
    offsets = np.array([]).reshape((0, 3))
    parents = np.array([], dtype=int)

    for line in f:

        if "HIERARCHY" in line: continue
        if "MOTION" in line: continue

        rmatch = re.match(r"ROOT (\w+)", line)
        if rmatch:
            names.append(rmatch.group(1))
            offsets = np.append(offsets, np.array([[0, 0, 0]]), axis=0)
            orients.qs = np.append(orients.qs,
                                   np.array([[1, 0, 0, 0]]),
                                   axis=0)
            parents = np.append(parents, active)
            active = (len(parents) - 1)
            continue

        if "{" in line: continue

        if "}" in line:
            if end_site: end_site = False
            else: active = parents[active]
            continue

        offmatch = re.match(
            r"\s*OFFSET\s+([\-\d\.e]+)\s+([\-\d\.e]+)\s+([\-\d\.e]+)", line)
        if offmatch:
            if not end_site:
                offsets[active] = np.array(
                    [list(map(float, offmatch.groups()))])
            continue

        chanmatch = re.match(r"\s*CHANNELS\s+(\d+)", line)
        if chanmatch:
            channels = int(chanmatch.group(1))
            if order is None:
                channelis = 0 if channels == 3 else 3
                channelie = 3 if channels == 3 else 6
                parts = line.split()[2 + channelis:2 + channelie]
                if any([p not in channelmap for p in parts]):
                    continue
                order = "".join([channelmap[p] for p in parts])
            continue

        jmatch = re.match("\s*JOINT\s+(\w+)", line)
        if jmatch:
            names.append(jmatch.group(1))
            offsets = np.append(offsets, np.array([[0, 0, 0]]), axis=0)
            orients.qs = np.append(orients.qs,
                                   np.array([[1, 0, 0, 0]]),
                                   axis=0)
            parents = np.append(parents, active)
            active = (len(parents) - 1)
            continue

        if "End Site" in line:
            end_site = True
            continue

        fmatch = re.match("\s*Frames:\s+(\d+)", line)
        if fmatch:
            if start and end:
                fnum = (end - start) - 1
            else:
                fnum = int(fmatch.group(1))
            jnum = len(parents)
            # result: [fnum, J, 3]
            positions = offsets[np.newaxis].repeat(fnum, axis=0)
            # result: [fnum, len(orients), 3]
            rotations = np.zeros((fnum, len(orients), 3))
            continue

        fmatch = re.match("\s*Frame Time:\s+([\d\.]+)", line)
        if fmatch:
            frametime = float(fmatch.group(1))
            continue

        if (start and end) and (i < start or i >= end - 1):
            i += 1
            continue

        dmatch = line.strip().split()
        if dmatch:
            data_block = np.array(list(map(float, dmatch)))
            N = len(parents)
            fi = i - start if start else i
            if channels == 3:
                # This should be root positions[0:1] & all rotations
                positions[fi, 0:1] = data_block[0:3]
                rotations[fi, :] = data_block[3:].reshape(N, 3)
            elif channels == 6:
                data_block = data_block.reshape(N, 6)
                # fill in all positions
                positions[fi, :] = data_block[:, 0:3]
                rotations[fi, :] = data_block[:, 3:6]
            elif channels == 9:
                positions[fi, 0] = data_block[0:3]
                data_block = data_block[3:].reshape(N - 1, 9)
                rotations[fi, 1:] = data_block[:, 3:6]
                positions[fi, 1:] += data_block[:, 0:3] * data_block[:, 6:9]
            else:
                raise Exception("Too many channels! %i" % channels)

            i += 1

    f.close()

    rotations = Quaternions.from_euler(np.radians(rotations),
                                       order=order,
                                       world=world)

    return (Animation(rotations, positions, orients, offsets,
                      parents), names, frametime)
예제 #15
0
def rotations_parents_global(anim):
    rotations = rotations_global(anim)
    rotations = rotations[:, anim.parents]
    rotations[:, 0] = Quaternions.id(len(anim))
    return rotations
예제 #16
0
    def __call__(self,
                 descendants=None,
                 maxjoints=4,
                 gamma=1.0,
                 transpose=False):
        """ Calculate Masses """
        if self.weights is None:
            self.weights = np.ones(self.animation.shape[1])

        if self.weights_translate is None:
            self.weights_translate = np.ones(self.animation.shape[1])

        nf = len(self.animation)
        nj = self.animation.shape[1]
        nv = self.goal.shape[1]

        weightids = np.argsort(-self.vweights, axis=1)[:, :maxjoints]
        weightvls = np.array(
            list(map(lambda w, i: w[i], self.vweights, weightids)))
        weightvls = weightvls / weightvls.sum(axis=1)[..., np.newaxis]

        if descendants is None:
            self.descendants = AnimationStructure.descendants_mask(
                self.animation.parents)
        else:
            self.descendants = descendants

        des_r = np.eye(nj) + self.descendants
        des_r = des_r[:, weightids].repeat(3, axis=0)

        des_t = np.eye(nj) + self.descendants
        des_t = des_t[:, weightids].repeat(3, axis=0)

        if not self.silent:
            curr = Animation.skin(self.animation,
                                  self.rest,
                                  self.vweights,
                                  self.mesh,
                                  maxjoints=maxjoints)
            error = np.mean(np.sqrt(np.sum((curr - self.goal)**2.0, axis=-1)))
            print('[ICP] Start | Error: %f' % error)

        for i in range(self.iterations):
            """ Get Global Rotations & Positions """
            gt = Animation.transforms_global(self.animation)
            gp = gt[:, :, :, 3]
            gp = gp[:, :, :3] / gp[:, :, 3, np.newaxis]
            gr = Quaternions.from_transforms(gt)

            x = self.animation.rotations.euler().reshape(nf, -1)
            w = self.weights.repeat(3)

            if self.translate:
                x = np.hstack([x, self.animation.positions.reshape(nf, -1)])
                w = np.hstack([w, self.weights_translate.repeat(3)])
            """ Get Current State """
            curr = Animation.skin(self.animation,
                                  self.rest,
                                  self.vweights,
                                  self.mesh,
                                  maxjoints=maxjoints)
            """ Find Cloest Points """
            if self.find_closest:
                mapping = np.argmin((curr[:, :, np.newaxis] -
                                     self.goal[:, np.newaxis, :])**2.0,
                                    axis=2)
                e = gamma * (np.array(
                    list(map(lambda g, m: g[m], self.goal, mapping))) -
                             curr).reshape(nf, -1)
            else:
                e = gamma * (self.goal - curr).reshape(nf, -1)
            """ Generate Jacobian """
            if self.recalculate or i == 0:
                j = self.jacobian(x, gp, gr, self.goal, weightvls, des_r,
                                  des_t)
            """ Update Variables """
            l = self.damping * (1.0 / (w + 1e-10))
            d = (l * l) * np.eye(x.shape[1])

            if transpose:
                x += np.array(list(map(lambda jf, ef: jf.T.dot(ef), j, e)))
            else:
                x += np.array(
                    list(
                        map(
                            lambda jf, ef: linalg.lu_solve(
                                linalg.lu_factor(jf.T.dot(jf) + d), jf.T.dot(
                                    ef)), j, e)))
            """ Set Back Rotations / Translations """
            self.animation.rotations = Quaternions.from_euler(
                x[:, :nj * 3].reshape((nf, nj, 3)), order='xyz', world=True)

            if self.translate:
                self.animation.positions = x[:, nj * 3:].reshape((nf, nj, 3))

            if not self.silent:
                curr = Animation.skin(self.animation, self.rest, self.vweights,
                                      self.mesh)
                error = np.mean(
                    np.sqrt(np.sum((curr - self.goal)**2.0, axis=-1)))
                print('[ICP] Iteration %i | Error: %f' % (i + 1, error))
예제 #17
0
def rotationMatrixByQuaternion(rotation, order='xzy', world=False):
    return np.array(
        Quaternions.from_euler(np.radians(rotation), order=order, world=world))
예제 #18
0
def fix_foot_contact(input_file, foot_file, output_file, ref_height):
    anim, name, ftime = BVH.load(input_file)

    fid = get_ee_id_by_names(name)
    contact = get_foot_contact(foot_file, ref_height)

    glb = Animation.positions_global(anim)  # [T, J, 3]

    T = glb.shape[0]

    for i, fidx in enumerate(fid):  # fidx: index of the foot joint
        fixed = contact[:, i]  # [T]
        s = 0
        while s < T:
            while s < T and fixed[s] == 0:
                s += 1
            if s >= T:
                break
            t = s
            avg = glb[t, fidx].copy()
            while t + 1 < T and fixed[t + 1] == 1:
                t += 1
                avg += glb[t, fidx].copy()
            avg /= (t - s + 1)

            for j in range(s, t + 1):
                glb[j, fidx] = avg.copy()
            s = t + 1

        for s in range(T):
            if fixed[s] == 1:
                continue
            l, r = None, None
            consl, consr = False, False
            for k in range(L):
                if s - k - 1 < 0:
                    break
                if fixed[s - k - 1]:
                    l = s - k - 1
                    consl = True
                    break
            for k in range(L):
                if s + k + 1 >= T:
                    break
                if fixed[s + k + 1]:
                    r = s + k + 1
                    consr = True
                    break
            if not consl and not consr:
                continue
            if consl and consr:
                litp = lerp(alpha(1.0 * (s - l + 1) / (L + 1)), glb[s, fidx],
                            glb[l, fidx])
                ritp = lerp(alpha(1.0 * (r - s + 1) / (L + 1)), glb[s, fidx],
                            glb[r, fidx])
                itp = lerp(alpha(1.0 * (s - l + 1) / (r - l + 1)), ritp, litp)
                glb[s, fidx] = itp.copy()
                continue
            if consl:
                litp = lerp(alpha(1.0 * (s - l + 1) / (L + 1)), glb[s, fidx],
                            glb[l, fidx])
                glb[s, fidx] = litp.copy()
                continue
            if consr:
                ritp = lerp(alpha(1.0 * (r - s + 1) / (L + 1)), glb[s, fidx],
                            glb[r, fidx])
                glb[s, fidx] = ritp.copy()

    # glb is ready

    anim = anim.copy()

    rot = torch.tensor(anim.rotations.qs, dtype=torch.float)
    pos = torch.tensor(anim.positions[:, 0, :], dtype=torch.float)
    offset = torch.tensor(anim.offsets, dtype=torch.float)

    glb = torch.tensor(glb, dtype=torch.float)

    ik_solver = InverseKinematics(rot, pos, offset, anim.parents, glb)

    print('Fixing foot contact using IK...')
    for i in tqdm(range(50)):
        ik_solver.step()

    rotations = ik_solver.rotations.detach()
    norm = torch.norm(rotations, dim=-1, keepdim=True)
    rotations /= norm

    anim.rotations = Quaternions(rotations.numpy())
    anim.positions[:, 0, :] = ik_solver.position.detach().numpy()

    BVH.save(output_file, anim, name, ftime)
예제 #19
0
 def quaternions(self, plane='xz'):
     fa = self._ellipsis()
     axises = np.ones(self.ps.shape + (3, ))
     axises[fa + ("xyz".index(plane[0]), )] = 0.0
     axises[fa + ("xyz".index(plane[1]), )] = 0.0
     return Quaternions.from_angle_axis(self.ps, axises)
예제 #20
0
    def __call__(self, descendants=None, gamma=1.0):

        self.descendants = descendants
        """ Calculate Masses """
        if self.weights is None:
            self.weights = np.ones(self.animation.shape[1])

        if self.weights_translate is None:
            self.weights_translate = np.ones(self.animation.shape[1])
        """ Calculate Descendants """
        if self.descendants is None:
            self.descendants = AnimationStructure.descendants_mask(
                self.animation.parents)

        self.tdescendants = np.eye(self.animation.shape[1]) + self.descendants

        self.first_descendants = self.descendants[:,
                                                  np.array(
                                                      list(self.targets.keys())
                                                  )].repeat(3,
                                                            axis=0).astype(int)
        self.first_tdescendants = self.tdescendants[:,
                                                    np.array(
                                                        list(self.targets.keys(
                                                        )))].repeat(
                                                            3,
                                                            axis=0).astype(int)
        """ Calculate End Effectors """
        self.endeff = np.array(list(self.targets.values()))
        self.endeff = np.swapaxes(self.endeff, 0, 1)

        if not self.references is None:
            self.second_descendants = self.descendants.repeat(
                3, axis=0).astype(int)
            self.second_tdescendants = self.tdescendants.repeat(
                3, axis=0).astype(int)
            self.second_targets = dict([
                (i, self.references[:, i])
                for i in xrange(self.references.shape[1])
            ])

        nf = len(self.animation)
        nj = self.animation.shape[1]

        if not self.silent:
            gp = Animation.positions_global(self.animation)
            gp = gp[:, np.array(list(self.targets.keys()))]
            error = np.mean(np.sqrt(np.sum((self.endeff - gp)**2.0, axis=2)))
            print('[JacobianInverseKinematics] Start | Error: %f' % error)

        for i in range(self.iterations):
            """ Get Global Rotations & Positions """
            gt = Animation.transforms_global(self.animation)
            gp = gt[:, :, :, 3]
            gp = gp[:, :, :3] / gp[:, :, 3, np.newaxis]
            gr = Quaternions.from_transforms(gt)

            x = self.animation.rotations.euler().reshape(nf, -1)
            w = self.weights.repeat(3)

            if self.translate:
                x = np.hstack([x, self.animation.positions.reshape(nf, -1)])
                w = np.hstack([w, self.weights_translate.repeat(3)])
            """ Generate Jacobian """
            if self.recalculate or i == 0:
                j = self.jacobian(x, gp, gr, self.targets,
                                  self.first_descendants,
                                  self.first_tdescendants)
            """ Update Variables """
            l = self.damping * (1.0 / (w + 0.001))
            d = (l * l) * np.eye(x.shape[1])
            e = gamma * (
                self.endeff.reshape(nf, -1) -
                gp[:, np.array(list(self.targets.keys()))].reshape(nf, -1))

            x += np.array(
                list(
                    map(
                        lambda jf, ef: linalg.lu_solve(
                            linalg.lu_factor(jf.T.dot(jf) + d), jf.T.dot(ef)),
                        j, e)))
            """ Generate Secondary Jacobian """
            if self.references is not None:

                ns = np.array(
                    list(
                        map(
                            lambda jf: np.eye(x.shape[1]) - linalg.solve(
                                jf.T.dot(jf) + d, jf.T.dot(jf)), j)))

                if self.recalculate or i == 0:
                    j2 = self.jacobian(x, gp, gr, self.second_targets,
                                       self.second_descendants,
                                       self.second_tdescendants)

                e2 = self.secondary * (self.references.reshape(nf, -1) -
                                       gp.reshape(nf, -1))

                x += np.array(
                    list(
                        map(
                            lambda nsf, j2f, e2f: nsf.dot(
                                linalg.lu_solve(
                                    linalg.lu_factor(j2f.T.dot(j2f) + d),
                                    j2f.T.dot(e2f))), ns, j2, e2)))
            """ Set Back Rotations / Translations """
            self.animation.rotations = Quaternions.from_euler(
                x[:, :nj * 3].reshape((nf, nj, 3)), order='xyz', world=True)

            if self.translate:
                self.animation.positions = x[:, nj * 3:].reshape((nf, nj, 3))
            """ Generate Error """

            if not self.silent:
                gp = Animation.positions_global(self.animation)
                gp = gp[:, np.array(list(self.targets.keys()))]
                error = np.mean(np.sum((self.endeff - gp)**2.0, axis=2)**0.5)
                print('[JacobianInverseKinematics] Iteration %i | Error: %f' %
                      (i + 1, error))