Beispiel #1
0
def rotationMatrixByQuaternion(rotation, order='xzy', world=False):
    return np.array(
        Quaternions.from_euler(np.radians(rotation), order=order, world=world))
Beispiel #2
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)
Beispiel #3
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))
Beispiel #4
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))
Beispiel #5
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