def create_motion_by_following(self, nodes): motion = velocity.MotionWithVelocity(skel=self.skel, fps=self.fps) for i in range(len(nodes) - 1): n1 = nodes[i] n2 = nodes[i + 1] nodes_inbetween = nx.shortest_path(self.graph, n1, n2) range_nodes = ( range(len(nodes_inbetween)) if i == len(nodes) - 2 else range(len(nodes_inbetween) - 1) ) for j in range_nodes: n = nodes_inbetween[j] motion_idx = self.graph.nodes[n]["motion_idx"] frame_start = self.graph.nodes[n]["frame_start"] frame_end = self.graph.nodes[n]["frame_end"] if self.motions[motion_idx] is None: self.load_motion_at_idx( motion_idx, self.motion_files[motion_idx] ) m = self.motions[motion_idx].detach( frame_start, frame_end + self.frames_blend ) motion = motion_ops.append_and_blend( motion, m, blend_length=self.blend_length, ) return motion
def create_random_motion(self, length, start_node=None): """ This funtion generate a motion from the given motion graph by randomly traversing the graph. length - length of the generated motion start_node - we can specify a start node if necessary """ motion = velocity.MotionWithVelocity(skel=self.skel) t_processed = 0.0 nodes = list(self.graph.nodes) if start_node is None or start_node not in self.graph.nodes: cur_node = random.choice(nodes) else: cur_node = start_node visited_nodes = [] while t_processed < length: # Record currently visiting node visited_nodes.append(cur_node) # Append the selected motion to the current motion motion_idx = self.graph.nodes[cur_node]["motion_idx"] frame_start = self.graph.nodes[cur_node]["frame_start"] frame_end = self.graph.nodes[cur_node]["frame_end"] # Load the motion if it is not loaded in advance if self.motions[motion_idx] is None: self.load_motion_at_idx(motion_idx, self.motion_files[motion_idx]) """ We should detach with the extra (frames_blend) because motion.append affects the end of current motion """ m = motion_ops.cut( self.motions[motion_idx], frame_start, frame_end + self.frames_blend, ) if self.verbose: logging.info(f"[{cur_node}] {self.graph.nodes[cur_node]}") motion = motion_ops.append_and_blend( motion, m, blend_length=self.blend_length, ) t_processed = motion.length() # Jump to adjacent node (motion) randomly if self.graph.out_degree(cur_node) == 0: if self.verbose: logging.info("Dead-end exists in the graph!") break cur_node = random.choice(list(self.graph.successors(cur_node))) return motion, visited_nodes
def load_motion_at_idx(self, idx, file): motion = velocity.MotionWithVelocity(skel=self.skel) motion = bvh.load( file=file, motion=motion, scale=self.scale, load_skel=self.skel is None, v_up_skel=self.skel.v_up, v_face_skel=self.skel.v_face, v_up_env=self.skel.v_up_env, ) motion.resample(fps=self.fps) self.motions[idx] = motion if self.verbose: logging.info(f"Loaded: {file}")
def motionify(self, nodes): """ Turn a list of nodes into motion. """ motion = velocity.MotionWithVelocity(skel=self.skel, fps=self.fps) t_processed = 0.0 cur_node = nodes[0] for motion_idx in nodes[1:]: # Append the selected motion to the current motion motion_idx = self.graph.nodes[cur_node]["motion_idx"] frame_start = self.graph.nodes[cur_node]["frame_start"] frame_end = self.graph.nodes[cur_node]["frame_end"] # Load the motion if it is not loaded in advance if self.motions[motion_idx] is None: self.load_motion_at_idx(motion_idx, self.motion_files[motion_idx]) """ We should detach with the extra (frames_blend) because motion.append affects the end of current motion """ m = motion_ops.cut( self.motions[motion_idx], frame_start, frame_end + self.frames_blend, ) if self.verbose: logging.info(f"[{cur_node}] {self.graph.nodes[cur_node]}") # motion = motion_ops.append( # motion, m # ) motion = motion_ops.append_and_blend( motion, m, blend_length=self.blend_length, ) return motion