def calc_direction_qq(bf: VmdBoneFrame, motion: VmdMotion, joints: dict, direction_from_name: str, direction_to_name: str, up_from_name: str, up_to_name: str): direction_from_vec = get_vec3(joints["joints"], direction_from_name) direction_to_vec = get_vec3(joints["joints"], direction_to_name) up_from_vec = get_vec3(joints["joints"], up_from_name) up_to_vec = get_vec3(joints["joints"], up_to_name) direction = (direction_to_vec - direction_from_vec).normalized() up = (up_to_vec - up_from_vec).normalized() cross = MVector3D.crossProduct(direction, up) qq = MQuaternion.fromDirection(direction, cross) return qq
def calc_bone_direction_qq2(bf: VmdBoneFrame, motion: VmdMotion, model: PmxModel, jname: str, direction_from_name: str, direction_to_name: str, up_from_name: str, up_to_name: str, cross_from_name: str, cross_to_name: str): direction_from_vec = get_bone_vec3(model, direction_from_name) direction_to_vec = get_bone_vec3(model, direction_to_name) up_from_vec = get_bone_vec3(model, up_from_name) up_to_vec = get_bone_vec3(model, up_to_name) cross_from_vec = get_bone_vec3(model, cross_from_name) cross_to_vec = get_bone_vec3(model, cross_to_name) direction = (direction_to_vec - direction_from_vec).normalized() up = (up_to_vec - up_from_vec).normalized() cross = (cross_to_vec - cross_from_vec).normalized() qq = MQuaternion.fromDirection(direction, MVector3D.crossProduct(up, cross)) return qq
def execute(cmd_args): folder_path = cmd_args.folder_path bone_csv_path = cmd_args.bone_csv_path model = read_bone_csv(bone_csv_path) logger.info(model) motion = VmdMotion() # 動画上の関節位置 for fno, joints_path in enumerate( glob.glob(osp.join(folder_path, '**/*_joints.json'))): logger.info(f"■ fno: {fno} -----") frame_joints = {} with open(joints_path, 'r') as f: frame_joints = json.load(f) bf = VmdBoneFrame(fno) bf.set_name("センター") bf.position = calc_center(frame_joints) motion.regist_bf(bf, bf.name, bf.fno) for jname, (bone_name, calc_bone, name_list, parent_list, ranges) in VMD_CONNECTIONS.items(): if name_list is None: continue bf = VmdBoneFrame(fno) bf.set_name(bone_name) if calc_bone is None: if len(name_list) == 4: rotation = calc_direction_qq(bf.fno, motion, frame_joints, *name_list) initial = calc_bone_direction_qq(bf, motion, model, jname, *name_list) else: rotation = calc_direction_qq2(bf.fno, motion, frame_joints, *name_list) initial = calc_bone_direction_qq2(bf, motion, model, jname, *name_list) qq = MQuaternion() for parent_name in reversed(parent_list): qq *= motion.calc_bf(parent_name, bf.fno).rotation.inverted() qq = qq * rotation * initial.inverted() if ranges: # 可動域指定がある場合 x_qq, y_qq, z_qq, _ = separate_local_qq( bf.fno, bf.name, qq, model.get_local_x_axis(bf.name)) local_x_axis = model.get_local_x_axis(bf.name) local_z_axis = MVector3D( 0, 0, -1 * (-1 if "right" in jname else 1)) local_y_axis = MVector3D.crossProduct( local_x_axis, local_z_axis) x_limited_qq = MQuaternion.fromAxisAndAngle( local_x_axis, max( ranges["x"]["min"], min( ranges["x"]["max"], x_qq.toDegree() * MVector3D.dotProduct( local_x_axis, x_qq.vector())))) y_limited_qq = MQuaternion.fromAxisAndAngle( local_y_axis, max( ranges["y"]["min"], min( ranges["y"]["max"], y_qq.toDegree() * MVector3D.dotProduct( local_y_axis, y_qq.vector())))) z_limited_qq = MQuaternion.fromAxisAndAngle( local_z_axis, max( ranges["z"]["min"], min( ranges["z"]["max"], z_qq.toDegree() * MVector3D.dotProduct( local_z_axis, z_qq.vector())))) bf.rotation = y_limited_qq * x_limited_qq * z_limited_qq else: bf.rotation = qq motion.regist_bf(bf, bf.name, bf.fno) # 動画内の半分は地面に足が着いていると見なす center_values = np.zeros((1, 3)) for bf in motion.bones["センター"].values(): center_values = np.insert( center_values, 0, np.array([bf.position.x(), bf.position.y(), bf.position.z()]), axis=0) center_median = np.median(center_values, axis=0) for bf in motion.bones["センター"].values(): bf.position.setY(bf.position.y() - center_median[1]) writer = VmdWriter( motion, model, osp.join( folder_path, "output_{0}.vmd".format( datetime.datetime.now().strftime('%Y%m%d_%H%M%S')))) writer.write()