class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1248, 737) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.splitter_2 = QtWidgets.QSplitter(self.centralwidget) self.splitter_2.setOrientation(QtCore.Qt.Horizontal) self.splitter_2.setObjectName("splitter_2") self.gridLayoutWidget_2 = QtWidgets.QWidget(self.splitter_2) self.gridLayoutWidget_2.setObjectName("gridLayoutWidget_2") self.gl_container = QtWidgets.QGridLayout(self.gridLayoutWidget_2) self.gl_container.setContentsMargins(0, 0, -1, -1) self.gl_container.setObjectName("gl_container") self.animationViewer = SceneViewerWidget(self.gridLayoutWidget_2) self.animationViewer.setMinimumSize(QtCore.QSize(640, 480)) self.animationViewer.setObjectName("animationViewer") self.gl_container.addWidget(self.animationViewer, 0, 0, 1, 1) self.splitter = QtWidgets.QSplitter(self.splitter_2) self.splitter.setOrientation(QtCore.Qt.Vertical) self.splitter.setObjectName("splitter") self.sceneObjectTableWidget = SceneObjectTableWidget(self.splitter) self.sceneObjectTableWidget.setColumnCount(3) self.sceneObjectTableWidget.setObjectName("sceneObjectTableWidget") self.sceneObjectTableWidget.setColumnCount(3) self.sceneObjectTableWidget.setRowCount(0) item = QtWidgets.QTableWidgetItem() self.sceneObjectTableWidget.setHorizontalHeaderItem(0, item) item = QtWidgets.QTableWidgetItem() self.sceneObjectTableWidget.setHorizontalHeaderItem(1, item) item = QtWidgets.QTableWidgetItem() self.sceneObjectTableWidget.setHorizontalHeaderItem(2, item) self.sceneObjectTableWidget.horizontalHeader().setDefaultSectionSize(50) self.sceneObjectTableWidget.horizontalHeader().setMinimumSectionSize(200) self.sceneObjectTableWidget.horizontalHeader().setStretchLastSection(True) self.objectPropertiesGroupBox = QtWidgets.QGroupBox(self.splitter) self.objectPropertiesGroupBox.setObjectName("objectPropertiesGroupBox") self.gridLayout_2 = QtWidgets.QGridLayout(self.objectPropertiesGroupBox) self.gridLayout_2.setObjectName("gridLayout_2") self.objectPropertiesLayout = QtWidgets.QGridLayout() self.objectPropertiesLayout.setObjectName("objectPropertiesLayout") self.gridLayout_2.addLayout(self.objectPropertiesLayout, 0, 0, 1, 1) self.gridLayout.addWidget(self.splitter_2, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menuBar = QtWidgets.QMenuBar(MainWindow) self.menuBar.setGeometry(QtCore.QRect(0, 0, 1248, 21)) self.menuBar.setObjectName("menuBar") MainWindow.setMenuBar(self.menuBar) self.statusBar = QtWidgets.QStatusBar(MainWindow) self.statusBar.setObjectName("statusBar") MainWindow.setStatusBar(self.statusBar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): MainWindow.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "Motion Preprocessing Tool", None, -1)) self.sceneObjectTableWidget.horizontalHeaderItem(0).setText(QtWidgets.QApplication.translate("MainWindow", "Index", None, -1)) self.sceneObjectTableWidget.horizontalHeaderItem(1).setText(QtWidgets.QApplication.translate("MainWindow", "Name", None, -1)) self.sceneObjectTableWidget.horizontalHeaderItem(2).setText(QtWidgets.QApplication.translate("MainWindow", "Color", None, -1)) self.objectPropertiesGroupBox.setTitle(QtWidgets.QApplication.translate("MainWindow", "Properties", None, -1))
class CopyFromSourceDialog(QDialog, Ui_Dialog): def __init__(self, controller, scene, share_widget, parent=None): QDialog.__init__(self, parent) Ui_Dialog.setupUi(self, self) self.leftView = SceneViewerWidget(parent, share_widget, size=(400, 400), use_frame_buffer=False) self.leftView.setObjectName("left") self.leftView.setMinimumSize(400, 400) self.leftView.initializeGL() self.leftView.enable_mouse_interaction = False self.leftViewerLayout.addWidget(self.leftView) self.rightView = SceneViewerWidget(parent, self.leftView, size=(400, 400), use_frame_buffer=False) self.rightView.setObjectName("right") self.rightView.setMinimumSize(400, 400) self.rightView.initializeGL() self.rightView.enable_mouse_interaction = False self.rightViewerLayout.addWidget(self.rightView) self.fps = 60 self.dt = 1 / 60 self.timer = QTimer() self.timer.timeout.connect(self.draw) self.timer.start(0) self.timer.setInterval(1000.0 / self.fps) self.scene = scene self.right_controller = None self.skeleton = None self.rightView.makeCurrent() self.right_scene = EditorScene(True) if controller is not None: self.right_controller = self.copy_controller( controller, self.right_scene) self.skeleton = self.right_controller.get_skeleton() n_frames = self.right_controller.getNumberOfFrames() self._fill_list_with_joints(controller) else: n_frames = 0 self.leftView.makeCurrent() self.left_scene = EditorScene(True) self.copyButton.clicked.connect(self.copy_from_left_to_right) self.left_controller = None self.controllers = dict() self._fill_list_with_scene_objects(scene) self.selectButton.clicked.connect(self.slot_accept) self.cancelButton.clicked.connect(self.slot_reject) self.selectAllJointsButton.clicked.connect(self.slot_select_all_joints) self.selectJointChildrenButton.clicked.connect( self.slot_select_joint_children) self.deselectJointChildrenButton.clicked.connect( self.slot_deselect_joint_children) self.clearSelectedJointsButton.clicked.connect( self.slot_clear_all_joints) self.leftStartFrameSlider.valueChanged.connect( self.left_slider_frame_changed) self.leftEndFrameSlider.valueChanged.connect( self.left_slider_frame_changed) self.leftStartFrameSpinBox.valueChanged.connect( self.left_spinbox_frame_changed) self.leftEndFrameSpinBox.valueChanged.connect( self.left_spinbox_frame_changed) self.leftDisplayFrameSlider.valueChanged.connect( self.left_display_changed) self.leftDisplayFrameSpinBox.valueChanged.connect( self.left_display_changed) self.rightStartFrameSlider.valueChanged.connect( self.right_slider_frame_changed) self.rightStartFrameSpinBox.valueChanged.connect( self.right_spinbox_frame_changed) self.rightEndFrameSlider.valueChanged.connect( self.right_slider_frame_changed) self.rightEndFrameSpinBox.valueChanged.connect( self.right_spinbox_frame_changed) self.rightDisplayFrameSpinBox.valueChanged.connect( self.right_display_changed) self.rightDisplayFrameSlider.valueChanged.connect( self.right_display_changed) self.sceneObjectListWidget.itemClicked.connect( self.load_src_controller) self.success = False self.n_frames = n_frames self.start_frame = 0 self.end_frame = n_frames - 1 # self.set_right_frame_range() self.initialized = False def closeEvent(self, e): self.timer.stop() self.leftView.makeCurrent() del self.leftView self.rightView.makeCurrent() del self.rightView def copy_from_left_to_right(self): """ copy values from left start to end to right start to end and interpolate with the rest """ if self.left_controller is not None and self.right_controller is not None and self.skeleton is not None: left_frames = self.left_controller.get_frames() right_frames = self.right_controller.get_frames() n_right_frames = self.right_controller.getNumberOfFrames() print("loaded", len(right_frames), n_right_frames) dest_start = self.rightStartFrameSlider.value() src_start = self.leftStartFrameSlider.value() src_end = self.leftEndFrameSlider.value() + 1 dest_end = self.rightEndFrameSlider.value() + 1 n_dest_frames = dest_end - dest_start if n_dest_frames <= 0: print("wrong dest frames", dest_start, dest_end) return #extract number of copied frames from source n_copied_frames = src_end - src_start if n_copied_frames <= 0: print("wrong src frames", src_start, src_end) return joint_list, joint_index_list = self.get_selected_joints() print("copy", joint_list, joint_index_list) modified_frames = self.copy_joint_values(left_frames, right_frames, joint_list, joint_index_list, src_start, src_end, dest_start, dest_end) n_blend_range = int(self.blendRangeLineEdit.text()) if n_blend_range > 0: modified_frames = self.apply_blending(modified_frames, joint_list, joint_index_list, dest_start, dest_end - 1, n_blend_range) self.right_controller.replace_frames(modified_frames) n_new_right_frames = self.right_controller.getNumberOfFrames() print("finished overwriting", n_right_frames, n_new_right_frames) def copy_joint_values(self, left_frames, right_frames, joint_list, joint_index_list, src_start, src_end, dest_start, dest_end): n_copied_frames = src_end - src_start n_dest_frames = dest_end - dest_start modified_frames = np.array(right_frames) if n_copied_frames > 1: src_frames = stretch_motion(self.skeleton, left_frames[src_start:src_end], n_dest_frames) else: src_frames = [] for i in range(n_dest_frames): src_frames.append(left_frames[src_start]) src_frames = np.array(src_frames) print("copy ", n_copied_frames, n_dest_frames) for frame_idx in range(n_dest_frames): modified_frames[dest_start + frame_idx][ joint_index_list] = src_frames[frame_idx][joint_index_list] return modified_frames def apply_blending(self, frames, joint_list, joint_index_list, dest_start, dest_end, n_blend_range): n_frames = len(frames) blend_start = max(dest_start - n_blend_range, 0) start_window = dest_start - blend_start blend_end = min(dest_end + n_blend_range, n_frames - 1) end_window = blend_end - dest_end #remove root indices print("blend ", dest_start, dest_end, n_blend_range, start_window, end_window) quat_joint_index_list = list(joint_index_list) if self.skeleton.root in joint_list: # apply root smnoothing and remove from index list if start_window > 0: frames = smooth_translation_in_quat_frames( frames, dest_start, start_window) if end_window > 0: frames = smooth_translation_in_quat_frames( frames, dest_end, end_window) for i in range(3): quat_joint_index_list.remove(i) if len(quat_joint_index_list) > 0: o = 0 for j in joint_list: q_indices = quat_joint_index_list[o:o + 4] if start_window > 0: frames = create_transition_for_joints_using_slerp( frames, q_indices, blend_start, dest_start, start_window, BLEND_DIRECTION_FORWARD) if end_window > 0: print(j, q_indices) frames = create_transition_for_joints_using_slerp( frames, q_indices, dest_end, blend_end, end_window, BLEND_DIRECTION_BACKWARD) o += 4 return frames def get_selected_joints(self): joint_list = [] joint_index_list = [] for row_idx in range(self.jointTableWidget.rowCount()): index_cell = self.jointTableWidget.item(row_idx, 0) if index_cell.checkState() == Qt.Checked: name_cell = self.jointTableWidget.item(row_idx, 1) joint_name = str(name_cell.text()) joint_list.append(joint_name) if joint_name == self.skeleton.root: offset = 0 n_channels = 7 else: offset = self.skeleton.nodes[ joint_name].quaternion_frame_index * 4 + 3 n_channels = 4 joint_index_list += list(range(offset, offset + n_channels)) return joint_list, joint_index_list def _fill_list_with_joints(self, controller): #self.jointTableWidget.clear() for joint_name in controller.get_animated_joints(): insertRow = self.jointTableWidget.rowCount() self.jointTableWidget.insertRow(insertRow) indexItem = QTableWidgetItem("") indexItem.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) indexItem.setCheckState(Qt.Unchecked) self.jointTableWidget.setItem(insertRow, 0, indexItem) self.jointTableWidget.setItem(insertRow, 1, QTableWidgetItem(str(joint_name))) def copy_controller(self, controller, target_scene): skeleton = controller.get_skeleton_copy() mv = controller.get_motion_vector_copy() o = target_scene.object_builder.create_object("animation_controller", "", skeleton, mv, mv.frame_time, semantic_annotation=None) return o._components["animation_controller"] def load_src_controller(self, item): if item is None: return selected_item = str(self.sceneObjectListWidget.currentItem().text()) if self.left_controller is not None: node_id = self.left_controller.scene_object.node_id self.left_scene.removeObject(node_id) src_controller = self.controllers[selected_item] self.left_controller = self.copy_controller(src_controller, self.left_scene) n_frames = src_controller.getNumberOfFrames() self.leftStartFrameSlider.setRange(0, n_frames - 1) self.leftStartFrameSlider.setValue(0) self.leftEndFrameSlider.setRange(0, n_frames - 1) self.leftEndFrameSlider.setValue(n_frames - 1) self.leftDisplayFrameSlider.setRange(0, n_frames - 1) self.leftDisplayFrameSlider.setRange(0, n_frames - 1) def draw(self): """ draw current scene on the given view (note before calling this function the context of the view has to be set as current using makeCurrent() and afterwards the doubble buffer has to swapped to display the current frame swapBuffers()) """ if not self.initialized: if self.leftView.graphics_context is not None and self.rightView.graphics_context is not None: self.leftView.resize(400, 400) self.rightView.resize(400, 400) self.initialized = True self.left_scene.update(self.dt) self.leftView.makeCurrent() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.leftView.graphics_context.render(self.left_scene) self.leftView.swapBuffers() self.right_scene.update(self.dt) self.rightView.makeCurrent() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.rightView.graphics_context.render(self.right_scene) self.rightView.swapBuffers() #print(len(self.right_scene.lightSources)) def right_display_changed(self, frame_idx): if self.right_controller is not None: self.right_controller.setCurrentFrameNumber(frame_idx) self.rightDisplayFrameSpinBox.setValue(frame_idx) def left_display_changed(self, frame_idx): if self.left_controller is not None: self.left_controller.setCurrentFrameNumber(frame_idx) self.leftDisplayFrameSpinBox.setValue(frame_idx) def _fill_list_with_scene_objects(self, scene): for sceneObject in get_animation_controllers(scene): item = QListWidgetItem() item.setText(sceneObject.name) item.setData(Qt.UserRole, sceneObject.node_id) self.sceneObjectListWidget.addItem(item) self.controllers[sceneObject.name] = sceneObject._components[ "animation_controller"] def set_right_frame_range(self): self.leftStartFrameSlider.setRange(0, self.n_frames - 1) self.leftEndFrameSlider.setRange(0, self.n_frames - 1) self.leftStartFrameSpinBox.setRange(0, self.n_frames - 1) self.leftEndFrameSpinBox.setRange(0, self.n_frames - 1) self.leftEndFrameSlider.setValue(self.n_frames - 1) self.leftEndFrameSpinBox.setValue(self.n_frames - 1) self.rightStartFrameSlider.setRange(0, self.n_frames - 1) self.rightStartFrameSpinBox.setRange(0, self.n_frames - 1) self.rightEndFrameSlider.setRange(0, self.n_frames - 1) self.rightEndFrameSpinBox.setRange(0, self.n_frames - 1) self.rightEndFrameSlider.setValue(self.n_frames - 1) self.rightEndFrameSpinBox.setValue(self.n_frames - 1) self.rightDisplayFrameSlider.setRange(0, self.n_frames - 1) self.rightDisplayFrameSpinBox.setRange(0, self.n_frames - 1) def left_spinbox_frame_changed(self, frame): self.leftStartFrameSlider.setValue(self.leftStartFrameSpinBox.value()) self.leftEndFrameSlider.setValue(self.leftEndFrameSpinBox.value()) def left_slider_frame_changed(self, frame): self.leftStartFrameSpinBox.setValue(self.leftStartFrameSlider.value()) self.leftEndFrameSpinBox.setValue(self.leftEndFrameSlider.value()) def right_spinbox_frame_changed(self, frame): self.rightStartFrameSlider.setValue( self.rightStartFrameSpinBox.value()) self.rightEndFrameSlider.setValue(self.rightEndFrameSpinBox.value()) def right_slider_frame_changed(self, frame): self.rightStartFrameSpinBox.setValue( self.rightStartFrameSlider.value()) self.rightEndFrameSpinBox.setValue(self.rightEndFrameSlider.value()) def slot_accept(self): self.success = True self.close() def slot_reject(self): self.close() def slot_select_all_joints(self): for row_idx in range(self.jointTableWidget.rowCount()): index_cell = self.jointTableWidget.item(row_idx, 0) index_cell.setCheckState(Qt.Checked) def slot_clear_all_joints(self): for row_idx in range(self.jointTableWidget.rowCount()): index_cell = self.jointTableWidget.item(row_idx, 0) index_cell.setCheckState(Qt.Unchecked) def slot_select_joint_children(self): for row_idx in range(self.jointTableWidget.rowCount()): index_cell = self.jointTableWidget.item(row_idx, 0) name_cell = self.jointTableWidget.item(row_idx, 1) if index_cell.isSelected() or name_cell.isSelected(): joint_name = str(name_cell.text()) self.change_joint_children_state(joint_name, Qt.Checked) def slot_deselect_joint_children(self): for row_idx in range(self.jointTableWidget.rowCount()): index_cell = self.jointTableWidget.item(row_idx, 0) name_cell = self.jointTableWidget.item(row_idx, 1) if index_cell.isSelected() or name_cell.isSelected(): joint_name = str(name_cell.text()) self.change_joint_children_state(joint_name, Qt.Unchecked) def change_joint_children_state(self, joint_name, state): self.change_joint_state(joint_name, state) if joint_name in self.skeleton.nodes: for n in self.skeleton.nodes[joint_name].children: self.change_joint_children_state(n.node_name, state) def change_joint_state(self, joint_name, state): print("select", joint_name) for row_idx in range(self.jointTableWidget.rowCount()): name_cell = self.jointTableWidget.item(row_idx, 1) if joint_name == str(name_cell.text()): index_cell = self.jointTableWidget.item(row_idx, 0) index_cell.setCheckState(state) break
class SkeletonEditorDialog(QDialog, Ui_Dialog): def __init__(self, name, skeleton, share_widget, parent=None, enable_line_edit=False, skeleton_model=None): self.initialized = False QDialog.__init__(self, parent) Ui_Dialog.setupUi(self, self) self.view = SceneViewerWidget(parent, share_widget, size=(400, 400)) self.view.setObjectName("left") self.view.setMinimumSize(400, 400) self.view.initializeGL() self.nameLineEdit.setText(name) self.nameLineEdit.setEnabled(enable_line_edit) self.name = name self.view.enable_mouse_interaction = True self.view.mouse_click.connect(self.on_mouse_click) self.viewerLayout.addWidget(self.view) self.radius = 1.0 self.fps = 60 self.dt = 1 / 60 self.timer = QTimer() self.timer.timeout.connect(self.draw) self.timer.start(0) self.timer.setInterval(1000.0 / self.fps) self.skeleton = skeleton self.view.makeCurrent() self.scene = EditorScene(True) self.scene.enable_scene_edit_widget = True if skeleton_model is not None: self.skeleton_model = skeleton_model elif skeleton.skeleton_model is not None: self.skeleton_model = skeleton.skeleton_model else: self.skeleton_model = dict() print("create new skeleton model") if "cos_map" not in self.skeleton_model: self.skeleton_model["cos_map"] = dict() if "joints" not in self.skeleton_model: self.skeleton_model["joints"] = dict() if "joint_constraints" not in self.skeleton_model: self.skeleton_model["joint_constraints"] = dict() motion_vector = MotionVector() self.reference_frame = skeleton.reference_frame print(self.reference_frame[:3]) motion_vector.frames = [skeleton.reference_frame] motion_vector.n_frames = 1 o = self.scene.object_builder.create_object("animation_controller", "skeleton", skeleton, motion_vector, skeleton.frame_time) self.controller = o._components["animation_controller"] self.skeleton = self.controller.get_skeleton() self.skeleton_vis = o._components["skeleton_vis"] self.init_joints(self.controller) self.fill_joint_map() self.selectButton.clicked.connect(self.slot_accept) self.cancelButton.clicked.connect(self.slot_reject) self.applyTwistRotationButton.clicked.connect(self.slot_set_twist) self.applySwingRotationButton.clicked.connect(self.slot_set_swing) self.setOrthogonalTwistButton.clicked.connect( self.slot_set_orthogonal_twist) self.setOrthogonalSwingButton.clicked.connect( self.slot_set_orthogonal_swing) self.rotateTwistButton.clicked.connect(self.slot_rotate_twist) self.rotateSwingButton.clicked.connect(self.slot_rotate_swing) self.flipTwistButton.clicked.connect(self.slot_flip_twist) self.flipSwingButton.clicked.connect(self.slot_flip_swing) self.flipZAxisButton.clicked.connect(self.slot_flip_z_axis) self.alignToUpAxisButton.clicked.connect(self.slot_align_to_up_axis) self.alignToForwardAxisButton.clicked.connect( self.slot_align_to_forward_axis) self.guessSelectedButton.clicked.connect( self.slot_guess_selected_cos_map) self.resetSelectedCosButton.clicked.connect( self.slot_reset_selected_cos_map) self.guessAllCosButton.clicked.connect(self.slot_guess_cos_map) self.resetAllCosButton.clicked.connect(self.slot_reset_cos_map) self.loadDefaultPoseButton.clicked.connect(self.slot_load_default_pose) self.applyScaleButton.clicked.connect(self.slot_apply_scale) self.jointMapComboBox.currentIndexChanged.connect( self.slot_update_joint_map) self.aligningRootComboBox.currentIndexChanged.connect( self.slot_update_aligning_root_joint) self.mirrorLeftButton.clicked.connect(self.slot_mirror_left_to_right) self.mirrorRightButton.clicked.connect(self.slot_mirror_right_to_left) self.is_updating_joint_info = False self.success = False self.initialized = False self.skeleton_data = None self.precision = 3 self.aligning_root_node = self.skeleton.aligning_root_node self.fill_root_combobox() self.init_aligning_root_node() def init_aligning_root_node(self): print("init", self.skeleton.root, self.skeleton.aligning_root_node) if self.aligning_root_node is None: self.aligning_root_node = self.skeleton.root if self.aligning_root_node is not None: index = self.aligningRootComboBox.findText(self.aligning_root_node, Qt.MatchFixedString) print("found index", index, self.aligning_root_node) if index >= 0: self.aligningRootComboBox.setCurrentIndex(index) def closeEvent(self, e): self.timer.stop() self.view.makeCurrent() del self.view def on_mouse_click(self, event, ray_start, ray_dir, pos, node_id): if event.button() == Qt.LeftButton: self.scene.select_object(node_id) joint_knob = self.get_selected_joint() self.update_joint_info(joint_knob) def update_joint_info(self, joint_knob): self.is_updating_joint_info = True self.scene.scene_edit_widget.reset_rotation() self.jointMapComboBox.setCurrentIndex(0) label = "Selected Joint: " if joint_knob is None: label += "None" self.jointLabel.setText(label) self.is_updating_joint_info = False return label += joint_knob.joint_name joint_name = joint_knob.joint_name if "joints" in self.skeleton_model: key = find_key(self.skeleton_model["joints"], joint_name) print("key", joint_name, key) if key is not None: index = self.jointMapComboBox.findText(key, Qt.MatchFixedString) if index >= 0: self.jointMapComboBox.setCurrentIndex(index) if "cos_map" in self.skeleton_model and joint_name in self.skeleton_model[ "cos_map"]: x_vector = self.skeleton_model["cos_map"][joint_name]["x"] if x_vector is None: x_vector = [1, 0, 0] self.skeleton_model["cos_map"][joint_name]["x"] = x_vector y_vector = self.skeleton_model["cos_map"][joint_name]["y"] if y_vector is None: y_vector = [0, 1, 0] self.skeleton_model["cos_map"][joint_name]["y"] = y_vector swing = np.round(x_vector, self.precision) twist = np.round(y_vector, self.precision) self.set_swing_text(swing) self.set_twist_text(twist) m = self.skeleton.nodes[joint_name].get_global_matrix( self.reference_frame)[:3, :3] g_swing = np.dot(m, swing) g_swing = normalize(g_swing) g_twist = np.dot(m, twist) g_twist = normalize(g_twist) q = axes_to_q(g_twist, g_swing) m = quaternion_matrix(q) #print("g_twist", g_twist, twist) #print("g_swing", g_swing, swing) self.scene.scene_edit_widget.rotation = m[:3, :3].T else: print("no cos map", self.skeleton_model.keys()) self.jointLabel.setText(label) self.is_updating_joint_info = False def set_swing_text(self, swing): self.swingXLineEdit.setText(str(swing[0])) self.swingYLineEdit.setText(str(swing[1])) self.swingZLineEdit.setText(str(swing[2])) def set_twist_text(self, twist): self.twistXLineEdit.setText(str(twist[0])) self.twistYLineEdit.setText(str(twist[1])) self.twistZLineEdit.setText(str(twist[2])) def fill_joint_map(self): self.jointMapComboBox.clear() for idx, joint in enumerate(STANDARD_JOINTS): print("add", joint) self.jointMapComboBox.addItem(joint, idx) def fill_root_combobox(self): self.aligningRootComboBox.clear() for idx, joint in enumerate(self.controller.get_animated_joints()): self.aligningRootComboBox.addItem(joint, idx) def init_joints(self, controller): for joint_name in controller.get_animated_joints(): if len(self.skeleton.nodes[joint_name].children ) > 0: # filter out end site joints node = self.skeleton.nodes[joint_name] if joint_name == self.skeleton.root or np.linalg.norm( node.offset) > 0: self.scene.object_builder.create_object( "joint_control_knob", controller, joint_name, self.radius * self.skeleton_vis.box_scale) def draw(self): """ draw current scene on the given view (note before calling this function the context of the view has to be set as current using makeCurrent() and afterwards the doubble buffer has to swapped to display the current frame swapBuffers()) """ if not self.initialized: if self.view.graphics_context is not None: self.view.resize(400, 400) self.initialized = True self.scene.update(self.dt) self.view.makeCurrent() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.view.graphics_context.render(self.scene) self.view.swapBuffers() def left_display_changed(self, frame_idx): if self.controller is not None: self.controller.setCurrentFrameNumber(frame_idx) self.leftDisplayFrameSpinBox.setValue(frame_idx) def left_spinbox_frame_changed(self, frame): self.leftStartFrameSlider.setValue(self.leftStartFrameSpinBox.value()) self.leftEndFrameSlider.setValue(self.leftEndFrameSpinBox.value()) def left_slider_frame_changed(self, frame): self.leftStartFrameSpinBox.setValue(self.leftStartFrameSlider.value()) self.leftEndFrameSpinBox.setValue(self.leftEndFrameSlider.value()) def slot_accept(self): self.name = str(self.nameLineEdit.text()) if self.name != "": print("accept") self.success = True self.skeleton = self.controller.get_skeleton() self.skeleton.set_reference_frame(self.reference_frame) if self.aligning_root_node is not None: self.skeleton.aligning_root_node = self.aligning_root_node self.skeleton_data = self.skeleton.to_unity_format() if "cos_map" in self.skeleton_model: for k in self.skeleton_model["cos_map"]: for l in self.skeleton_model["cos_map"][k]: if type(self.skeleton_model["cos_map"][k] [l]) == np.ndarray: self.skeleton_model["cos_map"][k][ l] = self.skeleton_model["cos_map"][k][ l].tolist() else: self.skeleton_model["cos_map"][k][ l] = self.skeleton_model["cos_map"][k][l] self.close() else: print("Please provide a name") def slot_reject(self): self.close() def get_selected_joint(self): joint_knob = None o = self.scene.selected_scene_object if o is not None and "joint_control_knob" in o._components: joint_knob = o._components["joint_control_knob"] return joint_knob def set_twist(self, joint_name): x = round(float(self.twistXLineEdit.text()), self.precision) y = round(float(self.twistYLineEdit.text()), self.precision) z = round(float(self.twistZLineEdit.text()), self.precision) #set twist axis twist = np.array([x, y, z]) magnitude = np.linalg.norm(twist) if magnitude > 0: twist /= magnitude self.skeleton_model["cos_map"][joint_name]["y"] = twist def set_swing(self, joint_name): x = round(float(self.swingXLineEdit.text()), self.precision) y = round(float(self.swingYLineEdit.text()), self.precision) z = round(float(self.swingZLineEdit.text()), self.precision) #set swing axis swing = np.array([x, y, z]) magnitude = np.linalg.norm(swing) if magnitude > 0: swing /= magnitude self.skeleton_model["cos_map"][joint_name]["x"] = swing.tolist() def slot_set_twist(self): plot = False joint_knob = self.get_selected_joint() if joint_knob is None: return self.set_swing(joint_knob.joint_name) self.set_twist(joint_knob.joint_name) self.update_joint_info(joint_knob) def slot_set_swing(self): joint_knob = self.get_selected_joint() if joint_knob is None: return self.set_swing(joint_knob.joint_name) self.set_twist(joint_knob.joint_name) self.update_joint_info(joint_knob) def slot_set_orthogonal_twist(self): """ https://stackoverflow.com/questions/33658620/generating-two-orthogonal-vectors-that-are-orthogonal-to-a-particular-direction """ joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name #get swing axis swing = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) # find orthogonal vector y = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) #y = np.random.randn(3) # take a random vector y -= y.dot(swing) * swing # make it orthogonal to twist y /= np.linalg.norm(y) # normalize it #replace twist axis self.set_twist_text(y) self.skeleton_model["cos_map"][joint_name]["y"] = y self.update_joint_info(joint_knob) def slot_set_orthogonal_swing(self): """ https://stackoverflow.com/questions/33658620/generating-two-orthogonal-vectors-that-are-orthogonal-to-a-particular-direction """ joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name #get twist axis twist = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) x = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) x -= x.dot(twist) * twist # make it orthogonal to twist x /= np.linalg.norm(x) # normalize it #replace twist axis self.set_swing_text(x) self.skeleton_model["cos_map"][joint_name]["x"] = x self.update_joint_info(joint_knob) def slot_flip_twist(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name #get twist axis twist = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) twist *= -1 self.skeleton_model["cos_map"][joint_name]["y"] = twist self.set_twist_text(twist) self.update_joint_info(joint_knob) def slot_flip_swing(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name swing = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) swing *= -1 self.skeleton_model["cos_map"][joint_name]["x"] = swing self.set_swing_text(swing) self.update_joint_info(joint_knob) def slot_rotate_twist(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name #get twist axis angle = round(float(self.twistRotationLineEdit.text()), self.precision) rotation_axis = np.array( self.skeleton_model["cos_map"][joint_name]["x"]) q = quaternion_about_axis(np.deg2rad(angle), rotation_axis) q = normalize(q) twist = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) twist = rotate_vector(q, twist) twist = normalize(twist) self.skeleton_model["cos_map"][joint_name]["y"] = twist self.set_twist_text(twist) self.update_joint_info(joint_knob) def slot_rotate_swing(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name angle = round(float(self.swingRotationLineEdit.text()), self.precision) rotation_axis = np.array( self.skeleton_model["cos_map"][joint_name]["y"]) q = quaternion_about_axis(np.deg2rad(angle), rotation_axis) q = normalize(q) swing = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) swing = rotate_vector(q, swing) swing = normalize(swing) self.skeleton_model["cos_map"][joint_name]["x"] = swing self.set_swing_text(swing) self.update_joint_info(joint_knob) def slot_flip_z_axis(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name twist = np.array(self.skeleton_model["cos_map"][joint_name]["y"]) swing = np.array(self.skeleton_model["cos_map"][joint_name]["x"]) new_swing = twist new_twist = swing #print("new swing", new_swing, swing) self.skeleton_model["cos_map"][joint_name]["y"] = new_twist self.skeleton_model["cos_map"][joint_name]["x"] = new_swing self.set_swing_text(new_swing) self.set_twist_text(new_twist) self.update_joint_info(joint_knob) def slot_guess_cos_map(self): """ creates a guess for the coordinate system for all joints""" temp_skeleton = copy(self.skeleton) temp_skeleton.skeleton_model = self.skeleton_model cos_map = create_local_cos_map_from_skeleton_axes_with_map( temp_skeleton) self.skeleton_model["cos_map"] = cos_map joint_knob = self.get_selected_joint() if joint_knob is not None: self.update_joint_info(joint_knob) def slot_reset_cos_map(self): """ resets the coordinate systems for all joints""" for joint_name in self.skeleton_model["cos_map"]: up_vector = self.skeleton_model["cos_map"][joint_name]["y"] x_vector = self.skeleton_model["cos_map"][joint_name]["x"] if up_vector is not None and x_vector is not None: new_up_vector, new_x_vector = self.reset_joint_cos( joint_name, up_vector, x_vector) self.skeleton_model["cos_map"][joint_name]["y"] = new_up_vector self.skeleton_model["cos_map"][joint_name]["x"] = new_x_vector joint_knob = self.get_selected_joint() if joint_knob is not None: self.update_joint_info(joint_knob) def slot_guess_selected_cos_map(self): """ creates a guess for the for the selected joint""" joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name temp_skeleton = copy(self.skeleton) temp_skeleton.skeleton_model = self.skeleton_model cos_map = create_local_cos_map_from_skeleton_axes_with_map( temp_skeleton) self.skeleton_model["cos_map"][joint_name] = cos_map[joint_name] self.update_joint_info(joint_knob) def slot_reset_selected_cos_map(self): """ creates resetrs the coordinate system for the selected joint""" joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name if joint_name in self.skeleton_model["cos_map"]: up_vector = self.skeleton_model["cos_map"][joint_name]["y"] x_vector = self.skeleton_model["cos_map"][joint_name]["x"] new_up_vector, new_x_vector = self.reset_joint_cos( joint_name, up_vector, x_vector) self.skeleton_model["cos_map"][joint_name]["y"] = new_up_vector self.skeleton_model["cos_map"][joint_name]["x"] = new_x_vector self.update_joint_info(joint_knob) def slot_update_joint_map(self): if not self.is_updating_joint_info and "joints" in self.skeleton_model: joint_knob = self.get_selected_joint() if joint_knob is not None: new_joint_key = str(self.jointMapComboBox.currentText()) old_joint_key = find_key(self.skeleton_model["joints"], joint_knob.joint_name) if old_joint_key in self.skeleton_model["joints"]: self.skeleton_model["joints"][old_joint_key] = None self.skeleton_model["joints"][ new_joint_key] = joint_knob.joint_name print("update joint mapping", joint_knob.joint_name, new_joint_key) else: print("is updating joint info") def reset_joint_cos(self, joint_name, up_vector, x_vector, target_up_vector=DEFAULT_TARGET_CS_UP): """ rotates the up_vector to look towards target_up_vector and rotates the x_vector with the same rotation """ m = self.skeleton.nodes[joint_name].get_global_matrix( self.skeleton.reference_frame)[:3, :3] m_inv = np.linalg.inv(m) target_up_vector = normalize(target_up_vector) local_target = np.dot(m_inv, target_up_vector) local_target = normalize(local_target) q = quaternion_from_vector_to_vector(up_vector, local_target) x_vector = rotate_vector(q, x_vector) x_vector -= x_vector.dot( local_target) * local_target # make it orthogonal to twist x_vector /= np.linalg.norm(x_vector) # normalize it x_vector = normalize(x_vector) return local_target, x_vector def slot_update_aligning_root_joint(self): if not self.is_updating_joint_info and "joints" in self.skeleton_model: self.aligning_root_node = str( self.aligningRootComboBox.currentText()) def slot_load_default_pose(self): filename = QFileDialog.getOpenFileName(self, 'Load From File', '.')[0] filename = str(filename) if os.path.isfile(filename): motion = load_motion_from_bvh(filename) if len(motion.frames): self.reference_frame = motion.frames[0] frames = [self.reference_frame] self.controller.replace_frames(frames) self.controller.set_reference_frame(0) self.controller.updateTransformation() print("replaced frames") def slot_apply_scale(self): scale = float(self.scaleLineEdit.text()) if scale > 0: self.controller.set_scale(scale) frames = [self.reference_frame] self.controller.replace_frames(frames) self.controller.currentFrameNumber = 0 self.controller.updateTransformation() def slot_align_to_up_axis(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name if joint_name in self.skeleton_model["cos_map"]: up_vector = self.skeleton_model["cos_map"][joint_name]["y"] x_vector = self.skeleton_model["cos_map"][joint_name]["x"] q_offset = get_axis_correction(self.skeleton, joint_name, up_vector, OPENGL_UP_AXIS) up_vector = rotate_vector(q_offset, up_vector) x_vector = rotate_vector(q_offset, x_vector) self.skeleton_model["cos_map"][joint_name]["x"] = normalize( x_vector) self.skeleton_model["cos_map"][joint_name]["y"] = normalize( up_vector) self.update_joint_info(joint_knob) def slot_align_to_forward_axis(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name if joint_name in self.skeleton_model["cos_map"]: up_vector = self.skeleton_model["cos_map"][joint_name]["y"] m = self.skeleton.nodes[joint_name].get_global_matrix( self.skeleton.reference_frame)[:3, :3] m_inv = np.linalg.inv(m) target_vector = np.dot(m, up_vector) target_vector[1] = 0 target_vector = normalize(target_vector) local_up = np.dot(m_inv, target_vector) local_up = normalize(local_up) self.skeleton_model["cos_map"][joint_name]["y"] = local_up x_vector = self.skeleton_model["cos_map"][joint_name]["x"] q = quaternion_from_vector_to_vector(up_vector, local_up) x_vector = rotate_vector(q, x_vector) x_vector -= x_vector.dot( local_up) * local_up # make it orthogonal to twist x_vector /= np.linalg.norm(x_vector) # normalize it self.skeleton_model["cos_map"][joint_name]["x"] = normalize( x_vector) self.update_joint_info(joint_knob) def slot_mirror_left_to_right(self): self.skeleton_model = mirror_join_map(self.skeleton, self.skeleton_model, STANDARD_MIRROR_MAP_LEFT) print("mirrored left to right") print(self.skeleton_model["joints"]) def slot_mirror_right_to_left(self): self.skeleton_model = mirror_join_map(self.skeleton, self.skeleton_model, STANDARD_MIRROR_MAP_RIGHT) print("mirrored right to left")
class AnimationEditorDialog(QDialog, Ui_Dialog): def __init__(self, controller, scene, share_widget, parent=None): QDialog.__init__(self, parent) Ui_Dialog.setupUi(self, self) self.leftView = SceneViewerWidget(parent, share_widget, size=(400, 400)) self.leftView.setObjectName("left") self.leftView.setMinimumSize(400, 400) self.leftView.initializeGL() self.leftView.enable_mouse_interaction = True self.leftView.mouse_click.connect(self.on_mouse_click) self.leftView.mouse_move.connect(self.on_mouse_move) self.leftView.mouse_release.connect(self.on_mouse_release) self.leftViewerLayout.addWidget(self.leftView) self.radius = 1.0 self.fps = 60 self.dt = 1 / 60 self.timer = QTimer() self.timer.timeout.connect(self.draw) self.timer.start(0) self.timer.setInterval(1000.0 / self.fps) self.scene = scene self.original_controller = controller self.controller = None self.skeleton = None self.leftView.makeCurrent() self.left_scene = EditorScene(True) self.left_scene.enable_scene_edit_widget = True self.left_scene.scene_edit_widget.register_move_callback( self.on_move_widget) self._animation_editor = None if controller is not None: self.controller = self.copy_controller(controller, self.left_scene) fps = int(1.0 / self.controller._motion.mv.frame_time) self.fpsLineEdit.setText(str(fps)) self.skeleton = self.controller.get_skeleton() n_frames = self.controller.getNumberOfFrames() self.skeleton_vis = self.controller.scene_object._components[ "skeleton_vis"] self.init_joints(self.controller) else: n_frames = 0 self.selectButton.clicked.connect(self.slot_accept) self.cancelButton.clicked.connect(self.slot_reject) self.deleteBeforeButton.clicked.connect(self.slot_delete_frames_before) self.deleteAfterButton.clicked.connect(self.slot_delete_frames_after) self.concatenateButton.clicked.connect(self.slot_concatenate) self.translateJointButton.clicked.connect(self.slot_translate_joint) self.rotateJointButton.clicked.connect(self.slot_rotate_joint) self.smoothFramesButton.clicked.connect(self.slot_smooth_frames) self.mirrorAnimationButton.clicked.connect(self.slot_mirror_animation) self.fixJointButton.clicked.connect(self.slot_fix_joint) self.clearConstraintsButton.clicked.connect( self.slot_clear_constraints) self.undoButton.clicked.connect(self.slot_undo) self.exportCommandsButton.clicked.connect( self.slot_export_command_history) self.applyConstraintsButton.clicked.connect( self.slot_apply_constraints) self.resampleButton.clicked.connect(self.slot_resample_motion) self.setFPSButton.clicked.connect(self.slot_set_fps) self.flipBlenderCoordinateSystemButton.clicked.connect( self.flip_blender_coordinate_systems) self.leftStartFrameSlider.valueChanged.connect( self.left_slider_frame_changed) self.leftEndFrameSlider.valueChanged.connect( self.left_slider_frame_changed) self.leftStartFrameSpinBox.valueChanged.connect( self.left_spinbox_frame_changed) self.leftEndFrameSpinBox.valueChanged.connect( self.left_spinbox_frame_changed) self.leftDisplayFrameSlider.valueChanged.connect( self.left_display_changed) self.leftDisplayFrameSpinBox.valueChanged.connect( self.left_display_changed) #self.close.triggered.connect(self.on_close) self.guessGroundHeightButton.clicked.connect(self.guess_ground_height) self.moveToGroundButton.clicked.connect(self.move_to_ground) self.detectFootContactsButton.clicked.connect( self.detect_foot_contacts) self.groundFeetButton.clicked.connect(self.ground_feet) self.setAnnotationStartButton.clicked.connect( self.set_annotation_edit_start) self.createAnnotationButton.clicked.connect( self.create_annotation_section) self.removeAnnotationButton.clicked.connect( self.remove_annotation_section) self.edited_knob = None self.success = False self.n_frames = n_frames self.start_frame = 0 self.end_frame = n_frames - 1 # self.set_frame_range() self.initialized = False self.collect_constraints = True self.original_frames = np.array(self.controller.get_frames()) self.annotation_editor = AnnotationEditor() self.contactLabelView.setTimeLineParameters(100000, 10) self.contactLabelView.initScene() self.contactLabelView.show() if not self._animation_editor.motion_grounding.initialized: self.detectFootContactsButton.setEnabled(False) self.groundFeetButton.setEnabled(False) else: ground_annotation = collections.OrderedDict() color_map = collections.OrderedDict() for label in self._animation_editor.foot_constraint_generator.contact_joints: color_map[label] = get_random_color() ground_annotation[label] = [] self.annotation_editor.set_annotation(ground_annotation, color_map) self.fill_label_combobox() self.init_label_time_line() def closeEvent(self, e): self.timer.stop() self.leftView.makeCurrent() try: del self.leftView except: print("ignore the error and keep going") def slot_undo(self): frames = self._animation_editor.undo() if frames is not None: self.n_frames = len(frames) self.set_frame_range() self.original_controller.replace_frames(frames) self.original_controller.updateTransformation() print("undo") else: print("nothing to undo") def on_mouse_click(self, event, ray_start, ray_dir, pos, node_id): if event.button() == Qt.LeftButton: self.left_scene.select_object(node_id, (ray_start, ray_dir)) joint_knob = self.get_selected_joint() label = "Selected Joint: " if joint_knob is not None: label += joint_knob.joint_name else: label += "None" self.jointLabel.setText(label) def on_mouse_release(self, event): self.left_scene.deactivate_axis() if self.edited_knob is None: return position = self.edited_knob.scene_object.getPosition() offset = position - self.left_scene.scene_edit_widget.original_position joint_name = self.edited_knob.joint_name ik_frame_idx = self.leftDisplayFrameSlider.value() copy_start = self.leftStartFrameSlider.value() copy_end = self.leftEndFrameSlider.value() + 1 if copy_start > copy_end: print("frame range is wrong", copy_start, copy_end) return frame_range = copy_start, copy_end self.edited_knob.edit_mode = True use_ccd = self.ccdCheckBox.checkState() == Qt.Checked blend_window_size = int(self.blendRangeLineEdit.text()) self._animation_editor.translate_joint(joint_name, offset, ik_frame_idx, frame_range, blend_window_size, use_ccd, plot=False, apply=True) self.edited_knob.edit_mode = False self.show_change() self.edited_knob = None def on_mouse_move(self, event, last_mouse_pos, cam_pos, cam_ray): self.left_scene.handle_mouse_movement(cam_pos, cam_ray) def init_joints(self, controller): for joint_name in controller.get_animated_joints(): if len(self.skeleton.nodes[joint_name].children ) > 0: # filter out end site joints child_node = self.skeleton.nodes[joint_name].children[0] if np.linalg.norm(child_node.offset) > 0: self.left_scene.object_builder.create_object( "joint_control_knob", controller, joint_name, self.radius * self.skeleton_vis.box_scale) def copy_controller(self, controller, target_scene): skeleton = controller.get_skeleton_copy() mv = controller.get_motion_vector_copy() print("copied", mv.n_frames, len(mv.frames), controller.getNumberOfFrames()) o = target_scene.object_builder.create_object("animation_controller", "", skeleton, mv, mv.frame_time, semantic_annotation=None) #target_scene.object_builder.create_component("animation_editor", o) self._animation_editor = AnimationEditor( o) #o._components["animation_editor"] return o._components["animation_controller"] def draw(self): """ draw current scene on the given view (note before calling this function the context of the view has to be set as current using makeCurrent() and afterwards the doubble buffer has to swapped to display the current frame swapBuffers()) """ try: if not self.initialized: if self.leftView.graphics_context is not None: self.leftView.resize(400, 400) self.initialized = True except: import sys sys.exit(0) self.left_scene.update(self.dt) self.leftView.makeCurrent() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.leftView.graphics_context.render(self.left_scene) self.leftView.swapBuffers() def left_display_changed(self, frame_idx): if self.controller is not None: self.controller.setCurrentFrameNumber(frame_idx) self.leftDisplayFrameSpinBox.setValue(frame_idx) self.contactLabelView.setFrame(frame_idx) def left_spinbox_frame_changed(self, frame): self.leftStartFrameSlider.setValue(self.leftStartFrameSpinBox.value()) self.leftEndFrameSlider.setValue(self.leftEndFrameSpinBox.value()) def left_slider_frame_changed(self, frame): self.leftStartFrameSpinBox.setValue(self.leftStartFrameSlider.value()) self.leftEndFrameSpinBox.setValue(self.leftEndFrameSlider.value()) def slot_accept(self): self.success = True self.close() def slot_reject(self): self.close() def set_frame_range(self): self.leftDisplayFrameSlider.setRange(0, self.n_frames - 1) self.leftDisplayFrameSpinBox.setRange(0, self.n_frames - 1) self.leftStartFrameSlider.setRange(0, self.n_frames - 1) self.leftEndFrameSlider.setRange(0, self.n_frames - 1) self.leftStartFrameSpinBox.setRange(0, self.n_frames - 1) self.leftEndFrameSpinBox.setRange(0, self.n_frames - 1) self.leftEndFrameSlider.setValue(self.n_frames - 1) self.leftEndFrameSpinBox.setValue(self.n_frames - 1) def get_selected_joint(self): joint_knob = None o = self.left_scene.selected_scene_object if o is not None and "joint_control_knob" in o._components: joint_knob = o._components["joint_control_knob"] return joint_knob def slot_translate_joint(self): plot = False joint_knob = self.get_selected_joint() if joint_knob is None: return x = float(self.translateXLineEdit.text()) y = float(self.translateYLineEdit.text()) z = float(self.translateZLineEdit.text()) offset = [x, y, z] joint_name = joint_knob.joint_name ik_frame_idx = self.leftDisplayFrameSlider.value() copy_start = self.leftStartFrameSlider.value() copy_end = self.leftEndFrameSlider.value() + 1 if copy_start > copy_end: print("frame range is wrong", copy_start, copy_end) return frame_range = copy_start, copy_end joint_knob.edit_mode = True apply = self.collectConstraintsCheckBox.checkState() == Qt.Unchecked use_ccd = self.ccdCheckBox.checkState() == Qt.Checked blend_window_size = int(self.blendRangeLineEdit.text()) self._animation_editor.translate_joint(joint_name, offset, ik_frame_idx, frame_range, blend_window_size, use_ccd, plot, apply) joint_knob.edit_mode = False self.show_change() def slot_clear_constraints(self): self._animation_editor.clear_constraints() def slot_rotate_joint(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name x = float(self.rotateXLineEdit.text()) y = float(self.rotateYLineEdit.text()) z = float(self.rotateZLineEdit.text()) edit_start = self.leftStartFrameSlider.value() edit_end = self.leftEndFrameSlider.value() + 1 if edit_start > edit_end: print("frame range is wrong", edit_start, edit_end) return frame_range = edit_start, edit_end offset = [x, y, z] window_size = int(self.blendRangeLineEdit.text()) self._animation_editor.rotate_joint(joint_name, offset, frame_range, window_size) self.show_change() def show_change(self): frames = np.array(self.controller.get_frames()) self.original_controller.replace_frames(frames) self.original_controller.updateTransformation() self.controller.updateTransformation() def slot_smooth_frames(self): window_size = int(self.smoothWindowSizeLineEdit.text()) if window_size >= 5: print("smooth frames using a window size of", window_size) self._animation_editor.smooth_using_moving_average(window_size) else: print("Error: window size must be >= 5") def slot_concatenate(self): options = dict() options["activate_smoothing"] = True options["window"] = 20 select_animation_dialog = SelectSceneObjectsDialog( self.scene, get_animation_controllers, self, name="Concatenate", properties=options) select_animation_dialog.exec_() if select_animation_dialog.success: o = self.scene.getObject(select_animation_dialog.selected_node_id) options = select_animation_dialog.properties animation_controller = o._components["animation_controller"] self.controller._motion.mv.skeleton = self.controller.get_skeleton( ) self._animation_editor.concatenate(animation_controller, options["activate_smoothing"], options["window"]) self.n_frames = self.controller.getNumberOfFrames() self.set_frame_range() self.show_change() def slot_mirror_animation(self): self._animation_editor.mirror_animation() self.show_change() def slot_delete_frames_before(self): frame_idx = self._animation_editor.get_current_frame_number() self._animation_editor.delete_frames_before(frame_idx) def slot_delete_frames_after(self): frame_idx = self._animation_editor.get_current_frame_number() self._animation_editor.delete_frames_after(frame_idx) def slot_fix_joint(self): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_name = joint_knob.joint_name apply = self.collectConstraintsCheckBox.checkState() == Qt.Unchecked edit_start = self.leftStartFrameSlider.value() edit_end = self.leftEndFrameSlider.value() + 1 joint_knob.edit_mode = True frame = self.controller.get_current_frame() p = self.controller.get_joint_position(joint_name, frame) p = p.tolist() if edit_start < edit_end: frame_range = edit_start, edit_end self._animation_editor.fix_joint(joint_name, p, frame_range, apply) else: print("frame range is wrong", edit_start, edit_end) joint_knob.edit_mode = False self.show_change() def slot_export_command_history(self): filename = QFileDialog.getSaveFileName(self, 'Save To File', '.')[0] save_json_file(self._animation_editor.command_history, filename) def slot_apply_constraints(self, plot=False): use_ccd = self.ccdCheckBox.checkState() == Qt.Checked if use_ccd: self._animation_editor.apply_constraints_using_ccd(plot) else: self._animation_editor.apply_constraints(plot) def slot_resample_motion(self): resample_factor = float(self.resampleFactorLineEdit.text()) if resample_factor >= 0: print("resample frames using a factor of", resample_factor) self._animation_editor.resample_motion(resample_factor) self.n_frames = self.controller.getNumberOfFrames() self.set_frame_range() self.show_change() else: print("Error: resample factor must be > 0", resample_factor) def slot_set_fps(self): fps = float(self.fpsLineEdit.text()) if fps >= 0: print("set fps to", fps) self.controller._motion.mv.frame_time = 1.0 / fps self.show_change() else: print("Error: window size must be > 0", fps) def flip_blender_coordinate_systems(self): self._animation_editor.flip_blender_coordinate_systems() def guess_ground_height(self): source_ground_height = self._animation_editor.guess_ground_height( False) self.sourceGroundHeightLineEdit.setText(str(source_ground_height)) def move_to_ground(self): source_ground_height = float(self.sourceGroundHeightLineEdit.text()) target_ground_height = float(self.targetGroundHeightLineEdit.text()) self._animation_editor.move_to_ground(source_ground_height, target_ground_height) self.show_change() def detect_foot_contacts(self): source_ground_height = float(self.sourceGroundHeightLineEdit.text()) ground_contacts = self._animation_editor.detect_ground_contacts( source_ground_height) ground_annotation = collections.OrderedDict() color_map = collections.OrderedDict() n_frames = self.controller.getNumberOfFrames() for idx in range(n_frames): for label in ground_contacts[idx]: if label not in ground_annotation: color_map[label] = get_random_color() ground_annotation[label] = [[]] ground_annotation[label][0].append(idx) self.annotation_editor.set_annotation(ground_annotation, color_map) self.init_label_time_line() def ground_feet(self): target_ground_height = float(self.targetGroundHeightLineEdit.text()) n_frames = self.controller.getNumberOfFrames() ground_contacts = [[] for f in range(n_frames)] ground_annotation = self.annotation_editor._semantic_annotation for label in ground_annotation: if label not in self.skeleton.nodes: print("ignore", label) continue for entry in ground_annotation[label]: for idx in entry: ground_contacts[idx].append(label) self._animation_editor.apply_foot_constraints(ground_contacts, target_ground_height) self.show_change() def init_label_time_line(self): n_frames = self.controller.getNumberOfFrames() self.contactLabelView.clearScene() self.contactLabelView.create_frame_indicator() self.contactLabelView.setTimeLineParameters(n_frames, 10) self.contactLabelView.set_edit_start_frame(0) ground_annotation = self.annotation_editor._semantic_annotation color_map = self.annotation_editor._label_color_map if len(ground_annotation) > 0: for label, indices in ground_annotation.items(): color = [0, 0, 1] if label in color_map: color = color_map[label] joint_indices = [] n_entries = len(indices) if n_entries > 0 and type(indices[0]) == list: for i in range(n_entries): joint_indices += indices[i] else: joint_indices = indices self.contactLabelView.addLabel(label, joint_indices, color) else: self.contactLabelView.addLabel("empty", [], [0, 0, 0]) def keyReleaseEvent(self, event): if event.key() == Qt.Key_G: self.create_annotation_section() elif event.key() == Qt.Key_H: self.remove_annotation_section() elif event.key() == Qt.Key_K: self.set_annotation_edit_start() def create_annotation_section(self): if self.labelComboBox.count() < 1: return frame_idx = self.controller._motion.frame_idx start_idx = self.annotation_editor.prev_annotation_edit_frame_idx label = str(self.labelComboBox.currentText()) self.annotation_editor.create_annotation_section(frame_idx, label) self.annotation_editor.set_annotation_edit_start(start_idx) self.init_label_time_line() def remove_annotation_section(self): if self.labelComboBox.count() < 1: return frame_idx = self.controller._motion.frame_idx start_idx = self.annotation_editor.prev_annotation_edit_frame_idx label = str(self.labelComboBox.currentText()) self.annotation_editor.remove_annotation_section(frame_idx, label) self.annotation_editor.set_annotation_edit_start(start_idx) self.init_label_time_line() def set_annotation_edit_start(self): frame_idx = self.controller._motion.frame_idx self.annotation_editor.set_annotation_edit_start(frame_idx) self.contactLabelView.set_edit_start_frame(frame_idx) def on_move_widget(self, position): joint_knob = self.get_selected_joint() if joint_knob is None: return joint_knob.edit_mode = True joint_knob.scene_object.setPosition(position) self.edited_knob = joint_knob def fill_label_combobox(self): self.labelComboBox.clear() for idx, label in enumerate( self.annotation_editor._semantic_annotation): self.labelComboBox.addItem(label, idx)