diff --git a/nxt/archetype/anim_rig.nxt b/nxt/archetype/anim_rig.nxt index 9e5b979..3b12405 100644 --- a/nxt/archetype/anim_rig.nxt +++ b/nxt/archetype/anim_rig.nxt @@ -13,11 +13,11 @@ "positions": { "/apply": [ 45.101567325149915, - -13.162854949084434 + -14.162854949084434 ], "/cleanup": [ - 464.7309816100551, - -10.474659993798152 + 467.7309816100551, + -15.474659993798152 ], "/cleanup/control_shapes": [ 0.0, @@ -27,6 +27,10 @@ -2.4974733523247323, 95.12116921241874 ], + "/main": [ + -679.5661157024792, + 324.3636363636364 + ], "/middle": [ -396.0467648945946, -12.903779307342678 @@ -39,6 +43,10 @@ -834.0036602069565, -12.525269102154974 ], + "/setup": [ + -858.5661157024792, + -11.63636363636364 + ], "/setup/rig_hierarchy": [ 0.0, 0.0 @@ -51,6 +59,10 @@ -1385.6737855003867, -12.961234388183893 ], + "/skin": [ + 180.10156732514997, + 346.8371450509156 + ], "/skin_geometry": [ -795.4972743705686, -408.77017313211803 @@ -61,9 +73,10 @@ ] }, "collapse": { + "/apply/deformation": false, "/cleanup/hide_joints": true, - "/root": false, - "/root/rig_hierarchy": true + "/root/rig_hierarchy": true, + "/setup/root": false }, "locks": { "$YRIG_NXT_DIR/core.nxt": false, @@ -90,9 +103,9 @@ "/apply": { "execute_in": "/middle", "child_order": [ - "control_shapes", "rest_pose", - "skin" + "control_shapes", + "deformation" ] }, "/apply/control_shapes": { @@ -106,35 +119,45 @@ "yrig.control.serialize.apply_control_shapes_file(Path(\"${control_shapes_filepath}\"))" ] }, - "/apply/rest_pose": { - "attrs": { - "rest_pose": { - "type": "raw", - "value": "dagPose1" - } - }, - "code": [ - "if STAGE.control_list:", - " cmds.dagPose(STAGE.control_list, name=\"${rest_pose}\", addToPose=True)" + "/apply/deformation": { + "child_order": [ + "main" + ] + }, + "/apply/deformation/main": { + "child_order": [ + "skin" ] }, - "/apply/skin": { + "/apply/deformation/main/skin": { "instance": "/skin_geometry", "child_order": [ "split" ], "attrs": { "geo_set": { - "value": "${/root/model.model_set}" + "value": "${/setup/root/model.model_set}" }, "skin_directory": { "value": "${file::${rig_path}/data/skin}" } } }, - "/apply/skin/split": { + "/apply/deformation/main/skin/split": { "instance": "/split_skin_weights" }, + "/apply/rest_pose": { + "attrs": { + "rest_pose": { + "type": "raw", + "value": "dagPose1" + } + }, + "code": [ + "if STAGE.control_list:", + " cmds.dagPose(STAGE.control_list, name=\"${rest_pose}\", addToPose=True)" + ] + }, "/cleanup": { "execute_in": "/apply", "child_order": [ @@ -147,14 +170,14 @@ "code": [ "if not ${dev_build}:", " # Hide Joints", - " cmds.setAttr(\"${/root.rig_root}.jnt_vis\", False) # type: ignore", + " cmds.setAttr(\"${/setup/root.rig_root}.jnt_vis\", False) # type: ignore", "" ] }, "/cleanup/model_override": { "code": [ "if not ${dev_build}:", - " geo_group = \"${/root/model.model_group}\"", + " geo_group = \"${/setup/root/model.model_group}\"", " cmds.setAttr(f\"{geo_group}.overrideEnabled\", True) # type: ignore", " cmds.setAttr(f\"{geo_group}.overrideDisplayType\", 2) # type: ignore", "" @@ -168,15 +191,21 @@ }, "/middle": { "instance": "/side", - "execute_in": "/root" + "execute_in": "/setup" }, - "/root": { + "/setup": { "start_point": true, + "child_order": [ + "root" + ] + }, + "/setup/root": { + "start_point": false, "child_order": [ "model", "guides", "controls", - "deformers" + "deformation" ], "attrs": { "rig_root": { @@ -200,12 +229,28 @@ " cmds.sets(name=rig_set)" ] }, - "/root/controls": { + "/setup/root/controls": { "code": [ "STAGE.control_list = []" ] }, - "/root/deformers": { + "/setup/root/deformation": { + "child_order": [ + "static_joint", + "main" + ], + "attrs": { + "joint_group": { + "type": "raw", + "value": "jnt_org" + }, + "model_set": { + "type": "raw", + "value": "${/setup/root/model.model_set}" + } + } + }, + "/setup/root/deformation/main": { "attrs": { "deformers_set": { "type": "raw", @@ -218,7 +263,18 @@ " cmds.sets(name=rig_set)" ] }, - "/root/guides": { + "/setup/root/deformation/static_joint": { + "attrs": { + "static_joint": { + "type": "raw", + "value": "static_jnt" + } + }, + "code": [ + "yrig.joint.create_joint(\"static\", parent=\"${joint_group}\")" + ] + }, + "/setup/root/guides": { "attrs": { "guides_filepath": { "type": "raw", @@ -226,7 +282,7 @@ } } }, - "/root/model": { + "/setup/root/model": { "attrs": { "model_filepath": { "type": "raw", diff --git a/nxt/archetype/biped/biped.nxt b/nxt/archetype/biped/biped.nxt index ccf2ad7..86331d5 100644 --- a/nxt/archetype/biped/biped.nxt +++ b/nxt/archetype/biped/biped.nxt @@ -19,18 +19,50 @@ 1296.6643526537218, -15.594755912117055 ], + "/component": [ + -871.1745871252489, + -1125.2381176092777 + ], "/deformation": [ 856.0087940139424, -9.668699423947338 ], + "/ear_component": [ + -849.5507090116776, + -365.5183048649902 + ], + "/eye_component": [ + -857.6859635911101, + -761.9860552804687 + ], + "/eye_def": [ + -855.304547848069, + -701.6364080255946 + ], + "/face_base_component": [ + -866.1340283878521, + -974.9116258957818 + ], "/left": [ 18.209666557736483, -12.063569759815769 ], + "/look_component": [ + -853.3603880127753, + -636.7830673903558 + ], "/middle": [ -396.0467648945946, -12.903779307342678 ], + "/mouth_component": [ + -864.3952489745639, + -908.067517878749 + ], + "/nose_component": [ + -849.4954333098872, + -574.777657650386 + ], "/right": [ 419.19959226227263, -11.329718709791148 @@ -40,15 +72,49 @@ -13.679528134599906 ], "/shifter_build": [ - -1328.4283558944185, - -109.8002192791547 + -1450.4047765525336, + 49.58230371411526 ], "/shifter_component_build": [ -1333.8722592666647, -13.21855392066065 + ], + "/shifter_component_build_pasted": [ + -1216.6259972304554, + 54.15622969038259 + ], + "/side": [ + -867.8719860022462, + -1054.7293578480908 + ], + "/simple_eyebrow": [ + -863.6678902886301, + -841.6006521236975 + ], + "/skin_geometry": [ + 860.1225287185864, + -263.3559470406896 + ], + "/split_skin_weights": [ + 855.8232656330174, + -319.5965655011383 + ], + "/teeth_component": [ + -844.5785455250948, + -503.15705362133156 + ], + "/tongue_component": [ + -853.2658834507188, + -429.3013749665338 + ], + "/transfer_skin_weights": [ + 862.0089522432202, + -212.17592278220042 ] }, "collapse": { + "/apply/deformation/face": false, + "/apply/deformation/face/duplicate_geo": false, "/left": false, "/right/ear": true, "/right/eye": true, @@ -103,19 +169,6 @@ } } }, - "/root": { - "start_point": false, - "execute_in": "/shifter_component_build" - }, - "/shifter_component_build/finger_meta_fix": { - "code": [ - "for side in [\"L\", \"R\"]:", - " for num in range(4):", - " control_name = f\"meta_{side}0_meta{num}_ctl\"", - " group_name = f\"finger_{side}{num}_root\"", - " cmds.parent(group_name, control_name)" - ] - }, "/tools_window/biped": { "instance": "/tab", "attrs": { diff --git a/nxt/archetype/biped/body.nxt b/nxt/archetype/biped/body.nxt index 2629436..8d7a109 100644 --- a/nxt/archetype/biped/body.nxt +++ b/nxt/archetype/biped/body.nxt @@ -16,7 +16,7 @@ } }, "nodes": { - "/apply/skin/transfer_sim_weights": { + "/apply/deformation/main/skin/transfer_sim_weights": { "instance": "/transfer_skin_weights", "attrs": { "transfer_mapping": { @@ -25,11 +25,18 @@ } } }, - "/shifter_component_build": { - "start_point": true, + "/setup": { + "child_order": [ + "shifter_component_build", + "root" + ] + }, + "/setup/shifter_component_build": { + "start_point": false, "instance": "/shifter_build", "child_order": [ - "attribute_defaults" + "attribute_defaults", + "finger_meta_fix" ], "attrs": { "body_rig_temp_filepath": { @@ -80,7 +87,7 @@ " yrig.io.export_maya_file(body_rig_temp_filepath, binary=True, force=True)" ] }, - "/shifter_component_build/attribute_defaults": { + "/setup/shifter_component_build/attribute_defaults": { "code": [ "for control in [\"armUI_L0_ctl\", \"armUI_R0_ctl\"]:", " cmds.setAttr(f\"{control}.arm_ikref\", 5)", @@ -88,6 +95,15 @@ "for control in [\"legUI_L0_ctl\", \"legUI_R0_ctl\"]:", " cmds.setAttr(f\"{control}.foot_angle_1\", -40)" ] + }, + "/setup/shifter_component_build/finger_meta_fix": { + "code": [ + "for side in [\"L\", \"R\"]:", + " for num in range(4):", + " control_name = f\"meta_{side}0_meta{num}_ctl\"", + " group_name = f\"finger_{side}{num}_root\"", + " cmds.parent(group_name, control_name)" + ] } } } \ No newline at end of file diff --git a/nxt/archetype/biped/face.nxt b/nxt/archetype/biped/face.nxt index 1d49bb3..2f9953b 100644 --- a/nxt/archetype/biped/face.nxt +++ b/nxt/archetype/biped/face.nxt @@ -5,6 +5,7 @@ "mute": false, "solo": false, "references": [ + "component/face/face_base.nxt", "component/face/eye.nxt", "component/face/eyebrow.nxt", "component/face/mouth.nxt", @@ -15,6 +16,10 @@ ], "meta_data": { "positions": { + "/cleanup": [ + 578.6271216105457, + 41.68783296905949 + ], "/ear": [ 318.8538364053693, 142.4484541260124 @@ -43,6 +48,10 @@ 280, 20 ], + "/face_base_component": [ + -1435.4748153869095, + 341.9310107006777 + ], "/left": [ 160.30801917363112, 39.76334630104233 @@ -112,10 +121,12 @@ "collapse": { "/ear_component": true, "/eye_component": true, + "/face_base_component": true, "/left/ear": true, "/left/eye": true, "/left/eyebrow": true, "/look_component": true, + "/middle/face/base": true, "/middle/face/look": true, "/middle/face/mouth": true, "/middle/face/nose": true, @@ -129,6 +140,49 @@ } }, "nodes": { + "/apply/deformation": { + "child_order": [ + "face", + "main" + ] + }, + "/apply/deformation/face": { + "child_order": [ + "skin" + ], + "attrs": { + "def_layer_group": { + "type": "raw", + "value": "${/setup/root/deformation/face.def_layer_group}" + }, + "def_layer_name": { + "type": "raw", + "value": "face" + } + } + }, + "/apply/deformation/face/skin": { + "instance": "/skin_geometry", + "child_order": [ + "split" + ], + "attrs": { + "geo_list": { + "value": "${/setup/root/deformation/face/duplicate_geo.duplicated_geo}" + }, + "skin_directory": { + "type": "raw", + "value": "${file::${rig_path}/data/face/skin}" + }, + "strip_suffix": { + "type": "raw", + "value": "_${def_layer_group}" + } + } + }, + "/apply/deformation/face/skin/split": { + "instance": "/split_skin_weights" + }, "/cleanup": { "child_order": [ "delete_face_guides", @@ -141,7 +195,7 @@ "attrs": { "face_guides_group": { "type": "raw", - "value": "${/root/guides/face.face_guides_group}" + "value": "${/setup/root/guides/face.face_guides_group}" } }, "code": [ @@ -156,21 +210,42 @@ ] }, "/left/ear": { - "instance": "/ear_component" + "instance": "/ear_component", + "attrs": { + "control_parent": { + "value": "face_muppet_M_ctl" + }, + "joint_parent": { + "value": "face_muppet_M_jnt" + } + } }, "/left/eye": { - "instance": "/eye_component" + "instance": "/eye_component", + "attrs": { + "control_parent": { + "value": "face_upper_M_ctl" + }, + "joint_parent": { + "value": "face_upper_M_jnt" + } + } }, "/left/eyebrow": { "instance": "/simple_eyebrow", "attrs": { + "control_parent": { + "value": "face_top_M_ctl" + }, "joint_parent": { - "value": "face_jnt" + "type": "raw", + "value": "face_top_M_jnt" } } }, "/middle/face": { "child_order": [ + "base", "nose", "mouth", "tongue", @@ -178,18 +253,18 @@ "look" ], "attrs": { - "joint_parent": { + "face_joint_parent": { "type": "raw", "value": "neck_M0_head_jnt" }, - "parent": { + "face_parent": { "type": "raw", "value": "neck_M0_head_ctl" } }, "code": [ - "parent=\"${parent}\"", - "joint_parent=\"${joint_parent}\"", + "parent=\"${face_parent}\"", + "joint_parent=\"${face_joint_parent}\"", "transform = \"face_M\" if cmds.objExists(\"face_M\") else None", "", "face_group = yrig.transform.create_transform(", @@ -204,6 +279,18 @@ " connect=False)" ] }, + "/middle/face/base": { + "instance": "/face_base_component", + "attrs": { + "joint_parent": { + "value": "face_jnt" + }, + "parent": { + "type": "raw", + "value": "${face_parent}" + } + } + }, "/middle/face/look": { "instance": "/look_component" }, @@ -217,25 +304,23 @@ "value": "1" }, "joint_parent": { - "value": "face_jnt" + "value": "${/setup/root/deformation/face.def_layer_group}" + }, + "parent": { + "value": "${/setup/root/deformation/face.def_layer_group}" } } }, "/middle/face/mouth/skin_surface": { "attrs": { "mouth_surface_skin_filepath": { + "type": "raw", "value": "${file::${rig_path}/data/face/mouth_surface.yskin}" } } }, "/middle/face/nose": { - "instance": "/nose_component", - "code": [ - "group = yrig.transform.create_transform(name=\"${component_group}\", parent=\"${parent}\")", - "cmds.setAttr(f\"{group}.overrideEnabled\", True)", - "cmds.setAttr(f\"{group}.drawOverride.overrideRGBColors\", True)", - "cmds.connectAttr(\"${control_layer}.controlColor\", f\"{group}.drawOverride.overrideColorRGB\")" - ] + "instance": "/nose_component" }, "/middle/face/teeth": { "instance": "/teeth_component" @@ -243,7 +328,58 @@ "/middle/face/tongue": { "instance": "/tongue_component" }, - "/root/guides/face": { + "/setup/root/deformation/face": { + "child_order": [ + "duplicate_geo" + ], + "attrs": { + "def_layer_group": { + "type": "raw", + "value": "${def_layer_name}_setup" + }, + "def_layer_name": { + "type": "raw", + "value": "face" + }, + "parent": { + "type": "raw", + "value": "setup" + } + }, + "code": [ + "def_layer_group = yrig.transform.create_transform(\"${def_layer_group}\", parent=\"${parent}\")", + "cmds.hide(def_layer_group)" + ] + }, + "/setup/root/deformation/face/duplicate_geo": { + "attrs": { + "duplicated_geo": { + "type": "list", + "value": "[]" + }, + "geo_to_duplicate": { + "type": "list", + "value": "[\"body_geo\"]" + } + }, + "code": [ + "from yrig.transform import get_shape", + "", + "geo_to_duplicate = ${geo_to_duplicate}", + "for geo in geo_to_duplicate:", + " duplicated = cmds.duplicate(geo, name=f\"{geo}_${def_layer_group}\")[0]", + " cmds.parent(duplicated, \"${def_layer_group}\")", + " geo_shape = get_shape(geo)", + " geo_input = cmds.deformableShape(geo_shape, frontOfChain=True)[0] or f\"{geo_shape}.{cmds.deformableShape(geo_shape, localShapeInAttr=True)[0]}\"", + " print(geo_input)", + " duplicated_shape = get_shape(duplicated)", + " duplicated_output = cmds.deformableShape(duplicated_shape, localShapeOutAttr=True)[0]", + " cmds.connectAttr(f\"{duplicated_shape}.{duplicated_output}\", geo_input)", + " cmds.sets(duplicated, remove=\"${model_set}\")", + " self.duplicated_geo.append(duplicated)" + ] + }, + "/setup/root/guides/face": { "attrs": { "face_guides_filepath": { "type": "raw", diff --git a/nxt/component/face/ear.nxt b/nxt/component/face/ear.nxt index 0aa380a..8190e86 100644 --- a/nxt/component/face/ear.nxt +++ b/nxt/component/face/ear.nxt @@ -19,8 +19,12 @@ "build" ], "attrs": { + "control_parent": { + "value": "face_muppet_M_ctl" + }, "joint_parent": { - "value": "face_jnt" + "type": "raw", + "value": "face_muppet_M_jnt" }, "name": { "type": "raw", @@ -29,13 +33,7 @@ "parent": { "value": "face_grp" } - }, - "code": [ - "group = yrig.transform.create_transform(name=\"${component_group}\", parent=\"${parent}\")", - "cmds.setAttr(f\"{group}.overrideEnabled\", True)", - "cmds.setAttr(f\"{group}.drawOverride.overrideRGBColors\", True)", - "cmds.connectAttr(\"${control_layer}.controlColor\", f\"{group}.drawOverride.overrideColorRGB\")" - ] + } }, "/ear_component/build": { "code": [ @@ -45,7 +43,7 @@ " part=\"${name}\",", " side=\"${side}\",", " parent=\"${component_group}\",", - " control_parent=\"${control_parent}\",", + " control_parent=\"${control_group}\",", " parent_jnt=\"${joint_parent}\",", " control_size=1,", ")", diff --git a/nxt/component/face/eye.nxt b/nxt/component/face/eye.nxt index acd6257..9583894 100755 --- a/nxt/component/face/eye.nxt +++ b/nxt/component/face/eye.nxt @@ -23,8 +23,12 @@ "build" ], "attrs": { + "control_parent": { + "value": "face_upper_M_ctl" + }, "joint_parent": { - "value": "face_jnt" + "type": "raw", + "value": "face_upper_M_jnt" }, "look_parent": { "type": "raw", @@ -46,7 +50,7 @@ " part=\"${name}\",", " side=\"${side}\",", " parent=\"${component_group}\",", - " control_parent=\"${control_parent}\",", + " control_parent=\"${control_group}\",", " parent_jnt=\"${joint_parent}\",", " control_size=1,", " look_parent='${look_parent}'", @@ -90,7 +94,7 @@ " parent = \"${component_group}\",", " part=\"${name}\",", " side=\"${side}\",", - " control_parent=\"${control_parent}\",", + " control_parent=\"${control_group}\",", " parent_spaces=parent_spaces,", ")", "look_rig.build()" diff --git a/nxt/component/face/eyebrow.nxt b/nxt/component/face/eyebrow.nxt index 54c172c..65e92e6 100644 --- a/nxt/component/face/eyebrow.nxt +++ b/nxt/component/face/eyebrow.nxt @@ -25,17 +25,19 @@ "attrs": { "control_parent": { "type": "raw", - "value": "${component_group}" + "value": "face_top_M_ctl" }, "control_size": { "type": "float", "value": "0.5" }, + "joint_parent": { + "value": "face_top_M_jnt" + }, "name": { "value": "eyebrow" }, "parent": { - "type": "raw", "value": "face_grp" } } @@ -45,7 +47,7 @@ "rotate_order = yrig.maya_api.enum.RotateOrder.XYZ", "", "with yrig.control.collect_controls() as component_controls:", - " control_parent = \"${control_parent}\"", + " control_parent = \"${control_group}\"", " ", " main_guide = \"${name}_${side}\"", " inner_guide = \"${name}_inner_${side}\"", diff --git a/nxt/component/face/face_base.nxt b/nxt/component/face/face_base.nxt new file mode 100644 index 0000000..847bd74 --- /dev/null +++ b/nxt/component/face/face_base.nxt @@ -0,0 +1,56 @@ +{ + "version": "1.17", + "alias": "face_base", + "color": "#cc704b", + "mute": false, + "solo": false, + "meta_data": { + "positions": { + "/face_base_component": [ + -1346.6964062960003, + 1060.749742372232 + ] + } + }, + "nodes": { + "/face_base_component": { + "instance": "/component", + "child_order": [ + "build" + ], + "attrs": { + "control_size": { + "type": "int", + "value": "4" + }, + "name": { + "value": "face_base" + } + } + }, + "/face_base_component/build": { + "code": [ + "from yrig.component.face_base import FaceBase, FaceBaseGuides", + "", + "guides = FaceBaseGuides(", + " lower = \"face_lower_M\",", + " muppet = \"face_muppet_M\",", + " upper = \"face_upper_M\",", + " top = \"face_top_M\",", + " jaw = \"jaw_M\",", + ")", + "", + "with yrig.control.collect_controls() as component_controls:", + " face_base = FaceBase(", + " guides=guides, ", + " parent=\"${component_group}\",", + " control_parent=\"${control_group}\", ", + " joint_parent=\"${joint_parent}\", ", + " control_size=${control_size}", + " )", + " ", + "STAGE.control_list.extend(component_controls)" + ] + } + } +} \ No newline at end of file diff --git a/nxt/component/face/mouth.nxt b/nxt/component/face/mouth.nxt index 0337056..bbae195 100755 --- a/nxt/component/face/mouth.nxt +++ b/nxt/component/face/mouth.nxt @@ -21,13 +21,23 @@ ], "attrs": { "control_parent": { - "type": "raw", - "value": "${component_group}" + "value": "face_lower_M_ctl" }, "control_size": { "type": "int", "value": "2" }, + "face_mid": { + "type": "raw", + "value": "face_mid_M_driven" + }, + "jaw_transform": { + "type": "raw", + "value": "jaw_M_ctl" + }, + "joint_parent": { + "value": "face_lower_M_jnt" + }, "name": { "value": "mouth" }, @@ -79,7 +89,6 @@ "mouth_guides = MouthGuides(", " mouth = \"mouth_M\",", " mouth_surface = \"face_surface\",", - " jaw = \"jaw_M\",", " left_corner = left_corner_guide,", " right_corner = right_corner_guide,", " upper_lip = upper_lip_guides,", @@ -91,9 +100,11 @@ " mouth = Mouth(", " guides=mouth_guides, ", " parent=\"${component_group}\",", - " control_parent=\"${control_parent}\", ", + " control_parent=\"${control_group}\", ", " joint_parent=\"${joint_parent}\", ", - " control_size=${control_size}", + " jaw = \"${jaw_transform}\",", + " face_mid = \"${face_mid}\",", + " control_size=${control_size},", " )", " ", "STAGE.control_list.extend(component_controls)" diff --git a/nxt/component/face/nose.nxt b/nxt/component/face/nose.nxt index 3b6ca7e..373bf6a 100644 --- a/nxt/component/face/nose.nxt +++ b/nxt/component/face/nose.nxt @@ -19,8 +19,12 @@ "build" ], "attrs": { + "control_parent": { + "value": "face_muppet_M_ctl" + }, "joint_parent": { - "value": "face_jnt" + "type": "raw", + "value": "face_muppet_M_jnt" }, "name": { "type": "raw", @@ -29,13 +33,7 @@ "parent": { "value": "face_grp" } - }, - "code": [ - "group = yrig.transform.create_transform(name=\"${component_group}\", parent=\"${parent}\")", - "cmds.setAttr(f\"{group}.overrideEnabled\", True)", - "cmds.setAttr(f\"{group}.drawOverride.overrideRGBColors\", True)", - "cmds.connectAttr(\"${control_layer}.controlColor\", f\"{group}.drawOverride.overrideColorRGB\")" - ] + } }, "/nose_component/build": { "code": [ @@ -45,7 +43,7 @@ " part=\"${name}\",", " side=\"${side}\",", " parent=\"${component_group}\",", - " control_parent=\"${control_parent}\",", + " control_parent=\"${control_group}\",", " parent_jnt=\"${joint_parent}\",", " control_size=1,", ")", diff --git a/nxt/component/face/teeth.nxt b/nxt/component/face/teeth.nxt index 378979d..9906262 100644 --- a/nxt/component/face/teeth.nxt +++ b/nxt/component/face/teeth.nxt @@ -24,10 +24,12 @@ ], "attrs": { "control_parent": { - "value": "jaw_M_ctl" + "type": "raw", + "value": "face_lower_M_ctl" }, "joint_parent": { - "value": "face_jnt" + "type": "raw", + "value": "face_lower_M_jnt" }, "name": { "type": "raw", @@ -36,13 +38,7 @@ "parent": { "value": "face_grp" } - }, - "code": [ - "group = yrig.transform.create_transform(name=\"${component_group}\", parent=\"${parent}\")", - "cmds.setAttr(f\"{group}.overrideEnabled\", True)", - "cmds.setAttr(f\"{group}.drawOverride.overrideRGBColors\", True)", - "cmds.connectAttr(\"${control_layer}.controlColor\", f\"{group}.drawOverride.overrideColorRGB\")" - ] + } }, "/teeth_component/build": { "code": [ @@ -52,7 +48,7 @@ " part=\"${name}\",", " side=\"${side}\",", " parent=\"${component_group}\",", - " control_parent=\"${control_parent}\",", + " control_parent=\"${control_group}\",", " parent_jnt=\"${joint_parent}\",", " control_size=1,", ")", diff --git a/nxt/component/face/tongue.nxt b/nxt/component/face/tongue.nxt index d660644..1f338d3 100644 --- a/nxt/component/face/tongue.nxt +++ b/nxt/component/face/tongue.nxt @@ -20,10 +20,12 @@ ], "attrs": { "control_parent": { + "type": "raw", "value": "jaw_M_ctl" }, "joint_parent": { - "value": "face_jnt" + "type": "raw", + "value": "jaw_M_jnt" }, "name": { "type": "raw", @@ -32,13 +34,7 @@ "parent": { "value": "face_grp" } - }, - "code": [ - "group = yrig.transform.create_transform(name=\"${component_group}\", parent=\"${parent}\")", - "cmds.setAttr(f\"{group}.overrideEnabled\", True)", - "cmds.setAttr(f\"{group}.drawOverride.overrideRGBColors\", True)", - "cmds.connectAttr(\"${control_layer}.controlColor\", f\"{group}.drawOverride.overrideColorRGB\")" - ] + } }, "/tongue_component/build": { "code": [ @@ -48,7 +44,7 @@ " part=\"${name}\",", " side=\"${side}\",", " parent=\"${component_group}\",", - " control_parent=\"${control_parent}\",", + " control_parent=\"${control_group}\",", " parent_jnt=\"${joint_parent}\",", " control_size=1,", ")", diff --git a/nxt/core.nxt b/nxt/core.nxt index 5c2067e..0eb4a66 100644 --- a/nxt/core.nxt +++ b/nxt/core.nxt @@ -34,6 +34,10 @@ "type": "raw", "value": "${name}_${side}_root" }, + "control_group": { + "type": "raw", + "value": "${name}_${side}_ctls" + }, "control_parent": { "comment": "Parent for the controls of this component", "type": "raw", @@ -59,10 +63,12 @@ } }, "code": [ - "group = yrig.transform.create_transform(name=\"${component_group}\", parent=\"${parent}\")", - "cmds.setAttr(f\"{group}.overrideEnabled\", True)", - "cmds.setAttr(f\"{group}.drawOverride.overrideRGBColors\", True)", - "cmds.connectAttr(\"${control_layer}.controlColor\", f\"{group}.drawOverride.overrideColorRGB\")" + "self.component_group = yrig.transform.create_transform(name=\"${component_group}\", parent=\"${parent}\")", + "", + "self.control_group = yrig.transform.create_transform(name=\"${control_group}\", parent=\"${control_parent}\")", + "cmds.setAttr(f\"{self.control_group}.overrideEnabled\", True)", + "cmds.setAttr(f\"{self.control_group}.drawOverride.overrideRGBColors\", True)", + "cmds.connectAttr(\"${control_layer}.controlColor\", f\"{self.control_group}.drawOverride.overrideColorRGB\")" ] }, "/side": { diff --git a/nxt/util/skin.nxt b/nxt/util/skin.nxt index 4b38baf..f60db08 100644 --- a/nxt/util/skin.nxt +++ b/nxt/util/skin.nxt @@ -74,7 +74,7 @@ "", "strip_suffix = \"${strip_suffix}\"", "def _map_geo_to_file(geometry: str):", - " geometry.removesuffix(strip_suffix)", + " return geometry.removesuffix(strip_suffix)", "", "", "skin_directories = [Path(dir) for dir in ${resolved_skin_directories}]", @@ -97,8 +97,9 @@ "code": [ "from yrig.skin.split import auto_split_weights", "", - "geo_in_set: list[str] = cmds.sets(\"${geo_set}\", query=True) # type: ignore", - "auto_split_weights(geo_in_set)" + "geo_list = ${geo_list}", + "geo_to_split = geo_list if geo_list else cmds.sets(\"${geo_set}\", query=True)", + "auto_split_weights(geo_to_split)" ] }, "/transfer_skin_weights": { diff --git a/src/yrig/component/__init__.py b/src/yrig/component/__init__.py index 949cb4e..70b8888 100644 --- a/src/yrig/component/__init__.py +++ b/src/yrig/component/__init__.py @@ -1,6 +1,7 @@ from . import corrective_joint as corrective_joint from . import ear as ear from . import eye as eye +from . import face_base as face_base from . import mouth as mouth from . import nose as nose from . import teeth as teeth diff --git a/src/yrig/component/ear/ear.py b/src/yrig/component/ear/ear.py index 877fefb..e328d75 100644 --- a/src/yrig/component/ear/ear.py +++ b/src/yrig/component/ear/ear.py @@ -35,7 +35,9 @@ def setup_structure(self) -> None: name=f"ear_component_{self.side}", parent=self.main_grp ) cmds.hide(self.component_grp) - self.control_grp = create_transform(name=f"ear_control_{self.side}", parent=self.main_grp) + self.control_grp = create_transform( + name=f"ear_control_{self.side}", parent=self.control_parent + ) def create_controls(self) -> None: self.main_ctrl = create_control( diff --git a/src/yrig/component/eye/aim.py b/src/yrig/component/eye/aim.py index f7204e1..5c9de84 100644 --- a/src/yrig/component/eye/aim.py +++ b/src/yrig/component/eye/aim.py @@ -73,7 +73,9 @@ def create_midpoint_locator( def setup_structure(self) -> None: self.main_grp = create_transform(name=f"eye_{self.side}", parent=self.parent) - self.control_grp = create_transform(name=f"eye_control_{self.side}", parent=self.main_grp) + self.control_grp = create_transform( + name=f"eye_control_{self.side}", parent=self.control_parent + ) """ def create_controls(self) -> None: self.main_ctrl = create_control( diff --git a/src/yrig/component/eye/eye.py b/src/yrig/component/eye/eye.py index 317a856..6058cea 100644 --- a/src/yrig/component/eye/eye.py +++ b/src/yrig/component/eye/eye.py @@ -73,7 +73,9 @@ def setup_structure(self) -> None: name=f"eye_component_{self.side}", parent=self.main_grp ) cmds.hide(self.component_grp) - self.control_grp = create_transform(name=f"eye_control_{self.side}", parent=self.main_grp) + self.control_grp = create_transform( + name=f"eye_control_{self.side}", parent=self.control_parent + ) def create_controls(self) -> None: diff --git a/src/yrig/component/face_base/__init__.py b/src/yrig/component/face_base/__init__.py new file mode 100644 index 0000000..4cc5050 --- /dev/null +++ b/src/yrig/component/face_base/__init__.py @@ -0,0 +1,3 @@ +from . import face_base as face_base +from .face_base import FaceBase as FaceBase +from .face_base import FaceBaseGuides as FaceBaseGuides diff --git a/src/yrig/component/face_base/face_base.py b/src/yrig/component/face_base/face_base.py new file mode 100644 index 0000000..b1781e3 --- /dev/null +++ b/src/yrig/component/face_base/face_base.py @@ -0,0 +1,104 @@ +from dataclasses import dataclass + +from yrig.control import Control, ControlShape, create_control +from yrig.joint import create_joint +from yrig.maya_api.enum import RotateOrder +from yrig.transform import create_transform, matrix_constraint +from yrig.transform.matrix import local_constraint + + +@dataclass +class FaceBaseGuides: + lower: str = "face_lower_M" + muppet: str = "face_muppet_M" + upper: str = "face_upper_M" + top: str = "face_top_M" + jaw: str = "jaw_M" + + +class FaceBase: + def __init__( + self, + guides: FaceBaseGuides, + parent: str, + control_parent: Control | str, + joint_parent: str, + control_size: float = 5, + ): + self.guides = guides + reference_space = str(control_parent) + + self.lower_control = create_control( + "face_lower_M", + transform=guides.lower, + parent=control_parent, + size=control_size, + control_shape=ControlShape.SQUARE, + direction="y", + ) + self.lower_joint = create_joint( + name="face_lower_M", transform=self.lower_control, parent=joint_parent + ) + + self.jaw_control = create_control( + "jaw_M", + transform=guides.jaw, + parent=self.lower_control, + size=control_size * 8, + control_shape=ControlShape.LINE, + direction="z", + rotation_order=RotateOrder.YZX, + ) + self.jaw_joint = create_joint( + name="jaw_M", transform=self.jaw_control, parent=self.lower_joint + ) + + self.muppet_control = create_control( + "face_muppet_M", + transform=guides.muppet, + parent=control_parent, + size=control_size, + control_shape=ControlShape.CIRCLE, + direction="y", + ) + self.muppet_joint = create_joint( + name="face_muppet_M", transform=self.muppet_control, parent=joint_parent + ) + self.muppet_space = create_transform( + "face_muppet_M_space", transform=self.muppet_control.transform, parent=parent + ) + matrix_constraint(self.muppet_control.transform, self.muppet_space) + self.mid_driven = create_transform("face_mid_M_driven", parent=self.muppet_space) + + local_constraint(self.lower_control.transform, self.mid_driven, reference_space) + self.mid_joint = create_joint( + name="face_mid_M", + transform=self.muppet_control, + parent=self.muppet_joint, + connect=False, + ) + matrix_constraint(self.mid_driven, self.mid_joint) + + self.upper_control = create_control( + "face_upper_M", + transform=guides.upper, + parent=self.muppet_control, + size=control_size, + control_shape=ControlShape.SQUARE, + direction="y", + ) + self.upper_joint = create_joint( + "face_upper_M", transform=self.upper_control, parent=self.mid_joint + ) + + self.top_control = create_control( + "face_top_M", + transform=guides.top, + parent=self.upper_control, + size=control_size, + control_shape=ControlShape.SQUARE, + direction="y", + ) + self.top_joint = create_joint( + "face_top_M", transform=self.top_control, parent=self.upper_joint + ) diff --git a/src/yrig/component/mouth/corner.py b/src/yrig/component/mouth/corner.py index f321d5e..2588de6 100644 --- a/src/yrig/component/mouth/corner.py +++ b/src/yrig/component/mouth/corner.py @@ -6,6 +6,8 @@ from yrig.maya_api.attribute import BooleanAttribute, ScalarAttribute from yrig.maya_api.node import MultiplyNode from yrig.surface import surface_slide_constraint +from yrig.transform import create_transform +from yrig.transform.utils import connect_transform class MouthCorner: @@ -14,7 +16,9 @@ def __init__( side: Literal["L", "R"], guide: str, mouth_surface: str, + mouth_surface_local: str, control_parent: Control | str, + parent: str, control_size: float = 1, sub_control_vis_attr: BooleanAttribute | None = None, ): @@ -25,6 +29,12 @@ def __init__( size=control_size, direction="z", ) + self.main_local_npo = create_transform( + f"mouth_corner_{side}_local_npo", transform=self.main_control.transform, parent=parent + ) + self.main_local = create_transform(f"mouth_corner_{side}_local", parent=self.main_local_npo) + connect_transform(self.main_control.transform, self.main_local) + self.sub_control = create_control( f"mouth_corner_{side}_sub", transform=guide, @@ -32,27 +42,65 @@ def __init__( size=control_size * 0.5, direction="z", ) - surface_slide_constraint( mouth_surface, driver_transform=self.main_control.transform, slider_transform=self.sub_control.offset, ) + self.sub_local_npo = create_transform( + f"mouth_corner_{side}_sub_local_npo", + transform=guide, + parent=self.main_local, + ) + self.sub_local = create_transform( + f"mouth_corner_{side}_sub_local", + parent=self.sub_local_npo, + ) + connect_transform(self.sub_control.transform, self.sub_local) + + surface_slide_constraint( + mouth_surface_local, + driver_transform=self.main_local, + slider_transform=self.sub_local_npo, + ) + self.upper_control = create_control( f"mouth_corner_{side}_up", - transform=self.sub_control.offset, - parent=self.sub_control.offset, + transform=self.sub_local_npo, + parent=self.sub_control, size=control_size * 0.5, direction="z", ) + self.upper_local_npo = create_transform( + f"mouth_corner_{side}_up_local_npo", + transform=self.sub_local_npo, + parent=self.sub_local_npo, + ) + self.upper_local = create_transform( + f"mouth_corner_{side}_up_local", + parent=self.upper_local_npo, + ) + connect_transform(self.upper_control.transform, self.upper_local) + self.lower_control = create_control( f"mouth_corner_{side}_lo", - transform=self.sub_control.offset, - parent=self.sub_control.offset, + transform=self.sub_local_npo, + parent=self.sub_control, size=control_size * 0.5, direction="z", ) + self.lower_local_npo = create_transform( + f"mouth_corner_{side}_lo_local_npo", + transform=self.sub_local_npo, + parent=self.sub_local_npo, + ) + self.lower_local = create_transform( + f"mouth_corner_{side}_lo_local", + parent=self.lower_local_npo, + ) + connect_transform(self.lower_control.transform, self.lower_local) + for control in (self.upper_control, self.lower_control): cmds.setAttr(f"{control.transform}.translateZ", lock=True) @@ -73,9 +121,13 @@ def __init__( roundness_side_offset.input[1].set(-0.25) upper_roundness_scaled.output.connect_to(f"{self.upper_control.offset}.translateY") + upper_roundness_scaled.output.connect_to(f"{self.upper_local_npo}.translateY") lower_roundness_scaled.output.connect_to(f"{self.lower_control.offset}.translateY") + lower_roundness_scaled.output.connect_to(f"{self.lower_local_npo}.translateY") roundness_side_offset.output.connect_to(f"{self.upper_control.offset}.translateX") + roundness_side_offset.output.connect_to(f"{self.upper_local_npo}.translateX") roundness_side_offset.output.connect_to(f"{self.lower_control.offset}.translateX") + roundness_side_offset.output.connect_to(f"{self.lower_local}.translateX") self.upper_sub_control = create_control( f"mouth_corner_{side}_up_sub", @@ -87,6 +139,18 @@ def __init__( surface_slide_constraint( mouth_surface, self.upper_control.transform, self.upper_sub_control.offset ) + + self.upper_sub_local_npo = create_transform( + f"mouth_corner_{side}_up_sub_local_npo", + parent=self.upper_local, + ) + self.upper_sub_local = create_transform( + f"mouth_corner_{side}_up_sub_local", + parent=self.upper_sub_local_npo, + ) + connect_transform(self.upper_sub_control.transform, self.upper_sub_local) + surface_slide_constraint(mouth_surface_local, self.upper_local, self.upper_sub_local_npo) + self.lower_sub_control = create_control( f"mouth_corner_{side}_lo_sub", transform=self.upper_control.transform, @@ -98,6 +162,17 @@ def __init__( mouth_surface, self.lower_control.transform, self.lower_sub_control.offset ) + self.lower_sub_local_npo = create_transform( + f"mouth_corner_{side}lo_sub_local_npo", + parent=self.lower_local, + ) + self.lower_sub_local = create_transform( + f"mouth_corner_{side}lo_sub_local", + parent=self.lower_sub_local_npo, + ) + connect_transform(self.lower_sub_control.transform, self.lower_sub_local) + surface_slide_constraint(mouth_surface_local, self.lower_local, self.lower_sub_local_npo) + self.sub_controls: list[Control] = [ self.sub_control, self.upper_sub_control, diff --git a/src/yrig/component/mouth/lip.py b/src/yrig/component/mouth/lip.py index 4aeac11..0cb7100 100644 --- a/src/yrig/component/mouth/lip.py +++ b/src/yrig/component/mouth/lip.py @@ -13,8 +13,9 @@ from yrig.spline import generate_knots from yrig.spline.curve import bound_curve_from_transforms, pin_to_curve_with_motion_path from yrig.surface import closest_point_on_surface_reader, surface_slide_constraint, uv_pin -from yrig.transform import create_transform -from yrig.transform.utils import distance_reader +from yrig.transform import create_transform, matrix_constraint +from yrig.transform.matrix import local_constraint +from yrig.transform.utils import connect_transform, distance_reader from .corner import MouthCorner @@ -32,10 +33,12 @@ def __init__( name: str, guide: str, mouth_surface: str, + mouth_surface_local: str, corner: MouthCorner, control_parent: Control | str, parent: str, distance_transform: str, + distance_transform_local: str, control_size: float = 1, mirror: bool = False, ): @@ -49,16 +52,38 @@ def __init__( limit_min_scale=False, ) cmds.setAttr(f"{self.main_control.transform}.translateZ", lock=True) + + self.main_local_npo = create_transform( + f"{name}_local_npo", + parent=parent, + transform=guide, + ) + self.main_local = create_transform( + f"{name}_local", + parent=self.main_local_npo, + ) + connect_transform(self.main_control.transform, self.main_local) + self.main_control_rest = create_transform( f"{name}_rest", + parent=str(control_parent), + transform=self.main_control.offset, + ) + self.main_local_rest = create_transform( + f"{name}_local_rest", parent=parent, - transform=self.main_control.transform, + transform=self.main_local_npo, ) + self.main_control_driven = create_transform(f"{name}_driven", parent=self.main_control_rest) + self.main_local_driven = create_transform( + f"{name}_local_driven", parent=self.main_local_rest + ) + corner_distance = distance_reader( corner.sub_control.offset, distance_transform, - space=parent, + space=str(control_parent), zero_at_rest=True, axes=(True, False, False), ) @@ -67,13 +92,32 @@ def __init__( corner_distance_scale.input[1].set(0.75) corner_distance_scale.output.connect_to(f"{self.main_control_driven}.translateX") - self.main_control_slide = create_transform(f"{name}_slide", parent=parent) + corner_distance_local = distance_reader( + corner.sub_local_npo, + distance_transform_local, + space=parent, + zero_at_rest=True, + axes=(True, False, False), + ) + corner_distance_scale = MultiplyNode.create(f"{name}_distance_scale_local") + corner_distance_scale.input[0].connect_from(corner_distance_local) + corner_distance_scale.input[1].set(0.75) + corner_distance_scale.output.connect_to(f"{self.main_local_driven}.translateX") + + self.main_control_slide = create_transform(f"{name}_slide", parent=str(control_parent)) surface_slide_constraint( mouth_surface, driver_transform=self.main_control_driven, slider_transform=self.main_control.offset, ) + self.main_local_slide = create_transform(f"{name}_local_slide", parent=parent) + surface_slide_constraint( + mouth_surface_local, + driver_transform=self.main_local_driven, + slider_transform=self.main_local_npo, + ) + self.sub_control = create_control( f"{name}_mid_L_sub", transform=guide, @@ -86,6 +130,20 @@ def __init__( driver_transform=self.main_control.transform, slider_transform=self.sub_control.offset, ) + self.sub_local_npo = create_transform( + f"{name}_mid_L_sub_local_npo", transform=guide, parent=self.main_local + ) + + self.sub_local = create_transform( + f"{name}_mid_L_sub_local", + parent=self.sub_local_npo, + ) + connect_transform(self.sub_control.transform, self.sub_local) + surface_slide_constraint( + mouth_surface_local, + driver_transform=self.main_local, + slider_transform=self.sub_local_npo, + ) if mirror: cmds.setAttr(f"{self.main_control.transform}.scaleY", -1) # type:ignore @@ -160,11 +218,15 @@ def __init__( upper: bool, guides: LipGuides, mouth_surface: str, + mouth_surface_local: str, left_corner: MouthCorner, right_corner: MouthCorner, parent: str, joint_parent: str, control_parent: Control | str, + control_follow: Control | str, + mouth_slide: str, + mouth_slide_ref: str, control_size: float = 1, sub_control_vis_attr: BooleanAttribute | None = None, uv_pin_node: UvPinNode | None = None, @@ -173,13 +235,45 @@ def __init__( side_string = "upper" if upper else "lower" self.name = f"{side_string}_lip" self.group = create_transform(self.name, parent=parent) - reference_space = str(control_parent) - self.lip_move = create_transform(f"{self.name}_move", parent=reference_space) + + self.lip_follow_space = create_transform( + f"{self.name}_follow_space", parent=str(control_parent) + ) + matrix_constraint(str(control_follow), self.lip_follow_space, keep_offset=False) + self.lip_follow = create_transform(f"{self.name}_follow", self.lip_follow_space) + local_constraint(mouth_slide, self.lip_follow, reference_space=mouth_slide_ref) + + self.lip_move_npo = create_transform( + f"{self.name}_move_npo", transform=self.guides.lip_mid, parent=str(control_parent) + ) + matrix_constraint(self.lip_follow, self.lip_move_npo) + self.lip_move = create_transform(f"{self.name}_move", parent=self.lip_move_npo) + self.lip_move_local_npo = create_transform( + f"{self.name}_move_local_npo", transform=self.lip_move, parent=parent + ) + self.lip_move_local = create_transform( + f"{self.name}_move_local", parent=self.lip_move_local_npo + ) + connect_transform(self.lip_move, self.lip_move_local) + self.slider = create_transform(f"{self.name}_slide", parent=str(control_parent)) + self.slider_local_npo = create_transform( + f"{self.name}_slide_local_npo", transform=self.slider, parent=parent + ) + self.slider_local = create_transform( + f"{self.name}_slide_local", transform=self.slider, parent=self.slider_local_npo + ) + surface_slide_constraint( mouth_surface, driver_transform=self.lip_move, slider_transform=self.slider ) + surface_slide_constraint( + mouth_surface_local, + driver_transform=self.lip_move_local, + slider_transform=self.slider_local, + ) + self.left_corner = left_corner self.right_corner = right_corner @@ -187,10 +281,12 @@ def __init__( name=f"{self.name}_mid_L", guide=guides.lip_mid_left, mouth_surface=mouth_surface, + mouth_surface_local=mouth_surface_local, corner=self.left_corner, - control_parent=control_parent, - parent=self.slider, + control_parent=self.slider, + parent=self.slider_local, distance_transform=self.slider, + distance_transform_local=self.slider_local, ) self.mid_control = create_control( f"{self.name}_mid_M", @@ -199,6 +295,17 @@ def __init__( size=control_size, direction="z", ) + self.mid_local_npo = create_transform( + f"{self.name}_mid_M_local_npo", + transform=guides.lip_mid, + parent=self.slider_local, + ) + self.mid_local = create_transform( + f"{self.name}_mid_M_local", + parent=self.mid_local_npo, + ) + connect_transform(self.mid_control.transform, self.mid_local) + self.mid_sub_control = create_control( f"{self.name}_mid_M_sub", transform=guides.lip_mid, @@ -206,19 +313,38 @@ def __init__( size=control_size * 0.5, direction="z", ) + self.mid_sub_local_npo = create_transform( + f"{self.name}_mid_M_sub_local_npo", + transform=guides.lip_mid, + parent=self.mid_local, + ) + self.mid_sub_local = create_transform( + f"{self.name}_mid_M_sub_local", + parent=self.mid_sub_local_npo, + ) + connect_transform(self.mid_sub_control.transform, self.mid_sub_local) + surface_slide_constraint( mouth_surface, driver_transform=self.mid_control.transform, slider_transform=self.mid_sub_control.offset, ) + surface_slide_constraint( + mouth_surface_local, + driver_transform=self.mid_local, + slider_transform=self.mid_sub_local_npo, + ) + self.mid_right = LipMidpoint( name=f"{self.name}_mid_R", guide=guides.lip_mid_right, mouth_surface=mouth_surface, + mouth_surface_local=mouth_surface_local, corner=self.right_corner, - control_parent=control_parent, - parent=self.slider, + control_parent=self.slider, + parent=self.slider_local, distance_transform=self.slider, + distance_transform_local=self.slider_local, mirror=True, ) @@ -232,21 +358,21 @@ def __init__( for control in self.sub_controls: sub_control_vis_attr.connect_to(f"{control.transform}.visibility") - lip_cvs: tuple[Control, ...] = ( - self.mid_left.sub_control, - self.mid_sub_control, - self.mid_right.sub_control, + lip_cvs: tuple[tuple[str, str], ...] = ( + (self.mid_left.sub_local, self.mid_left.sub_local_npo), + (self.mid_sub_local, self.mid_sub_local_npo), + (self.mid_right.sub_local, self.mid_right.sub_local_npo), ) - raw_left_corner_cvs: tuple[Control, ...] = ( - self.left_corner.lower_sub_control, - self.left_corner.sub_control, - self.left_corner.upper_sub_control, + raw_left_corner_cvs: tuple[tuple[str, str], ...] = ( + (self.left_corner.lower_sub_local, self.left_corner.lower_sub_local_npo), + (self.left_corner.sub_local, self.left_corner.sub_local_npo), + (self.left_corner.upper_sub_local, self.left_corner.upper_sub_local_npo), ) - raw_right_corner_cvs: tuple[Control, ...] = ( - self.right_corner.upper_sub_control, - self.right_corner.sub_control, - self.right_corner.lower_sub_control, + raw_right_corner_cvs: tuple[tuple[str, str], ...] = ( + (self.right_corner.upper_sub_local, self.right_corner.upper_sub_local_npo), + (self.right_corner.sub_local, self.right_corner.sub_local_npo), + (self.right_corner.lower_sub_local, self.right_corner.lower_sub_local_npo), ) if upper: @@ -265,19 +391,19 @@ def __init__( self.left_main_spline = LipSpline( f"{self.name}_L_main_spline", - [control.offset for control in left_lip_cvs], + [cv[1] for cv in left_lip_cvs], parent=self.group, joint_parent=self.main_joint, - surface=mouth_surface, + surface=mouth_surface_local, orient=False, uv_pin_node=uv_pin_node, ) self.right_main_spline = LipSpline( f"{self.name}_R_main_spline", - [control.offset for control in right_lip_cvs], + [cv[1] for cv in right_lip_cvs], parent=self.group, joint_parent=self.main_joint, - surface=mouth_surface, + surface=mouth_surface_local, orient=False, uv_pin_node=uv_pin_node, ) @@ -290,17 +416,17 @@ def __init__( self.left_sub_spline = LipSpline( f"{self.name}_L_sub_spline", - [control.transform for control in left_lip_cvs], + [cv[0] for cv in left_lip_cvs], parent=self.group, joint_parent=self.sub_joint, - surface=mouth_surface, + surface=mouth_surface_local, ) self.right_sub_spline = LipSpline( f"{self.name}_R_sub_spline", - [control.transform for control in right_lip_cvs], + [cv[0] for cv in right_lip_cvs], parent=self.group, joint_parent=self.sub_joint, - surface=mouth_surface, + surface=mouth_surface_local, ) tag_for_weight_split( self.sub_joint, diff --git a/src/yrig/component/mouth/mouth.py b/src/yrig/component/mouth/mouth.py index 699e10f..5d9494b 100644 --- a/src/yrig/component/mouth/mouth.py +++ b/src/yrig/component/mouth/mouth.py @@ -3,12 +3,11 @@ from maya import cmds from yrig.control import Control, ControlShape, create_control -from yrig.joint import create_joint -from yrig.maya_api.enum import RotateOrder from yrig.maya_api.node import UvPinNode from yrig.surface import get_surface_shapes, surface_slide_constraint from yrig.transform import create_transform, matrix_constraint from yrig.transform.matrix import local_constraint +from yrig.transform.utils import connect_transform from .cheek import CheekInterpolate, CheekInterpolateGuides from .corner import MouthCorner @@ -27,7 +26,6 @@ def _default_lip_guides(side: str) -> LipGuides: class MouthGuides: mouth: str = "mouth_M" mouth_surface: str = "face_surface" - jaw: str = "jaw_M" left_corner: str = "mouth_corner_L" right_corner: str = "mouth_corner_R" upper_lip: LipGuides = field(default_factory=lambda: _default_lip_guides(side="upper")) @@ -42,6 +40,8 @@ def __init__( parent: str, control_parent: Control | str, joint_parent: str, + jaw: str, + face_mid: str, control_size: float = 1, ): self.guides = guides @@ -51,6 +51,10 @@ def __init__( self.mouth_surface = cmds.rename(duplicated_mouth_surface, "mouth_surface") cmds.hide(self.mouth_surface) + duplicated_mouth_surface = cmds.duplicate(self.guides.mouth_surface)[0] + cmds.parent(duplicated_mouth_surface, parent) + self.mouth_surface_local = cmds.rename(duplicated_mouth_surface, "mouth_surface_local") + reference_space = str(control_parent) self.mouth_control = create_control( @@ -61,56 +65,75 @@ def __init__( control_shape=ControlShape.LINE, direction="z", ) - self.jaw_control = create_control( - "jaw_M", - transform=guides.jaw, - parent=control_parent, - size=control_size * 8, - control_shape=ControlShape.LINE, - direction="z", - rotation_order=RotateOrder.YZX, + + self.jaw_blend = create_transform("jaw_M_blend", parent=str(control_parent), transform=jaw) + cmds.parentConstraint( + jaw, + face_mid, + self.jaw_blend, + maintainOffset=True, ) - self.jaw_joint = create_joint(name="jaw_M", transform=self.jaw_control, parent=joint_parent) - self.jaw_blend = create_transform( - "jaw_M_blend", parent=parent, transform=self.jaw_control.transform + matrix_constraint(self.jaw_blend, self.mouth_control.offset) + + self.mouth_slide_reference = create_transform( + "mouth_M_slide_ref", parent=str(control_parent) ) + surface_slide_constraint( + self.mouth_surface, + driver_transform=self.mouth_control.offset, + slider_transform=self.mouth_slide_reference, + ) + self.mouth_slide = create_transform("mouth_M_slide", parent=self.mouth_control.transform) surface_slide_constraint( self.mouth_surface, driver_transform=self.mouth_control.transform, slider_transform=self.mouth_slide, ) + self.mouth_local_npo = create_transform( + "mouth_M_local_npo", transform=self.mouth_control.transform, parent=parent + ) + self.mouth_local = create_transform("mouth_M_local", parent=self.mouth_local_npo) + connect_transform(self.mouth_control.transform, self.mouth_local) + self.mouth_slide_local = create_transform("mouth_M_slide_local", parent=self.mouth_local) + surface_slide_constraint( + self.mouth_surface_local, + driver_transform=self.mouth_local, + slider_transform=self.mouth_slide_local, + ) + + self.jaw_local_npo = create_transform("jaw_M_local_npo", parent=parent, transform=jaw) + self.jaw_local = create_transform("jaw_M_local", parent=parent, transform=jaw) + local_constraint(jaw, self.jaw_local, reference_space=reference_space) + self.jaw_blend_local = create_transform("jaw_M_blend_local", parent=parent, transform=jaw) cmds.parentConstraint( - self.jaw_control.transform, + self.jaw_local, reference_space, - self.jaw_blend, + self.jaw_blend_local, maintainOffset=True, ) - self.jaw_blend_local = create_transform( - "jaw_M_blend_local", parent=self.mouth_slide, transform=self.jaw_control.transform - ) - local_constraint(self.jaw_blend, self.jaw_blend_local, reference_space=reference_space) self.left_corner = MouthCorner( side="L", guide=guides.left_corner, mouth_surface=self.mouth_surface, + mouth_surface_local=self.mouth_surface_local, control_parent=self.mouth_slide, + parent=self.mouth_slide_local, control_size=control_size, ) self.right_corner = MouthCorner( side="R", guide=guides.right_corner, mouth_surface=self.mouth_surface, + mouth_surface_local=self.mouth_surface_local, control_parent=self.mouth_slide, + parent=self.mouth_slide_local, control_size=control_size, ) - matrix_constraint(self.jaw_blend_local, self.left_corner.main_control.offset) - matrix_constraint(self.jaw_blend_local, self.right_corner.main_control.offset) - mouth_uv_pin = UvPinNode.create("mouth_surface_uvPin") - primary_shape, original_shape, shape_output = get_surface_shapes(self.mouth_surface) + primary_shape, original_shape, shape_output = get_surface_shapes(self.mouth_surface_local) mouth_uv_pin.original_geometry.connect_from(f"{original_shape}.{shape_output}") mouth_uv_pin.deformed_geometry.connect_from(f"{primary_shape}.{shape_output}") @@ -118,40 +141,45 @@ def __init__( upper=True, guides=guides.upper_lip, mouth_surface=self.mouth_surface, + mouth_surface_local=self.mouth_surface_local, left_corner=self.left_corner, right_corner=self.right_corner, - parent=parent, + parent=self.mouth_slide_local, joint_parent=joint_parent, control_parent=self.mouth_slide, + control_follow=face_mid, + mouth_slide=self.mouth_slide, + mouth_slide_ref=self.mouth_slide_reference, control_size=control_size, uv_pin_node=mouth_uv_pin, ) + self.lower_lip = Lip( upper=False, guides=guides.lower_lip, mouth_surface=self.mouth_surface, + mouth_surface_local=self.mouth_surface_local, left_corner=self.left_corner, right_corner=self.right_corner, - parent=parent, + parent=self.mouth_slide_local, joint_parent=joint_parent, control_parent=self.mouth_slide, + control_follow=jaw, + mouth_slide=self.mouth_slide, + mouth_slide_ref=self.mouth_slide_reference, control_size=control_size, uv_pin_node=mouth_uv_pin, ) self.cheek_interpolate = CheekInterpolate( guides=self.guides.cheek_interpolate, - mouth_surface=self.mouth_surface, + mouth_surface=self.mouth_surface_local, upper_left_lip_spline=self.upper_lip.left_main_spline, upper_right_lip_spline=self.upper_lip.right_main_spline, lower_left_lip_spline=self.lower_lip.left_main_spline, lower_right_lip_spline=self.lower_lip.right_main_spline, parent=parent, joint_parent=joint_parent, - control_parent=self.mouth_slide, + control_parent=self.mouth_slide_local, control_size=control_size, ) - - local_constraint( - self.jaw_control.transform, self.lower_lip.lip_move, reference_space=reference_space - ) diff --git a/src/yrig/component/nose/nose.py b/src/yrig/component/nose/nose.py index 0b4ae8b..01cf2b8 100644 --- a/src/yrig/component/nose/nose.py +++ b/src/yrig/component/nose/nose.py @@ -61,7 +61,7 @@ def setup_structure(self) -> None: self.control_grp = create_transform( name=f"nose_control_{self.side}", - parent=self.main_grp, + parent=self.control_parent, ) def create_controls(self) -> None: diff --git a/src/yrig/component/teeth/build_teeth.py b/src/yrig/component/teeth/build_teeth.py index 8122662..6f2c75e 100644 --- a/src/yrig/component/teeth/build_teeth.py +++ b/src/yrig/component/teeth/build_teeth.py @@ -5,7 +5,7 @@ from yrig.control import create_control from yrig.joint import create_joint from yrig.spline.matrix_spline.build import matrix_spline_from_transforms -from yrig.transform import create_transform +from yrig.transform import create_transform, matrix_constraint def get_teeth_locator_indices(cvs_count: int) -> list[int]: @@ -64,12 +64,10 @@ def build_single_teeth_spline(self, guide_name: str, num: int) -> tuple[object, name=f"{guide_name}_ofst_grp", parent=self.control_grp, ) + if num == 0: + matrix_constraint("face_mid_M_driven", group) if num == 1: - cmds.parentConstraint( - "jaw_M_ctl", - group, - maintainOffset=True, - ) + matrix_constraint("jaw_M_ctl", group) main_control = create_control( name=f"{guide_name}_main", diff --git a/src/yrig/component/teeth/teeth.py b/src/yrig/component/teeth/teeth.py index 18ab52c..d18cab0 100644 --- a/src/yrig/component/teeth/teeth.py +++ b/src/yrig/component/teeth/teeth.py @@ -49,7 +49,7 @@ def setup_structure(self) -> None: self.control_grp = create_transform( name=f"teeth_control_{self.side}", - parent=self.main_grp, + parent=self.control_parent, ) def create_controls(self) -> None: diff --git a/src/yrig/component/tongue/tongue.py b/src/yrig/component/tongue/tongue.py index 38e464c..15ef208 100644 --- a/src/yrig/component/tongue/tongue.py +++ b/src/yrig/component/tongue/tongue.py @@ -52,7 +52,7 @@ def setup_structure(self) -> None: self.control_grp = create_transform( name=f"tongue_control_{self.side}", - parent=self.main_grp, + parent=self.control_parent, ) def create_controls(self) -> None: diff --git a/src/yrig/control/utils.py b/src/yrig/control/utils.py index 8cd0f5b..e608c14 100644 --- a/src/yrig/control/utils.py +++ b/src/yrig/control/utils.py @@ -16,11 +16,12 @@ def get_tagged_controls(side: str | None = None) -> list[str]: connected: list[str] = cmds.listConnections( f"{control_node}.controllerObject", source=True, destination=False ) - control = connected[0] - if side: - if get_side(control_node) == side: + if connected: + control = connected[0] + if side: + if get_side(control_node) == side: + tagged_controls.append(control) + else: tagged_controls.append(control) - elif connected: - tagged_controls.append(control) return tagged_controls diff --git a/src/yrig/maya_api/utils.py b/src/yrig/maya_api/utils.py index 0b70416..966b8e4 100644 --- a/src/yrig/maya_api/utils.py +++ b/src/yrig/maya_api/utils.py @@ -22,7 +22,14 @@ def get_dag_path(node: str) -> MDagPath: selection.add(node) dag_path: MDagPath = selection.getDagPath(0) except RuntimeError as exc: - raise RuntimeError(f"Couldn't resolve an MDagPath for {node}") from exc + found_nodes = cmds.ls(node) + if found_nodes: + raise RuntimeError( + f"Couldn't resolve an MDagPath for '{node}' as there were multiple nodes with that name: " + f"{', '.join(found_nodes)}" + ) from exc + else: + raise RuntimeError(f"Couldn't resolve an MDagPath for {node}") from exc return dag_path diff --git a/src/yrig/transform/utils.py b/src/yrig/transform/utils.py index 60ac882..042ba54 100644 --- a/src/yrig/transform/utils.py +++ b/src/yrig/transform/utils.py @@ -252,6 +252,25 @@ def clean_parent(transform: str, parent: str, joint_orient: bool = True) -> None set_world_matrix(transform, object_world_matrix, use_joint_orient=joint_orient) +def connect_transform( + source: str, + driven: str, + translate: bool = True, + rotate: bool = True, + scale: bool = True, + shear: bool = False, +) -> None: + if translate: + cmds.connectAttr(f"{source}.translate", f"{driven}.translate") + if rotate: + cmds.connectAttr(f"{source}.rotate", f"{driven}.rotate") + cmds.connectAttr(f"{source}.rotateOrder", f"{driven}.rotateOrder") + if scale: + cmds.connectAttr(f"{source}.scale", f"{driven}.scale") + if shear: + cmds.connectAttr(f"{source}.shear", f"{driven}.shear") + + def distance_reader( transform1: str, transform2: str,