def compile(self, col, mkr_list, attr_list, withtest=False): assert isinstance(withtest, bool) # Options to affect how the solve is constructed. use_single_frame = self.get_use_single_frame() single_frame = self.get_single_frame() frame_list = self.get_frame_list() anim_iter_num = self.get_anim_iteration_num() lineup_iter_num = self.get_lineup_iteration_num() use_euler_filter = self._use_euler_filter precomputed_data = self.get_precomputed_data() if use_single_frame is True: # Single frame solve sol = solverstep.SolverStep() sol.set_max_iterations(lineup_iter_num) sol.set_frame_list([single_frame]) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(False) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(False) sol.set_use_stiffness(False) sol.set_precomputed_data(precomputed_data) for action, vaction in sol.compile(col, mkr_list, attr_list, withtest=withtest): yield (action, vaction) else: # Multiple frame solve, per-frame vaction_cache = api_compile.create_compile_solver_cache() for i, frm in enumerate(frame_list): is_first_frame = i == 0 one_frame_list = [frm] sol = solverstep.SolverStep() sol.set_max_iterations(anim_iter_num) sol.set_frame_list(one_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(False) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(not is_first_frame) sol.set_use_stiffness(not is_first_frame) sol.set_precomputed_data(precomputed_data) generator = api_compile.compile_solver_with_cache( sol, col, mkr_list, attr_list, withtest, vaction_cache) for action, vaction in generator: yield action, vaction # Perform an euler filter on all unlocked rotation attributes. if use_euler_filter is True: generator = solverutils.compile_euler_filter( attr_list, withtest) for action, vaction in generator: yield action, vaction return
def _compile_single_frame(mkr_list, attr_list, single_frame, block_iter_num, lineup_iter_num, auto_attr_blocks, test, verbose): if auto_attr_blocks is True: meta_mkr_list, meta_attr_list = _split_mkr_attr_into_categories( mkr_list, attr_list ) for new_mkr_list, new_attr_list in zip(meta_mkr_list, meta_attr_list): sol = solverstep.SolverStep() sol.set_verbose(verbose) sol.set_max_iterations(block_iter_num) sol.set_frame_list([single_frame]) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, new_mkr_list, new_attr_list, test, cache ) for action, vaction in generator: yield action, vaction # Single frame solve sol = solverstep.SolverStep() sol.set_verbose(verbose) sol.set_max_iterations(lineup_iter_num) sol.set_frame_list([single_frame]) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, mkr_list, attr_list, test, cache ) for action, vaction in generator: yield action, vaction return
def compile_solver_affects(col, mkr_list, attr_list, precomputed_data, withtest): sol = solveraffects.SolverAffects() sol.set_precomputed_data(precomputed_data) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache(sol, col, mkr_list, attr_list, withtest, cache) for action, vaction in generator: yield action, vaction return
def _compile_multi_inbetween_frames(mkr_list, attr_list, all_frame_list, global_solve, anim_iter_num, test, verbose): if global_solve is True: # Do Global Solve with all frames. sol = solverstep.SolverStep() sol.set_verbose(verbose) sol.set_max_iterations(anim_iter_num) sol.set_frame_list(all_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, mkr_list, attr_list, test, cache ) for action, vaction in generator: yield action, vaction else: cache = api_compile.create_compile_solver_cache() for frm in all_frame_list: one_frame_list = [frm] sol = solverstep.SolverStep() sol.set_verbose(verbose) sol.set_max_iterations(anim_iter_num) sol.set_frame_list(one_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(False) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) generator = api_compile.compile_solver_with_cache( sol, mkr_list, attr_list, test, cache ) for action, vaction in generator: yield action, vaction return
def compile_solver_affects(col, mkr_list, attr_list, precomputed_data, withtest): # Reset the used hints to 'unknown' before setting 'used' or # 'unused' flags. generator = compile_reset_used_hints(col, mkr_list, attr_list) for action, vaction in generator: yield action, vaction sol = solveraffects.SolverAffects() sol.set_precomputed_data(precomputed_data) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache(sol, col, mkr_list, attr_list, withtest, cache) for action, vaction in generator: yield action, vaction return
def compile(self, mkr_list, attr_list, withtest=False): assert isinstance(withtest, bool) # Options to affect how the solve is constructed. use_single_frame = self.get_use_single_frame() single_frame = self.get_single_frame() frame_list = self.get_frame_list() anim_iter_num = self.get_anim_iteration_num() lineup_iter_num = self.get_lineup_iteration_num() verbose = True actions = [] if use_single_frame is True: # Single frame solve sol = solverstep.SolverStep() sol.set_verbose(verbose) sol.set_max_iterations(lineup_iter_num) sol.set_frame_list([single_frame]) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(False) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) for action, vaction in sol.compile(mkr_list, attr_list, withtest=withtest): yield (action, vaction) else: # Multiple frame solve, per-frame vaction_cache = api_compile.create_compile_solver_cache() for frm in frame_list: one_frame_list = [frm] sol = solverstep.SolverStep() sol.set_verbose(verbose) sol.set_max_iterations(anim_iter_num) sol.set_frame_list(one_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(False) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) generator = api_compile.compile_solver_with_cache( sol, mkr_list, attr_list, withtest, vaction_cache) for action, vaction in generator: yield action, vaction return
def _compile_multi_root_frames(mkr_list, attr_list, batch_frame_list, root_iter_num, withtest, verbose): # Solve root frames. for frm_list in batch_frame_list: # Get root markers root_mkr_list, non_root_mkr_list = _filter_mkr_list_by_frame_list( mkr_list, frm_list ) assert len(root_mkr_list) > 0 mkr_attr_map = markerutils.find_marker_attr_mapping( root_mkr_list, attr_list ) root_attr_list = [] for i, mkr in enumerate(root_mkr_list): for j, attr in enumerate(attr_list): x = mkr_attr_map[i][j] if x is True and attr not in root_attr_list: root_attr_list.append(attr) sol = solverstep.SolverStep() sol.set_verbose(verbose) sol.set_max_iterations(root_iter_num) sol.set_frame_list(frm_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, root_mkr_list, root_attr_list, withtest, cache, ) for action, vaction in generator: yield action, vaction return
def _compile_single_frame(col, mkr_list, attr_list, single_frame, block_iter_num, lineup_iter_num, auto_attr_blocks, precomputed_data, withtest, verbose): """ Compile to Actions for a solve of a single frame. :param mkr_list: Markers to be solved with. :type mkr_list: [Marker, ..] :param attr_list: Attributes to be solved. :type attr_list: [Attribute, ..] :param single_frame: The Frame to solve on. :type single_frame: Frame :param auto_attr_blocks: Split attributes into stages (based on categories) to be solved together. :type auto_attr_blocks: bool :param block_iter_num: How many iterations to perform for attribute categories. :type block_iter_num: int :param lineup_iter_num: pass :type lineup_iter_num: int :param withtest: Should validation tests be generated? :type withtest: bool :param verbose: Print out more detail than usual. :type verbose: bool :return: Yields a generator of two Actions. First Action is for solving, the second Action is for validation of inputs. :rtype: (Action, Action) """ if auto_attr_blocks is True: meta_mkr_list, meta_attr_list = _split_mkr_attr_into_categories( mkr_list, attr_list) for new_mkr_list, new_attr_list in zip(meta_mkr_list, meta_attr_list): sol = solverstep.SolverStep() sol.set_max_iterations(block_iter_num) sol.set_frame_list([single_frame]) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(False) sol.set_use_stiffness(False) sol.set_precomputed_data(precomputed_data) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, col, new_mkr_list, new_attr_list, withtest, cache) for action, vaction in generator: yield action, vaction # Single frame solve sol = solverstep.SolverStep() sol.set_max_iterations(lineup_iter_num) sol.set_frame_list([single_frame]) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(False) sol.set_use_stiffness(False) sol.set_precomputed_data(precomputed_data) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache(sol, col, mkr_list, attr_list, withtest, cache) for action, vaction in generator: yield action, vaction return
def _compile_multi_frame(col, mkr_list, attr_list, root_frame_list, frame_list, auto_attr_blocks, block_iter_num, only_root_frames, root_iter_num, anim_iter_num, global_solve, root_frame_strategy, triangulate_bundles, use_euler_filter, precomputed_data, withtest, verbose): """ Generate Actions to solve multiple-frames. :param mkr_list: Markers to be solved with. :type mkr_list: [Marker, ..] :param attr_list: Attributes to be solved. :type attr_list: [Attribute, ..] :param root_frame_list: Frames to solve static and animated attributes. :type root_frame_list: [[Frame, ..], ..] :param frame_list: Frames to solve animated attributes. :type frame_list: [Frame, ..] :param auto_attr_blocks: Split attributes into stages (based on categories) to be solved together. :type auto_attr_blocks: bool :param block_iter_num: How many iterations to perform for attribute categories. :type block_iter_num: int :param only_root_frames: Only solve the root frames. :param only_root_frames: bool :param root_iter_num: Number of iterations for root frame solves. :type root_iter_num: int :param anim_iter_num: Number of iterations for animated attribute solves. :type anim_iter_num: int :param global_solve: Should all frames be solved together, both animated and static attributes? :type global_solve: bool :param root_frame_strategy: The strategy ordering of root frames and how to solve them. Value must be one in ROOT_FRAME_STRATEGY_VALUE_LIST :type root_frame_strategy: :param triangulate_bundles: If True, unlocked bundles will be triangulated before being further refined by the solver processes. :type triangulate_bundles: bool :param use_euler_filter: Perform a Euler Filter after solving? A Euler filter will make sure no two keyframes rotate by more than 180 degrees, which will remove "Euler Flipping". :type use_euler_filter: bool :param withtest: Should validation tests be generated? :type withtest: bool :param verbose: Print out more detail than usual. :type verbose: bool :return: Yields a generator of two Actions. First Action is for solving, the second Action is for validation of inputs. :rtype: (Action, Action) """ root_frame_list_num = [x.get_number() for x in root_frame_list] frame_list_num = [x.get_number() for x in frame_list] non_root_frame_list_num = set(frame_list_num) - set(root_frame_list_num) non_root_frame_list = [frame.Frame(x) for x in non_root_frame_list_num] all_frame_list_num = list(set(frame_list_num + root_frame_list_num)) all_frame_list_num = list(sorted(all_frame_list_num)) all_frame_list = [frame.Frame(x) for x in all_frame_list_num] start_frame = all_frame_list[0] end_frame = all_frame_list[-1] # Triangulate the (open) bundles here. We triangulate all # valid bundles after the root frames have solved. # # NOTE: Bundle triangulation can only happen if the camera # is not nodal. if triangulate_bundles is True: sol = solvertriangulate.SolverTriangulate() # sol.root_frame_list = root_frame_list_num cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, col, mkr_list, attr_list, withtest, cache) for action, vaction in generator: yield action, vaction # Solver root frames, breaking attributes into little blocks # to solve. root_mkr_list, non_root_mkr_list = _filter_mkr_list_by_frame_list( mkr_list, root_frame_list) if len(root_mkr_list) == 0: # TODO: Test we have enough markers to solve with, if not warn # the user. # action = api_action.Action(func='pass', args=[], kwargs={}) # vaction = api_action.Action(func='', args=[], kwargs={}) # yield action, vaction LOG.warn("Not enough Markers given for root frames.") return if auto_attr_blocks is True: meta_mkr_list, meta_attr_list = _split_mkr_attr_into_categories( root_mkr_list, attr_list) for new_mkr_list, new_attr_list in zip(meta_mkr_list, meta_attr_list): sol = solverstep.SolverStep() sol.set_max_iterations(block_iter_num) sol.set_frame_list(root_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(False) sol.set_use_stiffness(False) sol.set_precomputed_data(precomputed_data) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, col, new_mkr_list, new_attr_list, withtest, cache) for action, vaction in generator: yield action, vaction # TODO: Create a list of markers specially for root frames. # Loop over all given markers, determine which markers have 2 # or more root frames, only use those markers for root frame # computation. Overall, we must filter out all markers that # cannot/should not be used for different solves. # # TODO: We must make sure to allow the solver to detect that # not enough markers are being used, and warn the user. # # TODO: All markers that do not have enough root frames to solve # correctly, but the Bundle is still in the solver, then it should # be triangulated after the initial root frame solve is performed. # # TODO: Run the solver multiple times for a hierarchy. First, # solve DAG level 0 nodes, then add DAG level 1, then level 2, # etc. This will allow us to incrementally add solving of # hierarchy, without getting the optimiser confused which # attributes to solve first to get a stable solve. if root_frame_strategy == const.ROOT_FRAME_STRATEGY_GLOBAL_VALUE: # Global solve of root frames. sol = solverstep.SolverStep() sol.set_max_iterations(root_iter_num) sol.set_frame_list(root_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(False) sol.set_use_stiffness(False) sol.set_precomputed_data(precomputed_data) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, col, root_mkr_list, attr_list, withtest, cache) for action, vaction in generator: yield action, vaction else: # Get the order of frames to solve with. batch_frame_list = [] if root_frame_strategy == const.ROOT_FRAME_STRATEGY_FWD_PAIR_VALUE: # Two frames at a time, moving forward, plus a global solve # at the end. batch_frame_list = _gen_two_frame_fwd(root_frame_list_num) batch_frame_list.append(root_frame_list) elif root_frame_strategy == const.ROOT_FRAME_STRATEGY_FWD_PAIR_AND_GLOBAL_VALUE: # Two frames at a time, moving forward. batch_frame_list = _gen_two_frame_fwd(root_frame_list_num) else: # TODO: Root frame ordering can be determined by the # count of markers available at each frame. After we # have an ordering of these frames, we can solve the # frames incrementally, starting with the first # highest, then add the next highest, etc. This # should ensure stability of the solver is maximum. raise NotImplementedError generator = _compile_multi_root_frames(col, mkr_list, attr_list, batch_frame_list, root_iter_num, precomputed_data, withtest, verbose) for action, vaction in generator: yield action, vaction # Clear out all the frames between the solved root frames, this # helps us use the new solve root frames to hint the 'in-between' # frame solve. generator = _compile_remove_inbetween_frames(attr_list, non_root_frame_list, start_frame, end_frame, withtest, verbose) for action, vaction in generator: yield action, vaction if only_root_frames is True: return # Perform an euler filter on all unlocked rotation attributes. if use_euler_filter is True: generator = solverutils.compile_euler_filter(attr_list, withtest) for action, vaction in generator: yield action, vaction generator = _compile_multi_inbetween_frames( col, mkr_list, attr_list, all_frame_list, global_solve, anim_iter_num, precomputed_data, withtest, verbose, ) for action, vaction in generator: yield action, vaction return
def _compile_multi_inbetween_frames(col, mkr_list, attr_list, all_frame_list, global_solve, anim_iter_num, precomputed_data, withtest, verbose): """ Solve only animated attributes on frames between the root frames. :param mkr_list: Markers to be solved with. :type mkr_list: [Marker, ..] :param attr_list: Attributes to be solved. :type attr_list: [Attribute, ..] :param all_frame_list: List of Frames to be solved. :type all_frame_list: [Frame, ..] :param global_solve: If True, all attributes and frames will be solved as a single solve, rather than one solve per-frame. :type global_solve: bool :param anim_iter_num: Number of iterations for solving animated attributes. :type anim_iter_num: int :param withtest: Should validation tests be generated? :type withtest: bool :param verbose: Print out more detail than usual. :type verbose: bool :return: Yields a generator of two Actions. First Action is for solving, the second Action is for validation of inputs. :rtype: (Action, Action) """ if global_solve is True: # Do Global Solve with all frames. sol = solverstep.SolverStep() sol.set_max_iterations(anim_iter_num) sol.set_frame_list(all_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(False) sol.set_use_stiffness(False) sol.set_precomputed_data(precomputed_data) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, col, mkr_list, attr_list, withtest, cache) for action, vaction in generator: yield action, vaction else: cache = api_compile.create_compile_solver_cache() for i, frm in enumerate(all_frame_list): is_first_frame = i == 0 one_frame_list = [frm] sol = solverstep.SolverStep() sol.set_max_iterations(anim_iter_num) sol.set_frame_list(one_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(False) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(not is_first_frame) sol.set_use_stiffness(not is_first_frame) sol.set_precomputed_data(precomputed_data) generator = api_compile.compile_solver_with_cache( sol, col, mkr_list, attr_list, withtest, cache) for action, vaction in generator: yield action, vaction return
def _compile_multi_root_frames(col, mkr_list, attr_list, batch_frame_list, root_iter_num, precomputed_data, withtest, verbose): """ Compile actions for solving Root frames. :param mkr_list: List of Markers to use for Root frames. :type mkr_list: [Marker, ..] :param attr_list: List of Attributes to use for Root frames. :type attr_list: [Attribute, ..] :param batch_frame_list: List of frame lists to be computed successively. :type batch_frame_list: [[int, ..], ..] :param root_iter_num: Number of iterations to use, when solving root frames. :type root_iter_num: int :param withtest: Compile the test/validation Action, as well as the solve Action? :type withtest: bool :param verbose: Print out more detail to 'stderr'. :type verbose: bool :return: Yields two Actions at each iteration; first Action is for solving, second Action is to validate the inputs given. :rtype: (Action, Action or None) """ # Solve root frames. for frm_list in batch_frame_list: # Get root markers root_mkr_list, non_root_mkr_list = _filter_mkr_list_by_frame_list( mkr_list, frm_list) assert len(root_mkr_list) > 0 mkr_attr_map = markerutils.find_marker_attr_mapping( root_mkr_list, attr_list) root_attr_list = [] for i, mkr in enumerate(root_mkr_list): for j, attr in enumerate(attr_list): x = mkr_attr_map[i][j] if x is True and attr not in root_attr_list: root_attr_list.append(attr) sol = solverstep.SolverStep() sol.set_max_iterations(root_iter_num) sol.set_frame_list(frm_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(False) sol.set_use_stiffness(False) sol.set_precomputed_data(precomputed_data) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, col, root_mkr_list, root_attr_list, withtest, cache) for action, vaction in generator: yield action, vaction return
def _compile_multi_inbetween_frames(col, mkr_list, attr_list, all_frame_list, global_solve, eval_complex_graphs, anim_iter_num, remove_unused_objects, precomputed_data, withtest, verbose): """ Solve only animated attributes on frames between the root frames. :param mkr_list: Markers to be solved with. :type mkr_list: [Marker, ..] :param attr_list: Attributes to be solved. :type attr_list: [Attribute, ..] :param all_frame_list: List of Frames to be solved. :type all_frame_list: [Frame, ..] :param global_solve: If True, all attributes and frames will be solved as a single solve, rather than one solve per-frame. :type global_solve: bool :param eval_complex_graphs: If True, the solve will try to trigger evalation of complex node graphs (such as Mesh Rivets), by changing the timeEvalMode of the mmSolver command. :type eval_complex_graphs: bool :param anim_iter_num: Number of iterations for solving animated attributes. :type anim_iter_num: int :param remove_unused_objects: Should objects that are detected as 'unused' be removed from the solver? :type remove_unused_objects: bool :param withtest: Should validation tests be generated? :type withtest: bool :param verbose: Print out more detail than usual. :type verbose: bool :return: Yields a generator of two Actions. First Action is for solving, the second Action is for validation of inputs. :rtype: (Action, Action) """ assert isinstance(global_solve, bool) assert isinstance(eval_complex_graphs, bool) assert isinstance(anim_iter_num, int) assert isinstance(remove_unused_objects, bool) assert isinstance(precomputed_data, dict) assert isinstance(withtest, bool) assert isinstance(verbose, bool) if global_solve is True: # Do Global Solve with all frames. sol = solverstep.SolverStep() sol.set_max_iterations(anim_iter_num) sol.set_frame_list(all_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(False) sol.set_use_stiffness(False) sol.set_remove_unused_markers(remove_unused_objects) sol.set_remove_unused_attributes(remove_unused_objects) sol.set_precomputed_data(precomputed_data) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, col, mkr_list, attr_list, withtest, cache) for action, vaction in generator: yield action, vaction else: cache = api_compile.create_compile_solver_cache() for i, frm in enumerate(all_frame_list): is_first_frame = i == 0 one_frame_list = [frm] time_eval_mode = const.TIME_EVAL_MODE_DEFAULT if eval_complex_graphs is True: time_eval_mode = const.TIME_EVAL_MODE_SET_TIME sol = solverstep.SolverStep() sol.set_max_iterations(anim_iter_num) sol.set_frame_list(one_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(False) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(not is_first_frame) sol.set_use_stiffness(not is_first_frame) sol.set_remove_unused_markers(remove_unused_objects) sol.set_remove_unused_attributes(remove_unused_objects) sol.set_time_eval_mode(time_eval_mode) sol.set_precomputed_data(precomputed_data) generator = api_compile.compile_solver_with_cache( sol, col, mkr_list, attr_list, withtest, cache) for action, vaction in generator: yield action, vaction return
def _compile_multi_frame(mkr_list, attr_list, root_frame_list, frame_list, auto_attr_blocks, block_iter_num, only_root_frames, root_iter_num, anim_iter_num, global_solve, root_frame_strategy, triangulate_bundles, test, verbose): assert len(root_frame_list) >= 2 assert len(frame_list) >= 2 root_frame_list_num = [x.get_number() for x in root_frame_list] frame_list_num = [x.get_number() for x in frame_list] non_root_frame_list_num = set(frame_list_num) - set(root_frame_list_num) non_root_frame_list = [frame.Frame(x) for x in non_root_frame_list_num] all_frame_list_num = list(set(frame_list_num + root_frame_list_num)) all_frame_list_num = list(sorted(all_frame_list_num)) all_frame_list = [frame.Frame(x) for x in all_frame_list_num] start_frame = all_frame_list[0] end_frame = all_frame_list[-1] # Triangulate the (open) bundles here. We triangulate all # valid bundles after the root frames have solved. # # NOTE: Bundle triangulation can only happen if the camera # is not nodal. if triangulate_bundles is True: sol = solvertriangulate.SolverTriangulate() # sol.root_frame_list = root_frame_list_num cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, mkr_list, attr_list, test, cache ) for action, vaction in generator: yield action, vaction # Solver root frames, breaking attributes into little blocks # to solve. root_mkr_list, non_root_mkr_list = _filter_mkr_list_by_frame_list( mkr_list, root_frame_list ) if auto_attr_blocks is True: meta_mkr_list, meta_attr_list = _split_mkr_attr_into_categories( root_mkr_list, attr_list ) for new_mkr_list, new_attr_list in zip(meta_mkr_list, meta_attr_list): sol = solverstep.SolverStep() sol.set_verbose(verbose) sol.set_max_iterations(block_iter_num) sol.set_frame_list(root_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, new_mkr_list, new_attr_list, test, cache ) for action, vaction in generator: yield action, vaction # TODO: Create a list of markers specially for root frames. # Loop over all given markers, determine which markers have 2 # or more root frames, only use those markers for root frame # computation. Overall, we must filter out all markers that # cannot/should not be used for different solves. # # TODO: We must make sure to allow the solver to detect that # not enough markers are being used, and warn the user. # # TODO: All markers that do not have enough root frames to solve # correctly, but the Bundle is still in the solver, then it should # be triangulated after the initial root frame solve is performed. # # TODO: Run the solver multiple times for a hierarchy. First, # solve DAG level 0 nodes, then add DAG level 1, then level 2, # etc. This will allow us to incrementally add solving of # hierarchy, without getting the optimiser confused which # attributes to solve first to get a stable solve. if root_frame_strategy == const.ROOT_FRAME_STRATEGY_GLOBAL_VALUE: # Global solve of root frames. sol = solverstep.SolverStep() sol.set_verbose(verbose) sol.set_max_iterations(root_iter_num) sol.set_frame_list(root_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(True) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) cache = api_compile.create_compile_solver_cache() generator = api_compile.compile_solver_with_cache( sol, root_mkr_list, attr_list, test, cache ) for action, vaction in generator: yield action, vaction else: # Get the order of frames to solve with. batch_frame_list = [] if root_frame_strategy == const.ROOT_FRAME_STRATEGY_FWD_PAIR_VALUE: # Two frames at a time, moving forward, plus a global solve # at the end. batch_frame_list = _gen_two_frame_fwd(root_frame_list_num) batch_frame_list.append(root_frame_list) elif root_frame_strategy == const.ROOT_FRAME_STRATEGY_FWD_PAIR_AND_GLOBAL_VALUE: # Two frames at a time, moving forward. batch_frame_list = _gen_two_frame_fwd(root_frame_list_num) else: # TODO: Root frame ordering can be determined by the # count of markers available at each frame. After we # have an ordering of these frames, we can solve the # frames incrementally, starting with the first # highest, then add the next highest, etc. This # should ensure stability of the solver is maximum. raise NotImplementedError generator = _compile_multi_root_frames( mkr_list, attr_list, batch_frame_list, root_iter_num, test, verbose ) for action, vaction in generator: yield action, vaction # Clear out all the frames between the solved root frames, this # helps us use the new solve root frames to hint the 'in-between' # frame solve. generator = _compile_remove_inbetween_frames( attr_list, non_root_frame_list, start_frame, end_frame, test, verbose ) for action, vaction in generator: yield action, vaction if only_root_frames is True: return generator = _compile_multi_inbetween_frames( mkr_list, attr_list, all_frame_list, global_solve, anim_iter_num, test, verbose, ) for action, vaction in generator: yield action, vaction return
def compile(self, col, mkr_list, attr_list, withtest=False): assert isinstance(withtest, bool) # Options to affect how the solve is constructed. use_single_frame = self.get_use_single_frame() single_frame = self.get_single_frame() frame_list = self.get_frame_list() anim_iter_num = self.get_anim_iteration_num() lineup_iter_num = self.get_lineup_iteration_num() use_euler_filter = self._use_euler_filter eval_object_relationships = self.get_eval_object_relationships() remove_unused_objects = eval_object_relationships eval_complex_graphs = self.get_eval_complex_graphs() precomputed_data = self.get_precomputed_data() # Pre-calculate the 'affects' relationship. if eval_object_relationships is True: generator = solverutils.compile_solver_affects( col, mkr_list, attr_list, precomputed_data, withtest) for action, vaction in generator: yield action, vaction else: generator = solverutils.compile_reset_used_hints( col, mkr_list, attr_list) for action, vaction in generator: yield action, vaction if use_single_frame is True: # Single frame solve sol = solverstep.SolverStep() sol.set_max_iterations(lineup_iter_num) sol.set_frame_list([single_frame]) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(False) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(False) sol.set_use_stiffness(False) sol.set_remove_unused_markers(remove_unused_objects) sol.set_remove_unused_attributes(remove_unused_objects) sol.set_precomputed_data(precomputed_data) for action, vaction in sol.compile(col, mkr_list, attr_list, withtest=withtest): yield action, vaction else: # Multiple frame solve, per-frame vaction_cache = api_compile.create_compile_solver_cache() for i, frm in enumerate(frame_list): is_first_frame = i == 0 one_frame_list = [frm] time_eval_mode = const.TIME_EVAL_MODE_DEFAULT if eval_complex_graphs is True: time_eval_mode = const.TIME_EVAL_MODE_SET_TIME sol = solverstep.SolverStep() sol.set_max_iterations(anim_iter_num) sol.set_frame_list(one_frame_list) sol.set_attributes_use_animated(True) sol.set_attributes_use_static(False) sol.set_auto_diff_type(const.AUTO_DIFF_TYPE_FORWARD) sol.set_use_smoothness(not is_first_frame) sol.set_use_stiffness(not is_first_frame) sol.set_time_eval_mode(time_eval_mode) sol.set_remove_unused_markers(remove_unused_objects) sol.set_remove_unused_attributes(remove_unused_objects) sol.set_precomputed_data(precomputed_data) generator = api_compile.compile_solver_with_cache( sol, col, mkr_list, attr_list, withtest, vaction_cache) for action, vaction in generator: yield action, vaction # Perform an euler filter on all unlocked rotation attributes. if use_euler_filter is True: generator = solverutils.compile_euler_filter( attr_list, withtest) for action, vaction in generator: yield action, vaction return