diff --git a/BuildBodyFree.py b/BuildBodyFree.py new file mode 100644 index 0000000..82ecc4c --- /dev/null +++ b/BuildBodyFree.py @@ -0,0 +1,169 @@ +#All Rights Belongs to Uzay CALISKAN +#Artstation Marketplace Standart License +import os +import maya.cmds as cmds +def fixbody(): + # + # + # Transfer Body original skeleton to the new head Skeleton + CD = 15 + lower_CD = -1 + minCD = 0 + + # Define the joint names and namespaces + head_joint = "DHIhead:spine_04" + body_joint = "spine_04_drv" + + # Split the joint names into their respective namespaces and joint names + head_namespace, head_joint_name = head_joint.split(":") + + # Get the list of child joints for the head joint + head_child_joints = cmds.listRelatives(head_joint, children=True, allDescendents=True,type="joint") + body_child_joints = cmds.listRelatives(body_joint, children=True, allDescendents=True, type="joint") + + def move2target_joint(moving_joint, target_joint): + lower_lip_rotation_pos = cmds.xform(moving_joint, query=True, worldSpace=True, rotatePivot=True) + jaw_pos = cmds.xform(target_joint, query=True, worldSpace=True, rotatePivot=True) + # Get the child joints + child_joints = cmds.listRelatives(moving_joint, c=True, type="joint") + # Store the initial positions of the child joints + child_positions = [] + if child_joints: + for child_joint in child_joints: + child_positions.append(cmds.xform(child_joint, q=True, ws=True, t=True)) + + # Set the translate and rotate pivot attributes of the "FACIAL_C_LowerLipRotation" joint to match those of "FACIAL_C_MouthUpper" + cmds.xform(moving_joint, translation=jaw_pos, rotatePivot=lower_lip_rotation_pos, worldSpace=True) + if child_joints: + + # Move each child joint back to its original position + for i, child_joint in enumerate(child_joints): + cmds.xform(child_joint, ws=True, t=child_positions[i]) + moving_joint = body_joint + target_joint = head_joint + move2target_joint(moving_joint, target_joint) + while CD >= minCD: + joint_CD = [joint for joint in body_child_joints if cmds.getAttr(joint + ".chainDepth") == CD] + for joint_name in joint_CD: + + drvname = joint_name.replace("_drv", "") + # Build the joint names for the current joint + + + head_current_joint = "{}:{}".format(head_namespace, drvname) + if cmds.objExists(head_current_joint): + if joint_name[-5] == "r": + offnamer = joint_name.replace("_r_drv", "Off_r_drv") + if cmds.objExists(offnamer): + joint_name = offnamer + if joint_name[-5] == "l": + offnamel = joint_name.replace("_l_drv", "Off_l_drv") + if cmds.objExists(offnamel): + joint_name = offnamel + moving_joint = joint_name + target_joint = head_current_joint + move2target_joint(moving_joint, target_joint) + + + lower_CD -= 1 + CD -= 1 + + + +def bind_skin(gender_mesh): + + # Body + mesh_obj = cmds.ls(gender_mesh)[0] + + # Duplicate the mesh + duplicated_mesh_obj = cmds.duplicate(mesh_obj)[0] + + cmds.select([duplicated_mesh_obj, "DHIbody:root"]) + + # Bind skin to the mesh + skin_cluster = cmds.skinCluster("DHIbody:root", duplicated_mesh_obj)[0] + + cmds.select([mesh_obj, duplicated_mesh_obj]) + + cmds.copySkinWeights(noMirror=True, surfaceAssociation="closestPoint", influenceAssociation=["name", "oneToOne"]) + + cmds.delete(mesh_obj) + cmds.rename(duplicated_mesh_obj, gender_mesh) +gender=0 +gender_mesh = "m_med_nrw_body_lod0_mesh" + +def build_body(ROOT_DIR): + Body_DRV = f"{ROOT_DIR}/data/Body_Drv.mb" + + if not os.path.isfile(Body_DRV): + raise ValueError("Please prepare the body file first. Body_Drv file is not found") + skeleton_file_path = f"{ROOT_DIR}/data/Body_Drv.mb" + # Import the FBX file + cmds.file(skeleton_file_path, i=True, ignoreVersion=True, mergeNamespacesOnClash=False) + def add_chain_depth_attribute(joints): + for joint in joints: + if not cmds.attributeQuery('chainDepth', node=joint, exists=True): + cmds.addAttr(joint, longName='chainDepth', attributeType='long', defaultValue=0) + cmds.setAttr(joint + '.chainDepth', keyable=True) + + def set_chain_depth_value(joints, value): + for joint in joints: + cmds.setAttr(joint + '.chainDepth', value) + + # Get all joints in the scene + all_joints = cmds.ls(type="joint") + + # Remove joints in the "DHIhead:spine_04" hierarchy (Avoid HEAD) + exclude_joints = cmds.ls("DHIhead:spine_04", dag=True, type="joint") + all_joints = cmds.ls("root_drv", dag=True, type="joint") + add_chain_depth_attribute(all_joints) + + # Filter end joints (joints with no child joints) + end_joints = [joint for joint in all_joints if not cmds.listRelatives(joint, children=True, type='joint')] + + + # Set chainDepth attribute to 0 for all end joints + set_chain_depth_value(all_joints, 100) + set_chain_depth_value(end_joints, 0) + + parents1 = [] + + for joint_name in end_joints: + p_joint = cmds.listRelatives(joint_name, parent=True, type="joint") + if p_joint: + children = cmds.listRelatives(p_joint, children=True, type="joint") or [] + if all(cmds.getAttr(child + ".chainDepth") == 0 for child in children): + + parents1.append(p_joint[0]) + + set_chain_depth_value(parents1, 1) + #Chaindepth add Attr Loop + chainDepth = 1 + while parents1: + chainDepth += 1 + new_parents = [] + for joint_name in parents1: + p_joint = cmds.listRelatives(joint_name, parent=True, type="joint") + if p_joint: + children = cmds.listRelatives(p_joint, children=True, type="joint") or [] + if all(cmds.getAttr(child + ".chainDepth") < chainDepth for child in children): + new_parents.append(p_joint[0]) + if new_parents: + set_chain_depth_value(new_parents, chainDepth) + parents1 = new_parents + else: + break + DHIBODY_name = 'DHIbody:root' + bind_skin(gender_mesh) + +def connect_body(): + bodyNS = "DHIbody:" + headNS = "DHIhead:" + + for i in cmds.ls(type="joint"): + if headNS in i: + if i.replace(headNS,bodyNS) in cmds.ls(type="joint"): + cmds.parentConstraint(i.replace(headNS,bodyNS),i,mo=True) + cmds.scaleConstraint(i.replace(headNS,bodyNS),i,mo=True) + +#build_body() \ No newline at end of file diff --git a/MetaPipe.png b/MetaPipe.png new file mode 100644 index 0000000..fdc5c59 Binary files /dev/null and b/MetaPipe.png differ diff --git a/MetaPipeFree.py b/MetaPipeFree.py new file mode 100644 index 0000000..e6eaf51 --- /dev/null +++ b/MetaPipeFree.py @@ -0,0 +1,174 @@ +import maya.cmds as cmds +import os +import os.path as ospathe +from os import environ +from sys import path as syspath +from sys import platform +import sys + +import logging +import maya.OpenMaya as om +from maya import cmds + +from os import environ, makedirs +from os import path as ospath + +import BuildBodyFree +import dna_viewer + +maya_version = int(cmds.about(version=True)) +if maya_version == 2023: + if sys.version_info < (3, 9, 7): + raise ValueError("Python 3.9.7 or above is required. Please download correct Python Version!") +if maya_version == 2022: + if sys.version_info < (3, 7, 0): + raise ValueError("Python 3.9.7 or above is required. Please download correct Python Version!") + +auto_keyframe_toggle = cmds.autoKeyframe(q=True, state=True) + +if auto_keyframe_toggle: + raise ValueError("Auto Keyframe Toggle is On! Turn it of and try again.") + +def OpenDNA(ROOT_DIR): + calib_check = f"{ROOT_DIR}/dna_calibration.mod" + if not os.path.isfile(calib_check): + raise ValueError("Please download Epic Games Dna Calibration 1.1.0 Version. Files not found!") + metapipe_vcheck = f"{ROOT_DIR}/Metapipe_Free.py" + if os.path.isfile(metapipe_vcheck): + raise ValueError("Old Version file found. Please delete Metapipe_Free.py file in your dna_calibration path!") + root_check = f"{ROOT_DIR}/examples/dna_viewer_grab_changes_from_scene_and_propagate_to_dna.py" + if not os.path.isfile(root_check): + raise ValueError("Please check ROOT_DIR path for the dna_calibration files! Files are not in ROOT_DIR") + dna_datas = f"{ROOT_DIR}/examples/datas_dna.py" + + if not os.path.isfile(dna_datas): + raise ValueError("Please press Update button first") + import dna_viewer_run_in_maya + dna_viewer_run_in_maya.dna_viewer.show() + +def codeblock (dnaPath, ROOT_DIR, CHARACTER_NAME): + output_file_path = os.path.join(f"{ROOT_DIR}/examples", "datas_dna.py") + # Open the Python file and read the lines + with open(f"{ROOT_DIR}/examples/dna_viewer_grab_changes_from_scene_and_propagate_to_dna.py") as file: + lines_all = file.readlines() + lines = lines_all[43:204] + lineslists = lines_all[211:214] + linesload = lines_all[214:220] + lines2 = lines_all[226:242] + defload = ["def load_dna_data():\n"] + defsave = ["def save_dna_data():\n"] + lines = [line.replace('f"{ospath.dirname(ospath.abspath(__file__))}/..".replace("\\\\", "/")','"'+ROOT_DIR+'"') for line in lines] + lines = [line.replace('f"{DNA_DIR}/{CHARACTER_NAME}.dna"', '"'+dnaPath+'"') for line in lines] + lines = [line.replace('"Ada"','"'+CHARACTER_NAME+'"') for line in lines] + linesload = [" " + line for line in linesload] + lines2 = [" " + line for line in lines2] + + code_block = ''.join(lines + lineslists + defload + linesload + defsave + lines2) + + with open(output_file_path, "w") as output_file: + output_file.write(code_block) + + dnaCalibPath=ROOT_DIR + +def update_dna_dir(text_dna, ROOT_DIR): + character_dna = cmds.textField(text_dna, q=True, text=True) + CHARACTER_DNA = ospathe.abspath(character_dna) + CHARACTER_DNA = CHARACTER_DNA.replace("\\", "/") + CHARACTER_NAME = os.path.basename(CHARACTER_DNA).split(".")[0] + print(f"New DNA_DIR: {CHARACTER_DNA}") + print(f"New DNA_Name: {CHARACTER_NAME}") + codeblock (CHARACTER_DNA, ROOT_DIR, CHARACTER_NAME) + return CHARACTER_DNA, CHARACTER_NAME + +# Create a function that will be called when the button is clicked +def button_callback(text_field, *args): + path = cmds.textField(text_field, query=True, text=True) + run_dna_viewer(path, text_field) + cmds.scriptEditorInfo(suppressWarnings=True, echoAllCommands=False) + +def prepare_export(): + + # Detach spine_04 from head_grp and move it to the top level of the Outliner + cmds.parent('spine_04', w=True, r=True) + + if not cmds.namespace(exists="DHIhead"): + cmds.namespace(add="DHIhead", parent=":") + cmds.namespace(set="DHIhead") + cmds.namespace(set=":") + + # Get a list of all the joints in the scene + joints = cmds.ls(type="joint") + + # Add every joint to the "DHIhead" namespace and print a message if it already has the "DHIhead" prefix + for joint in joints: + if joint.startswith("DHIhead:"): + print(joint + " is already in the DHIhead namespace") + else: + cmds.rename(joint, "DHIhead:" + joint) + + + print("Ready") + +def loadimport(ROOT_DIR): + dna_datas = f"{ROOT_DIR}/examples/datas_dna.py" + + if not os.path.isfile(dna_datas): + raise ValueError("Please press Update button first") + sys.path.append(f"{ROOT_DIR}/examples") + import datas_dna + datas_dna.load_dna_data() + cmds.warning("Loaded Succesfully!") +def saveimport(ROOT_DIR): + sys.path.append(f"{ROOT_DIR}/examples") + import datas_dna + datas_dna.save_dna_data() + +dnaPath="" +dnaCalibPath="" +def show_dna_edit_window(dnaPath, ROOT_DIR): + # Create window + window_name = "MetaPipe" + if cmds.window(window_name, exists=True): + cmds.deleteUI(window_name) + cmds.window(window_name, title=window_name, width=300, height=380, sizeable=False, resizeToFitChildren=True) + + # Create layout + + color = (0.164, 0.384, 0) # RGB values for #0077c2 + colorbuttons = (.2, 0.2, 0.2) # RGB values for #0077c2 + layout = cmds.rowColumnLayout(numberOfColumns=1, columnWidth=[(1, 150)], columnSpacing=[(1,75)], backgroundColor=(0.1, 0.1, 0.1)) + + cmds.text(label="", height=15) + cmds.text(label="METAPIPE DNA CALIB UI 1.3.0", height=20, font="boldLabelFont") + cmds.text(label="(Free Edition)", height=20, font="boldLabelFont") + cmds.text(label="", height=15) + cmds.text(label="Metahuman DNA:",height=20) + text_dna = cmds.textField(text=dnaPath) + cmds.text(label="", height=5) + cmds.button(label="Update", command=lambda x: update_dna_dir(text_dna, ROOT_DIR), backgroundColor=color, height=20) + cmds.text(label="", height=20) + cmds.button(label="Open DNA Viewer", command=lambda x: dna_viewer.show(), backgroundColor=colorbuttons, height=40) + cmds.text(label="", height=5) + cmds.button(label="Load Dna", command=lambda x: loadimport(ROOT_DIR), backgroundColor=colorbuttons, height=40) + cmds.text(label="", height=5) + cmds.button(label="Save Dna", command=lambda x: saveimport(ROOT_DIR), backgroundColor=colorbuttons, height=40) + cmds.text(label="", height=5) + cmds.button(label="Prepare to Export", command=lambda x: prepare_export(), backgroundColor=colorbuttons, height=40) + cmds.text(label="", height=5) + cmds.button(label="Load Body", command=lambda x: BuildBodyFree.build_body(ROOT_DIR), backgroundColor=colorbuttons, height=40) + cmds.text(label="", height=5) + cmds.button(label="Fix Body", command=lambda x: BuildBodyFree.fixbody(), backgroundColor=colorbuttons, height=40) + cmds.text(label="", height=5) + cmds.button(label="Connect Body", command=lambda x: BuildBodyFree.connect_body(), backgroundColor=colorbuttons, height=40) + cmds.text(label="", height=5) + + #cmds.image(image='C:/Arts and Spells/pps.png', w=64, h=64) + cmds.text(label="ARTS AND SPELLS",height=40, font="boldLabelFont") + + + + # Show window + cmds.showWindow() + +# Show window +#show_dna_edit_window(dnaPath)