def interpolate_rot_circle(self, prev_bf: VmdBoneFrame,
                               now_bf: VmdBoneFrame, next_bf: VmdBoneFrame,
                               target_bf: VmdBoneFrame, local_axis: MVector3D):
        if local_axis != MVector3D():
            # 軸がある場合、その方向に回す
            p_qq = MQuaternion.fromAxisAndAngle(local_axis,
                                                prev_bf.rotation.toDegree())
            w_qq = MQuaternion.fromAxisAndAngle(local_axis,
                                                now_bf.rotation.toDegree())
            n_qq = MQuaternion.fromAxisAndAngle(local_axis,
                                                next_bf.rotation.toDegree())

            p = p_qq.toEulerAngles()
            w = w_qq.toEulerAngles()
            n = n_qq.toEulerAngles()
        else:
            p_qq = prev_bf.rotation.copy()
            w_qq = now_bf.rotation.copy()
            n_qq = next_bf.rotation.copy()

            # 軸がない場合、そのまま回転
            p = p_qq.toEulerAngles()
            w = w_qq.toEulerAngles()
            n = n_qq.toEulerAngles()

        if target_bf.fno < now_bf.fno:
            # 変化量
            t = (target_bf.fno - prev_bf.fno) / (now_bf.fno - prev_bf.fno)

            # デフォルト値
            d_qq = MQuaternion.slerp(p_qq, w_qq, t)
            d = d_qq.toEulerAngles()

            out = interpolate_vec3(p, w, n, d, t, target_bf.fno)
        else:
            # 変化量
            t = (target_bf.fno - now_bf.fno) / (next_bf.fno - now_bf.fno)

            # デフォルト値
            d_qq = MQuaternion.slerp(w_qq, n_qq, t)
            d = d_qq.toEulerAngles()

            out = interpolate_vec3(w, n, p, d, t, target_bf.fno)

        out_qq = MQuaternion.fromEulerAngles(out.x(), out.y(), out.z())

        if local_axis != MVector3D():
            # 回転を元に戻す
            if target_bf.fno < now_bf.fno:
                d2_qq = MQuaternion.slerp(prev_bf.rotation, now_bf.rotation, t)
            else:
                d2_qq = MQuaternion.slerp(now_bf.rotation, next_bf.rotation, t)

            result_qq = (d_qq.inverted() * out_qq * d2_qq)
        else:
            result_qq = out_qq

        target_bf.rotation = result_qq
Exemple #2
0
    def smooth_bf(self, data_set_no: int, bone_name: str, is_rot: bool, is_mov: bool, limit_degrees: float, start_fno=-1, end_fno=-1, is_show_log=True):
        # キーフレを取得する
        if start_fno < 0 and end_fno < 0:
            # 範囲指定がない場合、全範囲
            fnos = self.get_bone_fnos(bone_name)
        else:
            # 範囲指定がある場合はその範囲内だけ
            fnos = self.get_bone_fnos(bone_name, start_fno=start_fno, end_fno=end_fno)

        prev_sep_fno = 0
        if len(fnos) > 2:
            for fno in fnos:
                prev_bf = self.calc_bf(bone_name, fno - 1)
                now_bf = self.calc_bf(bone_name, fno)
                next_bf = self.calc_bf(bone_name, fno + 1)

                if is_rot and now_bf.key:
                    # 前後の内積
                    prev_next_dot = MQuaternion.dotProduct(prev_bf.rotation, next_bf.rotation)
                    # 自分と後の内積
                    now_next_dot = MQuaternion.dotProduct(now_bf.rotation, next_bf.rotation)
                    # 内積差分
                    diff = np.abs(np.diff([prev_next_dot, now_next_dot]))
                    logger.test("set: %s, %s, f: %s, diff: %s, prev_next_dot: %s, now_next_dot: %s", data_set_no, bone_name, fno, diff, prev_next_dot, now_next_dot)

                    # 前後と自分の内積の差が一定以上の場合、円滑化
                    if prev_next_dot > now_next_dot and diff > math.radians(limit_degrees):
                        logger.debug("★ 円滑化 set: %s, %s, f: %s, diff: %s, prev_next_dot: %s, now_next_dot: %s", \
                                     data_set_no, bone_name, fno, diff, prev_next_dot, now_next_dot)

                        now_bf.rotation = MQuaternion.slerp(prev_bf.rotation, next_bf.rotation, ((now_bf.fno - prev_bf.fno) / (next_bf.fno - prev_bf.fno)))
                
                if is_show_log and data_set_no > 0 and fno // 500 > prev_sep_fno and fnos[-1] > 0:
                    logger.info("-- %sフレーム目:終了(%s%)【No.%s - 円滑化 - %s】", fno, round((fno / fnos[-1]) * 100, 3), data_set_no, bone_name)
                    prev_sep_fno = fno // 500
Exemple #3
0
    def calc_bf_rot(self, prev_bf: VmdBoneFrame, fill_bf: VmdBoneFrame, next_bf: VmdBoneFrame):
        if prev_bf.rotation != next_bf.rotation:
            # 回転補間曲線
            rx, ry, rt = MBezierUtils.evaluate(next_bf.interpolation[MBezierUtils.R_x1_idxs[3]], next_bf.interpolation[MBezierUtils.R_y1_idxs[3]], \
                                               next_bf.interpolation[MBezierUtils.R_x2_idxs[3]], next_bf.interpolation[MBezierUtils.R_y2_idxs[3]], \
                                               prev_bf.fno, fill_bf.fno, next_bf.fno)
            return MQuaternion.slerp(prev_bf.rotation, next_bf.rotation, ry)

        return prev_bf.rotation.copy()
def interpolate_vec3(op: MVector3D, ow: MVector3D, on: MVector3D, d: MVector3D,
                     t: float, f: int):
    # 念のためコピー
    p = op.copy()
    w = ow.copy()
    n = on.copy()

    # 半径は3点間の距離の最長の半分
    r = max(p.distanceToPoint(w), p.distanceToPoint(n),
            w.distanceToPoint(n)) / 2

    logger.test("op: %s, ow: %s, on: %s, d: %s, t: %s, f: %s, r: %s",
                p.to_log(), w.to_log(), n.to_log(), d.to_log(), t, f, r)

    if r == 0:
        # 半径が取れなかった場合、そもそもまったく移動がないので、線分移動
        return (p + n) * t

    if p == w or p == n or w == n:
        # 半径が0の場合か、どれか同じ値の場合、線対称な値を使用する
        n = d

    # 3点を通る球体の原点を求める
    c, radius = calc_sphere_center(p, w, n, r)

    if radius == 0:
        # 半径が取れなかった場合、そもそもまったく移動がないので、線分移動
        return (p + n) * t

    # prev -> now の t分の回転量
    pn_qq = MQuaternion.rotationTo((p - c).normalized(), (c - c).normalized())
    pw_qq = MQuaternion.rotationTo((p - c).normalized(), (w - c).normalized())
    # 球形補間の移動量
    t_qq = MQuaternion.slerp(pn_qq, pw_qq, t)

    logger.test("(p - c): %s, (c - c): %s, (w - c): %s", (p - c).normalized(),
                (c - c).normalized(), (w - c).normalized())
    logger.test("pn_qq: %s, pw: %s, t: %s", pn_qq, pw_qq, t_qq)

    out = t_qq * (p - c) + c

    # 値の変化がない場合、上書き
    if p.x() == w.x() == n.x():
        out.setX(w.x())
    if p.y() == w.y() == n.y():
        out.setY(w.y())
    if p.z() == w.z() == n.z():
        out.setZ(w.z())

    out.effective()

    logger.test(out.to_log())

    return out