diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Animations.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Animations.py new file mode 100644 index 00000000..22020e33 --- /dev/null +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Animations.py @@ -0,0 +1,290 @@ +import bpy +import mathutils +from . import Global +from . import Versions +from . import DataBase + +class Animations: + total_key_count = 0 + + def update_total_key_count(self,key_count): + if key_count > self.total_key_count: + self.total_key_count = key_count + + + def reset_total_key_count(self): + self.total_key_count = 0 + + + def has_keyframe(self, ob): + anim = ob.animation_data + if anim is not None and anim.action is not None: + return True + return False + + + def get_or_create_fcurve(self, action, data_path, array_index=-1, group=None): + for fc in action.fcurves: + if fc.data_path == data_path and (array_index < 0 or fc.array_index == array_index): + return fc + + fc = action.fcurves.new(data_path, index=array_index) + fc.group = group + return fc + + + def add_keyframe_euler(self, action, euler, frame, bone_prefix, group): + for i in range(len(euler)): + fc = self.get_or_create_fcurve( + action, bone_prefix + "rotation_euler", + i, + group + ) + pos = len(fc.keyframe_points) + fc.keyframe_points.add(1) + fc.keyframe_points[pos].co = [frame, euler[i]] + fc.update() + + + def fcurves_group(self, action, data_path): + for fc in action.fcurves: + if fc.data_path == data_path and fc.group is not None: + return fc.group + return None + + + def frames_matching(self, action, data_path): + frames = set() + for fc in action.fcurves: + if fc.data_path == data_path: + fri = [kp.co[0] for kp in fc.keyframe_points] + frames.update(fri) + return frames + + + def convert_quaternion_to_euler(self, action, obj): + # Get all the bones with quaternion animation data + bone_prefixes = set() + for fcurve in action.fcurves: + if fcurve.data_path == "rotation_quaternion" or fcurve.data_path[-20:] == ".rotation_quaternion": + bone_prefixes.add(fcurve.data_path[:-19]) + + for bone_prefix in bone_prefixes: + if (bone_prefix == ""): + bone = obj + else: + # get the bone using the data path prefix + bone = eval("obj." + bone_prefix[:-1]) + + data_path = bone_prefix + "rotation_quaternion" + frames = self.frames_matching(action, data_path) + group = self.fcurves_group(action, data_path) + + for fr in frames: + # Get quaternion keyframe value + quat = bone.rotation_quaternion.copy() + for fcurve in action.fcurves: + if fcurve.data_path == data_path: + quat[fcurve.array_index] = fcurve.evaluate(fr) + + # Calculate euler equivalent for the quaternion + order = self.get_rotation_order(bone.name) + euler = quat.to_euler(order) + + # Add euler keyframe and set correct rotation order + self.add_keyframe_euler(action, euler, fr, bone_prefix, group) + bone.rotation_mode = order + + # delete all the curves with quaternion data + quat_fcurves = [] + for fcurve in action.fcurves: + if fcurve.data_path[-20:] == ".rotation_quaternion": + quat_fcurves.append(fcurve) + for fcurve in quat_fcurves: + action.fcurves.remove(fcurve) + + + def get_rotation_order(self, node_name): + bone_limits = Global.get_bone_limit() + for bone_limit in bone_limits: + if bone_limit[0] in node_name: + return bone_limit[1] + return "XYZ" + + def convert_rotation_orders(self): + Versions.active_object(Global.getAmtr()) + Global.setOpsMode('POSE') + for bone in Global.getAmtr().pose.bones: + order = bone.rotation_mode + if order == 'XYZ': + bone.rotation_mode = 'ZXY' + elif order == 'XZY': + bone.rotation_mode = 'YZX' + elif order == 'YZX': + bone.rotation_mode = 'YZX' + elif order == 'ZXY': + bone.rotation_mode = 'XYZ' + elif order == 'ZYX': + bone.rotation_mode = 'YZX' + + + def clean_animations(self): + Versions.active_object(Global.getAmtr()) + Global.setOpsMode('POSE') + scene_size = Global.get_size() + + #Choose Action + armature = Global.getAmtr() + action = armature.animation_data.action + + # Convert rotation animation data from quaternion to euler angles + self.convert_quaternion_to_euler(action, Global.getAmtr()) + + # Convert animation data from Studio to Blender + curve_count = len(action.fcurves) + index = 0 + while index < curve_count: + fcurve = action.fcurves[index] + start_index = fcurve.data_path.find('[') + end_index = fcurve.data_path.find(']') + if (start_index == -1 or end_index == -1): + # Convert Figure root bone animation data + if "Genesis" in action.name: + if fcurve.data_path == "rotation_euler": + for point in fcurve.keyframe_points: + point.co[1] = 0 + if fcurve.data_path == "scale": + for point in fcurve.keyframe_points: + point.co[1] = 1.0 + # Convert non Figure root bone animation data + else: + if fcurve.data_path == "location": + fcurve_x = action.fcurves[index + 0] + fcurve_y = action.fcurves[index + 1] + fcurve_z = action.fcurves[index + 2] + point_count = len(fcurve_x.keyframe_points) + + for i in range(point_count): + # Y invert (-Y) + fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] + + # Z invert (-Z) + fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] + + index += 2 + else: + node_name = fcurve.data_path[start_index + 2 : end_index - 1] + property_name = fcurve.data_path[end_index + 2 :] + rotation_order = self.get_rotation_order(node_name) + + # Convert location animation data for all the non root bones + if property_name == "location": + fcurve_x = action.fcurves[index + 0] + fcurve_y = action.fcurves[index + 1] + fcurve_z = action.fcurves[index + 2] + point_count = len(fcurve_x.keyframe_points) + self.update_total_key_count(point_count) + + for i in range(point_count): + # Y invert (-Y) + fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] + + # Z invert (-Z) + fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] + + # Get skeleton scale and set to location animation data + skeleton_data = DataBase.get_skeleton_data() + skeleton_scale = skeleton_data["skeletonScale"] + skeleton_scale *= scene_size # To match armature scale + for i in range(point_count): + fcurve_x.keyframe_points[i].co[1] *= skeleton_scale + fcurve_y.keyframe_points[i].co[1] *= skeleton_scale + fcurve_z.keyframe_points[i].co[1] *= skeleton_scale + + index += 2 + + # Convert rotation animation data for all the non root bones + if property_name == "rotation_euler": + fcurve_x = action.fcurves[index + 0] + fcurve_y = action.fcurves[index + 1] + fcurve_z = action.fcurves[index + 2] + point_count = len(fcurve_x.keyframe_points) + self.update_total_key_count(point_count) + + if rotation_order == 'XYZ': + for i in range(point_count): + # YZ switch (Y <-> Z) + temp = fcurve_y.keyframe_points[i].co[1] + fcurve_y.keyframe_points[i].co[1] = fcurve_z.keyframe_points[i].co[1] + fcurve_z.keyframe_points[i].co[1] = temp + + # XY switch (X <-> Y) + temp = fcurve_x.keyframe_points[i].co[1] + fcurve_x.keyframe_points[i].co[1] = fcurve_y.keyframe_points[i].co[1] + fcurve_y.keyframe_points[i].co[1] = temp + + if(node_name.startswith("r")): + # Y invert (-Y) + fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] + + # Z invert (-Z) + fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] + + elif rotation_order == 'XZY': + for i in range(point_count): + # XY switch (X <-> Y) + temp = fcurve_x.keyframe_points[i].co[1] + fcurve_x.keyframe_points[i].co[1] = fcurve_y.keyframe_points[i].co[1] + fcurve_y.keyframe_points[i].co[1] = temp + + # X invert (-X) + fcurve_x.keyframe_points[i].co[1] = -fcurve_x.keyframe_points[i].co[1] + + if(node_name.startswith("r")): + # Y invert (-Y) + fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] + + # Z invert (-Z) + fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] + + elif rotation_order == "YZX": + # Bones that are pointed down with YZX order + # TODO: remove hardcoding + if node_name in ["hip", "pelvis", "lThighBend", "rThighBend", "lThighTwist", "rThighTwist", "lShin", "rShin"]: + for i in range(point_count): + # Y invert (-Y) + fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] + + # Z invert (-Z) + fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] + + elif rotation_order == "ZXY": + for i in range(point_count): + # XY switch (X <-> Y) + temp = fcurve_x.keyframe_points[i].co[1] + fcurve_x.keyframe_points[i].co[1] = fcurve_y.keyframe_points[i].co[1] + fcurve_y.keyframe_points[i].co[1] = temp + + # YZ switch (Y <-> Z) + temp = fcurve_y.keyframe_points[i].co[1] + fcurve_y.keyframe_points[i].co[1] = fcurve_z.keyframe_points[i].co[1] + fcurve_z.keyframe_points[i].co[1] = temp + + elif rotation_order == "ZYX": + for i in range(point_count): + # YZ switch (Y <-> Z) + temp = fcurve_y.keyframe_points[i].co[1] + fcurve_y.keyframe_points[i].co[1] = fcurve_z.keyframe_points[i].co[1] + fcurve_z.keyframe_points[i].co[1] = temp + + # X invert (-X) + fcurve_x.keyframe_points[i].co[1] = -fcurve_x.keyframe_points[i].co[1] + + index += 2 + + index += 1 + + self.convert_rotation_orders() + + # Update Name + action.name = "{0} Animation".format(Global.get_asset_name()) \ No newline at end of file diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/CustomBones.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/CustomBones.py index 31b4d027..c3a5b1c5 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/CustomBones.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/CustomBones.py @@ -275,7 +275,7 @@ def makeCustomBone(self): pb.use_custom_shape_bone_size = True if pb.custom_shape_scale == 1.0: pb.custom_shape_scale = 0.3 - + pb.custom_shape_transform = pb def find_bone_roop(self,bone_group,rootbone): for b in bone_group: if len(b.children) > 0: diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DataBase.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DataBase.py index d12307b9..a0d98686 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DataBase.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DataBase.py @@ -1,10 +1,11 @@ from . import Global +import os bone_limits_dict = dict() skeleton_data = dict() def load_bone_limits(): - input_file = open(Global.getHomeTown() + Global.getFileSp() + "FIG_boneLimits.csv", "r") + input_file = open(os.path.join(Global.getHomeTown(), "FIG_boneLimits.csv"), "r") lines = input_file.readlines() input_file.close() @@ -27,7 +28,7 @@ def get_bone_limits_dict(): return bone_limits_dict def load_skeleton_data(): - input_file = open(Global.getHomeTown() + Global.getFileSp() + "FIG_skeletonData.csv", "r") + input_file = open(os.path.join(Global.getHomeTown(),"FIG_skeletonData.csv"), "r") lines = input_file.readlines() input_file.close() diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DazRigBlend.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DazRigBlend.py index 77bdc837..b9f3b58e 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DazRigBlend.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DazRigBlend.py @@ -88,21 +88,15 @@ def orthopedy_empty(self): Global.deselect() Versions.active_object_none() - def clear_pose(self): - Versions.select(Global.getAmtr(), True) - Versions.active_object(Global.getAmtr()) - Versions.show_x_ray(Global.getAmtr()) - Global.setOpsMode('POSE') - bpy.ops.pose.transforms_clear() - Global.setOpsMode('OBJECT') def orthopedy_everything(self): amtr_objs = [] self.del_empty = [] Global.deselect() + # Cycles through the objects and unparents the meshes from the figure. for dobj in Util.myacobjs(): if dobj.type == 'MESH': - if dobj.parent==Global.getAmtr(): + if dobj.parent == Global.getAmtr(): Versions.select(dobj, True) Versions.active_object(dobj) bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) @@ -110,6 +104,8 @@ def orthopedy_everything(self): bpy.ops.object.parent_clear() Versions.select(dobj, False) Global.deselect() + + # Zero out the transforms on the Armature Versions.select(Global.getAmtr(),True) Versions.active_object(Global.getAmtr()) Versions.show_x_ray(Global.getAmtr()) @@ -119,6 +115,8 @@ def orthopedy_everything(self): bpy.ops.object.scale_clear() bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) Global.deselect() + + # Reposition Objects for dobj in amtr_objs: Versions.select(dobj, True) Versions.active_object(dobj) @@ -129,6 +127,7 @@ def orthopedy_everything(self): dobj.lock_rotation[i] = True dobj.lock_scale[i] = True Global.deselect() + mainbone = Global.getAmtr() Versions.select(mainbone,True) Versions.active_object(mainbone) @@ -136,6 +135,8 @@ def orthopedy_everything(self): mainbone.lock_location[i] = True mainbone.lock_rotation[i] = True mainbone.lock_scale[i] = True + + # Reparent to Armature Global.setOpsMode('OBJECT') for btn in self.buttons: Versions.select(btn, True) @@ -149,7 +150,8 @@ def orthopedy_everything(self): bpy.ops.object.parent_set(type='ARMATURE') Versions.select(dobj,False) Versions.select(mainbone,False) - + + def fixGeniWeight(self, db): obj = Global.getBody() if Global.getIsMan()==False: @@ -219,6 +221,15 @@ def bone_limit_modify(self): bone_limit = bone_limits[bone.name] + # Store Custom Properties + bone["Daz Rotation Order"] = bone_limit[1] + bone["min x"] = bone_limit[2] + bone["max x"] = bone_limit[3] + bone["min y"] = bone_limit[4] + bone["max y"] = bone_limit[5] + bone["min z"] = bone_limit[6] + bone["max z"] = bone_limit[7] + bone.constraints.new('LIMIT_ROTATION') rot_limit = bone.constraints['Limit Rotation'] rot_limit.owner_space = 'LOCAL' @@ -266,7 +277,7 @@ def ifitsman(self, bname, roll): def set_bone_head_tail(self): # Read bone's head, tail and a vector to calculate roll - input_file = open(Global.getHomeTown() + Global.getFileSp() + "FIG_boneHeadTail.csv", "r") + input_file = open(os.path.join(Global.getHomeTown(), "FIG_boneHeadTail.csv"), "r") lines = input_file.readlines() input_file.close() bone_head_tail_dict = dict() @@ -469,9 +480,8 @@ def finishjob(self): self.foot_finger_forg3() Global.deselect() Versions.active_object_none() - if Global.want_real(): - Global.changeSize(1, [b[1] for b in self.mub_ary]) - Global.scale_environment() + Global.change_size(Global.getAmtr()) + Global.scale_settings() Versions.select(Global.getAmtr(), True) Versions.active_object(Global.getAmtr()) Global.setOpsMode('POSE') @@ -504,7 +514,7 @@ def fix_mub(self): obj.location[i] = 0 def mub_ary_A(self): - adr = Global.getHomeTown() + Global.getFileSp()+"FIG.dat" + adr = os.path.join(Global.getHomeTown(), "FIG.dat") if os.path.exists(adr): with open(adr) as f: ls = f.readlines() @@ -529,7 +539,7 @@ def mub_ary_Z(self): obj = Util.myacobjs().get(ss[1]) if obj.type != 'MESH': continue - vgs =obj.vertex_groups + vgs = obj.vertex_groups for vs in vgs: obj.vertex_groups.remove(vs) Versions.select(Util.myacobjs().get(ss[1]), True) diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/WCmd.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbCommands.py similarity index 86% rename from Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/WCmd.py rename to Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbCommands.py index d0caedfa..62730bfa 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/WCmd.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbCommands.py @@ -8,13 +8,60 @@ from . import DtbMaterial from . import Util from . import Global +from . import Poses from bpy_extras.io_utils import ImportHelper from bpy.props import StringProperty from bpy.types import Operator + +class SEARCH_OT_Commands(bpy.types.Operator): + bl_idname = "command.search" + bl_label = 'Command' + + def execute(self, context): + search_morph(context) + return {'FINISHED'} + + +def search_morph_(self, context): + search_morph(context) + +def search_morph(context): + w_mgr = context.window_manager + key = w_mgr.search_prop + nozero = False + if key.startswith("!"): + nozero = True + key = key[1:] + if len(key) < 2: + return + if key.startswith("#"): + WCmd.Command(key[1:], context) + return + cobj = bpy.context.object + mesh = cobj.data + for z in range(2): + find = False + max = len(mesh.shape_keys.key_blocks) + for kidx, kb in enumerate(mesh.shape_keys.key_blocks): + if kidx <= Versions.get_active_object().active_shape_key_index: + continue + if nozero and kb.value == 0.0: + continue + if (key.lower() in kb.name.lower()): + Versions.get_active_object().active_shape_key_index = kidx + find = True + break + if z == 0 and find == False: + if max > 1: + Versions.get_active_object().active_shape_key_index = 1 + else: + break + + get_obj_name = "" class ImportFilesCollection(bpy.types.PropertyGroup): - name = StringProperty( + name : StringProperty( name="File Path", description="Filepath used for importing the file", maxlen=1024, @@ -29,12 +76,12 @@ class IMP_OT_dir(bpy.types.Operator, ImportHelper): bl_description = 'processing select directry' bl_label = "Select Directory" - filepath = StringProperty( + filepath : StringProperty( name="input file", subtype= 'DIR_PATH' ) - filename_ext = ""#*.png;*.jpg;*.bmp;*.exr;*.jpeg;*.tif;*.gif" - filter_glob = StringProperty( + filename_ext : ""#*.png;*.jpg;*.bmp;*.exr;*.jpeg;*.tif;*.gif" + filter_glob : StringProperty( default="",#*.png;*.jpg;*.bmp;*.exr;*.jpeg;*.tif;*.gif", options={'HIDDEN'}, ) @@ -55,12 +102,12 @@ def execute(self, context): class IMP_OT_object(Operator, ImportHelper): bl_idname = "imp.object" bl_label = "Import Daz G8 Object" - filename_ext = ".obj" - filter_glob = StringProperty( + filename_ext : ".obj" + filter_glob : StringProperty( default="*.obj", options={'HIDDEN'}, ) - files = bpy.props.CollectionProperty(type=ImportFilesCollection) + files : bpy.props.CollectionProperty(type=ImportFilesCollection) def execute(self, context): dirname = os.path.dirname(self.filepath) @@ -88,18 +135,18 @@ def execute(self, context): class IMP_OT_dazG8_pose(Operator, ImportHelper): bl_idname = "import_daz_g8.pose" bl_label = "Import Daz G8 Pose" - filename_ext = ".duf" - filter_glob = StringProperty( + filename_ext : ".duf" + filter_glob : StringProperty( default="*.duf", options={'HIDDEN'}, ) - files = bpy.props.CollectionProperty(type=ImportFilesCollection) + files : bpy.props.CollectionProperty(type=ImportFilesCollection) def execute(self, context): dirname = os.path.dirname(self.filepath) for i, f in enumerate(self.files, 1): durPath = (os.path.join(dirname, f.name)) - up = Util.Posing() + up = Poses.Posing("POSE") up.pose_copy(durPath) return {'FINISHED'} diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbDazMorph.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbDazMorph.py index cc74ad58..da513b7b 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbDazMorph.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbDazMorph.py @@ -87,7 +87,7 @@ def top_exsport(self): objname = dobj.name if objname.endswith(".Shape"): objname =objname[0:len(objname)-6] - path = Global.getRootPath() + self.KWORD + Global.getFileSp() + objname + "_" + self.get_moment() + path = os.path.join(Global.getRootPath(), self.KWORD, objname + "_" + self.get_moment()) root = Global.getRootPath() + self.KWORD if (os.path.exists(path) and os.path.isdir(path))==False: os.makedirs(path) @@ -125,7 +125,7 @@ def exsport_1morph(self, objname, path): flg_executed = False for kidx, kb in enumerate(mesh.shape_keys.key_blocks): if (kb.name.startswith(self.KWORD)): - path_w = path + Global.getFileSp() + kb.name + ".obj" + path_w = os.path.join(path, kb.name + ".obj") with open(path_w, mode='w') as f: for idx, v in enumerate(kb.data): if self.flg_human and idx >= self.human_max: @@ -138,7 +138,7 @@ def exsport_1morph(self, objname, path): f.write(l) flg_executed = True if flg_executed == False and self.flg_human: - path_w = path + Global.getFileSp() + "Basic.obj" + path_w = os.path.join(path, "Basic.obj") with open(path_w, mode='w') as f: for v in mesh.vertices: if v.index >= self.human_max: diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbIKBones.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbIKBones.py new file mode 100644 index 00000000..0347df60 --- /dev/null +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbIKBones.py @@ -0,0 +1,440 @@ +import sys +import os +import math +sys.path.append(os.path.dirname(__file__)) +import bpy +import mathutils +from copy import deepcopy +from . import DazRigBlend +from . import DtbShapeKeys +from . import DataBase +from . import ToRigify +from . import Global +from . import Versions +from . import DtbDazMorph +from . import DtbOperators +from . import DtbPanels +from . import DtbMaterial +from . import CustomBones +from . import Poses +from . import Animations +from . import Util +from . import DtbCommands +from bpy.props import EnumProperty +from bpy.props import BoolProperty +from bpy.props import StringProperty +import threading +import time + +num_bones = [6, 6, 3, 3] +ik_name = ['rHand_IK', 'lHand_IK', 'rShin_IK', 'lShin_IK'] +bone_name = ['rHand', 'lHand', 'rShin', 'lShin'] +bone_name_rigify = ['MCH-upper_arm_ik.R','MCH-upper_arm_ik.L','MCH-thigh_ik.R','MCH-thigh_ik.L'] +mute_bones = [] +ik_access_ban = False +obj_exsported = "" + +def get_influece_data_path(bname): + amtr = Global.getAmtr() + if amtr is None: + return + if bname in amtr.pose.bones: + pbn = amtr.pose.bones[bname] + for c in pbn.constraints: + if bname + '_IK' in c.name: + return [c, 'influence'] + return None + +def get_ik_influence(data_path): + return eval("data_path[0].%s" % data_path[1]) + +def set_ik_influence(data_path, val): + exec("data_path[0].%s = %f" % (data_path[1], val)) + +def set_ik(data_path): + set_ik_influence(data_path, 1.0) + +def set_fk(data_path): + set_ik_influence(data_path, 0.0) + +def set_translation(matrix, loc): + trs = matrix.decompose() + rot = trs[1].to_matrix().to_4x4() + scale = mathutils.Matrix.Scale(1, 4, trs[2]) + if BV<2.80: + return mathutils.Matrix.Translation(loc) * (rot * scale) + else: + return mathutils.Matrix.Translation(loc) @ (rot @ scale) + +#TODO: Get intergate the setting into the import setup +def set_scene_settings(key_count): + scene = bpy.context.scene + + + # Set start and end playable range for the animations. + scene.frame_start = 0 + scene.frame_end = key_count - 1 + scene.frame_current = 0 + + # Set armature display settings + Global.setOpsMode('POSE') + armature = Global.getAmtr().data + armature.display_type = 'OCTAHEDRAL' + armature.show_names = False + armature.show_axes = False + armature.show_bone_custom_shapes = True + + +def manageKeyFrame(index, flg_to_ik, switch): + global mute_bones + amt = Global.getAmtr() + if index ==1000: + return + if amt is None: + return + if 'NG' in mute_bones: + return + if amt.animation_data is None: + return + act = amt.animation_data.action + if act is None: + return + ckey = bpy.context.scene.frame_current + if switch<0: + mute_bones = [] + my_bone = amt.pose.bones[bone_name[index]] + num = num_bones[index] + for i in range(num): + mute_bones.append(my_bone.name) + my_bone = my_bone.parent + mute_bones.append(ik_name[index]) + if index>1: + poles = ['', '', 'rShin_P', 'lShin_P'] + foots = ['', '', 'rFoot', 'lFoot'] + mute_bones.append(poles[index]) + mute_bones.append(foots[index]) + if flg_to_ik: + mute_bones.append("hip") + if switch < 0: + first_cr = bpy.context.scene.frame_start + first_ik = first_cr + prev_cr = -999 + fkp_ik = Find_KeyFrame_Point(act.fcurves, mute_bones, ['influence',ik_name[index],bone_name[index]], ckey) + prev_ik = fkp_ik.previous + first_ik = fkp_ik.skip_first(first_ik) + if index > 1: + foots = ['', '', 'rFoot', 'lFoot'] + fkp_cr = Find_KeyFrame_Point(act.fcurves, mute_bones, ['influence', 'Copy Rotation',foots[index]], ckey) + prev_cr = fkp_cr.previous + first_cr= fkp_cr.skip_first(first_cr) + if first_cr >= prev_cr: + first_cr = -999 + if first_ik >= prev_ik: + first_ik = -999 + for b in mute_bones: + for c in amt.pose.bones.get(b).constraints: + if (index > 1 and c.name == 'Copy Rotation' and b[1:]=='Foot'): + if first_cr > -1: + c.keyframe_insert(data_path='influence', frame=first_cr) + if prev_cr > -1: + c.keyframe_insert(data_path='influence', frame=prev_cr) + if c.name==ik_name[index]: + if first_ik >-1: + c.keyframe_insert(data_path='influence', frame=first_ik) + if prev_ik > -1: + c.keyframe_insert(data_path='influence', frame=prev_ik) + if switch==0: + for b in mute_bones: + if flg_to_ik==False: + if (b.endswith("_IK") or b.endswith("_P"))==False: + amt.pose.bones[b].keyframe_insert(data_path='rotation_euler', frame=ckey) + else: + if (b.endswith("_IK") or b.endswith("_P")): + + amt.pose.bones[b].keyframe_insert(data_path='location', frame=ckey) + if index > 1 and b.endswith("_IK"): + amt.pose.bones[b].keyframe_insert(data_path='rotation_euler', frame=ckey) + + for c in amt.pose.bones.get(b).constraints: + if (index > 1 and c.name == 'Copy Rotation') or c.name == ik_name[index]: + c.keyframe_insert(data_path='influence', frame=ckey) + else: + for fcu in act.fcurves: + if switch > 0 and fcu.mute: + fcu.mute = False + else: + names = fcu.data_path.split(sep='"', maxsplit=2) + if len(names) < 2: + continue + name = names[1] + if name in mute_bones and switch < 0: + fcu.mute = True + if switch==1: + mute_bones = [] + +class Find_KeyFrame_Point(): + find_collection = [] + skip_collection = [] + previous = -999 + + def skip_first(self,now_first): + if len(self.skip_collection)>1: + wk = self.skip_collection[len(self.skip_collection)-1] + if wk == now_first: + return -999 + else: + return now_first + else: + return now_first + + def __init__(self,fcurves,find_keys,skip_keys,now_posision): + self.find_collection = [] + self.skip_collection = [] + self.previous = -999 + for fc in fcurves: + for fk in find_keys: + if (fk in fc.data_path): + for point in fc.keyframe_points: + if point.co[0] < now_posision and (point.co[0] in self.find_collection) == False: + self.find_collection.append(point.co[0]) + err = False + for sk in skip_keys: + if (sk in fc.data_path)==False: + err = True + break + if err ==False: + for point in fc.keyframe_points: + if point.co[0] < now_posision and (point.co[0] in self.skip_collection)==False: + self.skip_collection.append(point.co[0]) + self.find_collection.sort() + self.find_collection.reverse() + self.skip_collection.sort() + self.skip_collection.reverse() + if len(self.find_collection)<=0: + self.previous = -999 + elif len(self.skip_collection)<=0 or self.skip_collection[0] < self.find_collection[0]: + self.previous = self.find_collection[0] + else: + self.previous = -999 + +def fktoik(index): + manageKeyFrame(index, True, -1) + amt = Global.getAmtr() + adjust_shin_y(index, True) + my_bone = amt.pose.bones[bone_name[index]] + ik_bone = amt.pose.bones[ik_name[index]] + set_fk(get_influece_data_path(bone_name[index])) + Global.setOpsMode('OBJECT') + Global.setOpsMode('POSE') + ik_bone.matrix = set_translation(ik_bone.matrix, my_bone.tail) + set_ik(get_influece_data_path(bone_name[index])) + if index>1: + rot3 = Global.getFootAngle(index-2) + for ridx,rot in enumerate(rot3): + ik_bone.rotation_euler[ridx] = math.radians(rot) + toFootCopyRotate(index,True) + manageKeyFrame(index, True, 0) + if index == 0: + t = threading.Thread(target=my_srv0_1) + t.start() + if index == 1: + t = threading.Thread(target=my_srv1_1) + t.start() + if index == 2: + t = threading.Thread(target=my_srv2_1) + t.start() + if index == 3: + t = threading.Thread(target=my_srv3_1) + t.start() + +def toFootCopyRotate(index,flg_ik): + copy_r = ['','','rFoot', 'lFoot'] + pbone = Global.getAmtr().pose.bones + if pbone is None: + return + for c in pbone.get(copy_r[index]).constraints: + if 'Copy Rotation' == c.name: + if flg_ik: + c.influence = 1.0 + else: + c.influence = 0.0 + +def my_service(index,flg_to_ik): + time.sleep(2) + manageKeyFrame(index, flg_to_ik, 1) + +def my_srv0_1(): + my_service(0,True) +def my_srv1_1(): + my_service(1,True) +def my_srv2_1(): + my_service(2,True) +def my_srv3_1(): + my_service(3,True) +def my_srv0_0(): + my_service(0,False) +def my_srv1_0(): + my_service(1,False) +def my_srv2_0(): + my_service(2,False) +def my_srv3_0(): + my_service(3,False) + +def iktofk(index): + manageKeyFrame(index, False, -1) + adjust_shin_y(index, False) + amt = Global.getAmtr() + ik_bone = amt.pose.bones[ik_name[index]] + my_bone = amt.pose.bones[bone_name[index]] + set_ik(get_influece_data_path(bone_name[index])) + Global.setOpsMode('OBJECT') + Global.setOpsMode('POSE') + ik_bone_matrixes = [] + if my_bone.name=='lShin': + my_bone = amt.pose.bones.get('lFoot') + elif my_bone.name == 'rShin': + my_bone = amt.pose.bones.get('rFoot') + it = my_bone + for i in range(num_bones[index]+1): + if it == None: + continue + mx = deepcopy(it.matrix) + ik_bone_matrixes.append(mx) + it = it.parent + set_fk(get_influece_data_path(bone_name[index])) + if index >1: + toFootCopyRotate(index,False) + it = my_bone + for i in range(num_bones[index] + 1): + if it == None: + continue + it.matrix = deepcopy(ik_bone_matrixes[i]) + it = it.parent + manageKeyFrame(index, False, 0) + if index == 0: + t = threading.Thread(target=my_srv0_0) + t.start() + if index == 1: + t = threading.Thread(target=my_srv1_0) + t.start() + if index == 2: + t = threading.Thread(target=my_srv2_0) + t.start() + if index == 3: + t = threading.Thread(target=my_srv3_0) + t.start() + +def bone_disp2(idx,pose_bone,amt_bone,flg_hide): + hfp = CustomBones.hikfikpole + scales = [hfp[0],hfp[0],hfp[1],hfp[1],hfp[2],hfp[2]] + if amt_bone is None or pose_bone is None: + return + isAnim = Global.isExistsAnimation() + if flg_hide and isAnim: + pose_bone.custom_shape_scale = scales[idx] * 0.4 + else: + pose_bone.custom_shape_scale = scales[idx] + if isAnim: + amt_bone.hide = False + else: + amt_bone.hide = flg_hide + +def bone_disp(idx, flg_hide): + if idx < 0 or idx > 3: + for i in range(4): + bone_disp(i, flg_hide) + return + abones = Global.getAmtrBones() + pbones = Global.getAmtr().pose.bones + if ik_name[idx] in abones: + bone_disp2(idx, pbones.get(ik_name[idx]),abones.get(ik_name[idx]), flg_hide) + if idx>1: + pole = ik_name[idx][0:len(ik_name[idx])-2] + pole = pole + 'P' + if pole in abones: + bone_disp2(idx+2, pbones.get(pole), abones.get(pole),flg_hide) + + + +def bonerange_onoff(self): + bonerange_onoff(self,bpy.contxt) + +def bonerange_onoff(self,context): + flg_on = context.window_manager.br_onoff_prop + Global.boneRotation_onoff(context, flg_on) + +def ifk_update0(self, context): + ifk_update(context, 0) + +def ifk_update1(self, context): + ifk_update(context, 1) + +def ifk_update2(self, context): + ifk_update(context, 2) + +def ifk_update3(self, context): + ifk_update(context, 3) + +def ifk_update(context, idx): + if Global.get_Amtr_name() == "" or ik_access_ban == True: + return {'FINISHED'} + if idx >= 0 and idx <= 3: + ik_force = (get_ik_influence(get_influece_data_path(bone_name[idx])) > 0.5) + gui_force = eval('context.window_manager.ifk' + str(idx)) + if ik_force != gui_force: + if ik_force == False: + bone_disp(idx, False) + fktoik(idx) + else: + bone_disp(idx, True) + iktofk(idx) + return {'FINISHED'} + +def adjust_shin_y(idx, flg_ik): + if Global.getAmtr() is None or idx < 2: + return + idx = idx - 2 + bns = ['rShin', 'lShin'] + Global.setOpsMode('EDIT') + mobj = Global.getBody() + if mobj is None: + Global.find_Both(Global.getAmtr()) + return + vgs = mobj.data.vertices + fm_ikfk = [[4708 ,3418],[4428,3217]] + vidx = 0 + if Global.getIsMan(): + if flg_ik: + vidx = fm_ikfk[1][0] + else: + vidx = fm_ikfk[1][1] + else: + if flg_ik: + vidx = fm_ikfk[0][0] + else: + vidx = fm_ikfk[0][1] + if Global.getIsGen(): + vidx = Global.toGeniVIndex(vidx) + Global.getAmtr().data.edit_bones[bns[idx]].head[1] = vgs[vidx].co[1] + Global.setOpsMode('POSE') + if flg_ik: + for i in range(2): + s = Global.getAmtr().pose.bones.get(bns[i]) + if s is not None: + if s.rotation_euler[0] <= 0.0: + s.rotation_euler[0] = 0.1 + +def gorl_update(self, context): + w_mgr = context.window_manager + gorl = w_mgr.gorl_prop + if gorl == False: + for i, bn in enumerate(bone_name): + v = get_ik_influence(get_influece_data_path(bn)) + if i == 0: + w_mgr.ifk0 = v > 0.5 + elif i == 1: + w_mgr.ifk1 = v > 0.5 + elif i == 2: + w_mgr.ifk2 = v > 0.5 + elif i == 3: + w_mgr.ifk3 = v > 0.5 \ No newline at end of file diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbMaterial.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbMaterial.py index 5e71194d..db17b4a0 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbMaterial.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbMaterial.py @@ -9,20 +9,8 @@ from . import MatDct from . import Util -ftable = [ - ["d", "Diffuse"], - ["b", "Bump"], - ["s", "Specular"], - ["r", "Roughness"], - ["z", "Subsurface"], - ["n", "Normal"] -] # region top-level methods - -def ngroup3(idx): - return NGROUP3[idx] + Util.get_dzidx() - def srgb_to_linear_rgb(srgb): if srgb < 0: return 0 elif srgb < 0.04045: return srgb/12.92 @@ -88,9 +76,6 @@ def forbitMinus(): if node_input.default_value < 0: node_input.default_value = 0.0 -def optimize_materials(): - print("To Clean Up Dupes") - def adjust_material(kind, inc_value, isEye): skincombi = [ ['Base Color.Hue', 11, 0], @@ -173,23 +158,40 @@ def getNidx(idx, nodes): class DtbShaders: def __init__(self): self.mat_data_dict = {} + self.mat_property_dict = {} self.node_groups = [] self.is_Diffuse = False + self.is_Refract = False + self.is_Alpha = False - #TODO: Deal with Materials having same name + #TODO: Find a better way to create the dict def make_dct(self): for file in os.listdir(Global.getHomeTown()): if file.endswith(".dtu"): - input_file = open(Global.getHomeTown() + Global.getFileSp() + file) + input_file = open(os.path.join(Global.getHomeTown(), file)) dtu_content = input_file.read() mat_info_list = json.loads(dtu_content)["Materials"] for mat_info in mat_info_list: - num = "001" - if mat_info["Material Name"] in self.mat_data_dict.keys(): - self.mat_data_dict[mat_info["Material Name"] + num] = mat_info - else: - self.mat_data_dict[mat_info["Material Name"]] = mat_info - + if mat_info["Asset Name"] == mat_info["Asset Label"]: + if mat_info["Asset Name"] in self.mat_data_dict.keys(): + self.mat_data_dict[mat_info["Asset Name"]][mat_info["Material Name"]] = mat_info + else: + self.mat_data_dict[mat_info["Asset Name"]] = {} + self.mat_data_dict[mat_info["Asset Name"]][mat_info["Material Name"]] = mat_info + elif mat_info["Asset Name"] != mat_info["Asset Label"]: + if mat_info["Asset Name"] not in self.mat_data_dict.keys(): + self.mat_data_dict[mat_info["Asset Name"]] = {} + self.mat_data_dict[mat_info["Asset Name"]][mat_info["Material Name"]] = mat_info + if mat_info["Asset Name"] in self.mat_data_dict.keys(): + if mat_info["Material Name"] not in self.mat_data_dict[mat_info["Asset Name"]]: + self.mat_data_dict[mat_info["Asset Name"]][mat_info["Material Name"]] = mat_info + if mat_info["Asset Label"] in self.mat_data_dict.keys(): + self.mat_data_dict[mat_info["Asset Label"]][mat_info["Material Name"]] = mat_info + if mat_info["Asset Label"] not in self.mat_data_dict.keys(): + self.mat_data_dict[mat_info["Asset Label"]] = {} + self.mat_data_dict[mat_info["Asset Label"]][mat_info["Material Name"]] = mat_info + + def load_shader_nodes(self): file_path = "./dependencies/link_library.blend" file_dir = os.path.dirname(os.path.realpath(__file__)) @@ -204,90 +206,117 @@ def load_shader_nodes(self): def get_mat_properties(self,mat_data): mat_property_dict = {} + #To deal with material names sometimes being undescriptive. for mat_property in mat_data["Properties"]: mat_property_dict[mat_property["Name"]] = mat_property + mat_property_dict[mat_property["Label"]] = mat_property return mat_property_dict - def get_mat_type(self,mat_data): - material_name = mat_data["Material Name"] - material_type = mat_data["Material Type"] - object_type = mat_data["Value"] - if material_type == "Iray Uber": + def get_mat_type(self,material): + material_name = material["Material Name"] + material_type = material["Material Type"] + object_type = material["Value"] + if material_name in [ + "Cornea", + "EyeMoisture", + "EyeMoisture.00", + "EylsMoisture", + "Tear" + ]: + return "EyeWet" + + elif material_name in ["Pupils", "Trises", "Sclera"]: + return "EyeDry" + + elif "Eyelashes" in object_type: + return "Eyelashes" + + elif material_type == "Iray Uber": if object_type == "Actor/Character": - if material_name in [ - "Cornea", - "EyeMoisture", - "EyeMoisture.00", - "EylsMoisture", - "Tear" - ]: - return "EyeWet" - elif material_name in ["Pupils", "Trises", "Sclera"]: - return "EyeDry" - else: - return "IrayUberSkin" - - if "Eyelashes" in object_type: - if material_name in [ - "Cornea", - "EyeMoisture", - "EyeMoisture.001", - "EylsMoisture", - "Tear" - ]: - return "EyeWet" - else: - return "Eyelashes" - if "Tear" in object_type: - if material_name in [ - "Cornea", - "EyeMoisture", - "EyeMoisture.001", - "EylsMoisture", - "Tear" - ]: - return "EyeWet" - + return "IrayUberSkin" else: return "IrayUber" + + elif material_type == "AoA_Subsurface": + return "AoA_Subsurface" + elif material_type == "omUberSurface": return "omUberSurface" + elif material_type == "PBRSkin": return "IrayUberSkin" + elif ("Hair" in material_type) or ("Hair" in object_type): return "IrayUber" + + elif material_type == "DAZ Studio Default": + return "DAZ Studio Default" else: return "DefaultMaterial" + + def optimize_materials(self, mat_slot): + mat = mat_slot.material + if "Genesis" in mat["Asset Name"]: + mat_name = mat["Asset Label"] + "_" + mat["Material Name"] + else: + mat_name = mat["Asset Name"] + "_" + mat["Material Name"] + if mat_name not in bpy.data.materials: + if mat["Asset Name"] != mat["Asset Label"]: + mat.name = mat["Asset Name"] + "_" + mat["Material Name"] + return + else: + return + + material = bpy.data.materials[mat_name] + if mat_name != mat.name: + if mat["Asset Name"] == material["Asset Name"]: + mat_slot.material = material + bpy.data.materials.remove(mat) + return True + #TODO: Check for all Color Maps + def check_map_type(self,property_key): + if "Diffuse" in property_key: + self.is_Diffuse = True + else: + self.is_Diffuse = False + if "Opacity" in property_key: + self.is_Alpha = True + else: + self.is_Alpha = False + + + def check_refract(self): + if "Refraction Weight" in self.mat_property_dict.keys(): + if self.mat_property_dict["Refraction Weight"]["Value"] > 0: + self.is_Refract = True + + def set_eevee_alpha(self,mat): - if mat.name in [ - "Eyelashes", - "Hair" - ]: - - Versions.eevee_alpha(mat, 'BLEND', 0) - if mat.name in [ + if self.is_Alpha: + Versions.eevee_alpha(mat, 'HASHED', 0) + else: + mat_name = mat["Material Name"] + if mat_name in [ "Cornea", "EyeMoisture", - "EyeMoisture.001", "EylsMoisture", - "Tear" + "Tear", + "Eyelashes", + "Glass" ]: Versions.eevee_alpha(mat, 'HASHED', 0) - - + + def set_eevee_refract(self,mat): + if self.is_Refract: + mat.use_screen_refraction = True + mat.refraction_depth = 0.8 * Global.get_size() + def find_node_property(self,input_key,mat_property_dict): property_key, property_type = input_key.split(": ") property_info = mat_property_dict[property_key][property_type] return property_key,property_type,property_info - - #TODO: Check for all Color Maps - def check_map_type(self,property_key): - if "Diffuse" in property_key: - self.is_Diffuse = True - else: - self.is_Diffuse = False - + def create_texture_input(self,tex_path,tex_image_node): tex_image = bpy.data.images.load(filepath=tex_path) tex_image_node.image = tex_image @@ -301,28 +330,50 @@ def convert_color(self,color,shader_node): color_rgb.append(1) # alpha return color_rgb - # TODO: Remove all the hardcoding - def body_texture(self): - for mat_slot in Global.getBody().material_slots: + + def setup_materials(self,obj): + for mat_slot in obj.material_slots: mat = mat_slot.material + mat_name = mat.name + + obj_name = obj.name.replace(".Shape","") + obj_name = obj_name.split(".")[0] + if mat is None: # Get or create a new material when slot is missing material mat = bpy.data.materials.get(mat_slot.name) \ or bpy.data.materials.new(name=mat_slot.name) mat_slot.material = mat - - # Get material data - # To Deal With Multiple Characters - if mat.name != "EyeMoisture001": - mat_name = mat.name.split(".0")[0] - else: - mat_name = mat.name - if mat_name not in self.mat_data_dict.keys(): + if obj_name not in self.mat_data_dict.keys(): continue + if mat_name not in self.mat_data_dict[obj_name].keys(): + mat_name = mat.name.split(".")[0] + if mat_name not in self.mat_data_dict[obj_name].keys(): + continue + + mat_data = self.mat_data_dict[obj_name][mat_name] + self.mat_property_dict = self.get_mat_properties(mat_data) + # Set Custom Properties + for key in mat_data: + if not key == "Properties": + mat[key] = mat_data[key] + + # Update Name + new_name = mat["Asset Label"] + "_" + mat["Material Name"] + + if (bpy.context.window_manager.combine_materials): + # To Deal with a duplicate being converted first. + if new_name in bpy.data.materials: + mat_slot.material = bpy.data.materials[new_name] + bpy.data.materials.remove(mat) + continue + mat.name = new_name + mat_name = mat.name + # To Deal with duplications + if self.optimize_materials(mat_slot): + continue - mat_data = self.mat_data_dict[mat_name] - mat.use_nodes = True mat_nodes = mat.node_tree.nodes mat_links = mat.node_tree.links @@ -339,9 +390,9 @@ def body_texture(self): # Create shader node and set links shader_node = mat_nodes.new(type='ShaderNodeGroup') - node_group = self.get_mat_type(mat_data) + node_group = self.get_mat_type(mat) shader_node.node_tree = bpy.data.node_groups[node_group] - + # Link corresponding nodes in the material render_output = None surface_input = out_node_cy.inputs['Surface'] @@ -351,14 +402,14 @@ def body_texture(self): shader_node.outputs['EEVEE'], out_node_ev.inputs['Surface'] ) - # Find and Attach Node Input - mat_property_dict = self.get_mat_properties(mat_data) + for input_key in shader_node.inputs.keys(): + if ("Texture" in input_key) or ("Value" in input_key): # To deal with Gen 8.1 Not Share the Same info as Gen 8 "temp" - if input_key.split(": ")[0] in mat_property_dict.keys(): - property_key,property_type,property_info = self.find_node_property(input_key,mat_property_dict) + if input_key.split(": ")[0] in self.mat_property_dict.keys(): + property_key,property_type,property_info = self.find_node_property(input_key,self.mat_property_dict) if property_type == "Value": # Check if Info is a Hex Color if isinstance(property_info,str): @@ -377,8 +428,12 @@ def body_texture(self): tex_node_output, shader_node.inputs[input_key] ) + # Set Alpha Modes + self.check_refract() + self.set_eevee_refract(mat) self.set_eevee_alpha(mat) + # Set the cycles displacement method if node_group == "IrayUberSkin": mat_links.new( @@ -388,183 +443,7 @@ def body_texture(self): mat.cycles.displacement_method = 'BOTH' else: mat.cycles.displacement_method = 'BUMP' - if mat_nodes is not None: - NodeArrange.toNodeArrange(mat_nodes) - - def wardrobe_texture(self): - fig_objs_names = [ - Global.get_Body_name(), - Global.get_Hair_name() + "OK", - Global.get_Eyls_name() - ] - for obj in Util.myacobjs(): - # Skip for any of the following cases - case1 = not Global.isRiggedObject(obj) - case2 = obj.name in fig_objs_names - if case1 or case2: - continue - - for mat_slot in obj.material_slots: - mat = mat_slot.material - if mat is None: - # Get or create a new material when slot is missing material - mat = bpy.data.materials.get(mat_slot.name) \ - or bpy.data.materials.new(name=mat_slot.name) - mat_slot.material = mat - - # Get material data - # To Deal With Multiple Characters - if mat.name != "EyeMoisture001": - mat_name = mat.name.split(".0")[0] - else: - mat_name = mat.name - if mat_name not in self.mat_data_dict.keys(): - continue - - mat_data = self.mat_data_dict[mat_name] - - mat.use_nodes = True - mat_nodes = mat.node_tree.nodes - mat_links = mat.node_tree.links - - # Remove all the nodes from the material - for mat_node in mat_nodes: - mat_nodes.remove(mat_node) - - # Create material output nodes and set corresponding targets - out_node_cy = mat_nodes.new(type="ShaderNodeOutputMaterial") - out_node_cy.target = 'CYCLES' - out_node_ev = mat_nodes.new(type="ShaderNodeOutputMaterial") - out_node_ev.target = 'EEVEE' - - # Create shader node and set links - shader_node = mat_nodes.new(type='ShaderNodeGroup') - node_group = self.get_mat_type(mat_data) - shader_node.node_tree = bpy.data.node_groups[node_group] - - # Link corresponding nodes in the material - render_output = None - surface_input = out_node_cy.inputs['Surface'] - render_output = shader_node.outputs['Cycles'] - mat_links.new(render_output, surface_input) - mat_links.new( - shader_node.outputs['EEVEE'], - out_node_ev.inputs['Surface'] - ) - # Find and Attach Node Input - mat_property_dict = self.get_mat_properties(mat_data) - for input_key in shader_node.inputs.keys(): - - if ("Texture" in input_key) or ("Value" in input_key): - # To deal with Gen 8.1 Not Sharing the Same info as Gen 8 "temp" - if input_key.split(": ")[0] in mat_property_dict.keys(): - property_key,property_type,property_info = self.find_node_property(input_key,mat_property_dict) - if property_type == "Value": - # Check if Info is a Hex Color - if isinstance(property_info,str): - property_info = self.convert_color(property_info,shader_node) - shader_node.inputs[input_key].default_value = property_info - - if property_type == "Texture": - if os.path.exists(property_info): - self.check_map_type(property_key) - tex_image_node = mat_nodes.new( - type='ShaderNodeTexImage' - ) - self.create_texture_input(property_info,tex_image_node) - tex_node_output = tex_image_node.outputs['Color'] - mat_links.new( - tex_node_output, - shader_node.inputs[input_key] - ) - # Set Alpha Modes - self.set_eevee_alpha(mat) - - # Set the cycles displacement method - if node_group == "IrayUberSkin": - mat_links.new( - shader_node.outputs['Displacement'], - out_node_cy.inputs['Displacement'] - ) - mat.cycles.displacement_method = 'BOTH' - else: - mat.cycles.displacement_method = 'BUMP' - - if mat_nodes is not None: - NodeArrange.toNodeArrange(mat_nodes) - - def env_textures(self,obj): - for mat_slot in obj.material_slots: - mat = mat_slot.material - if mat is None: - # Get or create a new material when slot is missing material - mat = bpy.data.materials.get(mat_slot.name) \ - or bpy.data.materials.new(name=mat_slot.name) - mat_slot.material = mat - mat_name = mat.name.split(".0")[0] - if mat_name not in self.mat_data_dict.keys(): - continue - mat_data = self.mat_data_dict[mat_name] - mat.use_nodes = True - mat_nodes = mat.node_tree.nodes - mat_links = mat.node_tree.links - # Remove all the nodes from the material - for mat_node in mat_nodes: - mat_nodes.remove(mat_node) - # Create material output nodes and set corresponding targets - out_node_cy = mat_nodes.new(type="ShaderNodeOutputMaterial") - out_node_cy.target = 'CYCLES' - out_node_ev = mat_nodes.new(type="ShaderNodeOutputMaterial") - out_node_ev.target = 'EEVEE' - - # Create shader node and set links - shader_node = mat_nodes.new(type='ShaderNodeGroup') - node_group = self.get_mat_type(mat_data) - shader_node.node_tree = bpy.data.node_groups[node_group] - - # Link corresponding nodes in the material - render_output = None - surface_input = out_node_cy.inputs['Surface'] - render_output = shader_node.outputs['Cycles'] - mat_links.new(render_output, surface_input) - mat_links.new( - shader_node.outputs['EEVEE'], - out_node_ev.inputs['Surface'] - ) - # Find and Attach Node Input - mat_property_dict = self.get_mat_properties(mat_data) - for input_key in shader_node.inputs.keys(): - - if ("Texture" in input_key) or ("Value" in input_key): - # To deal with Gen 8.1 Not Share the Same info as Gen 8 "temp" - if input_key.split(": ")[0] in mat_property_dict.keys(): - property_key,property_type,property_info = self.find_node_property(input_key,mat_property_dict) - if property_type == "Value": - # Check if Info is a Hex Color - if isinstance(property_info,str): - property_info = self.convert_color(property_info,shader_node) - shader_node.inputs[input_key].default_value = property_info - if property_type == "Texture": - if os.path.exists(property_info): - self.check_map_type(property_key) - tex_image_node = mat_nodes.new( - type='ShaderNodeTexImage' - ) - self.create_texture_input(property_info,tex_image_node) - tex_node_output = tex_image_node.outputs['Color'] - mat_links.new( - tex_node_output, - shader_node.inputs[input_key] - ) - # Set Alpha Modes - self.set_eevee_alpha(mat) - - - # Set the cycles displacement method - mat.cycles.displacement_method = 'BUMP' - - if mat_nodes is not None: NodeArrange.toNodeArrange(mat_nodes) diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbOperators.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbOperators.py new file mode 100644 index 00000000..380a3dac --- /dev/null +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbOperators.py @@ -0,0 +1,357 @@ +from . import DazRigBlend +from . import DtbShapeKeys +from . import DataBase +from . import ToRigify +from . import Global +from . import Versions +from . import DtbDazMorph +from . import DtbMaterial +from . import CustomBones +from . import Poses +from . import Animations +from . import Util +from . import DtbCommands +from . import DtbIKBones +import bpy +from bpy_extras.io_utils import ImportHelper +from bpy.props import EnumProperty +from bpy.props import BoolProperty +from bpy.props import StringProperty +import os +import mathutils +from copy import deepcopy + +region = 'UI' +BV = Versions.getBV() + + +# Start of Utlity Classes +def reload_dropdowns(version): + if version == "choose_daz_figure": + w_mgr = bpy.types.WindowManager + prop = w_mgr.choose_daz_figure[1] + for arm in Util.all_armature(): + check = [x for x in prop["items"] if x[0] == arm.name] + if len(check) == 0: + if "Asset Name" in arm.keys(): + prop["items"].append((arm.name, arm["Asset Name"], arm["Collection"])) + w_mgr.choose_daz_figure = EnumProperty( + name = prop["name"], + description = prop["description"], + items = prop["items"], + default = Global.get_Amtr_name() + ) + +class ImportFilesCollection(bpy.types.PropertyGroup): + name : StringProperty( + name="File Path", + description="Filepath used for importing the file", + maxlen=1024, + subtype='FILE_PATH', + ) + +bpy.utils.register_class(ImportFilesCollection) +class REFRESH_DAZ_FIGURES(bpy.types.Operator): + bl_idname = "refresh.alldaz" + bl_label = "Refresh All Daz Figures" + bl_description = "Refreshes List of Figures\nOnly needed if figure is not in dropdown" + bl_options = {'REGISTER', 'UNDO'} + + def execute(self, context): + w_mgr = bpy.types.WindowManager + prop = w_mgr.choose_daz_figure[1] + check = ["null"] + for arm in Util.all_armature(): + check = [x for x in prop["items"] if x[0] == arm.name] + if len(check) == 0: + if "Asset Name" in arm.keys(): + prop["items"].append((arm.name, arm["Asset Name"], arm["Collection"])) + if "null" in check: + prop["items"] = [("null" , "Choose Character", "Default Value")] + w_mgr.choose_daz_figure = EnumProperty( + name = prop["name"], + description = prop["description"], + items = prop["items"], + default = prop["default"] + ) + return {'FINISHED'} + +class REMOVE_DAZ_OT_button(bpy.types.Operator): + bl_idname = "remove.alldaz" + bl_label = "Remove All Daz" + bl_description = "Clears out all imported assets\nCurrently deletes all Materials" + bl_options = {'REGISTER', 'UNDO'} + + def invoke(self,context,event): + return context.window_manager.invoke_confirm(self, event) + + def execute(self, context): + col = bpy.data.collections.get('DAZ_ROOT') + if col is not None: + for c in col.children: + for obj in c.objects: + bpy.data.objects.remove(obj) + bpy.data.collections.remove(c) + for material in bpy.data.materials: + material.user_clear() + bpy.data.materials.remove(material) + return {'FINISHED'} + +# End of Utlity Classes +# Start of Import Classes +class IMP_OT_FBX(bpy.types.Operator): + """Supports Genesis 3, 8, and 8.1""" + bl_idname = "import.fbx" + bl_label = "Import New Genesis Figure" + bl_options = {'REGISTER', 'UNDO'} + root = Global.getRootPath() + + def invoke(self, context, event): + if bpy.data.is_dirty: + return context.window_manager.invoke_confirm(self, event) + return self.execute(context) + + def finish_obj(self): + Versions.reverse_language() + Versions.pivot_active_element_and_center_and_trnormal() + Global.setRenderSetting(True) + + def layGround(self): + bpy.context.preferences.inputs.use_mouse_depth_navigate = True + Util.deleteEmptyDazCollection() + bpy.context.scene.render.engine = 'CYCLES' + bpy.context.space_data.shading.type = 'SOLID' + bpy.context.space_data.shading.color_type = 'OBJECT' + bpy.context.space_data.shading.show_shadows = False + Versions.set_english() + bco = bpy.context.object + if bco != None and bco.mode != 'OBJECT': + Global.setOpsMode('OBJECT') + bpy.ops.view3d.snap_cursor_to_center() + + def pbar(self,v,wm): + wm.progress_update(v) + + def import_one(self,fbx_adr): + Versions.active_object_none() + Util.decideCurrentCollection('FIG') + wm = bpy.context.window_manager + wm.progress_begin(0, 100) + Global.clear_variables() + DtbIKBones.ik_access_ban = True + + # Instant of classes + drb = DazRigBlend.DazRigBlend() + dtb_shaders = DtbMaterial.DtbShaders() + anim = Animations.Animations() + pose = Poses.Posing("FIG") + db = DataBase.DB() + self.pbar(5,wm) + anim.reset_total_key_count() + drb.convert_file(filepath=fbx_adr) + self.pbar(10, wm) + Global.decide_HERO() + self.pbar(15, wm) + + if Global.getAmtr() is not None and Global.getBody() is not None: + Global.getAmtr()["Asset Name"] = Global.get_asset_name() + Global.getAmtr()["Collection"] = Util.cur_col_name() + reload_dropdowns("choose_daz_figure") + Global.deselect() # deselect all the objects + pose.clear_pose() # Select Armature and clear transform + drb.mub_ary_A() # Find and read FIG.dat file + drb.orthopedy_empty() # On "EMPTY" type objects + self.pbar(18, wm) + drb.orthopedy_everything() # clear transform, clear and reapply parent, CMs -> METERS + Global.deselect() + self.pbar(20, wm) + drb.set_bone_head_tail() # Sets head and tail positions for all the bones + Global.deselect() + self.pbar(25, wm) + drb.bone_limit_modify() + if anim.has_keyframe(Global.getAmtr()): + anim.clean_animations() + Global.deselect() + self.pbar(30, wm) + drb.unwrapuv() + Global.deselect() + + # materials + dtb_shaders.make_dct() + dtb_shaders.load_shader_nodes() + body = Global.getBody() + dtb_shaders.setup_materials(body) + self.pbar(35, wm) + + fig_objs_names = [ + Global.get_Body_name() + ] + for obj in Util.myacobjs(): + # Skip for any of the following cases + case1 = not Global.isRiggedObject(obj) + case2 = obj.name in fig_objs_names + if case1 or case2: + continue + dtb_shaders.setup_materials(obj) + + self.pbar(40, wm) + + if Global.getIsGen(): + drb.fixGeniWeight(db) + Global.deselect() + self.pbar(45, wm) + Global.setOpsMode('OBJECT') + Global.deselect() + + # Shape keys + dsk = DtbShapeKeys.DtbShapeKeys(False) + dsk.make_drivers() + Global.deselect() + self.pbar(60,wm) + + drb.makeRoot() + drb.makePole() + drb.makeIK() + drb.pbone_limit() + drb.mub_ary_Z() + self.pbar(70,wm) + Global.setOpsMode("OBJECT") + CustomBones.CBones() + self.pbar(80,wm) + Global.setOpsMode('OBJECT') + Global.deselect() + self.pbar(90,wm) + # dsk.delete001_sk() + amt = Global.getAmtr() + for bname in DtbIKBones.bone_name: + bone = amt.pose.bones[bname] + for bc in bone.constraints: + if bc.name == bname + "_IK": + pbik = amt.pose.bones.get(bname + "_IK") + amt.pose.bones[bname].constraints[bname + '_IK'].influence = 0 + drb.makeBRotationCut(db) # lock movements around axes with zeroed limits for each bone + Global.deselect() + + # materials + DtbMaterial.forbitMinus() + self.pbar(95,wm) + Global.deselect() + + Versions.active_object(Global.getAmtr()) + Global.setOpsMode("POSE") + drb.mub_ary_Z() + Global.setOpsMode("OBJECT") + drb.finishjob() + Global.setOpsMode("OBJECT") + if not anim.has_keyframe(Global.getAmtr()): + pose.restore_pose() #Run when no animation exists. + DtbIKBones.bone_disp(-1, True) + DtbIKBones.set_scene_settings(anim.total_key_count) + self.pbar(100,wm) + DtbIKBones.ik_access_ban = False + self.report({"INFO"}, "Success") + else: + self.show_error() + + wm.progress_end() + DtbIKBones.ik_access_ban = False + + def execute(self, context): + if self.root == "": + self.report({"ERROR"}, "Appropriate FBX does not exist!") + return {'FINISHED'} + self.layGround() + for i in range(10): + fbx_adr = os.path.join(self.root, "FIG", "FIG" + str(i), "B_FIG.fbx") + if os.path.exists(fbx_adr)==False: + break + Global.setHomeTown(os.path.join(self.root, "FIG/FIG" + str(i))) + Global.load_asset_name() + self.import_one(fbx_adr) + self.finish_obj() + return {'FINISHED'} + + def show_error(self): + Global.setOpsMode("OBJECT") + for b in Util.myacobjs(): + bpy.data.objects.remove(b) + filepath = os.path.join(os.path.dirname(__file__), "img", "Error.fbx") + if os.path.exists(filepath): + bpy.ops.import_scene.fbx(filepath=filepath) + bpy.context.space_data.shading.type = 'SOLID' + bpy.context.space_data.shading.color_type = 'TEXTURE' + for b in Util.myacobjs(): + for i in range(3): + b.scale[i] = 0.01 + + +class IMP_OT_ENV(bpy.types.Operator): + bl_idname = "import.env" + bl_label = "Import New Env/Prop" + bl_description = "" + bl_options = {'REGISTER', 'UNDO'} + def invoke(self, context, event): + if bpy.data.is_dirty: + return context.window_manager.invoke_confirm(self, event) + return self.execute(context) + + def execute(self, context): + from . import Environment + Environment.EnvProp() + return {'FINISHED'} + + +# Start of Pose Classes +class IMP_OT_POSE(bpy.types.Operator, ImportHelper): + """Imports Daz Poses (.DUF)""" + bl_idname = "import.pose" + bl_label = "Import Pose" + bl_options = {'REGISTER', 'UNDO'} + filename_ext : ".duf" + filter_glob : StringProperty( + default="*.duf", + options={'HIDDEN'}, + ) + files : bpy.props.CollectionProperty(type=ImportFilesCollection) + def execute(self, context): + # Instance Classes + pose = Poses.Posing("POSE") + dirname = os.path.dirname(self.filepath) + for i, f in enumerate(self.files, 1): + durPath = (os.path.join(dirname, f.name)) + pose.pose_copy(durPath) + return {'FINISHED'} + + +class CLEAR_OT_Pose(bpy.types.Operator): + + bl_idname = "my.clear" + bl_label = 'Clear All Pose' + def clear_pose(self): + if bpy.context.object is None: + return + if Global.getAmtr() is not None and Versions.get_active_object() == Global.getAmtr(): + for pb in Global.getAmtr().pose.bones: + pb.bone.select = True + if Global.getRgfy() is not None and Versions.get_active_object() == Global.getRgfy(): + for pb in Global.getRgfy().pose.bones: + pb.bone.select = True + bpy.ops.pose.transforms_clear() + bpy.ops.pose.select_all(action='DESELECT') + + def execute(self, context): + self.clear_pose() + return {'FINISHED'} + +# End of Pose Classes + +# Start of Material Classes + +class OPTIMIZE_OT_material(bpy.types.Operator): + bl_idname = "df.optimize" + bl_label = 'Optimize Materials(WIP)' + def execute(self, context): + DtbMaterial.optimize_materials() + return {'FINISHED'} + +# End of Material Classes diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbPanels.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbPanels.py new file mode 100644 index 00000000..f70959db --- /dev/null +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbPanels.py @@ -0,0 +1,193 @@ +import bpy +import mathutils +from copy import deepcopy +from . import DazRigBlend +from . import DtbShapeKeys +from . import DataBase +from . import ToRigify +from . import Global +from . import Versions +from . import DtbDazMorph +from . import DtbOperators +from . import DtbMaterial +from . import CustomBones +from . import Poses +from . import Animations +from . import Util +from . import DtbCommands +from . import DtbIKBones +from bpy.props import EnumProperty +from bpy.props import BoolProperty +from bpy.props import StringProperty +import threading +import time + + +region = 'UI' +BV = Versions.getBV() + + +class View3DPanel: + bl_space_type = 'VIEW_3D' + bl_region_type = region + if BV <2.80: + bl_category = "Tools" + else: + bl_category = "Daz To Blender" + + +class DTB_PT_MAIN(View3DPanel, bpy.types.Panel): + bl_label = "Daz To Blender" + bl_idname = "VIEW3D_PT_main_daz" + def draw(self, context): + l = self.layout + box = l.box() + w_mgr = context.window_manager + box.operator('import.fbx', icon='POSE_HLT') + box.operator('import.env', icon='WORLD') + if context.object and context.active_object: + cobj = context.active_object + if Global.get_Body_name() == "" and Global.get_Rgfy_name() == "" and Global.get_Amtr_name() == "": + Global.clear_variables() + Global.decide_HERO() + if context.object.type == 'ARMATURE' and Global.getRgfy() is None and Global.getAmtr() is None: + Global.clear_variables() + Global.find_AMTR(cobj) + Global.find_RGFY(cobj) + if context.object.type == 'MESH' and Global.getBody() is None: + Global.clear_variables() + Global.find_BODY(cobj) + if cobj.mode == 'POSE': + if Global.get_Amtr_name() != cobj.name and len(cobj.data.bones) > 90 and len(cobj.data.bones) < 200: + Global.clear_variables() + Global.find_Both(cobj) + if Global.get_Rgfy_name() != cobj.name and len(cobj.data.bones) > 600: + Global.clear_variables() + Global.find_Both(cobj) + elif context.object.type == 'MESH': + if Global.get_Body_name() != "" and Global.get_Body_name() != cobj.name and len( + cobj.vertex_groups) > 163 \ + and len(cobj.data.vertices) >= 16384 \ + and len(cobj.vertex_groups) < 500 and len(cobj.data.vertices) < 321309: + Global.clear_variables() + Global.find_Both(cobj) + if DtbIKBones.ik_access_ban == False and context.active_object.mode == 'POSE': + l.separator() + if Global.amIAmtr(context.object): + col = l.column(align=True) + r = col.row(align=True) + for i in range(len(DtbIKBones.ik_name)): + if i == 2: + r = col.row(align=True) + influence_data_path = DtbIKBones.get_influece_data_path(DtbIKBones.bone_name[i]) + if influence_data_path is not None: + r.prop(w_mgr, 'ifk' + str(i), text=DtbIKBones.ik_name[i], toggle=True) + col.operator('limb.redraw',icon='LINE_DATA') + l.separator() + elif Global.amIRigfy(context.object): + if BV<2.81: + row = l.row(align=True) + row.alignment = 'EXPAND' + row.operator('my.iktofk', icon="MESH_CIRCLE") + row.operator('my.fktoik', icon="MESH_CUBE") + if Global.amIAmtr(context.object): + l.operator('to.rigify', icon='ARMATURE_DATA') + if Global.amIRigfy(context.object): + if BV<2.81: + row = l.row(align=True) + row.alignment = 'EXPAND' + row.operator('match.ikfk') + row.prop(w_mgr, "br_onoff_prop", text="Joint Range", toggle=True) + else: + l.prop(w_mgr, "br_onoff_prop", text="Joint Range", toggle=True) + + if Global.amIBody(context.object): + col = l.column(align=True) + box = col.box() + row = box.row(align=True) + row.alignment = 'EXPAND' + row.prop(w_mgr, "is_eye", text="Eye") + row.prop(w_mgr, "ftime_prop", text="x 4") + if w_mgr.is_eye: + box.prop(w_mgr, "eye_prop", text="") + else: + box.prop(w_mgr, "skin_prop", text="") + row = box.row(align=True) + row.alignment = 'EXPAND' + row.operator('material.up', icon="TRIA_UP") + row.operator('material.down', icon="TRIA_DOWN") + box.operator('df.material') + if context.object.type == 'MESH': + if Global.isRiggedObject(context.object): + if Versions.get_active_object().mode == 'OBJECT': + l.prop(w_mgr, 'new_morph', text="Make New Morph") + row = l.row(align=True) + row.operator('exsport.morph', icon="TRIA_LEFT") + row.operator('to.sculpt', icon="MONKEY") + if DtbIKBones.obj_exsported != "": + l.label(text=DtbIKBones.obj_exsported) + + l.separator() + + # l.operator('df.optimize', icon="MATERIAL") + +class DTB_PT_POSE(View3DPanel, bpy.types.Panel): + bl_idname = "VIEW3D_PT_pose_daz" + bl_label = "Pose Tools" + + def draw(self, context): + l = self.layout + box = l.box() + w_mgr = context.window_manager + l.operator('my.clear') + l.separator() + box.prop(w_mgr, "choose_daz_figure", text = "") + box.operator('import.pose', icon='POSE_HLT') + row = box.row(align=True) + row.prop(w_mgr, "add_pose_lib", text="Add to Pose Library", toggle=False) + +class DTB_PT_MATERIAL(View3DPanel, bpy.types.Panel): + bl_idname = "VIEW3D_PT_material_daz" + bl_label = "Material Settings" + + def draw(self, context): + l = self.layout + box = l.box() + w_mgr = context.window_manager + box.label(text = "Import Settings") + row = box.row(align=True) + row.prop(w_mgr, "combine_materials", text="Combine Dupe Materials", toggle=False) + + +class DTB_PT_GENERAL(View3DPanel, bpy.types.Panel): + bl_idname = "VIEW3D_PT_general_daz" + bl_label = "General Settings" + + def draw(self, context): + l = self.layout + box = l.box() + w_mgr = context.window_manager + row = box.row(align=True) + row.prop(w_mgr, "quick_heavy", text="Quick But Heavy", toggle=False) + l.prop(w_mgr, "scene_scale", text = "") + l.operator('refresh.alldaz', icon='BOIDS') + l.operator('remove.alldaz', icon='BOIDS') + + +class DTB_PT_COMMANDS(View3DPanel, bpy.types.Panel): + bl_idname = "VIEW3D_PT_commands_daz" + bl_label = "Commands List" + + def draw(self, context): + l = self.layout + w_mgr = context.window_manager + l.label(text = "What does it do?: Command") + l.label(text = "Imports Pose: #getpose") + row = l.row(align=True) + row.alignment = 'EXPAND' + row.prop(w_mgr, "search_prop") + if context.object and context.active_object: + if context.object.type == 'MESH': + row.operator('command.search', icon='VIEWZOOM') + else: + row.operator('command.search', icon='HAND') \ No newline at end of file diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbShapeKeys.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbShapeKeys.py index 584f8d05..08e40b26 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbShapeKeys.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/DtbShapeKeys.py @@ -1,11 +1,17 @@ -import bpy -import sys import os -sys.path.append(os.path.dirname(__file__)) -from . import Global -from . import DataBase -from . import Versions +import sys +import math +import json +import bpy + from . import Util +from . import Versions +from . import DataBase +from . import Global + +sys.path.append(os.path.dirname(__file__)) + + class DtbShapeKeys: root = Global.getRootPath() flg_rigify = False @@ -13,10 +19,324 @@ class DtbShapeKeys: def __init__(self, flg_rigify): self.flg_rigify = flg_rigify - def makeDrives(self,db): + def make_drivers(self): + body_obj = Global.getBody() for dobj in Util.myccobjs(): if Global.isRiggedObject(dobj): - self.makeDrive(dobj,db) + self.make_driver(dobj, body_obj) + + def get_transform_type(self, morph_link): + bone_name = morph_link["Bone"] + property_name = morph_link["Property"] + + bone_limits = DataBase.get_bone_limits_dict() + bone_order = bone_limits[bone_name][1] + + # Conversions for corresponding rotation properties betweem Daz Studio + # and Blender. + if bone_order == 'XYZ': + if "XRotate" in property_name: + return 'ROT_Z' + elif "YRotate" in property_name: + return 'ROT_X' + elif "ZRotate" in property_name: + return 'ROT_Y' + elif bone_order == 'XZY': + if "XRotate" in property_name: + return 'ROT_Y' + elif "YRotate" in property_name: + return 'ROT_X' + elif "ZRotate" in property_name: + return 'ROT_Z' + elif bone_order == 'YZX': + if "XRotate" in property_name: + return 'ROT_X' + elif "YRotate" in property_name: + return 'ROT_Y' + elif "ZRotate" in property_name: + return 'ROT_Z' + elif bone_order == 'ZXY': + if "XRotate" in property_name: + return 'ROT_Y' + elif "YRotate" in property_name: + return 'ROT_Z' + elif "ZRotate" in property_name: + return 'ROT_X' + elif bone_order == 'ZYX': + if "XRotate" in property_name: + return 'ROT_X' + elif "YRotate" in property_name: + return 'ROT_Z' + elif "ZRotate" in property_name: + return 'ROT_Y' + + return 'LOC_X' + + def get_var_correction(self, var_name, morph_link): + # Correction factor for the cases where the property value is sign is + # reversed between Daz Studio and Blender + correction_factor = 1 + + bone_name = morph_link["Bone"] + property_name = morph_link["Property"] + + # Return when controller is not a Bone + if bone_name == "None": + return var_name + + bone_limits = DataBase.get_bone_limits_dict() + bone_order = bone_limits[bone_name][1] + + prefix = bone_name[0:1] + post_prefix = bone_name[1:2] + is_right = False + if prefix == "r" and post_prefix.isupper(): + is_right = True + is_down = False + if bone_name in ["hip", "pelvis", "lThighBend", "rThighBend", "lThighTwist", "rThighTwist", "lShin", "rShin"]: + is_down = True + + if bone_order == 'XYZ': + if "XRotate" in property_name: + correction_factor = 1 + elif "YRotate" in property_name and is_right: + correction_factor = -1 + elif "ZRotate" in property_name and is_right: + correction_factor = -1 + elif bone_order == 'XZY': + if "XRotate" in property_name: + correction_factor = -1 + elif "YRotate" in property_name and is_right: + correction_factor = -1 + elif "ZRotate" in property_name and is_right: + correction_factor = -1 + elif bone_order == 'YZX': + if "XRotate" in property_name: + correction_factor = 1 + elif "YRotate" in property_name and is_down: + correction_factor = -1 + elif "ZRotate" in property_name and is_down: + correction_factor = -1 + elif bone_order == 'ZXY': + if "XRotate" in property_name: + correction_factor = 1 + elif "YRotate" in property_name: + correction_factor = 1 + elif "ZRotate" in property_name: + correction_factor = 1 + elif bone_order == 'ZYX': + if "XRotate" in property_name: + correction_factor = -1 + elif "YRotate" in property_name: + correction_factor = 1 + elif "ZRotate" in property_name: + correction_factor = 1 + + # Include radians to degree convesion factor + correction_factor = math.degrees(correction_factor) + + var_name = "(" + var_name + "*" + str(correction_factor) + ")" + return var_name + + def get_target_expression(self, var_name, morph_link, driver): + link_type = morph_link["Type"] + scalar = str(morph_link["Scalar"]) + addend = str(morph_link["Addend"]) + + var_name = self.get_var_correction(var_name, morph_link) + + if link_type == 0: + # ERCDeltaAdd + return "(" + var_name + "*" + scalar + " + " + addend + ")" + elif link_type == 1: + # ERCDivideInto + driver.use_self = True + return "(" + var_name + "/self.value + " + addend + ")" + elif link_type == 2: + # ERCDivideBy + driver.use_self = True + return "(" + "self.value/" + var_name + " + " + addend + ")" + elif link_type == 3: + # ERCMultiply + driver.use_self = True + return "(" + var_name + "*self.value + " + addend + ")" + elif link_type == 4: + # ERCSubtract + driver.use_self = True + return "(" + "self.value - " + var_name + " + " + addend + ")" + elif link_type == 5: + # ERCAdd + driver.use_self = True + return "(" + "self.value + " + var_name + " + " + addend + ")" + elif link_type == 6: + # ERCKeyed + # TODO: Figure out a way to represent in Blender. + return "(" + var_name + ")" + + return var_name + + def get_morph_link_control_type(self, morph_link): + if morph_link["Type"] == 6: + # skip links that are 'ERCKeyed' for now + return 'CONTROL_BY_NONE' + elif morph_link["Bone"] == "None": + return 'CONTROL_BY_MORPH' + else: + return 'CONTROL_BY_BONE' + + def make_bone_var(self, link_index, morph_link, driver): + # Add Variable + link_var = driver.variables.new() + link_var.name = "var" + str(link_index) + link_var.type = 'TRANSFORMS' + + # Set variable target + target = link_var.targets[0] + target.id = Global.getAmtr() + target.bone_target = morph_link["Bone"] + target.transform_space = 'LOCAL_SPACE' + target.transform_type = self.get_transform_type(morph_link) + + return link_var + + def make_morph_var(self, link_index, morph_link, driver, shape_key, mesh_name): + # Add variable + link_var = driver.variables.new() + link_var.name = "var" + str(link_index) + link_var.type = 'SINGLE_PROP' + + # Set variable target + target = link_var.targets[0] + target.id_type = 'KEY' + target.id = shape_key + block_id = mesh_name + "__" + morph_link["Property"] + rna_data_path = "key_blocks[\"" + block_id + "\"].value" + target.data_path = rna_data_path + + return link_var + + def property_in_shape_keys(self, morph_link, shape_key_blocks, mesh_name): + property_name = morph_link["Property"] + is_found = False + for key_block in shape_key_blocks: + if property_name == key_block.name[len(mesh_name + "__"): ]: + is_found = True + break + return is_found + + def load_morph_link_list(self): + # Read all the morph links from the DTU + for file in os.listdir(Global.getHomeTown()): + if file.endswith(".dtu"): + input_file = open(Global.getHomeTown() + Global.getFileSp() + file) + dtu_content = input_file.read() + return json.loads(dtu_content)["MorphLinks"] + + def make_body_mesh_drivers(self, body_mesh_obj): + mesh_name = body_mesh_obj.data.name + shape_key = body_mesh_obj.data.shape_keys + if shape_key is None: + return + + # Create drivers for shape key blocks on the body mesh + morph_links_list = self.load_morph_link_list() + shape_key_blocks = shape_key.key_blocks + for key_block in shape_key_blocks: + key_name = key_block.name[len(mesh_name + "__"):] + if key_name not in morph_links_list: + # Continue if the key is not found in the morph links list + continue + + # Add driver + driver = key_block.driver_add("value").driver + driver.type = 'SCRIPTED' + + morph_links = morph_links_list[key_name] + expression = "" + var_count = 0 + for link_index, morph_link in enumerate(morph_links): + # Determine if the controller is a Bone or other shape key + control_type = self.get_morph_link_control_type(morph_link) + if control_type == 'CONTROL_BY_NONE': + continue + if control_type == 'CONTROL_BY_MORPH': + is_found = self.property_in_shape_keys( + morph_link, + shape_key_blocks, + mesh_name + ) + if not is_found: + # If the controller morph is not in listed shape keys + continue + var = self.make_morph_var( + link_index, + morph_link, + driver, + shape_key, + mesh_name + ) + var_count += 1 + elif control_type == 'CONTROL_BY_BONE': + var = self.make_bone_var(link_index, morph_link, driver) + var_count += 1 + + expression += self.get_target_expression(var.name, morph_link, driver) + "+" + + # Delete the driver and continue if there are no variables + if var_count == 0: + key_block.driver_remove("value") + continue + + # Trim the extra '+' char + if expression.endswith("+"): + expression = expression[:-1] + driver.expression = expression + + def make_other_mesh_drivers(self, other_mesh_obj, body_mesh_obj): + other_mesh_name = other_mesh_obj.data.name + body_mesh_name = body_mesh_obj.data.name + + other_shape_key = other_mesh_obj.data.shape_keys + body_shape_key = body_mesh_obj.data.shape_keys + if other_shape_key is None or body_shape_key is None: + return + + other_key_blocks = other_shape_key.key_blocks + body_key_blocks = body_shape_key.key_blocks + + # Add drivers to the key blocks that have same name as in body mesh + # Driver copies the value of the controller key block + for other_block in other_key_blocks: + other_key_name = other_block.name[len(other_mesh_name + "__"):] + for body_block in body_key_blocks: + body_key_name = body_block.name[len(body_mesh_name + "__"):] + if other_key_name != body_key_name: + continue + + # Add driver + driver = other_block.driver_add("value").driver + driver.type = 'SUM' + + # Add variable + link_var = driver.variables.new() + link_var.name = "var" + link_var.type = 'SINGLE_PROP' + + # Set variable target + target = link_var.targets[0] + target.id_type = 'KEY' + target.id = body_shape_key + block_id = body_mesh_name + "__" + body_key_name + rna_data_path = "key_blocks[\"" + block_id + "\"].value" + target.data_path = rna_data_path + + def make_driver(self, other_mesh_obj, body_mesh_obj): + if other_mesh_obj == body_mesh_obj: + # Create drivers on the body mesh shape keys + self.make_body_mesh_drivers(body_mesh_obj) + else: + # Create drivers on the other (non body) mesh shape keys + self.make_other_mesh_drivers(other_mesh_obj, body_mesh_obj) def delete001_sk(self): Global.setOpsMode('OBJECT') @@ -24,7 +344,7 @@ def delete001_sk(self): Versions.select(obj, True) Versions.active_object(obj) aobj = bpy.context.active_object - sp = aobj.data.shape_keys + sp = aobj.data.shape_keys if sp is not None: max = len(sp.key_blocks) i = 0 @@ -36,122 +356,72 @@ def delete001_sk(self): else: i = i + 1 - def get_rigify_bone_name(self,bname): + def get_rigify_bone_name(self, bname): rtn = "" db = DataBase.DB() for trf in db.toRigify: if trf[0] < 2: continue ops_trf = 'r' + trf[1][1:] - bool_ops = ops_trf==bname - if trf[1]==bname or bool_ops: + bool_ops = ops_trf == bname + if trf[1] == bname or bool_ops: rtn = trf[2] if bool_ops: - rtn = rtn.replace(".L",".R") + rtn = rtn.replace(".L", ".R") break - if rtn=='' and 'Toe' in bname and len(bname)>4: + if rtn == '' and 'Toe' in bname and len(bname) > 4: rtn = bname elif rtn.startswith('f_') or rtn.startswith('thumb.'): pass elif ('DEF-' + rtn) in Global.getRgfyBones(): rtn = 'DEF-' + rtn - swap = [['DEF-shoulder.','shoulder.'],['DEF-pelvis.L','tweak_spine']] + swap = [['DEF-shoulder.', 'shoulder.'], + ['DEF-pelvis.L', 'tweak_spine']] for sp in swap: if sp[0] in rtn: - rtn = rtn.replace(sp[0],sp[1]) + rtn = rtn.replace(sp[0], sp[1]) return rtn - def makeOneDriver(self,db): + def makeOneDriver(self, db): cur = db.tbl_mdrive aobj = Global.getBody() if Global.getIsG3(): cur.extend(db.tbl_mdrive_g3) for row in cur: - sk_name =aobj.active_shape_key.name + sk_name = aobj.active_shape_key.name if row[0] in sk_name and sk_name.endswith(".001") == False: - dvr = aobj.data.shape_keys.key_blocks[sk_name].driver_add('value') + dvr = aobj.data.shape_keys.key_blocks[sk_name].driver_add( + 'value') dvr.driver.type = 'SCRIPTED' var = dvr.driver.variables.new() Versions.set_debug_info(dvr) - self.setDriverVariables(var, 'val', Global.getAmtr(), row[1], row[2]) + self.setDriverVariables( + var, 'val', Global.getAmtr(), row[1], row[2]) exp = row[3] dvr.driver.expression = exp break - def makeDrive(self,dobj,db): - mesh_name = dobj.data.name - Versions.active_object(dobj) - aobj = bpy.context.active_object - if bpy.data.meshes[mesh_name].shape_keys is None: - return - ridx = 0 - cur = db.tbl_mdrive - if Global.getIsG3(): - cur.extend(db.tbl_mdrive_g3) - while ridx < len(cur): - max = len(bpy.data.meshes[mesh_name].shape_keys.key_blocks) - row = cur[ridx] - for i in range(max): - if aobj is None: - continue - aobj.active_shape_key_index = i - if aobj.active_shape_key is None: - continue - sk_name = aobj.active_shape_key.name - if row[0] in sk_name and sk_name.endswith(".001")==False: - dvr = aobj.data.shape_keys.key_blocks[sk_name].driver_add('value') - dvr.driver.type = 'SCRIPTED' - var = dvr.driver.variables.new() - Versions.set_debug_info(dvr) - if self.flg_rigify: - target_bone = self.get_rigify_bone_name(row[1]) - xyz = self.toRgfyXyz(row[2],target_bone) - self.setDriverVariables(var, 'val', Global.getRgfy(), target_bone, xyz) - exp = self.getRgfyExp(row[3],target_bone,row[0]) - if ridx < len(cur) - 1 and cur[ridx + 1][0] in sk_name: - row2 = cur[ridx + 1] - target_bone2 = self.get_rigify_bone_name(row2[1]) - var2 = dvr.driver.variables.new() - xyz2 = self.toRgfyXyz(row2[2],target_bone2) - self.setDriverVariables(var2, 'val2', Global.getRgfy(), target_bone2, xyz2) - exp2 = self.getRgfyExp(row2[3], target_bone2, row2[0]) - exp += '+' + exp2 - ridx = ridx + 1 - dvr.driver.expression = exp - else: - self.setDriverVariables(var, 'val', Global.getAmtr(), row[1], row[2]) - exp = row[3] - if ridx < len(cur)-1 and cur[ridx+1][0] in sk_name: - row2 = cur[ridx+1] - var2 = dvr.driver.variables.new() - self.setDriverVariables(var2, 'val2', Global.getAmtr(), row2[1], row2[2]) - exp += '+' + row2[3] - ridx = ridx + 1 - dvr.driver.expression = exp - break - ridx = ridx + 1 - - def toRgfyXyz(self,xyz,bname): - zy_switch = ['chest','hips'] + def toRgfyXyz(self, xyz, bname): + zy_switch = ['chest', 'hips'] for zy in zy_switch: - if bname==zy: - if xyz==1: + if bname == zy: + if xyz == 1: return 2 - elif xyz==2: + elif xyz == 2: return 1 return xyz - def getRgfyExp(self,exp,target_bone,sk_name): + def getRgfyExp(self, exp, target_bone, sk_name): exp = exp.replace(' ', '') exp_kind = [ - ['upper_arm', '', '' ], + ['upper_arm', '', ''], ['forearm', '', ''], ['hand', '', ''], - ['hip','',''], - ['tweak_spine','',''], - ['toe','',''], - ['chest','','Side'], - ['DEF-spine','spine','pJCMAbdomenFwd_35'] + ['hip', '', ''], + ['tweak_spine', '', ''], + ['toe', '', ''], + ['chest', '', 'Side'], + ['DEF-spine', 'spine', 'pJCMAbdomenFwd_35'] ] for ek in exp_kind: if(ek[0] in target_bone) and target_bone.endswith(ek[1]) and (ek[2] in sk_name): @@ -159,7 +429,7 @@ def getRgfyExp(self,exp,target_bone,sk_name): break return exp - def setDriverVariables(self,var,varname,target_id,bone_target,xyz): + def setDriverVariables(self, var, varname, target_id, bone_target, xyz): var.name = varname var.type = 'TRANSFORMS' target = var.targets[0] @@ -173,21 +443,21 @@ def setDriverVariables(self,var,varname,target_id,bone_target,xyz): elif xyz == 2: target.transform_type = 'ROT_Z' - def invert_exp(self,exp): - flg_ToMs = ('val-' in exp) or ('*-' in exp)==False#In case of Plus + def invert_exp(self, exp): + flg_ToMs = ('val-' in exp) or ('*-' in exp) == False # In case of Plus if flg_ToMs: if ('val-' in exp): exp = exp.replace("val-", "val+") - if ('*-' in exp)==False: + if ('*-' in exp) == False: exp = exp.replace("*", "*-") else: if ('val+' in exp): exp = exp.replace("val+", "val-") if ('*-' in exp): - exp = exp.replace("*-", "*") + exp = exp.replace("*-", "*") return exp - def toHeadMorphMs(self,db): + def toHeadMorphMs(self, db): dobj = Global.getBody() Versions.select(dobj, True) cur = db.tbl_facems @@ -198,75 +468,19 @@ def toHeadMorphMs(self,db): continue for kb in mesh.shape_keys.key_blocks: for row in cur: - if kb.name.lower()==row.lower(): - kb.slider_min =-1 + if kb.name.lower() == row.lower(): + kb.slider_min = -1 - def add_sk(self,dobj): + def add_sk(self, dobj): Versions.select(dobj, True) Versions.active_object(dobj) for mesh in bpy.data.meshes: if mesh.name == dobj.data.name: - bpy.ops.object.shape_key_add(from_mix = False) + bpy.ops.object.shape_key_add(from_mix=False) kblen = len(mesh.shape_keys.key_blocks) bpy.context.active_object.active_shape_key_index = kblen-1 - def toshortkey(self): - for k in bpy.data.shape_keys: - for b in k.key_blocks: - a = b.name.find("__pJCM") - if a > 2: - bpy.data.shape_keys[k.name].key_blocks[b.name].name = b.name[a:] - keys = [Global.get_Amtr_name(),'head','_','_','eCTRL','PHM'] - for sidx,s in enumerate(keys): - if b.name.startswith(s): - wk = b.name[len(s):] - if sidx==0: - wk = "D"+ wk - elif sidx==4: - wk = "H-" + wk - bpy.data.shape_keys[k.name].key_blocks[b.name].name = wk - - def deleteExtraSkey(self): - dels = [] - for k in bpy.data.shape_keys: - for aidx, a in enumerate(k.key_blocks): - if ('eCTRL' in a.name) and a.name.startswith("D"): - for bidx, b in enumerate(k.key_blocks): - if aidx == bidx: - continue - if b.name.startswith("H-"): - astart = a.name.find('eCTRL') - if a.name[astart + 5:] == b.name[2:]: - if not (aidx in dels): - dels.append(aidx) - dels.sort() - ms = 0 - for d in dels: - Global.getBody().active_shape_key_index = d - ms - bpy.ops.object.shape_key_remove(all=False) - ms += 1 - - def deleteEyelashes(self): - Global.setOpsMode('OBJECT') - dobj = Global.getBody() - Versions.select(dobj, True) - Versions.active_object(dobj) - sp = dobj.data.shape_keys - eylsname = Global.get_KeepEyls_name() - if eylsname.endswith(".Shape"): - eylsname = eylsname[:len(eylsname)-6] - if sp is not None and eylsname!="": - max = len(sp.key_blocks) - i = 0 - for notouch in range(max): - dobj.active_shape_key_index = i - if (eylsname in dobj.active_shape_key.name): - bpy.ops.object.shape_key_remove(all=False) - max = max-1 - else: - i = i + 1 - - def delete_old_vgroup(self,db): + def delete_old_vgroup(self, db): dobj = Global.getBody() for fv in db.fvgroup: for vg in dobj.vertex_groups: @@ -275,20 +489,20 @@ def delete_old_vgroup(self,db): dobj.vertex_groups.remove(vg) break - def swap_fvgroup(self,db): + def swap_fvgroup(self, db): dobj = Global.getBody() for z in range(2): for _fs in db.fvgroup_swap: - fs = [_fs[0],_fs[1]] - if z==1: - if fs[1].startswith("l") and fs[1].startswith("lower")==False: + fs = [_fs[0], _fs[1]] + if z == 1: + if fs[1].startswith("l") and fs[1].startswith("lower") == False: fs[1] = "r" + fs[1][1:] - fs[0] = fs[0].replace(".L",".R") + fs[0] = fs[0].replace(".L", ".R") else: continue vgs = dobj.vertex_groups for vg in vgs: - if vg.name==fs[1]: + if vg.name == fs[1]: vg.name = fs[0] def delete_oneobj_sk_from_command(self): @@ -297,17 +511,18 @@ def delete_oneobj_sk_from_command(self): aobj = Versions.get_active_object() if aobj is None: return - self.delete_oneobj_sk(0,100, 0,aobj, wm) + self.delete_oneobj_sk(0, 100, 0, aobj, wm) wm.progress_end() - def delete_oneobj_sk(self,min,onesa,oidx,obj,wm): + def delete_oneobj_sk(self, min, onesa, oidx, obj, wm): v = min + onesa * oidx wm.progress_update(int(v)) Versions.active_object(obj) if obj.data.shape_keys is None: return kbs = obj.data.shape_keys.key_blocks - root_kb = [d.co[0] for didx,d in enumerate(kbs[0].data) if didx%4==0] + root_kb = [d.co[0] + for didx, d in enumerate(kbs[0].data) if didx % 4 == 0] max = len(kbs) z0_same_idx_ary = [] dels = [] @@ -320,7 +535,7 @@ def delete_oneobj_sk(self,min,onesa,oidx,obj,wm): if old_dv != dv: wm.progress_update(dv) kb = kbs[i] - if root_kb == [d.co[0] for didx,d in enumerate(kb.data) if didx%4==0 ]: + if root_kb == [d.co[0] for didx, d in enumerate(kb.data) if didx % 4 == 0]: z0_same_idx_ary.append(i) old_dv = dv else: @@ -328,13 +543,14 @@ def delete_oneobj_sk(self,min,onesa,oidx,obj,wm): break decisa = onesa / (2.0 * len(z0_same_idx_ary)) old_dv = v - root_kb_yz = [[d.co[1], d.co[2]] for didx,d in enumerate(kbs[0].data) if didx%4==0] + root_kb_yz = [[d.co[1], d.co[2]] + for didx, d in enumerate(kbs[0].data) if didx % 4 == 0] for i in z0_same_idx_ary: dv = int(v + onesa / 2.0 + decisa * i) if old_dv != dv: wm.progress_update(dv) kb = kbs[i] - if root_kb_yz == [[d.co[1], d.co[2]] for didx,d in enumerate(kb.data) if didx%4==0]: + if root_kb_yz == [[d.co[1], d.co[2]] for didx, d in enumerate(kb.data) if didx % 4 == 0]: dels.append(i) old_dv = dv dels.sort(reverse=True) @@ -345,9 +561,9 @@ def delete_oneobj_sk(self,min,onesa,oidx,obj,wm): def delete_all_extra_sk(self, min, max, wm): objs = [] for obj in Util.myccobjs(): - if obj.type=='MESH': + if obj.type == 'MESH': objs.append(obj) allsa = max-min onesa = allsa/len(objs) - for oidx,obj in enumerate(objs): - self.delete_oneobj_sk(min,onesa,oidx,obj,wm) + for oidx, obj in enumerate(objs): + self.delete_oneobj_sk(min, onesa, oidx, obj, wm) diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Environment.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Environment.py index 2defdf64..6215975d 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Environment.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Environment.py @@ -1,62 +1,70 @@ import bpy import os +import json import math from . import Versions from . import Global from . import Util from . import DtbMaterial from . import NodeArrange +from . import Poses import re -def pbar(v): - bpy.context.window_manager.progress_update(v) +def set_transform(obj,data,type): + if type == "scale": + transform = obj.scale + if type == "rotate": + transform = obj.rotation_euler + for i in range(len(data)): + data[i] = math.radians(data[i]) + if type == "translate": + transform = obj.location + for i in range(3): + transform[i] = float(data[i]) +def progress_bar(percent): + bpy.context.window_manager.progress_update(percent) + class EnvProp: - bmeshs = [] - bamtr = [] - env_root = Global.getRootPath() + "ENV"+Global.getFileSp() + env_root = os.path.join(Global.getRootPath(), "ENV") def __init__(self): - Util.deleteEmptyDazCollection() - self.bstart() + Util.deleteEmptyDazCollection() # Remove Empty Collections + self.execute() - def bstart(self): + def execute(self): wm = bpy.context.window_manager wm.progress_begin(0, 100) - Versions.active_object_none() - self.layGround() + Versions.active_object_none() # deselect all + self.set_default_settings() if os.path.exists(self.env_root)==False: return - pbar(0) - files = os.listdir(self.env_root) - files = [f for f in files if os.path.isdir(os.path.join(self.env_root, f))] - max = len(files) - one = 100/max - for i in range(max): + progress_bar(0) + env_dirs = os.listdir(self.env_root) + env_dirs = [f for f in env_dirs if os.path.isdir(os.path.join(self.env_root, f))] + + int_progress = 100/len(env_dirs) + for i in range(len(env_dirs)): Global.clear_variables() - Global.setHomeTown( - Global.getRootPath() + Global.getFileSp() + "ENV" + - Global.getFileSp() + "ENV" + str(i) - ) + Global.setHomeTown(os.path.join( + Global.getRootPath(), "ENV", "ENV" + str(i) + )) + Global.load_asset_name() Util.decideCurrentCollection('ENV') - pbar(int(one * i)+5) - ReadFbx(self.env_root + 'ENV' + str(i) + Global.getFileSp(), i,one) + progress_bar(int(int_progress * i) + 5) + ReadFbx(os.path.join(self.env_root, 'ENV' + str(i)), i, int_progress) Versions.active_object_none() - pbar(100) - Versions.reverse_language() + progress_bar(100) Global.setOpsMode("OBJECT") wm.progress_end() Versions.make_sun() - def layGround(self): - Versions.set_english() - Util.deleteEmptyDazCollection() + def set_default_settings(self): bpy.context.scene.render.engine = 'CYCLES' bpy.context.space_data.shading.type = 'SOLID' bpy.context.space_data.shading.color_type = 'OBJECT' bpy.context.space_data.shading.show_shadows = False - Versions.set_english() bco = bpy.context.object if bco != None and bco.mode != 'OBJECT': Global.setOpsMode('OBJECT') @@ -65,194 +73,115 @@ def layGround(self): class ReadFbx: adr = "" index = 0 - _pose_ary = None - _bone_ary = None - ss_ary = [] - asc_ary = [] my_meshs = [] + pose = None - def __init__(self,dir,i,one): + def __init__(self,dir,i,int_progress): + self.adr = dir self.my_meshs = [] self.index = i - self.ss_ary = [] - self._pose_ary = None - self._bone_ary = None - self.asc_ary = [] - if self.readFbx(): - pbar(int(i*one)+int(one/2)) - self.readAsc() + if self.read_fbx(): + progress_bar(int(i * int_progress)+int(int_progress / 2)) self.setMaterial() - Global.scale_environment() + Global.scale_settings() - def readFbx(self): + def read_fbx(self): self.my_meshs = [] - adr = self.adr + "B_ENV.fbx" - if os.path.exists(adr)==False: + adr = os.path.join(self.adr, "B_ENV.fbx") + if os.path.exists(adr) == False: return objs = self.convert_file(adr) for obj in objs: - if obj.type=='MESH': + if obj.type == 'MESH': self.my_meshs.append(obj) - if objs is None or len(objs)==0: + if objs is None or len(objs) == 0: return Global.find_ENVROOT(objs[0]) root = Global.getEnvRoot() - if len(objs)>1: + if len(objs) > 1: if root is None: return else: objs.remove(root) else: root = objs[0] + # Temporaily Delete Animation Until Support is Added + root.animation_data_clear() + for obj in objs: + obj.animation_data_clear() Versions.active_object(root) Global.deselect() - if root.type=='ARMATURE': - self.orthopedy_armature(objs, root) - elif root.type=='EMPTY': + if root.type == 'ARMATURE': + self.import_as_armature(objs, root) + #TODO: Remove Groups with no MESH + elif root.type == 'EMPTY': no_empty = False for o in objs: if o.type != 'EMPTY': no_empty = True break - if no_empty==False: + if no_empty == False: for o in objs: bpy.data.objects.remove(o) return False else: - self.orthopedy_empty(objs, Global.getEnvRoot()) - if Global.want_real(): - Global.changeSize(1,[]) - return True - - #Bone property - def get_bone_info(self,bname): - if self._bone_ary is None: - with open(self.adr + "ENV.bon") as f: - self._bone_ary = f.readlines() - if self._bone_ary is None: - return None - for p in self._bone_ary: - if p.endswith("\n"): - p = p[0:len(p) - 1] - ss = p.split(',') - if ss[0]==bname: - return ss - for i in range(1,10): - if bname==ss[0]+".00" + str(i): - return ss - return None - - def readAsc(self): - adr = self.adr + "A_ENV.fbx" - if os.path.exists(adr) == False: - return - with open(adr) as f: - ls= f.readlines() - max = len(ls) - args = ['Material','Texture','Model']#,'Pose'] - for idx,l in enumerate(ls): - l = l.replace('"','') - if l.endswith("\n"): - l = l[0:len(l)-1] - for pidx,arg in enumerate(args): - pt = "^\s+" + arg + ":\s\d+,\s" + arg + "::[\w\s]+,[\w\s]+\{" - rep = re.compile(pt) - result = rep.search(l) - if result: - a = l.rfind("::") - b = l.rfind(',') - if b=max: - break - getp = ls[idx+i].strip() - if pidx==0 and ("}" in getp): - break - yoko = [] - if pidx==1: - if getp.startswith("FileName: "): - getp = getp[10:] - getp = getp.replace('"', '') - yoko = [getp] - else: - if getp.startswith("P: "): - getp = getp[3:] - getp = getp.replace('"",','"-",') - getp = getp.replace('"','') - getp = getp.replace(" ","") - yoko = getp.split(",") - if len(yoko)>0: - yoko.insert(0,title) - if pidx==2: - yoko.insert(0, "B") - else: - yoko.insert(0, arg[0:1]) - self.asc_ary.append(yoko) - if pidx>0: - break - #for aa in self.asc_ary: - # print(aa) - - def Maru(self): - if 'daz_door' in Util.colobjs('DAZ_HIDE'): - return - Global.setOpsMode('OBJECT') - bpy.ops.mesh.primitive_circle_add() - Global.setOpsMode('EDIT') - args = [(0, 0, math.radians(90)), (math.radians(90), 0, 0), (0, math.radians(90), 0)] - for i in range(3): - bpy.ops.mesh.primitive_circle_add( - rotation=args[i] - ) - Global.setOpsMode('OBJECT') - bpy.context.object.name = 'daz_door' - Util.to_other_collection([bpy.context.object],'DAZ_HIDE',Util.cur_col_name()) - - def is_armature_modified(self,dobj): - if dobj.type == 'MESH': - for modifier in dobj.modifiers: - if modifier.type=='ARMATURE' and modifier.object is not None: - return True - return False - - def is_yukobone(self,amtr,myebone,vgroups): - rtn = self.has_child(amtr,myebone) - if rtn is None or len(rtn) == 0: - return False - for r in rtn: - if r not in vgroups: - return False + self.import_empty(objs, Global.getEnvRoot()) + Global.change_size(Global.getEnvRoot()) + return True + + + def convert_file(self, filepath): + Global.store_ary(False) #Gets all objects before. + basename = os.path.basename(filepath) + (filename, fileext) = os.path.splitext(basename) + ext = fileext.lower() + if os.path.isfile(filepath): + if ext == '.fbx': + bpy.ops.import_scene.fbx( + filepath = filepath, + use_manual_orientation = False, + bake_space_transform = False, + use_image_search = True, + use_anim = True, + anim_offset = 0, + ignore_leaf_bones = False, + force_connect_children = False, + automatic_bone_orientation = False, + primary_bone_axis = 'Y', + secondary_bone_axis = 'X', + use_prepost_rot = False + ) + Global.store_ary(True) #Gets all objects after. + return self.new_objects() - def has_child(self,amtr,myebone): + def new_objects(self): rtn = [] - for eb in amtr.data.edit_bones: - if eb.parent == myebone: - rtn.append(eb.name) + if len(Global.now_ary) == len(Global.pst_ary): + return "" + rtn = [bpy.data.objects[n] for n in Global.now_ary if not n in Global.pst_ary] return rtn - - def orthopedy_armature(self, objs, amtr): + + #TODO: combine shared code with figure import + def import_as_armature(self, objs, amtr): + pose = Poses.Posing("ENV") Global.deselect() - self.Maru() - vgroups = [] + self.create_controller() + vertex_group_names = [] empty_objs = [] amtr_objs = [] - + for i in range(3): amtr.scale[i] = 1 + + #Apply Armature Modifer if it does not exist for obj in objs: if obj.type == 'MESH': amtr_objs.append(obj) vgs = obj.vertex_groups - flg_vg = False - for vg in vgs: - flg_vg = True - vgroups.append(vg.name) - if flg_vg: + if len(vgs) > 0: + vertex_group_names = [vg.name for vg in vgs] if self.is_armature_modified(obj) == False: amod = obj.modifiers.new(type='ARMATURE', name="ama" + obj.name) amod.object = amtr @@ -260,6 +189,8 @@ def orthopedy_armature(self, objs, amtr): if obj.parent == amtr: empty_objs.append(obj) Global.deselect() + + #Apply rest pose Versions.select(amtr, True) Versions.active_object(amtr) Global.setOpsMode("POSE") @@ -267,217 +198,95 @@ def orthopedy_armature(self, objs, amtr): bpy.ops.pose.armature_apply(selected=False) bpy.ops.pose.select_all(action='DESELECT') Global.setOpsMode("EDIT") + hides = [] - ebones = amtr.data.edit_bones - bcnt = 0 - for eb in ebones: - bcnt += 1 - notbuilding = bcnt > 30 - for eb in ebones: - binfo = self.get_bone_info(eb.name) - if binfo is None: - hides.append(eb.name) + bones = amtr.data.edit_bones + + #Fix and Check Bones to Hide + for bone in bones: + if not pose.set_bone_head_tail(bone): + hides.append(bone.name) continue - if eb.name not in vgroups: - if self.is_yukobone(amtr, eb,vgroups) == False: - hides.append(eb.name) + if bone.name not in vertex_group_names: + if self.is_child_bone(amtr, bone, vertex_group_names) == False: + hides.append(bone.name) continue - if '1' not in binfo[7:]: - hides.append(eb.name) - continue - else: - if '1' not in binfo[7:]: - hides.append(eb.name) - - # for bidx,bi in enumerate(binfo): - # if bidx>6: - # binfo[bidx] = 1 - if notbuilding: - for i in range(3): - eb.tail[i] = float(binfo[4 + i]) - - else: - len = 100 - eb.roll = 0 - for i in range(3): - if i == 1: - eb.tail[i] = float(eb.head[i]) + len - else: - eb.tail[i] = float(eb.head[i]) - - Global.setOpsMode('OBJECT') - Versions.select(amtr, True) - Versions.active_object(amtr) - bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) - Global.deselect() + for obj in objs: Versions.select(obj, True) Versions.active_object(obj) bpy.ops.object.transform_apply(location=False, rotation=True, scale=False) - for i in range(3): - obj.location[i] = 0 Versions.select(obj,False) + Versions.select(amtr, True) Versions.active_object(amtr) Global.setOpsMode("POSE") amtr.show_in_front = True + + #Apply Custom Shape for pb in amtr.pose.bones: - binfo = self.get_bone_info(pb.name) + binfo = pose.get_bone_limits_dict(pb.name) if binfo is None: continue else: - if notbuilding==False: - ob = Util.allobjs().get('daz_door') - if ob is not None: - pb.custom_shape = ob - pb.custom_shape_scale = 0.4 - amtr.data.bones.get(pb.name).show_wire = True - lrs = [False, False, False] - for i in range(3): - for j in range(3): - if binfo[7 + (i * 3) + j] == '0': - if i == 0 and lrs[i] == False: - lrs[i] = True - lim = pb.constraints.new(type='LIMIT_LOCATION') - lim.owner_space = 'LOCAL' - elif i == 1 and lrs[i] == False: - lim = pb.constraints.new(type='LIMIT_ROTATION') - lim.owner_space = 'LOCAL' - lrs[i] = True - elif i == 2 and lrs[i] == False: - lrs[i] = True - lim = pb.constraints.new(type='LIMIT_SCALE') - lim.owner_space = 'LOCAL' - if j == 0: - if i == 1: - lim.use_limit_x = True - lim.use_limit_x = True - else: - lim.use_min_x = True - lim.use_max_x = True - elif j == 1: - if i == 1: - lim.use_limit_y = True - lim.use_limit_y = True - else: - lim.use_min_y = True - lim.use_max_y = True - elif j == 2: - if i == 1: - lim.use_limit_z = True - lim.use_limit_z = True - else: - lim.use_min_z = True - lim.use_max_z = True - if i == 2: - lim.min_x = 1 - lim.min_y = 1 - lim.min_z = 1 - lim.max_x = 1 - lim.max_y = 1 - lim.max_z = 1 + ob = Util.allobjs().get('daz_prop') + if ob is not None: + pb.custom_shape = ob + pb.custom_shape_scale = 0.04 + amtr.data.bones.get(pb.name).show_wire = True + #Apply Limits and Change Rotation Order + pose.bone_limit_modify(pb) + + # Hide Bones for hide in hides: amtr.data.bones.get(hide).hide = True - def convert_file(self, filepath): - Global.store_ary(False) - basename = os.path.basename(filepath) - (filename, fileext) = os.path.splitext(basename) - ext = fileext.lower() - if os.path.isfile(filepath): - if ext == '.fbx': - bpy.ops.import_scene.fbx( - filepath = filepath, - use_manual_orientation = False, - bake_space_transform = False, - use_image_search = True, - use_anim = True, - anim_offset = 0, - ignore_leaf_bones = False, - force_connect_children = False, - automatic_bone_orientation = False, - use_prepost_rot = False - ) - Global.store_ary(True) - return self.what_news() + + def create_controller(self): + if 'daz_prop' in Util.colobjs('DAZ_HIDE'): + return + Global.setOpsMode('OBJECT') + bpy.ops.mesh.primitive_circle_add() + Global.setOpsMode('EDIT') + args = [(0, 0, math.radians(90)), (math.radians(90), 0, 0), (0, math.radians(90), 0)] + for i in range(3): + bpy.ops.mesh.primitive_circle_add( + rotation=args[i] + ) + Global.setOpsMode('OBJECT') + bpy.context.object.name = 'daz_prop' + Util.to_other_collection([bpy.context.object],'DAZ_HIDE',Util.cur_col_name()) - def what_news(self): - rtn = [] - if len(Global.now_ary) - len(Global.pst_ary) < 1: - return "" - for n in Global.now_ary: - hit = False - for p in Global.pst_ary: - if n == p: - hit = True - break - if hit == False: - rtn.append(bpy.data.objects[n]) - return rtn + + def is_armature_modified(self,dobj): + if dobj.type == 'MESH': + for modifier in dobj.modifiers: + if modifier.type=='ARMATURE' and modifier.object is not None: + return True + return False - def setMaterial(self): - dtb_shaders = DtbMaterial.DtbShaders() - dtb_shaders.make_dct() - dtb_shaders.load_shader_nodes() - for mesh in self.my_meshs: - dtb_shaders.env_textures(mesh) - - def before_edit_prop(self): - BV = 2.83 - if BV < 2.80: - for space in bpy.context.area.spaces: - if space.type == 'VIEW_3D': - space.pivot_point = 'BOUNDING_BOX_CENTER' - space.cursor_location = (0.0, 0.0, 0.0) - bpy.context.space_data.transform_orientation = 'GLOBAL' - bpy.context.space_data.transform_manipulators = {'TRANSLATE', 'ROTATE'} - else: - bpy.context.scene.tool_settings.transform_pivot_point = 'BOUNDING_BOX_CENTER' - bpy.ops.view3d.snap_cursor_to_center() - for s in bpy.context.scene.transform_orientation_slots: - s.type = 'GLOBAL' + def is_child_bone(self,amtr,bone,vertex_groups): + rtn = self.has_child(amtr,bone) + if rtn is None or len(rtn) == 0: + return False + for r in rtn: + if r not in vertex_groups: + return False + return True - def orthopedy_one(self,single): - for i in range(3): - single.scale[i] = 1 - if single.type=='LIGHT': - pose = self.get_pose(single) - single.location[0] = float(pose[0 + 3]) - single.location[1] = 0-float(pose[2 + 3]) - single.location[2] = float(pose[1 + 3]) + def has_child(self,amtr,vertex_groups): + rtn = [] + for bone in amtr.data.edit_bones: + if bone.parent == vertex_groups: + rtn.append(bone.name) + return rtn + - def orthopedy_empty(self, objs, root): - for i in range(3): - root.scale[i] = 1 + def import_empty(self, objs, root): + # Load an instance of the pose info + set_transform(root,[1,1,1],"scale") Global.deselect() - root_pose = self.get_pose(root) - for obj in objs: - if obj is None or obj==root: - continue - Versions.select(obj, True) - Versions.active_object(obj) - pose = self.get_pose(obj) - for i in range(3): - obj.scale[i] = 1 - - if obj.type=='EMPTY': - for i in range(3): - obj.scale[i] = float(pose[i+9]) - obj.rotation_euler[i] = 0 - elif obj.type=='LIGHT' or obj.type=='CAMERA': - for i in range(3): - print(obj.name,obj.type,"#####",pose[i+3]) - obj.lock_location[i] = False - obj.location[i] = float(pose[i+3]) + float(root_pose[i+3]) - self.before_edit_prop() - obj.rotation_euler[i] = math.radians(float(pose[i+6])) - obj.scale[i] = 1 - for i in range(3): - obj.lock_location[i] = True - obj.lock_rotation[i] = True - obj.lock_scale[i] = True - Global.deselect() Versions.select(root, True) Versions.active_object(root) @@ -485,38 +294,16 @@ def orthopedy_empty(self, objs, root): root.lock_location[i] = True root.lock_rotation[i] = True root.lock_scale[i] = True - Global.setOpsMode('OBJECT') + Global.setOpsMode('OBJECT') + + + def setMaterial(self): + dtb_shaders = DtbMaterial.DtbShaders() + dtb_shaders.make_dct() + dtb_shaders.load_shader_nodes() + for mesh in self.my_meshs: + dtb_shaders.setup_materials(mesh) + + - def get_pose(self,obj): - obj_name = obj.name - for i in range(5): - if obj_name.endswith(".00"+str(i)): - obj_name = obj_name[0:len(obj_name)-4] - a = obj_name.find(".Shape") - if a > 0: - obj_name = obj_name[0:a] - if self.ss_ary==[]: - if self._pose_ary is None: - with open(self.adr+"ENV.csv") as f: - self._pose_ary = f.readlines() - if self._pose_ary is None: - return None - for p in self._pose_ary: - if p.endswith("\n"): - p = p[0:len(p)-1] - ss = p.split(',') - #manage [_dup_] files - for i in range(2,20): - if ss[0]!=ss[1] and ss[0].endswith(" (" + str(i) + ")"): - if not ss[1].endswith("_dup_" + str(i)): - ss[1] = ss[1] + "_dup_" + str(i) - break - self.ss_ary.append(ss) - for ss in self.ss_ary: - if ss[1] == obj_name: - if ss[2]=='E' and obj.type=='EMPTY' or \ - ss[2]=='M' and obj.type=='MESH' or \ - ss[2]=='L' and obj.type=='LIGHT' or \ - ss[2]=='C' and obj.type=='CAMERA': - return ss - return [obj_name,obj_name,"?",0,0,0,0,0,0,1,1,1] + diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Global.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Global.py index a5b18b3d..8b9c1d86 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Global.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Global.py @@ -1,10 +1,12 @@ import bpy import os import math +import json from copy import deepcopy from . import DataBase from . import Versions from . import Util + isMan = False root = "" isGen = False @@ -27,6 +29,7 @@ root ="" _ISG3 = 0 _HOMETOWN = "" +_ASSETNAME = "" already_use_newmtl = [] _ENVROOT = "" @@ -79,7 +82,6 @@ def getSubdivLevel(): return 0 - def get_root(): return root @@ -383,13 +385,13 @@ def find_ENVROOT(dobj): frombtm.append(obj) if (len(fromtop) == 1 and len(frombtm) == 1) == False: return - if fromtop[0]!=frombtm[0]: + if fromtop[0] != frombtm[0]: return - if fromtop[0].type=='ARMATURE' or fromtop[0].type=='EMPTY': + if fromtop[0].type == 'ARMATURE' or fromtop[0].type == 'EMPTY': _ENVROOT = fromtop[0].name def getEnvRoot(): - if _ENVROOT !="" and (_ENVROOT in Util.allobjs()): + if _ENVROOT != "" and (_ENVROOT in Util.allobjs()): return Util.allobjs().get(_ENVROOT) def decide_HERO(): @@ -567,19 +569,26 @@ def getRootPath(): hdir = os.path.expanduser('~') else: hdir = os.environ['HOME'] - fname = "DTB" - hdir += getFileSp() + "Documents" + getFileSp() + "DTB" + getFileSp() - if os.path.exists(hdir)==False or os.path.isdir(hdir) == False: - if os.name == 'nt': - hdir = "C:\\Documents\\DTB\\" - else: - hdir = "/Documents/DTB/" + hdir = os.path.join(hdir, "Documents", "DAZ 3D", "Bridges", "Daz To Blender", "Exports") if os.path.exists(hdir): root = hdir else: root = "" return root +def load_asset_name(): + global _ASSETNAME + for file in os.listdir(getHomeTown()): + if file.endswith(".dtu"): + dtu = os.path.join(getHomeTown(), file) + break + with open(dtu, "r") as file: + _ASSETNAME = json.load(file)["Asset Name"] + +def get_asset_name(): + return _ASSETNAME + + def clear_already_use_newmtl(): global already_use_newmtl already_use_newmtl = [] @@ -606,6 +615,7 @@ def clear_variables(): global _AMTR global _BODY global _EYLS + global _TEAR global _HAIR global _RGFY global keep_EYLS @@ -986,145 +996,91 @@ def ifNeedToSnapKnee(r_l): return iks[r_l].head[2] > poles[r_l].head[2] -def judgeSize(): - max = 0 - for z in range(2): - if z>0 and max>0: - break - for obj in Util.myacobjs(): - for i in range(3): - if z == 0: - if obj.dimensions[i]>max: - max = obj.dimensions[i] - else: - if obj.location[i] > max: - max = obj.location[i] - if max==0: - if bpy.context.window_manager.size_100: - max = 71 - global _SIZE - if max <70: - _SIZE = 1 - else: - _SIZE= 100 - -def want_real(): - return bpy.context.window_manager.size_100==False - -def getSize(): - if _SIZE==0: - judgeSize() - return _SIZE - -def scale_environment(): - for scene in bpy.data.scenes: - scene.tool_settings.use_keyframe_insert_auto = False - scene.unit_settings.system = 'METRIC' - scene.unit_settings.scale_length = 1.0/getSize() - lens = [0.01*getSize(),1000*getSize(),50.0+math.floor(0.3*getSize())] - bpy.context.space_data.clip_start = lens[0] - bpy.context.space_data.clip_end = lens[1] - bpy.context.space_data.lens = lens[2] - size_1_100 = [[(0.2721, -0.2184, 0.9022),(-0.7137, -0.5870, -0.2612,-0.2790),3], - [(7.15, -4.35, 100.0),(-0.7150, -0.5860, -0.2601, -0.2788) ,430]] - idx = 0 if getSize()==1 else 1 - for area in bpy.context.screen.areas: - if area.type == "VIEW_3D": - rv3d = area.spaces[0].region_3d - if rv3d is not None: - rv3d.view_location = size_1_100[idx][0] - rv3d.view_rotation = size_1_100[idx][1] - rv3d.view_distance = size_1_100[idx][2] - rv3d.view_camera_zoom = 0 - bpy.context.preferences.inputs.use_mouse_depth_navigate = True - normal_and_bump_to_size() +def get_size(): + return float(bpy.context.window_manager.scene_scale) -def normal_and_bump_to_size(): - objs = Util.myacobjs() - for obj in objs: - if obj==getBody(): - continue - for slot in obj.material_slots: - mat = bpy.data.materials.get(slot.name) - if mat is None or mat.node_tree is None: - print(mat,mat.node_tree) - continue - ROOT = mat.node_tree.nodes - for n in ROOT: - if n.type=='BUMP': - n.inputs['Strength'].default_value = 0.01 * getSize() - n.inputs['Distance'].default_value = 0.01 * getSize() - elif n.type=='NORMAL_MAP': - n.inputs['Strength'].default_value = 0.01 * getSize() +def change_size(root): + if get_size() < 1: + # Scale Import + for i in range(3): + og_scale = root.scale[i] + root.scale[i] = og_scale * get_size() + setOpsMode("OBJECT") + Versions.active_object(root) + Versions.select(root, True) + bpy.ops.object.transform_apply(scale=True) + deselect() -def changeSize(size, mub_ary): - global _SIZE - if _SIZE==0: - getSize() - flg_env = False - if getAmtr() is not None and (get_Amtr_name() in Util.myacobjs()): - armature = getAmtr() - elif getRgfy() is not None and (get_Rgfy_name() in Util.myacobjs()): - armature = getRgfy() - elif getEnvRoot() is not None and (_ENVROOT in Util.myacobjs()): - armature = getEnvRoot() - flg_env = True - else: - return - change_size = 1 if size == 100 else 0.01 - setOpsMode("OBJECT") - for i in range(3): - if armature.scale[i] != change_size: - armature.scale[i] = change_size - deselect() - if mub_ary !=[]: for obj in Util.myacobjs(): - if obj.name in mub_ary: - Versions.active_object(obj) + if obj.type == 'MESH': + if obj.parent == root: + Versions.select(obj, True) + Versions.active_object(obj) + bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) + deselect() + elif obj.type=='LIGHT' or obj.type=='CAMERA': + for i in range(3): + og_scale = obj.scale[i] + obj.scale[i] = og_scale * get_size() Versions.select(obj, True) - bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) - Versions.active_object_none() - Versions.select(obj, False) - if flg_env==False: - Versions.active_object(armature) - Versions.select(armature, True) - bpy.ops.object.transform_apply(scale=True) - deselect() - if flg_env==False: - for obj in Util.myacobjs(): - if isRiggedObject(obj): - Versions.select(obj,True) Versions.active_object(obj) bpy.ops.object.transform_apply(scale=True) - elif obj.type=='LIGHT' or obj.type=='CAMERA': + deselect() + # Scale Daz_Pub + for d in Util.colobjs('DP'): + if d.type=='CAMERA' or d.type=='LIGHT': + og_location = (140, 100, 150) for i in range(3): - if obj.scale[i] != change_size: - obj.scale[i] = change_size + d.location[i] = og_location[i] * get_size() Versions.select(obj, True) Versions.active_object(obj) bpy.ops.object.transform_apply(scale=True) - deselect() - find = False - for d in Util.colobjs('DP'): - if d.type=='CAMERA' or d.type=='LIGHT': - find = True - for i in range(3): - if d.scale[i] !=change_size: - d.location[i] = d.location[i]*change_size - d.scale[i] = change_size - _SIZE = size - if getBody() is not None: - Versions.select(getBody(), True) - from . import DtbMaterial - DtbMaterial.default_material() - - #scale_environment(size) - deselect() - # Versions.select(armature,True) - # Versions.active_object(armature) - # setOpsMode("POSE") - #Versions.view_from_camera() + deselect() + +def float_by_size(float): + return float * get_size() + + +def scale_settings(): + scene = bpy.context.scene + scene.tool_settings.use_keyframe_insert_auto = False + scene.unit_settings.system = 'METRIC' + scene.unit_settings.scale_length = 1.0 + if get_size() == 0.01: + scene.unit_settings.length_unit = 'CENTIMETERS' + else: + scene.unit_settings.length_unit = 'METERS' + + # Change View Clipping + bpy.context.space_data.clip_start = get_size() + bpy.context.space_data.clip_end = 10000.00 * get_size() + bpy.context.space_data.lens = 50 + + + location = [float_by_size(7.15), float_by_size(-4.35), float_by_size(100.0)] + rotation = [0.6888, 0.6246, 0.2473, 0.2727] + distance = float_by_size(430) + + for area in bpy.context.screen.areas: + if area.type == "VIEW_3D": + rv3d = area.spaces[0].region_3d + if rv3d is not None: + rv3d.view_location = location + rv3d.view_rotation = rotation + rv3d.view_distance = distance + rv3d.view_camera_zoom = 0 + # Set Camera Position + rv3d.update() + bpy.context.scene.camera.matrix_world = rv3d.view_matrix + bpy.context.scene.camera.matrix_world.invert() + + # Set Camera Clipping + bpy.context.scene.camera.data.sensor_width = 64 + bpy.context.scene.camera.data.clip_start = bpy.context.space_data.clip_start + bpy.context.scene.camera.data.clip_end = bpy.context.space_data.clip_end + bpy.context.preferences.inputs.use_mouse_depth_navigate = True + def heigou_vgroup(): vgs = getBody().vertex_groups @@ -1234,7 +1190,7 @@ def finger(zindex): def getCon(): import sqlite3 - cadr = os.path.dirname(__file__) + getFileSp() + "img" + getFileSp() + "dtb.sqlite" + cadr = os.path.join(os.path.dirname(__file__), "img", "dtb.sqlite") con = sqlite3.connect(cadr) return con diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/MatDct.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/MatDct.py index c777b074..b6376c55 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/MatDct.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/MatDct.py @@ -356,7 +356,7 @@ def search_directory(self, dir_path): if mat_type_prop[0] == '6': mat_type_prop[0] = '7' key = mat_type_prop[0] + mat_type_prop[1] - value = fig_tex_path + Global.getFileSp() + tex_name + value = os.path.join(fig_tex_path, tex_name) self.add_to_dct(key, value) def cloth_dct_0(self, adr): @@ -416,7 +416,7 @@ def cloth_dct(self, cname, aadr, skip_adr): wd = "" break if wd != "": - ans = aadr + Global.getFileSp() + L + ans = os.path.join(aadr, L) ans = os.path.realpath(os.path.abspath(ans)) if skip_adr != ans: cloth_dct.append([wd, ans]) diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Poses.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Poses.py new file mode 100644 index 00000000..ff12839b --- /dev/null +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Poses.py @@ -0,0 +1,507 @@ +import bpy +import os +import math +import json +import mathutils +import gzip +import urllib.parse +from . import DataBase +from . import Versions +from . import Global +import re + +#TODO: Figure out a way to use for Figure and Prop +class Posing: + + bone_head_tail_dict = {} + bone_limits_dict = {} + pose_data_dict = {} + fig_object = "" + fig_object_name = "" + + def __init__(self, asset): + if asset == "FIG": + self.bone_limits = DataBase.get_bone_limits_dict() + self.get_pose_data(asset) + + if asset == "POSE": + pass + + if asset == "ENV": + self.load_bone_limits(asset) + self.load_bone_head_tail_data(asset) + self.get_pose_data(asset) + + + def is_json(self, myjson): + try: + json_object = json.load(myjson) + except ValueError as e: + return False + return True + + + def load_duf(self, input_duf): + with open(input_duf, "r") as file: + string = file + if self.is_json(string): + with open(input_duf, "r") as file: + return json.load(file) + else: + data = gzip.open(input_duf, "rb") + return json.load(data) + + + + def load_bone_head_tail_data(self, asset): + input_file = open(os.path.join(Global.getHomeTown(), asset + "_boneHeadTail.csv"), "r") + lines = input_file.readlines() + input_file.close() + self.bone_head_tail_dict = dict() + for line in lines: + line_split = line.split(",") + self.bone_head_tail_dict[line_split[0]] = line_split + + + #Bone property + def get_bone_head_tail_data(self, bname): + bname = bname.split(".00")[0] # To deal with Duplicates + if self.bone_head_tail_dict is None: + self.get_bone_head_tail_data() + if bname in self.bone_head_tail_dict.keys(): + return self.bone_head_tail_dict[bname] + return None + + + def set_bone_head_tail(self, bone): + binfo = self.get_bone_head_tail_data(bone.name) + if binfo is None: + return False + else: + # set head + bone.head[0] = float(binfo[1]) + bone.head[1] = -float(binfo[3]) + bone.head[2] = float(binfo[2]) + + # set tail + bone.tail[0] = float(binfo[4]) + bone.tail[1] = -float(binfo[6]) + bone.tail[2] = float(binfo[5]) + + # calculate roll aligning bone towards a vector + align_axis_vec = mathutils.Vector(( + float(binfo[7]), + -float(binfo[9]), + float(binfo[8]) + )) + bone.align_roll(align_axis_vec) + + return True + + + def load_bone_limits(self, asset): + input_file = open(os.path.join(Global.getHomeTown(), asset + "_boneLimits.csv"), "r") + lines = input_file.readlines() + input_file.close() + + for line in lines: + line_split = line.split(',') + bone_limit = [] + + bone_limit.append(line_split[0]) + bone_limit.append(line_split[1]) + bone_limit.append(float(line_split[2])) + bone_limit.append(float(line_split[3])) + bone_limit.append(float(line_split[4])) + bone_limit.append(float(line_split[5])) + bone_limit.append(float(line_split[6])) + bone_limit.append(float(line_split[7])) + self.bone_limits_dict[bone_limit[0]] = bone_limit + + + def get_bone_limits_dict(self, bname): + bname = bname.split(".00")[0] # To deal with Duplicates + if len(self.bone_limits_dict.keys()) == 0: + self.load_bone_limits() + if bname in self.bone_limits_dict.keys(): + return self.bone_limits_dict[bname] + + def bone_limit_modify(self, bone): + bone_limit = self.get_bone_limits_dict(bone.name) + order = bone_limit[1] + new_bone_limit = self.reorder_limits(order, bone_limit, bone.name) + new_order = self.get_rotation_order(order) + bone.rotation_mode = new_order + bone.constraints.new('LIMIT_ROTATION') + rot_limit = bone.constraints['Limit Rotation'] + rot_limit.owner_space = 'LOCAL' + rot_limit.use_transform_limit = True + rot_limit.use_limit_x = True + rot_limit.min_x = math.radians(new_bone_limit[2]) + rot_limit.max_x = math.radians(new_bone_limit[3]) + rot_limit.use_limit_y = True + rot_limit.min_y = math.radians(new_bone_limit[4]) + rot_limit.max_y = math.radians(new_bone_limit[5]) + rot_limit.use_limit_z = True + rot_limit.min_z = math.radians(new_bone_limit[6]) + rot_limit.max_z = math.radians(new_bone_limit[7]) + + bone.use_ik_limit_x = True + bone.use_ik_limit_y = True + bone.use_ik_limit_z = True + if 'shin' in bone.name.lower(): + bone.ik_min_x = math.radians(1) + bone.use_ik_limit_x = False + else: + bone.ik_min_x = math.radians(new_bone_limit[2]) + bone.ik_max_x = math.radians(new_bone_limit[3]) + bone.ik_min_y = math.radians(new_bone_limit[4]) + bone.ik_max_y = math.radians(new_bone_limit[5]) + bone.ik_min_z = math.radians(new_bone_limit[6]) + bone.ik_max_z = math.radians(bone_limit[7]) + + if bone.name[1:] == 'Shin' or 'Thigh' in bone.name: + bone.ik_stiffness_y = 0.99 + bone.ik_stiffness_z = 0.99 + if 'ThighTwist' in bone.name: + bone.ik_stiffness_x = 0.99 + + def reorder_limits(self, rotation_order, limits, name): + if rotation_order == 'XYZ': + # YZ switch (Y <-> Z) + temp1 = limits[4] + temp2 = limits[5] + limits[4] = limits[6] + limits[5] = limits[7] + limits[6] = temp1 + limits[7] = temp2 + + # XY switch (X <-> Y) + temp1 = limits[2] + temp2 = limits[3] + limits[2] = limits[4] + limits[3] = limits[5] + limits[4] = temp1 + limits[5] = temp2 + + if "right" in name.lower(): + # Y invert (-Y) + limits[4] = -limits[4] + limits[5] = -limits[5] + # Z invert (-Z) + limits[6] = -limits[6] + limits[7] = -limits[7] + + elif rotation_order == 'XZY': + # XY switch (X <-> Y) + temp1 = limits[2] + temp2 = limits[3] + limits[2] = limits[4] + limits[3] = limits[5] + limits[4] = temp1 + limits[5] = temp2 + + # X invert (-X) + limits[2] = -limits[2] + limits[3] = -limits[3] + + if "right" in name.lower(): + # Y invert (-Y) + limits[4] = -limits[4] + limits[5] = -limits[5] + # Z invert (-Z) + limits[6] = -limits[6] + limits[7] = -limits[7] + + elif rotation_order == "ZXY": + # XY switch (X <-> Y) + temp1 = limits[2] + temp2 = limits[3] + limits[2] = limits[4] + limits[3] = limits[5] + limits[4] = temp1 + limits[5] = temp2 + + # YZ switch (Y <-> Z) + temp1 = limits[4] + temp2 = limits[5] + limits[4] = limits[6] + limits[5] = limits[7] + limits[6] = temp1 + limits[7] = temp2 + + elif rotation_order == "ZYX": + # YZ switch (Y <-> Z) + temp1 = limits[4] + temp2 = limits[5] + limits[4] = limits[6] + limits[5] = limits[7] + limits[6] = temp1 + limits[7] = temp2 + + # X invert (-X) + limits[2] = -limits[2] + limits[3] = -limits[3] + + # TODO: Check how to convert it. + elif rotation_order == "YXZ": + return limits + return limits + + def get_pose_data(self, asset): + hometown = Global.getHomeTown() + + padr = os.path.join(hometown, asset + ".transforms") + if os.path.exists(padr) == False: + return + with open(padr, errors='ignore', encoding='utf-8') as f: + data = json.load(f) + + # Rename the root bone + for key in data: + if key.startswith('Genesis'): + new_key = 'root' + data[key]["Name"] = new_key + data[key]["Object Type"] = 'BONE' + data[new_key] = data.pop(key) + + self.pose_data_dict = data + + + def get_objects_pose(self,obj): + obj_name = obj.name.replace(".Shape", "") + if obj_name in self.pose_data_dict: + return self.pose_data_dict[obj_name] + + for key in self.pose_data_dict: + if obj_name == key: + return self.pose_data_dict[obj_name] + elif obj_name.replace("_dup_", " ") == key: + return self.pose_data_dict[key] + elif len(obj_name.split(".00")) > 1: + temp_name = obj_name.split(".00")[0] + " " + str(int(obj_name.split(".00")[1]) + 1) + if temp_name == key: + return self.pose_data_dict[key] + elif self.pose_data_dict[key]["Name"] == obj_name: + return self.pose_data_dict[key] + return {} + + + def clear_pose(self): + Versions.select(Global.getAmtr(), True) + Versions.active_object(Global.getAmtr()) + Versions.show_x_ray(Global.getAmtr()) + Global.setOpsMode('POSE') + bpy.ops.pose.transforms_clear() + Global.setOpsMode('OBJECT') + + #TODO Refactor and update to Reenable + def pose_copy(self,dur): + self.pose_data_dict = {} + if os.path.exists(dur) == False: + return + pose_data = self.load_duf(dur) + self.pose_data_dict["Asset Name"] = pose_data["asset_info"]["id"].split("/")[-1].replace("%20"," ").replace(".duf","") + for info in pose_data["scene"]["animations"]: + url = info["url"] + keys = info["keys"] + sep = url.split("/") + # To Deal with Shape_keys info + if "#" in sep[2]: + continue + + # To Deal with Root Bone + if "?" in sep[2]: + bone = "root" + transform = sep[2].split("?")[1] + axis = sep[3] + else: + bone = sep[3].split(":?")[0] + transform = sep[3].split(":?")[1] + axis = sep[4] + + value = keys[0][1] + if bone not in self.pose_data_dict.keys(): + self.pose_data_dict[bone] = {} + if "Position" not in self.pose_data_dict[bone].keys(): + self.pose_data_dict[bone]["Position"] = [0, 0, 0] + if "Rotation" not in self.pose_data_dict[bone].keys(): + self.pose_data_dict[bone]["Rotation"] = [0, 0, 0] + if axis == "x": + index = 0 + if axis == "y": + index = 1 + if axis == "z": + index = 2 + if transform == "translation": + trans_key = "Position" + if transform == "rotation": + trans_key = "Rotation" + self.pose_data_dict[bone][trans_key][index] = value + + self.make_pose() + + def reorder_rotation(self,rotation_order,rotations,name): + if rotation_order == 'XYZ': + # YZ switch (Y <-> Z) + temp = rotations[1] + rotations[1] = rotations[2] + rotations[2] = temp + + # XY switch (X <-> Y) + temp = rotations[0] + rotations[0] = rotations[1] + rotations[1] = temp + if(name.startswith("r")): + # Y invert (-Y) + rotations[1] = -rotations[1] + # Z invert (-Z) + rotations[2] = -rotations[2] + + elif rotation_order == 'XZY': + # XY switch (X <-> Y) + temp = rotations[0] + rotations[0] =rotations[1] + rotations[1] = temp + + # X invert (-X) + rotations[0] = -rotations[0] + + if(name.startswith("r")): + # Y invert (-Y) + rotations[1] = -rotations[1] + + # Z invert (-Z) + rotations[2] = -rotations[-2] + + elif rotation_order == "YZX": + # Bones that are pointed down with YZX order + # TODO: remove hardcoding + if name in ["hip", "pelvis", "lThighBend", "rThighBend", "lThighTwist", "rThighTwist", "lShin", "rShin"]: + # Y invert (-Y) + rotations[1] = -rotations[1] + + # Z invert (-Z) + rotations[2] = -rotations[2] + + elif rotation_order == "ZXY": + # XY switch (X <-> Y) + temp = rotations[0] + rotations[0] = rotations[1] + rotations[1] = temp + + # YZ switch (Y <-> Z) + temp = rotations[1] + rotations[1] = rotations[2] + rotations[2] = temp + + elif rotation_order == "ZYX": + # YZ switch (Y <-> Z) + temp = rotations[1] + rotations[2] = rotations[1] + + # X invert (-X) + rotations[0] = -rotations[0] + + elif rotation_order == "YXZ": + return rotations + return rotations + + def get_rotation_order(self,order): + if order == 'XYZ': + return 'ZXY' + elif order == 'XZY': + return 'YZX' + elif order == 'YZX': + return 'YZX' + elif order == 'ZXY': + return 'XYZ' + elif order == 'ZYX': + return 'YZX' + elif order == "YXZ": + return 'YXZ' + + + def make_pose(self): + Global.setOpsMode("POSE") + bone_limits = self.bone_limits_dict + transform_data = self.pose_data_dict + self.fig_object_name = bpy.context.window_manager.choose_daz_figure + self.fig_object = bpy.data.objects[self.fig_object_name] + if self.fig_object_name == "null": + return + pbs = self.fig_object.pose.bones + for pb in pbs: + if "Daz Rotation Order" in pb.keys(): + order = pb["Daz Rotation Order"] + bname = pb.name + new_order = self.get_rotation_order(order) + if bname in transform_data.keys(): + position = transform_data[bname]["Position"] + rotation = transform_data[bname]["Rotation"] + + # Position + for i in range(len(position)): + position[i] = position[i] * Global.get_size() + + pbs[bname].location[0] = float(position[0]) + # Y invert (-Y) + pbs[bname].location[1] = -float(position[1]) + # Z invert (-Z) + pbs[bname].location[2] = -float(position[2]) + + + # Rotation + fixed_rotation = self.reorder_rotation(order,rotation,bname) + pbs[bname].rotation_mode = order + for i in range(len(rotation)): + pbs[bname].rotation_euler[i] = math.radians(float(fixed_rotation[i])) + pbs[bname].rotation_mode = new_order + + if (bpy.context.window_manager.add_pose_lib): + if self.pose_lib_check(): + self.add_pose(transform_data) + else: + num = "" + if ".0" in self.fig_object_name: + num = " " + self.fig_object_name[-1] + bpy.ops.pose.select_all(action="SELECT") + bpy.ops.poselib.pose_add(frame=0, name=str(self.fig_object["Asset Name"] + " Pose")) + action = bpy.data.actions["PoseLib"] + action.name = self.fig_object["Asset Name"] + num + " Pose Library" + bpy.ops.pose.select_all(action="DESELECT") + + def pose_lib_check(self): + if ".0" in self.fig_object_name: + num = " " + self.fig_object_name[-1] + name = self.fig_object["Asset Name"] + num + " Pose Library" + else: + name = self.fig_object["Asset Name"] + " Pose Library" + if name in bpy.data.actions.keys(): + return True + + # Add Pose to Library + def add_pose(self,transform_data): + if ".0" in self.fig_object_name: + num = "" + if ".0" in self.fig_object_name: + num = " " + self.fig_object_name[-1] + name = self.fig_object["Asset Name"] + num + " Pose Library" + else: + name = self.fig_object["Asset Name"] + " Pose Library" + action = bpy.data.actions[name] + frame_count = len(action.fcurves) + 1 + + if "Asset Name" in transform_data.keys(): + pose_name = transform_data["Asset Name"] + else: + pose_name = frame_count + + bpy.ops.pose.select_all(action="SELECT") + bpy.ops.poselib.pose_add(frame=frame_count, name=str(pose_name)) + bpy.ops.pose.select_all(action="DESELECT") + + def restore_pose(self): + Versions.active_object(Global.getAmtr()) + Global.setOpsMode("POSE") + self.make_pose() diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/ToRigify.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/ToRigify.py index e15a316a..4d445200 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/ToRigify.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/ToRigify.py @@ -318,7 +318,7 @@ def finish_job(self): add = 1 if i==1: add = -1 - add = add * (0.01 * Global.getSize()) + add = add * (0.01 * Global.get_size()) Global.getRgfy().pose.bones[nper[i]].location[1] += add #bpy.ops.pose.armature_apply(selected = False) # nper = 'tweak_spine.001' @@ -473,8 +473,8 @@ def all_rigity_bone(self,db): mch_ti = ['MCH-shin_ik.L', 'MCH-shin_ik.R'] for mt in mch_ti: if bone.name == mt: - if bone.head[1] > -0.002*Global.getSize(): - bone.head[1] = -0.002 * Global.getSize() + if bone.head[1] > -0.002*Global.get_size(): + bone.head[1] = -0.002 * Global.get_size() if '.L' in bone.name: bone.roll = math.radians(-8) else: @@ -902,7 +902,7 @@ def make_metarig(self): Versions.select(self.METARIG, True) for i in range(3): - self.METARIG.scale[i] = Global.getSize() + self.METARIG.scale[i] = Global.get_size() bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) return "" diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Util.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Util.py index 52ae3401..83494662 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Util.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Util.py @@ -2,10 +2,12 @@ import bpy import os import math +import json from . import DataBase from . import Versions from . import Global import re +from mathutils import Euler _CURRENT_COL = "" @@ -22,6 +24,14 @@ def colobjs(col_name): return col.objects return bpy.context.scene.collection.objects +def all_armature(): + objs = bpy.data.objects + armatures = [] + for obj in objs: + if obj.type == "ARMATURE": + armature = obj + armatures.append(armature) + return armatures def allobjs(): return bpy.data.objects @@ -87,7 +97,7 @@ def getUsersCollection(object): def getUsersCollectionName(object): rtn = getUsersCollection(object) - if rtn !=None: + if rtn != None: return rtn.name else: return "" @@ -248,216 +258,4 @@ def getMatName(src_name): find = True if find==False: break - -class Posing: - def pose_copy(self,dur): - if os.path.exists(dur) == False: - return - with open(dur, errors='ignore', encoding='utf-8') as f: - ls = f.readlines() - ptn = ['"url" : ','"keys" : '] - xyz = ["/x/value","/y/value","/z/value"] - v3ary = [] - v3 = [] - for l in ls: - for i in range(2): - f = l.find(ptn[i]) - if f >=0: - l = l[f+len(ptn[i]):] - else: - continue - if '#' in l: - continue - if i == 0: - k = "@selection/" - f = l.find(k) - if f >= 0: - l = l[f+len(k):] - f = l.find("rotation") - if f>=0: - v3 = [] - v3.append(l[:f-2]) - for kidx,k in enumerate(xyz): - if k in l: - v3.append(kidx) - break - elif i == 1 and len(v3) == 2: - a = l.find(",") - if a > 0: - l = l[a+1:] - a = l.find("]") - if a > 0: - l = l[:a] - v3.append(float(l.strip())) - v3ary.append(v3) - self.make_pose(v3ary) - - def order_1ary(self, ary, bname): - new_ary = [] - pb = Global.getAmtr().pose.bones.get(bname) - if pb is None: - return ary - odr = pb.rotation_mode - k3 = ['X', 'Y', 'Z'] - for od in odr: - for kidx, k in enumerate(k3): - if od == k: - for ar in ary: - if ar[1] == kidx: - new_ary.append(ar) - break - - if len(new_ary) == 3: - return new_ary - return ary - - def order_v3ary(self, v3ary): - all_ary = [] - ary = [] - - old_bname = "" - for v3 in v3ary: - if old_bname != v3[0] and len(ary) == 3: - all_ary.append(self.order_1ary(ary, old_bname)) - ary = [] - ary.append(v3) - old_bname = v3[0] - if len(ary) == 3: - all_ary.append(self.order_1ary(ary, old_bname)) - newv3ary = [] - for al in all_ary: - for a in al: - newv3ary.append(a) - return newv3ary - - def make_pose(self, v3ary): - bone_limits = DataBase.get_bone_limits_dict() - pbs = Global.getAmtr().pose.bones - # cur.append(['hip', 'ZYX'])#YXZ#'ZXY'#YXZ - # cur.append(['root', 'ZZZ']) - v3ary = self.order_v3ary(v3ary) - for bone_limit_key in bone_limits: - bone_limit = bone_limits[bone_limit_key] - order = bone_limit[1] - bname = bone_limit[0] - for v3 in v3ary: - if v3[0].startswith("-"): - v3[0] = v3[0][1:] - if v3[0] != bname: - continue - flg_zi = False - z_invert = ['neckUpper', 'chestUpper', 'chestLower', 'neckLower', 'abdomenUpper', 'abdomenLower'] - for zi in z_invert: - if zi == v3[0]: - flg_zi = True - break - if (order == 'YZX' or order == 'XYZ' or order == 'ZYX') and flg_zi == False: - if v3[1] == 2: - v3[2] = 0 - v3[2] - xy_invert = ['rCollar', 'rShldrBend', 'rForearmBend', 'rForearmTwist', 'rShldrTwist', 'rThumb2', - 'rThumb3', - 'rThumb1', 'rHand', 'rThighTwist', 'lThighTwist'] - for xyi in xy_invert: - if bname == xyi: - if v3[1] != 2: - v3[2] = 0 - v3[2] - if order == 'XZY' or order == 'XYZ': - if v3[1] == 0: - v3[1] = 1 - elif v3[1] == 1: - v3[1] = 0 - if order == 'ZYX': # YZ switch - if v3[1] == 1: - v3[1] = 2 - elif v3[1] == 2: - v3[1] = 1 - if v3[1] < 3: - x_invert = ['rIndex', 'rMid', 'rPinky', 'rRing','pelvis'] - for xi in x_invert: - if xi in bname: - if v3[1] == 0: - v3[2] = 0 - v3[2] - # if bname=='hip': - # if v3[1]==2: - # v3[1] = 1 - # elif v3[1]==1: - # v3[1] = 0 - # v3[2] = 0 - v3[2] - # elif v3[1]==0: - # v3[1] = 2 - # v3[2] = 0 - v3[2] - - # if v3[1]==2: - # v3[1] = 0 - # v3[2] = 0-v3[2] - # elif v3[1]==1: - # v3[1] = 2 - # elif v3[1]==0: - # v3[1] = 1 - - # if v3[1] == 1: - # v3[1] = 2 - # elif v3[1] == 2: - # v3[1] = 1 - y_invert = ['Shin']#,'hip'] - for yi in y_invert: - if yi in bname: - if v3[1] == 1: - v3[2] = 0 - v3[2] - - z_invert2 = ['F______oot', 'lThumb1'] - for zi in z_invert2: - if zi in bname: - if v3[1] == 2: - v3[2] = 0 - v3[2] - - if v3[0] in pbs: - if v3[1]>6: - if Global.getSize()==1: - v3[2] = v3[2]/100.0 - if v3[1]==8: - pbs[v3[0]].location[v3[1] - 7] = 0-v3[2] - else: - pbs[v3[0]].location[v3[1] - 7] = v3[2] - else: - pbs[v3[0]].rotation_euler[v3[1]] = math.radians(v3[2]) - - def setpose(self): - v3ary = [] - Versions.active_object(Global.getAmtr()) - Global.setOpsMode("POSE") - hometown = Global.getHomeTown() - # idx = -1 - # print("hometown = ",hometown) - # if len(hometown)>3 and hometown.startswith("FIG"): - # idx = int(hometown[3:]) - # if idx<0: - # return - padr = hometown+ "/FIG.csv" - if os.path.exists(padr) == False: - return - with open(padr, errors='ignore', encoding='utf-8') as f: - ls = f.readlines() - for l in ls: - ss = l.split(",") - if ss[1].startswith('Genesis'): - ss[1] = 'root' - ss[2] = 'B' - if ss[2]!='B': - continue - for pb in Global.getAmtr().pose.bones: - if ss[1] == pb.name: - for i in range(3): - v3 = [ss[1], i, float(ss[6 + i])] - v3ary.append(v3) - if ss[1]=='root' or ss[1]=='hip': - add = i - if add==1: - add = 2 - elif add==2: - add = 1 - [] - v3 = ["-"+ss[1], add+7, float(ss[3 + i])] - v3ary.append(v3) - break - self.make_pose(v3ary) + diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Versions.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Versions.py index 871769c6..5b814405 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Versions.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/Versions.py @@ -72,15 +72,15 @@ def make_sun(): return if BV < 2.80: bpy.ops.object.lamp_add(type='SUN', radius=6.0, location=( - -0.55*Global.getSize(), - -0.6*Global.getSize(), - 2.3*Global.getSize() + 140, + 100, + 150 ), rotation=(0.77, -0.401, -0.244)) else: bpy.ops.object.light_add(type='SUN', radius=6.0, location=( - -0.55 * Global.getSize(), - -0.6 * Global.getSize(), - 2.3 * Global.getSize() + 140, + 100, + 150 ), rotation=(0.77, -0.401, -0.244)) sun = bpy.context.object sun.name = 'daz_sun' diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/__init__.py b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/__init__.py index 8da66c11..3dc41a7b 100644 --- a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/__init__.py +++ b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/__init__.py @@ -1,7 +1,7 @@ bl_info = { "name": "DazToBlender", "author": "Daz 3D | https://www.daz3d.com", - "version": (2, 2, 2), + "version": (2, 3, 0), "blender": (2, 80, 0), "location": "3DView > ToolShelf", "description": "Daz 3D Genesis 3/8 transfer to Blender", @@ -26,10 +26,15 @@ from . import Global from . import Versions from . import DtbDazMorph +from . import DtbOperators +from . import DtbPanels from . import DtbMaterial from . import CustomBones +from . import Poses +from . import Animations from . import Util -from . import WCmd +from . import DtbCommands +from . import DtbIKBones from bpy.props import EnumProperty from bpy.props import BoolProperty from bpy.props import StringProperty @@ -61,636 +66,11 @@ 'Bump.Strength', 'Bump.Distance', ] -num_bones = [6, 6, 3, 3] -ik_name = ['rHand_IK', 'lHand_IK', 'rShin_IK', 'lShin_IK'] -bone_name = ['rHand', 'lHand', 'rShin', 'lShin'] -bone_name_rigify = ['MCH-upper_arm_ik.R','MCH-upper_arm_ik.L','MCH-thigh_ik.R','MCH-thigh_ik.L'] -fbx_exsported = "" -obj_exsported = "" -mute_bones = [] -ik_access_ban = False + region = 'UI' BV = Versions.getBV() -total_key_count = 0 # To keep track of the max number of the keys in actions, so to set fps - -def get_influece_data_path(bname): - amtr = Global.getAmtr() - if amtr is None: - return - if bname in amtr.pose.bones: - pbn = amtr.pose.bones[bname] - for c in pbn.constraints: - if bname + '_IK' in c.name: - return [c, 'influence'] - return None - -def get_ik_influence(data_path): - return eval("data_path[0].%s" % data_path[1]) - -def set_ik_influence(data_path, val): - exec("data_path[0].%s = %f" % (data_path[1], val)) - -def set_ik(data_path): - set_ik_influence(data_path, 1.0) - -def set_fk(data_path): - set_ik_influence(data_path, 0.0) - -def set_translation(matrix, loc): - trs = matrix.decompose() - rot = trs[1].to_matrix().to_4x4() - scale = mathutils.Matrix.Scale(1, 4, trs[2]) - if BV<2.80: - return mathutils.Matrix.Translation(loc) * (rot * scale) - else: - return mathutils.Matrix.Translation(loc) @ (rot @ scale) - -def reset_total_key_count(): - global total_key_count - total_key_count = 0 - -def update_total_key_count(key_count): - global total_key_count - if key_count > total_key_count: - total_key_count = key_count - -def get_total_key_count(): - global total_key_count - return total_key_count - -def set_scene_settings(): - scene = bpy.context.scene - scene.unit_settings.length_unit = 'CENTIMETERS' - - # Set start and end playable range for the animations. - scene.frame_start = 0 - scene.frame_end = get_total_key_count() - 1 - scene.frame_current = 0 - - # Set armature display settings - Global.setOpsMode('POSE') - armature = Global.getAmtr().data - armature.display_type = 'OCTAHEDRAL' - armature.show_names = False - armature.show_axes = False - armature.show_bone_custom_shapes = True - -# region - Quaternion to Euler - -def get_rotation_order(node_name): - bone_limits = Global.get_bone_limit() - for bone_limit in bone_limits: - if bone_limit[0] in node_name: - return bone_limit[1] - return "XYZ" - - -def get_or_create_fcurve(action, data_path, array_index=-1, group=None): - for fc in action.fcurves: - if fc.data_path == data_path and (array_index < 0 or fc.array_index == array_index): - return fc - - fc = action.fcurves.new(data_path, index=array_index) - fc.group = group - return fc - - -def add_keyframe_euler(action, euler, frame, bone_prefix, group): - for i in range(len(euler)): - fc = get_or_create_fcurve( - action, bone_prefix + "rotation_euler", - i, - group - ) - pos = len(fc.keyframe_points) - fc.keyframe_points.add(1) - fc.keyframe_points[pos].co = [frame, euler[i]] - fc.update() - - -def frames_matching(action, data_path): - frames = set() - for fc in action.fcurves: - if fc.data_path == data_path: - fri = [kp.co[0] for kp in fc.keyframe_points] - frames.update(fri) - return frames - - -def fcurves_group(action, data_path): - for fc in action.fcurves: - if fc.data_path == data_path and fc.group is not None: - return fc.group - return None - - -def convert_quaternion_to_euler(action, obj): - # Get all the bones with quaternion animation data - bone_prefixes = set() - for fcurve in action.fcurves: - if fcurve.data_path == "rotation_quaternion" or fcurve.data_path[-20:] == ".rotation_quaternion": - bone_prefixes.add(fcurve.data_path[:-19]) - - for bone_prefix in bone_prefixes: - if (bone_prefix == ""): - bone = obj - else: - # get the bone using the data path prefix - bone = eval("obj." + bone_prefix[:-1]) - - data_path = bone_prefix + "rotation_quaternion" - frames = frames_matching(action, data_path) - group = fcurves_group(action, data_path) - - for fr in frames: - # Get quaternion keyframe value - quat = bone.rotation_quaternion.copy() - for fcurve in action.fcurves: - if fcurve.data_path == data_path: - quat[fcurve.array_index] = fcurve.evaluate(fr) - - # Calculate euler equivalent for the quaternion - order = get_rotation_order(bone.name) - euler = quat.to_euler(order) - - # Add euler keyframe and set correct rotation order - add_keyframe_euler(action, euler, fr, bone_prefix, group) - bone.rotation_mode = order - - # delete all the curves with quaternion data - quat_fcurves = [] - for fcurve in action.fcurves: - if fcurve.data_path[-20:] == ".rotation_quaternion": - quat_fcurves.append(fcurve) - for fcurve in quat_fcurves: - action.fcurves.remove(fcurve) - -# endregion - Quaternion to Euler - -def convert_rotation_orders(): - Versions.active_object(Global.getAmtr()) - Global.setOpsMode('POSE') - for bone in Global.getAmtr().pose.bones: - order = bone.rotation_mode - if order == 'XYZ': - bone.rotation_mode = 'ZXY' - elif order == 'XZY': - bone.rotation_mode = 'YZX' - elif order == 'YZX': - bone.rotation_mode = 'YZX' - elif order == 'ZXY': - bone.rotation_mode = 'XYZ' - elif order == 'ZYX': - bone.rotation_mode = 'YZX' - -def clean_animations(): - Versions.active_object(Global.getAmtr()) - Global.setOpsMode('POSE') - - for action in bpy.data.actions: - - # Convert rotation animation data from quaternion to euler angles - convert_quaternion_to_euler(action, Global.getAmtr()) - - # Convert animation data from Studio to Blender - curve_count = len(action.fcurves) - index = 0 - while index < curve_count: - fcurve = action.fcurves[index] - start_index = fcurve.data_path.find('[') - end_index = fcurve.data_path.find(']') - if (start_index == -1 or end_index == -1): - # Convert Figure root bone animation data - if "Genesis" in action.name: - if fcurve.data_path == "rotation_euler": - for point in fcurve.keyframe_points: - point.co[1] = 0 - if fcurve.data_path == "scale": - for point in fcurve.keyframe_points: - point.co[1] = 1.0 - # Convert non Figure root bone animation data - else: - if fcurve.data_path == "location": - fcurve_x = action.fcurves[index + 0] - fcurve_y = action.fcurves[index + 1] - fcurve_z = action.fcurves[index + 2] - point_count = len(fcurve_x.keyframe_points) - - for i in range(point_count): - # Y invert (-Y) - fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] - - # Z invert (-Z) - fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] - - index += 2 - else: - node_name = fcurve.data_path[start_index + 2 : end_index - 1] - property_name = fcurve.data_path[end_index + 2 :] - rotation_order = get_rotation_order(node_name) - - # Convert location animation data for all the non root bones - if property_name == "location": - fcurve_x = action.fcurves[index + 0] - fcurve_y = action.fcurves[index + 1] - fcurve_z = action.fcurves[index + 2] - point_count = len(fcurve_x.keyframe_points) - update_total_key_count(point_count) - - for i in range(point_count): - # Y invert (-Y) - fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] - - # Z invert (-Z) - fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] - - # Get skeleton scale and set to location animation data - skeleton_data = DataBase.get_skeleton_data() - skeleton_scale = skeleton_data["skeletonScale"] - skeleton_scale *= 0.01 # To match armature scale - for i in range(point_count): - fcurve_x.keyframe_points[i].co[1] *= skeleton_scale - fcurve_y.keyframe_points[i].co[1] *= skeleton_scale - fcurve_z.keyframe_points[i].co[1] *= skeleton_scale - - index += 2 - - # Convert rotation animation data for all the non root bones - if property_name == "rotation_euler": - fcurve_x = action.fcurves[index + 0] - fcurve_y = action.fcurves[index + 1] - fcurve_z = action.fcurves[index + 2] - point_count = len(fcurve_x.keyframe_points) - update_total_key_count(point_count) - - if rotation_order == 'XYZ': - for i in range(point_count): - # YZ switch (Y <-> Z) - temp = fcurve_y.keyframe_points[i].co[1] - fcurve_y.keyframe_points[i].co[1] = fcurve_z.keyframe_points[i].co[1] - fcurve_z.keyframe_points[i].co[1] = temp - - # XY switch (X <-> Y) - temp = fcurve_x.keyframe_points[i].co[1] - fcurve_x.keyframe_points[i].co[1] = fcurve_y.keyframe_points[i].co[1] - fcurve_y.keyframe_points[i].co[1] = temp - - if(node_name.startswith("r")): - # Y invert (-Y) - fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] - - # Z invert (-Z) - fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] - - elif rotation_order == 'XZY': - for i in range(point_count): - # XY switch (X <-> Y) - temp = fcurve_x.keyframe_points[i].co[1] - fcurve_x.keyframe_points[i].co[1] = fcurve_y.keyframe_points[i].co[1] - fcurve_y.keyframe_points[i].co[1] = temp - - # X invert (-X) - fcurve_x.keyframe_points[i].co[1] = -fcurve_x.keyframe_points[i].co[1] - - if(node_name.startswith("r")): - # Y invert (-Y) - fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] - - # Z invert (-Z) - fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] - - elif rotation_order == "YZX": - # Bones that are pointed down with YZX order - # TODO: remove hardcoding - if node_name in ["hip", "pelvis", "lThighBend", "rThighBend", "lThighTwist", "rThighTwist", "lShin", "rShin"]: - for i in range(point_count): - # Y invert (-Y) - fcurve_y.keyframe_points[i].co[1] = -fcurve_y.keyframe_points[i].co[1] - - # Z invert (-Z) - fcurve_z.keyframe_points[i].co[1] = -fcurve_z.keyframe_points[i].co[1] - - elif rotation_order == "ZXY": - for i in range(point_count): - # XY switch (X <-> Y) - temp = fcurve_x.keyframe_points[i].co[1] - fcurve_x.keyframe_points[i].co[1] = fcurve_y.keyframe_points[i].co[1] - fcurve_y.keyframe_points[i].co[1] = temp - - # YZ switch (Y <-> Z) - temp = fcurve_y.keyframe_points[i].co[1] - fcurve_y.keyframe_points[i].co[1] = fcurve_z.keyframe_points[i].co[1] - fcurve_z.keyframe_points[i].co[1] = temp - - elif rotation_order == "ZYX": - for i in range(point_count): - # YZ switch (Y <-> Z) - temp = fcurve_y.keyframe_points[i].co[1] - fcurve_y.keyframe_points[i].co[1] = fcurve_z.keyframe_points[i].co[1] - fcurve_z.keyframe_points[i].co[1] = temp - - # X invert (-X) - fcurve_x.keyframe_points[i].co[1] = -fcurve_x.keyframe_points[i].co[1] - - index += 2 - - index += 1 - - convert_rotation_orders() - -class DTB_PT_Main(bpy.types.Panel): - bl_label = "DazToBlender" - bl_space_type = 'VIEW_3D' - bl_region_type = region - if BV <2.80: - bl_category = "Tools" - else: - bl_category = "DazToBlender" - t_non = None - def draw(self, context): - l = self.layout - box = l.box() - w_mgr = context.window_manager - row = box.row(align=True) - row.prop(w_mgr, "quick_heavy", text="Quick But Heavy", toggle=False) - row.prop(w_mgr, "size_100", text="Size * 100", toggle=False) - box.operator('import.fbx', icon='POSE_HLT') - box.operator('import.env', icon='WORLD') - if context.object and context.active_object: - cobj = context.active_object - if Global.get_Body_name() == "" and Global.get_Rgfy_name() == "" and Global.get_Amtr_name() == "": - Global.clear_variables() - Global.decide_HERO() - if context.object.type == 'ARMATURE' and Global.getRgfy() is None and Global.getAmtr() is None: - Global.clear_variables() - Global.find_AMTR(cobj) - Global.find_RGFY(cobj) - if context.object.type == 'MESH' and Global.getBody() is None: - Global.clear_variables() - Global.find_BODY(cobj) - if cobj.mode == 'POSE': - if Global.get_Amtr_name() != cobj.name and len(cobj.data.bones) > 90 and len(cobj.data.bones) < 200: - Global.clear_variables() - Global.find_Both(cobj) - if Global.get_Rgfy_name() != cobj.name and len(cobj.data.bones) > 600: - Global.clear_variables() - Global.find_Both(cobj) - elif context.object.type == 'MESH': - if Global.get_Body_name() != "" and Global.get_Body_name() != cobj.name and len( - cobj.vertex_groups) > 163 \ - and len(cobj.data.vertices) >= 16384 \ - and len(cobj.vertex_groups) < 500 and len(cobj.data.vertices) < 321309: - Global.clear_variables() - Global.find_Both(cobj) - if ik_access_ban == False and context.active_object.mode == 'POSE': - l.separator() - if Global.amIAmtr(context.object): - col = l.column(align=True) - r = col.row(align=True) - for i in range(len(ik_name)): - if i == 2: - r = col.row(align=True) - influence_data_path = get_influece_data_path(bone_name[i]) - if influence_data_path is not None: - r.prop(w_mgr, 'ifk' + str(i), text=ik_name[i], toggle=True) - col.operator('limb.redraw',icon='LINE_DATA') - l.separator() - elif Global.amIRigfy(context.object): - if BV<2.81: - row = l.row(align=True) - row.alignment = 'EXPAND' - row.operator('my.iktofk', icon="MESH_CIRCLE") - row.operator('my.fktoik', icon="MESH_CUBE") - if Global.amIAmtr(context.object): - l.operator('to.rigify', icon='ARMATURE_DATA') - if Global.amIRigfy(context.object): - if BV<2.81: - row = l.row(align=True) - row.alignment = 'EXPAND' - row.operator('match.ikfk') - row.prop(w_mgr, "br_onoff_prop", text="Joint Range", toggle=True) - else: - l.prop(w_mgr, "br_onoff_prop", text="Joint Range", toggle=True) - l.separator() - l.operator('my.clear') - if Global.amIBody(context.object): - col = l.column(align=True) - box = col.box() - row = box.row(align=True) - row.alignment = 'EXPAND' - row.prop(w_mgr, "is_eye", text="Eye") - row.prop(w_mgr, "ftime_prop", text="x 4") - if w_mgr.is_eye: - box.prop(w_mgr, "eye_prop", text="") - else: - box.prop(w_mgr, "skin_prop", text="") - row = box.row(align=True) - row.alignment = 'EXPAND' - row.operator('material.up', icon="TRIA_UP") - row.operator('material.down', icon="TRIA_DOWN") - box.operator('df.material') - if context.object.type == 'MESH': - if Global.isRiggedObject(context.object): - if Versions.get_active_object().mode == 'OBJECT': - l.prop(w_mgr, 'new_morph', text="Make New Morph") - row = l.row(align=True) - row.operator('exsport.morph', icon="TRIA_LEFT") - row.operator('to.sculpt', icon="MONKEY") - if obj_exsported != "": - l.label(text=obj_exsported) - - l.separator() - row = l.row(align=True) - row.alignment = 'EXPAND' - row.prop(w_mgr, "search_prop") - if context.object.type == 'MESH': - row.operator('search.morph', icon='VIEWZOOM') - else: - row.operator('search.morph', icon='HAND') - else: - l.prop(w_mgr, "search_prop") - l.operator('remove.alldaz', icon='BOIDS') - l.operator('df.optimize', icon="MATERIAL") - - - - -class IMP_OT_FBX(bpy.types.Operator): - bl_idname = "import.fbx" - bl_label = "Import New Genesis 3/8" - bl_options = {'REGISTER', 'UNDO'} - root = Global.getRootPath() - - def invoke(self, context, event): - if bpy.data.is_dirty: - return context.window_manager.invoke_confirm(self, event) - return self.execute(context) - - def finish_obj(self): - Versions.reverse_language() - Versions.pivot_active_element_and_center_and_trnormal() - Global.setRenderSetting(True) - - def layGround(self): - bpy.context.preferences.inputs.use_mouse_depth_navigate = True - Util.deleteEmptyDazCollection() - bpy.context.scene.render.engine = 'CYCLES' - bpy.context.space_data.shading.type = 'SOLID' - bpy.context.space_data.shading.color_type = 'OBJECT' - bpy.context.space_data.shading.show_shadows = False - Versions.set_english() - bco = bpy.context.object - if bco != None and bco.mode != 'OBJECT': - Global.setOpsMode('OBJECT') - bpy.ops.view3d.snap_cursor_to_center() - - def pbar(self,v,wm): - wm.progress_update(v) - - def import_one(self,fbx_adr): - Versions.active_object_none() - Util.decideCurrentCollection('FIG') - wm = bpy.context.window_manager - wm.progress_begin(0, 100) - Global.clear_variables() - ik_access_ban = True - reset_total_key_count() - drb = DazRigBlend.DazRigBlend() - dtb_shaders = DtbMaterial.DtbShaders() - self.pbar(5,wm) - drb.convert_file(filepath=fbx_adr) - self.pbar(10, wm) - db = DataBase.DB() - Global.decide_HERO() - self.pbar(15, wm) - - if Global.getAmtr() is not None and Global.getBody() is not None: - Global.deselect() # deselect all the objects - drb.clear_pose() # Select Armature and clear transform - drb.mub_ary_A() # Find and read FIG.dat file - drb.orthopedy_empty() # On "EMPTY" type objects - self.pbar(18, wm) - drb.orthopedy_everything() # clear transform, clear and reapply parent - Global.deselect() - self.pbar(20, wm) - drb.set_bone_head_tail() # Sets head and tail positions for all the bones - Global.deselect() - self.pbar(25, wm) - drb.bone_limit_modify() - clean_animations() - Global.deselect() - self.pbar(30, wm) - drb.unwrapuv() - Global.deselect() - if Global.getIsEyls(): - drb.integrationEyelashes() - Global.deselect() - if Global.getIsTEAR(): - drb.integrationTear() - Global.deselect() - - # materials - dtb_shaders.make_dct() - dtb_shaders.load_shader_nodes() - dtb_shaders.body_texture() - self.pbar(35, wm) - dtb_shaders.wardrobe_texture() - self.pbar(40, wm) - - if Global.getIsGen(): - drb.fixGeniWeight(db) - Global.deselect() - self.pbar(45, wm) - Global.setOpsMode('OBJECT') - Global.deselect() - - # Shape keys - dsk = DtbShapeKeys.DtbShapeKeys(False) - #dsk.deleteEyelashes() #Removes Eyelashes but does not connect right now - self.pbar(50, wm) - #dsk.toshortkey() #Renaming does not work correctly as Alias Change in Daz 4.12 - dsk.deleteExtraSkey() - dsk.toHeadMorphMs(db) - wm.progress_update(55) - if wm.quick_heavy==False: - dsk.delete_all_extra_sk(55, 75, wm) - self.pbar(75,wm) - dsk.makeDrives(db) - Global.deselect() - self.pbar(80,wm) - - drb.makeRoot() - drb.makePole() - drb.makeIK() - drb.pbone_limit() - drb.mub_ary_Z() - Global.setOpsMode("OBJECT") - CustomBones.CBones() - Global.setOpsMode('OBJECT') - Global.deselect() - self.pbar(90,wm) - dsk.delete001_sk() - amt = Global.getAmtr() - for bname in bone_name: - bone = amt.pose.bones[bname] - for bc in bone.constraints: - if bc.name == bname + "_IK": - pbik = amt.pose.bones.get(bname + "_IK") - amt.pose.bones[bname].constraints[bname + '_IK'].influence = 0 - drb.makeBRotationCut(db) # lock movements around axes with zeroed limits for each bone - Global.deselect() - - # materials - DtbMaterial.forbitMinus() - self.pbar(95,wm) - Global.deselect() - - Versions.active_object(Global.getAmtr()) - Global.setOpsMode("POSE") - drb.mub_ary_Z() - Global.setOpsMode("OBJECT") - drb.finishjob() - Global.setOpsMode("OBJECT") - Util.Posing().setpose() - bone_disp(-1, True) - set_scene_settings() - self.pbar(100,wm) - ik_access_ban = False - self.report({"INFO"}, "Success") - else: - self.show_error() - wm.progress_end() - ik_access_ban = False - def execute(self, context): - global ik_access_ban - - if self.root == "": - self.report({"ERROR"}, "Appropriate FBX does not exist!") - return {'FINISHED'} - self.layGround() - for i in range(10): - fbx_adr = self.root + "FIG/FIG" + str(i) + "/B_FIG.fbx" - if os.path.exists(fbx_adr)==False: - break - Global.setHomeTown(self.root+"FIG/FIG" + str(i)) - self.import_one(fbx_adr) - self.finish_obj() - return {'FINISHED'} - - def show_error(self): - Global.setOpsMode("OBJECT") - for b in Util.myacobjs(): - bpy.data.objects.remove(b) - filepath = os.path.dirname(__file__) + Global.getFileSp()+"img" + Global.getFileSp() + "Error.fbx" - if os.path.exists(filepath): - bpy.ops.import_scene.fbx(filepath=filepath) - bpy.context.space_data.shading.type = 'SOLID' - bpy.context.space_data.shading.color_type = 'TEXTURE' - for b in Util.myacobjs(): - for i in range(3): - b.scale[i] = 0.01 class MATERIAL_OT_up(bpy.types.Operator): bl_idname = "material.up" @@ -726,13 +106,7 @@ def execute(self, context): adjust_material(context, True) return {'FINISHED'} -class CLEAR_OT_Pose(bpy.types.Operator): - bl_idname = "my.clear" - bl_label = 'CLEAR ALL POSE' - def execute(self, context): - clear_pose() - return {'FINISHED'} def clear_pose(): if bpy.context.object is None: @@ -760,8 +134,8 @@ def execute(self, context): trf = ToRigify.ToRigify() db = DataBase.DB() - adjust_shin_y(2, False) - adjust_shin_y(3, False) + DtbIKBones.adjust_shin_y(2, False) + DtbIKBones.adjust_shin_y(3, False) trf.toRigify(db, self) return {'FINISHED'} @@ -773,12 +147,7 @@ def execute(self, context): default_material(context) return {'FINISHED'} -class OPTIMIZE_OT_material(bpy.types.Operator): - bl_idname = "df.optimize" - bl_label = 'Optimize Materials(WIP)' - def execute(self, context): - DtbMaterial.optimize_materials() - return {'FINISHED'} + def default_material(context): w_mgr = context.window_manager @@ -804,13 +173,7 @@ def execute(self, context): trf.match_ikfk(influence4) return {'FINISHED'} -class SEARCH_OT_morph(bpy.types.Operator): - bl_idname = "search.morph" - bl_label = 'Command' - def execute(self, context): - search_morph(context) - return {'FINISHED'} class SCULPT_OT_push(bpy.types.Operator): bl_idname = 'to.sculpt' @@ -856,28 +219,14 @@ def execute(self, context): rgfy = ToRigify.ToRigify() rgfy.ik2fk(-1) else: - bone_disp(-1, False) - global mute_bones - mute_bones.append('NG') - for i in range(len(bone_name)): - fktoik(i) - adjust_shin_y(i, True) - mute_bones = [] + DtbIKBones.bone_disp(-1, False) + DtbIKBones.mute_bones.append('NG') + for i in range(len(DtbIKBones.bone_name)): + DtbIKBones.fktoik(i) + DtbIKBones.adjust_shin_y(i, True) + DtbIKBones.mute_bones = [] return {'FINISHED'} -class IMP_OT_ENV(bpy.types.Operator): - bl_idname = "import.env" - bl_label = "Import New Env/Prop" - bl_options = {'REGISTER', 'UNDO'} - def invoke(self, context, event): - if bpy.data.is_dirty: - return context.window_manager.invoke_confirm(self, event) - return self.execute(context) - - def execute(self, context): - from . import Environment - Environment.EnvProp() - return {'FINISHED'} class IK2FK_OT_button(bpy.types.Operator): bl_idname = "my.iktofk" @@ -890,33 +239,15 @@ def execute(self, context): rgfy = ToRigify.ToRigify() rgfy.fk2ik(-1) else: - bone_disp(-1, True) - global mute_bones - mute_bones.append('NG') - for i in range(len(bone_name)): - iktofk(i) - adjust_shin_y(i, False) - mute_bones = [] + DtbIKBones.bone_disp(-1, True) + DtbIKBones.mute_bones.append('NG') + for i in range(len(DtbIKBones.bone_name)): + DtbIKBones.iktofk(i) + DtbIKBones.adjust_shin_y(i, False) + DtbIKBones.mute_bones = [] return {'FINISHED'} -class REMOVE_DAZ_OT_button(bpy.types.Operator): - bl_idname = "remove.alldaz" - bl_label = "Remove All Daz" - bl_options = {'REGISTER', 'UNDO'} - - def invoke(self,context,event): - return context.window_manager.invoke_confirm(self, event) - - def execute(self, context): - col = bpy.data.collections.get('DAZ_ROOT') - if col is not None: - for c in col.children: - for obj in c.objects: - bpy.data.objects.remove(obj) - bpy.data.collections.remove(c) - return {'FINISHED'} - class LIMB_OT_redraw(bpy.types.Operator): bl_idname = "limb.redraw" bl_label = "ReDisplay Subtle FK/IK" @@ -926,9 +257,9 @@ def execute(self, context): return w_mgr = bpy.context.window_manager for i in range(4): - ik_value = get_ik_influence(get_influece_data_path(bone_name[i])) + ik_value = DtbIKBones.get_ik_influence(DtbIKBones.get_influece_data_path(DtbIKBones.bone_name[i])) flg_ik = ik_value >= 0.5 - bone_disp(i, flg_ik == False) + DtbIKBones.bone_disp(i, flg_ik == False) if i == 0: if w_mgr.ifk0 != flg_ik: w_mgr.ifk0 = flg_ik @@ -949,392 +280,7 @@ def execute(self, context): c.influence = ik_value return {'FINISHED'} -def manageKeyFrame(index, flg_to_ik, switch): - global mute_bones - amt = Global.getAmtr() - if index ==1000: - return - if amt is None: - return - if 'NG' in mute_bones: - return - if amt.animation_data is None: - return - act = amt.animation_data.action - if act is None: - return - ckey = bpy.context.scene.frame_current - if switch<0: - mute_bones = [] - my_bone = amt.pose.bones[bone_name[index]] - num = num_bones[index] - for i in range(num): - mute_bones.append(my_bone.name) - my_bone = my_bone.parent - mute_bones.append(ik_name[index]) - if index>1: - poles = ['', '', 'rShin_P', 'lShin_P'] - foots = ['', '', 'rFoot', 'lFoot'] - mute_bones.append(poles[index]) - mute_bones.append(foots[index]) - if flg_to_ik: - mute_bones.append("hip") - if switch < 0: - first_cr = bpy.context.scene.frame_start - first_ik = first_cr - prev_cr = -999 - fkp_ik = Find_KeyFrame_Point(act.fcurves, mute_bones, ['influence',ik_name[index],bone_name[index]], ckey) - prev_ik = fkp_ik.previous - first_ik = fkp_ik.skip_first(first_ik) - if index > 1: - foots = ['', '', 'rFoot', 'lFoot'] - fkp_cr = Find_KeyFrame_Point(act.fcurves, mute_bones, ['influence', 'Copy Rotation',foots[index]], ckey) - prev_cr = fkp_cr.previous - first_cr= fkp_cr.skip_first(first_cr) - if first_cr >= prev_cr: - first_cr = -999 - if first_ik >= prev_ik: - first_ik = -999 - for b in mute_bones: - for c in amt.pose.bones.get(b).constraints: - if (index > 1 and c.name == 'Copy Rotation' and b[1:]=='Foot'): - if first_cr > -1: - c.keyframe_insert(data_path='influence', frame=first_cr) - if prev_cr > -1: - c.keyframe_insert(data_path='influence', frame=prev_cr) - if c.name==ik_name[index]: - if first_ik >-1: - c.keyframe_insert(data_path='influence', frame=first_ik) - if prev_ik > -1: - c.keyframe_insert(data_path='influence', frame=prev_ik) - if switch==0: - for b in mute_bones: - if flg_to_ik==False: - if (b.endswith("_IK") or b.endswith("_P"))==False: - amt.pose.bones[b].keyframe_insert(data_path='rotation_euler', frame=ckey) - else: - if (b.endswith("_IK") or b.endswith("_P")): - - amt.pose.bones[b].keyframe_insert(data_path='location', frame=ckey) - if index > 1 and b.endswith("_IK"): - amt.pose.bones[b].keyframe_insert(data_path='rotation_euler', frame=ckey) - - for c in amt.pose.bones.get(b).constraints: - if (index > 1 and c.name == 'Copy Rotation') or c.name == ik_name[index]: - c.keyframe_insert(data_path='influence', frame=ckey) - else: - for fcu in act.fcurves: - if switch > 0 and fcu.mute: - fcu.mute = False - else: - names = fcu.data_path.split(sep='"', maxsplit=2) - if len(names) < 2: - continue - name = names[1] - if name in mute_bones and switch < 0: - fcu.mute = True - if switch==1: - mute_bones = [] - -class Find_KeyFrame_Point(): - find_collection = [] - skip_collection = [] - previous = -999 - - def skip_first(self,now_first): - if len(self.skip_collection)>1: - wk = self.skip_collection[len(self.skip_collection)-1] - if wk == now_first: - return -999 - else: - return now_first - else: - return now_first - - def __init__(self,fcurves,find_keys,skip_keys,now_posision): - self.find_collection = [] - self.skip_collection = [] - self.previous = -999 - for fc in fcurves: - for fk in find_keys: - if (fk in fc.data_path): - for point in fc.keyframe_points: - if point.co[0] < now_posision and (point.co[0] in self.find_collection) == False: - self.find_collection.append(point.co[0]) - err = False - for sk in skip_keys: - if (sk in fc.data_path)==False: - err = True - break - if err ==False: - for point in fc.keyframe_points: - if point.co[0] < now_posision and (point.co[0] in self.skip_collection)==False: - self.skip_collection.append(point.co[0]) - self.find_collection.sort() - self.find_collection.reverse() - self.skip_collection.sort() - self.skip_collection.reverse() - if len(self.find_collection)<=0: - self.previous = -999 - elif len(self.skip_collection)<=0 or self.skip_collection[0] < self.find_collection[0]: - self.previous = self.find_collection[0] - else: - self.previous = -999 - -def fktoik(index): - manageKeyFrame(index, True, -1) - amt = Global.getAmtr() - adjust_shin_y(index, True) - my_bone = amt.pose.bones[bone_name[index]] - ik_bone = amt.pose.bones[ik_name[index]] - set_fk(get_influece_data_path(bone_name[index])) - Global.setOpsMode('OBJECT') - Global.setOpsMode('POSE') - ik_bone.matrix = set_translation(ik_bone.matrix, my_bone.tail) - set_ik(get_influece_data_path(bone_name[index])) - if index>1: - rot3 = Global.getFootAngle(index-2) - for ridx,rot in enumerate(rot3): - ik_bone.rotation_euler[ridx] = math.radians(rot) - toFootCopyRotate(index,True) - manageKeyFrame(index, True, 0) - if index == 0: - t = threading.Thread(target=my_srv0_1) - t.start() - if index == 1: - t = threading.Thread(target=my_srv1_1) - t.start() - if index == 2: - t = threading.Thread(target=my_srv2_1) - t.start() - if index == 3: - t = threading.Thread(target=my_srv3_1) - t.start() - -def toFootCopyRotate(index,flg_ik): - copy_r = ['','','rFoot', 'lFoot'] - pbone = Global.getAmtr().pose.bones - if pbone is None: - return - for c in pbone.get(copy_r[index]).constraints: - if 'Copy Rotation' == c.name: - if flg_ik: - c.influence = 1.0 - else: - c.influence = 0.0 - -def my_service(index,flg_to_ik): - time.sleep(2) - manageKeyFrame(index, flg_to_ik, 1) -def my_srv0_1(): - my_service(0,True) -def my_srv1_1(): - my_service(1,True) -def my_srv2_1(): - my_service(2,True) -def my_srv3_1(): - my_service(3,True) -def my_srv0_0(): - my_service(0,False) -def my_srv1_0(): - my_service(1,False) -def my_srv2_0(): - my_service(2,False) -def my_srv3_0(): - my_service(3,False) - -def iktofk(index): - manageKeyFrame(index, False, -1) - adjust_shin_y(index, False) - amt = Global.getAmtr() - ik_bone = amt.pose.bones[ik_name[index]] - my_bone = amt.pose.bones[bone_name[index]] - set_ik(get_influece_data_path(bone_name[index])) - Global.setOpsMode('OBJECT') - Global.setOpsMode('POSE') - ik_bone_matrixes = [] - if my_bone.name=='lShin': - my_bone = amt.pose.bones.get('lFoot') - elif my_bone.name == 'rShin': - my_bone = amt.pose.bones.get('rFoot') - it = my_bone - for i in range(num_bones[index]+1): - if it == None: - continue - mx = deepcopy(it.matrix) - ik_bone_matrixes.append(mx) - it = it.parent - set_fk(get_influece_data_path(bone_name[index])) - if index >1: - toFootCopyRotate(index,False) - it = my_bone - for i in range(num_bones[index] + 1): - if it == None: - continue - it.matrix = deepcopy(ik_bone_matrixes[i]) - it = it.parent - manageKeyFrame(index, False, 0) - if index == 0: - t = threading.Thread(target=my_srv0_0) - t.start() - if index == 1: - t = threading.Thread(target=my_srv1_0) - t.start() - if index == 2: - t = threading.Thread(target=my_srv2_0) - t.start() - if index == 3: - t = threading.Thread(target=my_srv3_0) - t.start() - -def bone_disp2(idx,pose_bone,amt_bone,flg_hide): - hfp = CustomBones.hikfikpole - scales = [hfp[0],hfp[0],hfp[1],hfp[1],hfp[2],hfp[2]] - if amt_bone is None or pose_bone is None: - return - isAnim = Global.isExistsAnimation() - if flg_hide and isAnim: - pose_bone.custom_shape_scale = scales[idx] * 0.4 - else: - pose_bone.custom_shape_scale = scales[idx] - if isAnim: - amt_bone.hide = False - else: - amt_bone.hide = flg_hide - -def bone_disp(idx, flg_hide): - if idx < 0 or idx > 3: - for i in range(4): - bone_disp(i, flg_hide) - return - abones = Global.getAmtrBones() - pbones = Global.getAmtr().pose.bones - if ik_name[idx] in abones: - bone_disp2(idx, pbones.get(ik_name[idx]),abones.get(ik_name[idx]), flg_hide) - if idx>1: - pole = ik_name[idx][0:len(ik_name[idx])-2] - pole = pole + 'P' - if pole in abones: - bone_disp2(idx+2, pbones.get(pole), abones.get(pole),flg_hide) - -def search_morph_(self, context): - search_morph(context) - -def search_morph(context): - w_mgr = context.window_manager - key = w_mgr.search_prop - nozero = False - if key.startswith("!"): - nozero = True - key = key[1:] - if len(key) < 2: - return - if key.startswith("#"): - WCmd.Command(key[1:], context) - return - cobj = bpy.context.object - mesh = cobj.data - for z in range(2): - find = False - max = len(mesh.shape_keys.key_blocks) - for kidx, kb in enumerate(mesh.shape_keys.key_blocks): - if kidx <= Versions.get_active_object().active_shape_key_index: - continue - if nozero and kb.value == 0.0: - continue - if (key.lower() in kb.name.lower()): - Versions.get_active_object().active_shape_key_index = kidx - find = True - break - if z == 0 and find == False: - if max > 1: - Versions.get_active_object().active_shape_key_index = 1 - else: - break - -def bonerange_onoff(self): - bonerange_onoff(self,bpy.contxt) - -def bonerange_onoff(self,context): - flg_on = context.window_manager.br_onoff_prop - Global.boneRotation_onoff(context, flg_on) - -def ifk_update0(self, context): - ifk_update(context, 0) - -def ifk_update1(self, context): - ifk_update(context, 1) - -def ifk_update2(self, context): - ifk_update(context, 2) - -def ifk_update3(self, context): - ifk_update(context, 3) - -def ifk_update(context, idx): - if Global.get_Amtr_name() == "" or ik_access_ban == True: - return {'FINISHED'} - if idx >= 0 and idx <= 3: - ik_force = (get_ik_influence(get_influece_data_path(bone_name[idx])) > 0.5) - gui_force = eval('context.window_manager.ifk' + str(idx)) - if ik_force != gui_force: - if ik_force == False: - bone_disp(idx, False) - fktoik(idx) - else: - bone_disp(idx, True) - iktofk(idx) - return {'FINISHED'} - -def adjust_shin_y(idx, flg_ik): - if Global.getAmtr() is None or idx < 2: - return - idx = idx - 2 - bns = ['rShin', 'lShin'] - Global.setOpsMode('EDIT') - mobj = Global.getBody() - if mobj is None: - Global.find_Both(Global.getAmtr()) - return - vgs = mobj.data.vertices - fm_ikfk = [[4708 ,3418],[4428,3217]] - vidx = 0 - if Global.getIsMan(): - if flg_ik: - vidx = fm_ikfk[1][0] - else: - vidx = fm_ikfk[1][1] - else: - if flg_ik: - vidx = fm_ikfk[0][0] - else: - vidx = fm_ikfk[0][1] - if Global.getIsGen(): - vidx = Global.toGeniVIndex(vidx) - Global.getAmtr().data.edit_bones[bns[idx]].head[1] = vgs[vidx].co[1] - Global.setOpsMode('POSE') - if flg_ik: - for i in range(2): - s = Global.getAmtr().pose.bones.get(bns[i]) - if s is not None: - if s.rotation_euler[0] <= 0.0: - s.rotation_euler[0] = 0.1 - -def gorl_update(self, context): - w_mgr = context.window_manager - gorl = w_mgr.gorl_prop - if gorl == False: - for i, bn in enumerate(bone_name): - v = get_ik_influence(get_influece_data_path(bn)) - if i == 0: - w_mgr.ifk0 = v > 0.5 - elif i == 1: - w_mgr.ifk1 = v > 0.5 - elif i == 2: - w_mgr.ifk2 = v > 0.5 - elif i == 3: - w_mgr.ifk3 = v > 0.5 def init_props(): w_mgr = bpy.types.WindowManager @@ -1378,48 +324,75 @@ def init_props(): name="", default="", description="Search_shape_keys", - update=search_morph_ + update= DtbCommands.search_morph_ ) w_mgr.is_eye = BoolProperty(name="eyes") w_mgr.ftime_prop = BoolProperty(name="ftime") - w_mgr.br_onoff_prop = BoolProperty(name="br_onoff", default=True, update=bonerange_onoff) - w_mgr.ifk0 = BoolProperty(name="ifk0", default=False, update=ifk_update0) - w_mgr.ifk1 = BoolProperty(name="ifk1", default=False, update=ifk_update1) - w_mgr.ifk2 = BoolProperty(name="ifk2", default=False, update=ifk_update2) - w_mgr.ifk3 = BoolProperty(name="fik3", default=False, update=ifk_update3) + w_mgr.br_onoff_prop = BoolProperty(name="br_onoff", default=True, update=DtbIKBones.bonerange_onoff) + w_mgr.ifk0 = BoolProperty(name="ifk0", default=False, update=DtbIKBones.ifk_update0) + w_mgr.ifk1 = BoolProperty(name="ifk1", default=False, update=DtbIKBones.ifk_update1) + w_mgr.ifk2 = BoolProperty(name="ifk2", default=False, update=DtbIKBones.ifk_update2) + w_mgr.ifk3 = BoolProperty(name="fik3", default=False, update=DtbIKBones.ifk_update3) w_mgr.new_morph = BoolProperty(name="_new_morph",default=False) w_mgr.skip_isk = BoolProperty(name = "_skip_isk",default = False) w_mgr.quick_heavy = BoolProperty(name="quick_heavy", default=False) - w_mgr.size_100 = BoolProperty(name="size_100", default=False) + w_mgr.combine_materials = BoolProperty(name="combine_materials", default=True) + w_mgr.add_pose_lib = BoolProperty(name="add_pose_lib", default=True) + figure_items = [("null" , "Choose Character", "Select which figure you wish to import")] + w_mgr.choose_daz_figure = EnumProperty( + name = "Highlight for Collection", + description = "Choose any figure in your scene to which you wish to add a pose.", + items = figure_items, + default = "null", + ) + w_mgr.scene_scale = EnumProperty( + name = "Scene Scale", + description = "Used to change scale of imported object and scale settings", + items = [ + ('0.01', 'Real Scale (Centimeters)', 'Daz Scale'), + ('0.1', 'x10', '10 x Daz Scale'), + ('1', 'x100 (Meters)', '100 x Daz Scale') + ], + default = '0.01' + ) + classes = ( - DTB_PT_Main, - IMP_OT_FBX, + + DtbPanels.DTB_PT_MAIN, + DtbPanels.DTB_PT_POSE, + DtbPanels.DTB_PT_MATERIAL, + DtbPanels.DTB_PT_GENERAL, + DtbPanels.DTB_PT_COMMANDS, + DtbOperators.IMP_OT_POSE, + DtbOperators.IMP_OT_FBX, + DtbOperators.IMP_OT_ENV, + DtbOperators.CLEAR_OT_Pose, + DtbOperators.REFRESH_DAZ_FIGURES, + DtbOperators.REMOVE_DAZ_OT_button, + DtbOperators.OPTIMIZE_OT_material, + DtbCommands.SEARCH_OT_Commands, IK2FK_OT_button, FK2IK_OT_button, - CLEAR_OT_Pose, MATERIAL_OT_up, MATERIAL_OT_down, DEFAULT_OT_material, - OPTIMIZE_OT_material, - SEARCH_OT_morph, TRANS_OT_Rigify, MATCH_OT_ikfk, LIMB_OT_redraw, EXP_OT_morph, SCULPT_OT_push, - IMP_OT_ENV, - REMOVE_DAZ_OT_button, - - + + ) def register(): for cls in classes: bpy.utils.register_class(cls) init_props() + def unregister(): for cls in classes: bpy.utils.unregister_class(cls) diff --git a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/dependencies/link_library.blend b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/dependencies/link_library.blend index 0d54b419..6983d4ec 100644 Binary files a/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/dependencies/link_library.blend and b/Blender/appdata_common/Blender Foundation/Blender/BLENDER_VERSION/scripts/addons/DTB/dependencies/link_library.blend differ diff --git a/Daz Studio/appdir_common/scripts/support/DAZ/Daz to Blender.dsa b/Daz Studio/appdir_common/scripts/support/DAZ/Daz to Blender.dsa index 7d7b150f..752cf34e 100644 --- a/Daz Studio/appdir_common/scripts/support/DAZ/Daz to Blender.dsa +++ b/Daz Studio/appdir_common/scripts/support/DAZ/Daz to Blender.dsa @@ -2,10 +2,15 @@ (function(){ + var s_sDazBridgeName = "Daz To Blender" var s_oFileInfo = new DzFileInfo( getScriptFileName() ); - var s_sToolName = s_oFileInfo.baseName(); + var s_sScriptPath = s_oFileInfo.path(); + // To be able to use the IDE Input your absolute Path. + //s_sScriptPath = "I:/Scripts/Git Repos/DazToBlender/Daz Studio/appdir_common/scripts/support/DAZ" + var s_sToolName = s_sDazBridgeName; + var s_sMorphDialog = "DzBlenderMorphSelectionDialog" s_oFileInfo.deleteLater(); - + var s_aFigures = []; var s_aEnvProp = []; @@ -29,16 +34,15 @@ }; var s_nExportType = s_oExportTypes.None; + var s_sRootPath = ""; + var s_sPresetPath = ""; + var s_sMorphRules = ""; var s_aMorphExported = []; - var s_sRootPath = ""; + var s_oMorphLinks = {}; - var s_oMorphs = {}; - var s_aSearch = []; var s_nLenName = 0; var s_nMaxName = 19; - var s_nMaxAll = 63; - var s_s3Spaces = " "; var s_sAlf = "1234567890abcdefghijklmnopqrstuvwxyz"; var s_vecDef = new DzVec3( 0, 0, 0 ); @@ -46,71 +50,96 @@ var s_mtxDef = new DzMatrix3( s_quatDef ); var s_aPoseData = []; - + var s_oOrgName = {}; + // Setting variables var s_nSubDivLevel; var s_bIncludeAnim; + + + +// --- START Sub Script ---- + /********************************************************************** + + The following is derived from a work published as part of the + Daz Script Documentation. This portion of the script, and/or any + portion thereof, may only be used in accordance with the + following license: + + Creative Commons Attribution 3.0 Unported (CC BY 3.0) + - http://creativecommons.org/licenses/by/3.0 + + **********************************************************************/ + // Source: http://docs.daz3d.com/doku.php/public/software/dazstudio/4/referenceguide/scripting/api_reference/samples/remote_operation/sub_script/start + + // - Extracted functions + // - Returns Scripts Paramater + // - Adjusted to be used within bridge /*********************************************************************/ - // void : ... - // Note: destructive - modifies the scene contents - // TODO: Redo Morph export need to give users a choice - function buildMorphList( oNode ) - { - if( oNode.inherits( "DzFigure" ) ){ - oNode = oNode.getSkeleton(); - var aProperties = getElementProperties( oNode, true, true ); - } - else{ - var aProperties = getElementProperties( oNode, true, true ); - } - var nAlfIdx = 0; - var aTops = [ "Morphs", "Hidden", "Pose" ]; - - var oProp; - var oOwner; - var oTop; - var sPath; - var sHead; - var sLabel; - var sTmp; - - for( var i = 0; i < aProperties.length; i += 1 ){ - oProp = aProperties[i]; - oOwner = oProp.getOwner(); - sPath = oProp.getPath(); - sHead = ""; - - for( var j = 0; j < aTops.length; j += 1 ){ - oTop = aTops[j]; - if( sPath.indexOf( "/" + oTop ) == 0 ){ - sHead = "<" + oTop + ">"; - break; - } - } - - if( sHead.isEmpty() ){ - continue; + // Object? + function executeSubScript( sScript, aArgs ){ + + /*********************************************************************/ + // String : A function for retrieving a translation if one exists + function text( sText ) + { + // If the version of the application supports qsTr() + if( typeof( qsTr ) != "undefined" ){ + // Return the translated (if any) text + return qsTr( sText ); } - - sLabel = oProp.getLabel(); - if( ( sLabel.length + 2 + s_nMaxName ) > s_nMaxAll ){ - sLabel = sLabel.slice( 0, s_nMaxAll - s_nMaxName - 2 - 2 ); - sLabel = sLabel + "_" + s_sAlf.substr( nAlfIdx, 1 ); - oOwner.name = sLabel; - nAlfIdx += 1; - nAlfIdx = nAlfIdx % 36; + + // Return the original text + return sText; + }; + + /*********************************************************************/ + // Declare working variables + var sTitle, sMessage; + + // Define common strings + var sButton = text( "&OK" ); + + // Define the base path of the script we'll call; without the file extension + var sBasePath = String( "%1/%2" ).arg( s_sScriptPath ).arg( sScript ); + + // Create a script object + var oScript = new DzScript(); + + // Attempt to find our script; doing it this way, we can debug with an + // ascii file and distribute a binary [encrypted] file with the same name... + // without having to update the contents of the script or manually handle + // the file extensions; requires 3.0.1.5 or newer + var sScriptPath = oScript.getScriptFile( sBasePath ); + + // If a script is found + if( !sScriptPath.isEmpty() ){ + // If the script loads + if( oScript.loadFromFile( sScriptPath ) ){ + // Execute the script; pass in an array of arguments; + // passing in arguments requires 2.2.2.17 or newer + oScript.execute( aArgs ); + return oScript.result(); + // If the script doesn't load + } else { + // Define text variables for the message + sTitle = text( "Read Error" ); + sMessage = text( "The '%1' file could not be loaded." ).arg( sScriptPath ); + // Inform the user + MessageBox.information( sMessage, sTitle, sButton ); } - - sName = oProp.getName() - s_oMorphs[sLabel] = { - "sMorphHead": sHead, - "sMorphName" : sName, - "sMorphPath" : sPath - }; + // If a script is not found + } else { + // Define text variables for the message + sTitle = text( "File Not Found" ); + sMessage = text( "A '%1.ds(a|b|e)' file could not be found." ).arg( sBasePath ); + // Inform the user + MessageBox.information( sMessage, sTitle, sButton ); } }; - + +// --- END Sub Script ---- // --- START node_properties ---- /********************************************************************** @@ -127,7 +156,7 @@ // Source: http://docs.daz3d.com/doku.php/public/software/dazstudio/4/referenceguide/scripting/api_reference/samples/properties/node_properties/start // - Extraccted functions - + /*********************************************************************/ // Array : A function for getting a list of the properties in a group function getGroupProperties( oGroup, bTraverse, bRecurse ) @@ -187,7 +216,7 @@ // Return the properties for the element return getGroupProperties( oPropertyGroup, bTraverse, bRecurse ); }; - + // --- END node_properties ---- @@ -505,81 +534,6 @@ // --- END export_obj_silent ---- - /*********************************************************************/ - // Array : ... - // TODO: Only export base Morphs - function getMinimalMorphRules() - { - var sResult; - - for( sMorphLabel in s_oMorphs ){ - var sMorphPath = s_oMorphs[sMorphLabel]['sMorphPath'] - var sMorphName = s_oMorphs[sMorphLabel]['sMorphName'] - if( sMorphPath.indexOf( '/Head' ) > 0 ){ - if( sMorphPath.endsWith( 'Expressions' ) ){ - sResult += sMorphName + "\n1\n"; - s_aMorphExported.push( sMorphName ); - } - if( sMorphPath.indexOf( '/Expressions' ) < 0 ){ - sResult += sMorphName + "\n1\n"; - s_aMorphExported.push( sMorphName ); - } - } - } - - return sResult; - }; - - /*********************************************************************/ - // Array : ... - // TODO: Add better customization for Presets - function getMorphPresets( sPreset ) - { - var sResult - - for( sMorphLabel in s_oMorphs ){ - var sMorphPath = s_oMorphs[sMorphLabel]['sMorphPath'] - var sMorphName = s_oMorphs[sMorphLabel]['sMorphName'] - if ( sPreset == "All Body Morphs" ){ - if ( sMorphPath.indexOf( '/Arms' ) > 0 - || sMorphPath.indexOf( '/Hip' ) > 0 - || sMorphPath.indexOf( '/Torso' ) > 0 - || sMorphPath.indexOf( '/Neck' ) > 0 - || sMorphPath.indexOf( '/Legs' ) > 0 - || sMorphPath.indexOf( '/Hands' ) > 0 - || sMorphPath.indexOf( '/Feet' ) > 0 ){ - sResult += sMorphName + "\n1\n"; - s_aMorphExported.push(sMorphName ); - } - } - else{ - if ( sMorphPath.indexOf( '/Head' ) > 0 ){ - if ( sPreset == "Face Controls" ){ - if(!( sMorphPath.indexOf( 'Expressions' ) > 0 - || sMorphPath.indexOf( 'Visemes' ) > 0 ) ){ - sResult += sMorphName + "\n1\n"; - s_aMorphExported.push( sMorphName ); - } - } - if ( sPreset == "Expressions" ){ - if( sMorphPath.indexOf( 'Expressions' ) > 0 ){ - sResult += sMorphName + "\n1\n"; - s_aMorphExported.push( sMorphName ); - } - } - if ( sPreset == "Visemes" ){ - if ( sMorphPath.indexOf( 'Visemes' ) > 0 ){ - sResult += sMorphName + "\n1\n"; - s_aMorphExported.push( sMorphName ); - } - } - } - } - } - - return sResult; - }; - /*********************************************************************/ // void : ... @@ -593,193 +547,6 @@ wDlg.addWidget( wLabel ); }; - /*********************************************************************/ - // Boolean : ... - // TODO: Replace a listbox for a more functional option, Allow user to Choose From Their Expressions - function promptMorphRules( oNode ) - { - - var wDlg = new DzBasicDialog(); - wDlg.caption = s_sToolName + ": Morph Names"; - - var sKey = wDlg.caption.replace( / /g, "" ) + "Dlg"; - - if( oNode ){ - wDlg.caption += " - " + oNode.getLabel(); - } - - var oDlgWgt = wDlg.getWidget(); - oDlgWgt.objectName = sKey; - - //addBanner( wDlg, App.getResourcesPath() + "/images/bridges/" + s_sToolName + ".png" ); - - var wMinimalMorphsCbx = new DzCheckBox( wDlg ); - wMinimalMorphsCbx.text = qsTr( "Include Minimal Morphs" ); - wMinimalMorphsCbx.checked = true; - wDlg.addWidget( wMinimalMorphsCbx ); - - var wLbl = new DzLabel( wDlg ); - wDlg.addWidget( wLbl ); - - var wMorphNamesLbl = new DzLabel( wDlg ); - wMorphNamesLbl.text = qsTr( "Morph Names: (line separated)\n[empty = OK, partial words = OK, 3+ letters required]" ); - wDlg.addWidget( wMorphNamesLbl ); - - var wMorphNamesTEdit = new DzTextEdit( wDlg ); - wMorphNamesTEdit.text = ""; - wDlg.addWidget( wMorphNamesTEdit ); - - wLbl = new DzLabel( wDlg ); - wDlg.addWidget( wLbl ); - - var wValidMorphNamesLbl = new DzLabel( wDlg ); - wValidMorphNamesLbl.text = qsTr( "Valid Morph Names and Presets:\n[double-click to copy above]" ); - wDlg.addWidget( wValidMorphNamesLbl ); - - var aMorphList = [] - var wValidMorphNamesLBox = new DzListBox( wDlg ); - var sMorphHead; - var sMorphPath; - - for(var s_aMorphLabel in s_oMorphs) { - sMorphHead = s_oMorphs[s_aMorphLabel]["sMorphHead"]; - sMorphPath = s_oMorphs[s_aMorphLabel]["sMorphPath"]; - if( sMorphHead != "Hidden" ){ - var sMorphHeaders = sMorphPath.split("/") - aMorphList.push( - sMorphHeaders[sMorphHeaders.length - 2] + " " - + sMorphHeaders[sMorphHeaders.length - 1] + " :" - + s_s3Spaces + s_aMorphLabel - ); - } - } - - // Organize the Visible Morphs - aMorphList.sort() - - for( var sMorphLabel in s_oMorphs ){ - sMorphHead = s_oMorphs[sMorphLabel]["sMorphHead"]; - if( sMorphHead == "Hidden" ){ - aMorphList.push( sMorphHead + ":" + s_s3Spaces + sMorphLabel ); - } - } - - // Add a few temporary presets for ease of use. - wValidMorphNamesLBox.insertItem( "Presets:" + s_s3Spaces +"Face Controls" ); - wValidMorphNamesLBox.insertItem( "Presets:" + s_s3Spaces +"Expressions" ); - wValidMorphNamesLBox.insertItem( "Presets:" + s_s3Spaces +"Visemes" ); - wValidMorphNamesLBox.insertItem( "Presets:" + s_s3Spaces +"All Body Morphs" ); - - for( var i = 0; i < aMorphList.length; i += 1 ){ - wValidMorphNamesLBox.insertItem( aMorphList[i] ); - } - wDlg.addWidget( wValidMorphNamesLBox ); - - function addValidMorphName(){ - var sCurText = wValidMorphNamesLBox.currentText; - sCurText = sCurText.split( ":" + s_s3Spaces )[1]; - wMorphNamesTEdit.append( sCurText ); - }; - wValidMorphNamesLBox.doubleClicked.connect( wValidMorphNamesLBox, addValidMorphName ); - - var sizeHint = oDlgWgt.minimumSizeHint; - var nHeight = sizeHint.height; - var nWidth = sizeHint.width < 300 ? 300 : sizeHint.width; - wDlg.setFixedSize( nWidth, sizeHint.height * 2 ); - - if( !wDlg.exec() ){ - return false; - } - - if( wMinimalMorphsCbx.checked ){ - s_sMorphRules = getMinimalMorphRules(); - } - - createMorphRules( wMorphNamesTEdit.text.split( "\n" ) ); - - return true; - }; - - /*********************************************************************/ - // Take List of Morph Labels and Convert to Format for FBX Exporter - // void : ... - // TODO: Allow Partial Names to Export Morphs, Refactor Code to Grab Morph Info Cleaner - function createMorphRules( aMorphLabels ) - { - var sMorphName; - var sMorphLabel; - - // To do find a better way to stop if nothing is chosen - if ( aMorphLabels !==undefined ){ - for( var i = 0; i < aMorphLabels.length; i += 1 ){ - sMorphLabel = aMorphLabels[i]; - - if ( s_oMorphs[sMorphLabel] !== undefined ){ - - if (s_oMorphs[sMorphLabel]["sMorphHead"] == 'Pose' ){ - sMorphName = s_oMorphs[sMorphLabel]["sMorphName"]; - } - else{ - //Hidden Morphs do not have labels - sMorphName = sMorphLabel; - } - s_aMorphExported.push( sMorphName ); - } - else{ - s_sMorphRules += getMorphPresets( sMorphLabel ); - } - s_sMorphRules += sMorphName + "\n1\n"; - - } - } - s_sMorphRules += "Anything\n0"; - - return true; - }; - - /*********************************************************************/ - // void : ... - function writeBoneData( oBaseNode, sFilename ) - { - var oNode; - var vecOrigin; - var vecEnd; - - var aChildren = oBaseNode.getNodeChildren( true ); - var nChildren = aChildren.length; - - var aData = new Array( nChildren ); - - for( var i = 0; i < nChildren; i += 1 ){ - oNode = aChildren[i]; - if( !oNode.inherits( "DzBone" ) ){ - continue; - } - - vecOrigin = oNode.getOrigin( true ); - vecEnd = oNode.getEndPoint( true ); - - aData[i] = [ - oNode.name, - vecOrigin.x, - vecOrigin.y, - vecOrigin.z, - vecEnd.x, - vecEnd.y, - vecEnd.z - ] - .concat( getBoneTransformValues( oNode ) ) - .join( "," ); - } - - aData = aData.filter( Boolean ); - if( aData.length < 1 ){ - return; - } - - writeDataFile( aData, sFilename ); - }; - /*********************************************************************/ // Array : ... // TODO : refactor - efficiency @@ -841,7 +608,7 @@ var aChildren = oBaseNode.getNodeChildren( true ); for( var i = 0; i < aChildren.length; i += 1 ){ oNode = aChildren[i]; - if( getKigo( oNode ) == "B" ){ + if( getObjectType( oNode ) == "BONE" ){ oNode.setLocalPos( s_vecDef ); oNode.setLocalRot( s_quatDef ); oNode.setLocalScale( s_mtxDef ); @@ -852,7 +619,56 @@ oBaseNode.setLocalRot( s_quatDef ); oBaseNode.setLocalScale( s_mtxDef ); }; - + + /*********************************************************************/ + // Destructive Changes the names of the Assets in Daz + // void : ... + function updateName( oBaseNode, bIsFigure ) + { + s_aPoseData = []; + + var aTopNodes = oBaseNode.getNodeChildren( false ); + if( aTopNodes.length == 0 && !bIsFigure ){ + aTopNodes.push( oBaseNode ); + } + + var oTopNode; + + var aNodes = []; + + for( var i = 0; i < aTopNodes.length; i += 1 ){ + oTopNode = aTopNodes[i]; + if( bIsFigure && oTopNode.name != "hip" ){ + continue; + } + + if( i == 0 ){ + aNodes = aNodes.concat( oBaseNode, oTopNode, oTopNode.getNodeChildren( true ) ); + } else { + aNodes = aNodes.concat( oTopNode, oTopNode.getNodeChildren( true ) ); + } + } + + var nNodes = aNodes.length; + if( nNodes < 1 ){ + return; + } + + for( var i = 0; i < nNodes; i += 1 ){ + oNode = aNodes[i]; + sLabel =oNode.getLabel(); + sName = oNode.name; + if( sLabel in s_oOrgName ){ + oNode.setName(s_oOrgName[sLabel]) + } + else{ + s_oOrgName[sLabel] = sName + oNode.setName( sLabel ) + } + + }; + }; + /*********************************************************************/ // void : ... function writePoseData( oBaseNode, sFilename, bIsFigure ) @@ -887,40 +703,51 @@ } var oNode; - var sKigo; + var sObjectType; var vecPos; var quatRot; var mtxScale; var sLine; - - var aData = new Array( nNodes ); - + var oData = {}; + var oParent; for( var i = 0; i < nNodes; i += 1 ){ oNode = aNodes[i]; - sKigo = getKigo( oNode ); + sObjectType = getObjectType( oNode ); vecPos = oNode.getLocalPos(); quatRot = oNode.getLocalRot(); mtxScale = oNode.getLocalScale(); - - s_aPoseData.push( [ oNode.name, sKigo, vecPos, quatRot, mtxScale ] ); - - aData[i] = [ - oNode.getLabel(), - oNode.name, - sKigo, + oParent = oNode.getNodeParent(); + s_aPoseData.push( [ oNode.name, sObjectType, vecPos, quatRot, mtxScale ] ); + sLabel = oNode.getLabel(); + sName = oNode.name; + oName = oData[sName] = {}; + oName["Name"] = sName; + oName["Label"] = sLabel; + oName["Object Type"] = sObjectType; + if(sObjectType == "MESH"){ + oName["Object"] = oNode.getObject().name; + } + else{ + oName["Object"] = "EMPTY" + }; + oName["Position"] = [ vecPos.x, vecPos.y, - vecPos.z, + vecPos.z + ]; + oName["Rotation"] = [ oNode.getXRotControl().getLocalValue(), oNode.getYRotControl().getLocalValue(), oNode.getZRotControl().getLocalValue(), + ]; + oName["Scale"] = [ mtxScale.m11, mtxScale.m22, mtxScale.m33 - ].join( "," ); + ]; } - - writeDataFile( aData, sFilename ); + sData = JSON.stringify( oData, undefined, 4 ) + writeDataFile( sData, sFilename ); }; /*********************************************************************/ @@ -960,86 +787,94 @@ } } }; - + + /*********************************************************************/ + // void : ... + function changeLock ( oProperty, bLock ) { + if ( ! oProperty ) { + return; + } + oProperty.lock( bLock ); + } + /*********************************************************************/ // void : ... - // TODO : refactor - efficiency function setLock( oBaseNode, bLock, bIsFigure ) { var aNodes = oBaseNode.getNodeChildren( true ); if( !bIsFigure ){ aNodes.push( oBaseNode ); } - - var aAxis = [ "X", "Y", "Z" ]; - + var oNode; - var aProperties; - var oProperty; - var oOwner; - var aNames; - var sAxis; - + var oTransform; + for( var i = 0; i < aNodes.length; i += 1 ){ oNode = aNodes[i]; - if( getKigo( oNode ) == 'B' ){ + if( getObjectType( oNode ) == 'BONE' ){ continue; } + // Translations + oTransform = oNode.getXPosControl(); + changeLock( oTransform, bLock ); + oTransform = oNode.getYPosControl(); + changeLock( oTransform, bLock ); + oTransform = oNode.getZPosControl(); + changeLock( oTransform, bLock ); - aProperties = getElementProperties( oNode, true, true ); - for( var j = 0; j < aProperties.length; j += 1 ){ - oProperty = aProperties[ j ]; - oOwner = oProperty.getOwner(); - if( !oOwner.inherits( "DzBone" ) ){ - continue; - } - - for( var k = 0; k < aAxis.length; k += 1 ){ - sAxis = aAxis[k]; - aNames = [ sAxis + "Translate", sAxis + "Rotate", sAxis + "Scale" ]; - for( var m = 0; m < aNames.length; m += 1 ){ - if( oProperty.name == aNames[m] ){ - oProperty.lock( bLock ); - } - } - } - } + // Rotations + oTransform = oNode.getXRotControl(); + changeLock( oTransform, bLock ); + oTransform = oNode.getYRotControl(); + changeLock( oTransform, bLock ); + oTransform = oNode.getZRotControl(); + changeLock( oTransform, bLock ); + + // Scale + oTransform = oNode.getScaleControl(); + changeLock( oTransform, bLock ); + oTransform = oNode.getXScaleControl(); + changeLock( oTransform, bLock ); + curTransform = oNode.getYScaleControl(); + changeLock( oTransform, bLock ); + curTransform = oNode.getZScaleControl(); + changeLock( oTransform, bLock ); } }; /*********************************************************************/ // String : ... // TODO : rename - function getKigo( oNode ) + function getObjectType( oNode ) { if( oNode.inherits( "DzBone" ) ){ - return "B"; + return "BONE"; } if( oNode.inherits( "DzLight" ) ){ - return "L"; + return "LIGHT"; } if( oNode.inherits( "DzCamera" ) ){ - return "C"; + return "CAMERA"; } var oObject = oNode.getObject(); if( !oObject ){ - return "E"; + return "EMPTY"; } var oShape = oObject.getCurrentShape(); if( !oShape ){ - return "E"; + return "EMPTY"; } var oMesh = oShape.getGeometry(); if( !oMesh ){ - return "E"; + return "EMPTY"; } - return "M"; + return "MESH"; }; /*********************************************************************/ @@ -1075,7 +910,7 @@ /*********************************************************************/ // void : ... // Delete previous export - // TODO : refactor - efficiency + // TODO : Create a Config folder to Hold the User's Daz Directories function prepareForExport( nType ) { var oDir = new DzDir( "" ); @@ -1087,40 +922,56 @@ var sDelPath; var oDelDir = new DzDir( "" ); - var aSubs = [ "Documents", "DTB", s_sEnv, s_sFig ]; - for( var i = 0; i < aSubs.length; i += 1 ){ - sPath = s_sRootPath + aSubs[i] + "/"; - oDir.setPath( sPath ); - if( !oDir.exists() ){ - oDir.mkdir( sPath ); - } + var aRoot = ["Documents","DAZ 3D", "Bridges", s_sDazBridgeName, "Presets", "Exports"]; + var aSubs = [s_sEnv, s_sFig] + + for( var i = 0; i < aRoot.length; i += 1 ){ + // Create Base Directory + + sPath = s_sRootPath + aRoot[i] + "/"; - if( i < 2 ){ + if( i != 4 ){ s_sRootPath = sPath; - } else { - if( (i == 3 && nType == s_oExportTypes.EnvProp) - || (i == 2 && nType == s_oExportTypes.Figure) ){ - continue; - } - - oDir.setPath( sPath ); - - aFiles = oDir.getFilesFromDir( [], true ); - for( var j = 0; j < aFiles.length; j += 1 ){ - oDir.remove( aFiles[j] ); - } - - for( var j = 0; j < 100; j += 1 ){ - sDelPath = sPath + "/" + aSubs[i] + j; - oDelDir.setPath( sDelPath ); - if( oDelDir.exists() ){ - oDir.rmdir( sDelPath ); - } else { - break; - } + } + if ( i == 4 ){ + s_sPresetPath = sPath; + } + // Create Directories + oDir.setPath( sPath ); + if( !oDir.exists() ){ + oDir.mkdir( sPath ); } + }; + + // Create Type Directories + if(nType == s_oExportTypes.EnvProp ){ + sPath = s_sRootPath + aSubs[0] + "/" } - } + if(nType == s_oExportTypes.Figure ){ + sPath = s_sRootPath + aSubs[1] + "/" + } + + // Create Directories + oDir.setPath( sPath ); + if( !oDir.exists() ){ + oDir.mkdir( sPath ); + } + // Clear Directory + oDir.setPath( sPath ); + // Delete Files + aFiles = oDir.getFilesFromDir( [], true ); + for( var j = 0; j < aFiles.length; j += 1 ){ + oDir.remove( aFiles[j] ); + } + // Delete Dirs + var aDirs = oDir.entryList(); + for ( var j = 0; j < aDirs.length; j += 1 ){ + sDelPath = sPath + aDirs[j] + oDelDir.setPath( sDelPath ); + if( oDelDir.exists() ){ + oDelDir.rmdir( sDelPath ); + } + }; }; /*********************************************************************/ @@ -1398,10 +1249,15 @@ return; } - - for( var i = 0; i < aData.length; i += 1 ){ - oFile.writeLine( aData[i] ); + if (aData.constructor === Array){ + for( var i = 0; i < aData.length; i += 1 ){ + oFile.writeLine( aData[i] ); + } + } + else{ + oFile.write( aData ) } + oFile.close(); }; @@ -1827,13 +1683,16 @@ vecSecondAxis.x, vecSecondAxis.y, vecSecondAxis.z - ].join(","); + ] + .concat( getBoneTransformValues( oNode ) ) + .join(","); } writeDataFile( aLimitsData, sFilename + "_boneLimits.csv" ); writeDataFile( aHeadTailData, sFilename + "_boneHeadTail.csv" ); writeDataFile( aSkeletonData, sFilename + "_skeletonData.csv" ); }; + /*********************************************************************/ // void : ... // Note: Configure DTU File @@ -1851,6 +1710,8 @@ aFigureMats = writeMaterials( oNode ); oDtuJson["Materials"].push( aFigureMats ); oDtuJson['Morphs'] = s_aMorphExported; + oDtuJson["MorphLinks"] = s_oMorphLinks; + if (nChildren > 0){ for ( var i = 0; i < nChildren; i++ ){ var oChild = aChildren[ i ]; @@ -1898,7 +1759,8 @@ var aProperties = []; var oMat = oShape.getMaterial( k ); if( oMat ){ - oMaterialInfo["Asset Name"] = oNode.getLabel(); + oMaterialInfo["Asset Name"] = oNode.name; + oMaterialInfo["Asset Label"] = oNode.getLabel(); oMaterialInfo["Material Name"] = oMat.getName(); oMaterialInfo["Material Type"] = oMat.getMaterialName(); @@ -1918,6 +1780,7 @@ var oPropertyInfo = {}; oPropertyInfo["Name"] = oProperty.getName(); + oPropertyInfo["Label"] = oProperty.getLabel(); var bImageProperty = oProperty.inherits( "DzImageProperty" ); var bColorProperty = oProperty.inherits( "DzColorProperty" ); @@ -1967,6 +1830,73 @@ } }; + /*********************************************************************/ + // String : Get the name of the Property + function getPropertyName( oProperty ) + { + var sPropertyName = oProperty.name; + var oOwnerProperty = oProperty.getOwner(); + if( oOwnerProperty.inherits( "DzMorph" ) ){ + sPropertyName = oOwnerProperty.name; + } + return sPropertyName; + }; + /*********************************************************************/ + // String : Returns the morph rules to be used at Export + function getMorphString(s_aMorphsToExport){ + var aMorphNamesToExport; + var sMorphString + + if ( s_aMorphsToExport.length == 0 ) + { + return ""; + } + aMorphNamesToExport = []; + sMorphString = ""; + for( var i = 0; i < s_aMorphsToExport.length; i++ ){ + oMorphInfo = s_aMorphsToExport[i] + aMorphNamesToExport.push( oMorphInfo.name ); + } + sMorphString = aMorphNamesToExport.join("\n1\n"); + sMorphString += "\n1\n.CTRLVS\n2\nAnything\n0"; + return sMorphString; + }; + + /*********************************************************************/ + // Void : Load morph links that are directly controlled by skeleton bones + function loadMorphLinks( aExportableProperties ) + { + // Load all the controller links on the properties + for( var i = 0; i < aExportableProperties.length; i += 1 ){ + var oMorphProperty = aExportableProperties[i].property; + var nControllerCount = oMorphProperty.getNumControllers(); + var aLinks = [] + for( var j = 0; j < nControllerCount; j += 1 ){ + var oErcLink = new DzERCLink(); + oErcLink = oMorphProperty.getController( j ); + var oControllerProp = oErcLink.getProperty(); + + var oLink = { + "Bone": "None", + "Property": getPropertyName( oControllerProp ), + "Type": oErcLink.type, + "Scalar": oErcLink.scalar, + "Addend": oErcLink.addend + }; + var oOwnerNode = oControllerProp.getOwner(); + if( oOwnerNode.inherits( "DzBone" ) ){ + oLink["Bone"] = oOwnerNode.name + } + aLinks.push( oLink ); + } + if( aLinks.length > 0 ){ + s_oMorphLinks[getPropertyName( oMorphProperty )] = aLinks; + } + } + + return; + }; + /*********************************************************************/ // void : ... function main() @@ -2025,15 +1955,20 @@ makeEndDir( i, s_sFig ); setSubDivLevelAll( oFigure ); - buildMorphList( oFigure ); - if( !promptMorphRules( oFigure) ){ - continue; - } + // Define Subscripts + aExportableProperties = executeSubScript( + s_sMorphDialog, + [oFigure, s_sPresetPath, s_sDazBridgeName] + ); + + s_sMorphRules = getMorphString( aExportableProperties ); + loadMorphLinks( aExportableProperties ); + // Write data sFileBasename = String( "%1%2/%2%3/%2" ).arg( s_sRootPath ).arg( s_sFig ).arg( i ); writeFigureBoneData( oFigure, sFileBasename ); - writePoseData( oFigure, sFileBasename + ".csv", true ); + writePoseData( oFigure, sFileBasename + ".transforms", true ); writeParentingData( oFigure, sFileBasename + ".dat" ); writeConfiguration( oFigure, sFileBasename ); @@ -2054,7 +1989,7 @@ var bIsBone; var sEnvPath; var sPoseFilename; - var sBoneFilename; + var sFileBasename; for( var i = 0; i < s_aEnvProp.length; i += 1 ){ oNode = s_aEnvProp[i]; @@ -2078,20 +2013,23 @@ applyDefaultTransforms( oNode ); } + updateName( oNode ); + exportFBX( oNode, s_sEnv, i, bDebugFBX ); sFileBasename = sEnvPath + s_sEnv; - sPoseFilename = sFileBasename + ".csv"; - sBoneFilename = sFileBasename + ".bon"; - - writeConfiguration( oNode, sFileBasename ); + sPoseFilename = sFileBasename + ".transforms"; + if( bIsBone ){ - writeBoneData( oNode, sBoneFilename ); + writeFigureBoneData( oNode, sFileBasename ); } else { writePoseData( oNode, sPoseFilename, false ); writeMemo( sEnvPath + "nobone.txt", "not skeleton" ); } + updateName( oNode ); + writeConfiguration( oNode, sFileBasename ); + setLock( oNode, false, false ); } } @@ -2102,5 +2040,5 @@ /*********************************************************************/ main(); - + })(); \ No newline at end of file diff --git a/Daz Studio/appdir_common/scripts/support/DAZ/DzBlenderMorphSelectionDialog.dsa b/Daz Studio/appdir_common/scripts/support/DAZ/DzBlenderMorphSelectionDialog.dsa new file mode 100644 index 00000000..3a1e8d1b --- /dev/null +++ b/Daz Studio/appdir_common/scripts/support/DAZ/DzBlenderMorphSelectionDialog.dsa @@ -0,0 +1,642 @@ +// DAZ Studio version 4.15.0.2 filetype DAZ Script + +(function( aArgs ){ + // Imported Arguments + var s_oNode; + var s_sDazBridgeName = ""; + var s_sPresetPath = ""; + + // Returned Values + var s_sMorphRules = ""; + + // Static Arrays + var s_aMorphList = []; + var s_aMorphsToExport = []; + + // Static Objects + var s_oMorphs = {}; + var s_oMorphsForNode = {}; + var s_oSelectedInTree = {}; + + // Static Widgets + var s_wMorphTreeWidget = null; + var s_wMorphListWidget = null; + var s_wMorphExportListWidget = null; + var s_wFilterEdit = null; + var s_wPresetCombo = null; + + /*********************************************************************/ + // void : ... + // TODO: Find a better method to setup of Variables + function initilizeArgs(){ + for( var i = 0, nArgs = aArgs.length; i < nArgs; i += 1 ){ + vArg = aArgs[i]; + sType = typeof( vArg ); + if( sType == "object" ){ + s_oNode = vArg + } + else{ + if( vArg.indexOf( "Documents" ) > 0 ){ + s_sPresetPath = vArg; + } + else{ + s_sDazBridgeName = vArg; + }; + }; + }; + + }; + + /*********************************************************************/ + // void : ... + function morphInfo( sName, sLabel, sPath, sType, oProperty ){ + this.name = sName; + this.label = sLabel; + this.path = sPath; + this.type = sType; + this.property = oProperty; + }; + + /*********************************************************************/ + // void : ... + // TODO: Create A Struct that can be used to create items in a more organizedway + function sortListItem(){ + DzListViewItem(s_wMorphListWidget); + }; + + /*********************************************************************/ + // void : ... + function morphSelectionDialog( wDlg ){ + // Get the current style + var oStyle = App.getStyle(); + // Get the general margin + var nMargin = oStyle.pixelMetric( "DZ_GeneralMargin" ) + + // Set the dialog title + wDlg.caption = "Select Morphs"; + + var wMainWgt = new DzWidget( wDlg ); + + // Create Layouts + var lytMain = new DzVBoxLayout( wMainWgt ); + lytMain.margin = nMargin; + lytMain.spacing = nMargin; + var lytSettings = new DzHBoxLayout( lytMain ); + lytSettings.margin = nMargin; + lytSettings.spacing = nMargin; + var lytMorphs = new DzHBoxLayout( lytMain ); + lytMorphs.margin = nMargin; + lytMorphs.spacing = nMargin; + var lytTree = new DzVBoxLayout( lytMorphs ); + lytTree.margin = nMargin; + lytTree.spacing = nMargin; + var lytMorphList = new DzVBoxLayout( lytMorphs ); + lytMorphList.margin = nMargin; + lytMorphList.spacing = nMargin; + var lytSelectedList = new DzVBoxLayout( lytMorphs ); + lytSelectedList.margin = nMargin; + lytSelectedList.spacing = nMargin; + + // Left tree with morph structure + s_wMorphTreeWidget = new DzListView( wMainWgt ); + s_wMorphTreeWidget.resizeMode = DzListView.Maximum + s_wMorphTreeWidget.widthMode = DzListView.NoColumn + s_wMorphTreeWidget.addColumn("") + s_wMorphTreeWidget.rootIsDecorated = true; + s_wMorphTreeWidget.treeStepSize = 20; + + // Center list showing morphs for selected tree items + s_wMorphListWidget = new DzListView( wMainWgt ); + s_wMorphListWidget.resizeMode = DzListView.Maximum + s_wMorphListWidget.widthMode = DzListView.NoColumn + s_wMorphListWidget.addColumn("") + s_wMorphListWidget.selectionMode = DzListView.Extended + + + // Right list showing morphs that will export + s_wMorphExportListWidget = new DzListView( wMainWgt ); + s_wMorphExportListWidget.resizeMode = DzListView.Maximum + s_wMorphExportListWidget.widthMode = DzListView.NoColumn + s_wMorphExportListWidget.addColumn("") + s_wMorphExportListWidget.selectionMode = DzListView.Extended + + + // Quick filter box + var wFilterLabel = new DzLabel( wMainWgt ); + wFilterLabel.text = 'filter' + s_wFilterEdit = new DzLineEdit( wMainWgt ); + + + // Presets + var wChoosePresetLabel = new DzLabel( wMainWgt ); + wChoosePresetLabel.text = "Choose Preset"; + var wSavePresetButton = new DzPushButton( wMainWgt ); + wSavePresetButton.text = "Save Preset"; + s_wPresetCombo = new DzComboBox( wMainWgt ); + lytSettings.addWidget( wChoosePresetLabel ); + lytSettings.addWidget( s_wPresetCombo ); + lytSettings.addWidget( wSavePresetButton ); + lytSettings.addStretch(); + + + // Left Tree + var wMorphGrpLabel = new DzLabel( wMainWgt ); + wMorphGrpLabel.text = 'Morph Groups'; + var wAvailMorphLabel = new DzLabel( wMainWgt ); + wAvailMorphLabel.text = 'Select to see available morphs'; + lytTree.addWidget( wMorphGrpLabel ); + lytTree.addWidget( wAvailMorphLabel ); + lytTree.addWidget( s_wMorphTreeWidget ); + + // TODO: Add buttons + + // Center List of morphs based on tree selection + var wMorphSelGrpLabel = new DzLabel( wMainWgt ) + wMorphSelGrpLabel.text = 'Morphs in Group'; + var wAvailSelMorphLabel = new DzLabel( wMainWgt ) + wAvailSelMorphLabel.text = 'Select and click Add for Export'; + lytMorphList.addWidget( wMorphSelGrpLabel ); + lytMorphList.addWidget( wAvailSelMorphLabel ); + var lytFilter = new DzVBoxLayout( lytMorphList ); + lytFilter.margin = nMargin; + lytFilter.spacing = nMargin; + lytFilter.addWidget( wFilterLabel ) + lytFilter.addWidget( s_wFilterEdit ); + lytMorphList.addWidget( s_wMorphListWidget ); + + // Button for adding morphs + var wAddMorphsButton = new DzPushButton( wMainWgt ); + wAddMorphsButton.text = "Add For Export"; + lytMorphList.addWidget( wAddMorphsButton ); + + // Right List of morphs that will export + var wMorphExportLabel = new DzLabel( wMainWgt ); + wMorphExportLabel.text = 'Morphs to Export'; + lytSelectedList.addWidget( wMorphExportLabel ); + lytSelectedList.addWidget( s_wMorphExportListWidget ); + + // Button for clearing morphs from export + var wRemoveMorphsButton = new DzPushButton( wMainWgt ); + wRemoveMorphsButton.text = "Remove From Export"; + lytSelectedList.addWidget( wRemoveMorphsButton ); + + wDlg.addWidget( wMainWgt ); + wDlg.setFixedWidth( 800 ); + wDlg.setFixedHeight( 800 ); + refreshPresetsCombo(); + + // Create Connections + connect( s_wMorphTreeWidget, "currentChanged(DzListViewItem*)",itemSelectionChanged ) + connect( s_wFilterEdit, "textChanged(const QString&)", filterChanged ); + wSavePresetButton.released.connect( handleSavePreset ) + wAddMorphsButton.released.connect( handleAddMorphsButton ) + wRemoveMorphsButton.released.connect( handleRemoveMorphsButton ) + }; + + + /*********************************************************************/ + // void : ... + // Build out the Left morphs tree based on the current selection + function prepareDialog(){ + var oSelectedNode; + var oParentNode; + var oParentFigureNode; + + oSelectedNode = s_oNode; + // For item like clothing, create the morph list from the character + oParentNode = oSelectedNode; + if (oParentNode = oSelectedNode.getNodeParent()){ + if(oParentNode.inherits( "DzFigure" )){ + oParentFigureNode = oParentNode.getSkeleton(); + oSelectedNode = oParentFigureNode; + } + }; + + s_oMorphs = {}; + s_aMorphList = getAvailableMorphs( oSelectedNode ); + for ( var i = 0; i < oSelectedNode.getNumNodeChildren(); i++ ){ + oChildNode = oSelectedNode.getNodeChild( i ); + s_aMorphList.push( getAvailableMorphs( oChildNode ) ); + }; + updateMorphsTree(); + handlePresetChanged("LastUsed.csv"); + }; + + /*********************************************************************/ + // void : ... + // When the filter text is changed, update the center list + function filterChanged(){ + var sNewFilter; + var oMorphInfo; + + s_wMorphListWidget.clear(); + sNewFilter = s_wFilterEdit.text.toLowerCase(); + s_wMorphListWidget.clear(); + for(var i = 0; i < s_oSelectedInTree.length; i++){ + oMorphInfo = s_oSelectedInTree[i] + if( sNewFilter == "" || sNewFilter.isEmpty() || oMorphInfo.label.toLowerCase().indexOf(sNewFilter) != -1 ) + { + oItem = DzListViewItem( s_wMorphListWidget ) + oItem.setText( 0 ,oMorphInfo.label ); + oItem.addDataItem( "name", oMorphInfo.name ); + } + } + + s_wMorphListWidget.sort(); + }; + + /*********************************************************************/ + // array : ... + function getAvailableMorphs( oNode ){ + var aNewMorphList; + var oObject; + var oShape; + var oProperty; + var oPresentation; + var sPropName; + var sPropLabel; + var oMorphInfo; + var sPath; + + + aNewMorphList = []; + oObject = oNode.getObject(); + if( oObject != null ){ + oShape = oObject.getCurrentShape(); + }; + for( var i = 0; i < oNode.getNumProperties(); i++ ){ + oProperty = oNode.getProperty( i ); + sPropName = oProperty.getName(); + sPropLabel = oProperty.getLabel(); + oPresentation = oProperty.getPresentation(); + if (oPresentation != undefined){ + sPath = oNode.getLabel() + "/" + oProperty.getPath(); + oMorphInfo = new morphInfo( + sPropName, + sPropLabel, + sPath, + oPresentation.type, + oProperty + ); + + if( !( oMorphInfo.name in s_oMorphs ) ){ + s_oMorphs[oMorphInfo.name] = oMorphInfo; + }; + }; + if (oPresentation != undefined && oPresentation.type == "Modifier/Shape"){ + aNewMorphList.push( sPropName ) + }; + } + if( oObject ){ + for( var i = 0; i < oObject.getNumModifiers(); i++ ){ + oModifer = oObject.getModifier( i ); + sModName = oModifer.getName(); + sModLabel = oModifer.getLabel(); + if(oModifer.inherits( "DzMorph" ) ){ + for( var j = 0; j < oModifer.getNumProperties(); j++ ){ + oProperty = oModifer.getProperty( j ); + sPropName = oProperty.getName(); + sPropLabel = oProperty.getLabel(); + oPresentation = oProperty.getPresentation(); + if (oPresentation != undefined){ + sPath = oNode.getLabel() + "/" + oProperty.getPath(); + oMorphInfo = new morphInfo( + sModName, + sPropLabel, + sPath, + oPresentation.type, + oProperty + ); + if( !( oMorphInfo.name in s_oMorphs ) ){ + s_oMorphs[oMorphInfo.name] = oMorphInfo; + }; + }; + }; + }; + }; + }; + return aNewMorphList + }; + + /*********************************************************************/ + // void : ... + // Build out the left tree + function updateMorphsTree(){ + var sPath; + var sPathPart; + var sMorph; + var oParentItem; + var sID; + + s_wMorphTreeWidget.clear(); + s_oMorphsForNode = {}; + for( sMorph in s_oMorphs ){ + sPath = s_oMorphs[sMorph].path; + aPathParts = sPath.split("/"); + oParentPath = aPathParts[0] + oParentItem = null; + for( var i = 0; i < aPathParts.length; i++ ){ + sPathPart = aPathParts[i]; + // Used to Match to correct node. + sID = oParentPath + "/" + sPathPart; + if( sPathPart == "" ){ + continue; + }; + oParentItem = findTreeItem( oParentItem, sPathPart, sID ); + if( !( sID in s_oMorphsForNode ) ){ + s_oMorphsForNode[sID] = [] + }; + + s_oMorphsForNode[sID].push(s_oMorphs[sMorph]); + }; + }; + + }; + + /*********************************************************************/ + // void : ... + // This function could be better named. It will find the node matching the property path + // but it will also create the structure of that path in the tree as needed as it searches + function findTreeItem( oParent, sName, sID ){ + if ( oParent == null ){ + oItem = s_wMorphTreeWidget.findItem( sName, 0 ); + if(oItem != null){ + if (oItem.text( 0 ) == sName){ + return oItem; + }; + }; + + oNewItem = new DzListViewItem( s_wMorphTreeWidget ); + oNewItem.addDataItem("id", sID ); + oNewItem.setText( 0, sName ); + oNewItem.open = true; + oNewItem.expandable = true; + return oNewItem; + } + else{ + oItem = oParent.firstChild(); + while(oItem){ + if( oItem.text( 0 ) == sName ){ + return oItem; + }; + oItem = oItem.nextSibling(); + }; + oNewItem = new DzListViewItem( oParent ); + oNewItem.setText( 0, sName ); + oNewItem.open = true; + oNewItem.expandable = true; + oNewItem.addDataItem("id", sID ); + oParent.insertItem( oNewItem ); + return oNewItem; + }; + }; + + /*********************************************************************/ + // void : ... + // For selection changes in the Left Tree + function itemSelectionChanged(){ + s_oSelectedInTree = {}; + selectMorphsInNode(s_wMorphTreeWidget.currentItem()); + filterChanged(); + }; + + /*********************************************************************/ + // void : ... + // Updates the list of selected morphs in the Left Tree + // including any children + function selectMorphsInNode( oSelectedItem ){ + sId = oSelectedItem.getDataItem("id"); + if (sId in s_oMorphsForNode){ + s_oSelectedInTree = s_oMorphsForNode[sId]; + }; + }; + + /*********************************************************************/ + // void : ... + // Add Morphs for export + function handleAddMorphsButton(){ + for(var i = 0; i < s_oSelectedInTree.length; i++){ + oMorphInfo = s_oSelectedInTree[i] + oItem = s_wMorphListWidget.findItem( oMorphInfo.label, 0 ); + if(oItem != null){ + if(oItem.selected){ + sMorphName = oItem.getDataItem("name"); + if(sMorphName in s_oMorphs + && !( s_oMorphs[sMorphName] in s_aMorphsToExport ) ){ + s_aMorphsToExport.push( s_oMorphs[sMorphName] ); + }; + }; + }; + }; + refreshExportMorphList(); + refreshPresetsCombo(); + }; + + /*********************************************************************/ + // void : ... + // Remove morph from export list + function handleRemoveMorphsButton(){ + for(var i = 0; i < s_aMorphsToExport.length; i++){ + oMorphInfo = s_aMorphsToExport[i] + oItem = s_wMorphExportListWidget.findItem( oMorphInfo.label, 0 ); + if(oItem != null){ + if(oItem.selected){ + sMorphName = oItem.getDataItem("name"); + s_aMorphsToExport.splice( i, 1 ); + i--; + }; + }; + }; + refreshExportMorphList(); + refreshPresetsCombo(); + }; + + /*********************************************************************/ + // void : ... + // Brings up a dialog for choosing a preset name + function handleSavePreset(){ + var sFile; + var sFilters; + + sFilters = "CSV Files (*.csv)"; + sFile = FileDialog.doFileDialog( + false, + qsTr( "Save Preset" ), + s_sPresetPath, + sFilters ) + if( sFile != null ){ + savePresetFile( sFile ); + }; + }; + + /*********************************************************************/ + // void : ... + // Saves out a preset. If the path isn't supplied, it's saved as the last selection + function savePresetFile( sFilePath ){ + var oDir; + var oFile; + + oDir = new DzDir( "" ); + oDir.setPath( s_sPresetPath ); + if (sFilePath == null){ + sFilePath = s_sPresetPath + "LastUsed.csv"; + } + oFile = new DzFile( sFilePath ); + if( !oFile.open( DzFile.WriteOnly ) ){ + print( String( "Unable to open \"%1\" for writing." ).arg( sFilePath ) ); + oFile.close(); + return; + }; + + oData = getMorphCSVString(); + if (oData.constructor === Array){ + for( var i = 0; i < oData.length; i += 1 ){ + oFile.writeLine( oData[i] ); + }; + } + else{ + oFile.write( oData ) + }; + oFile.close(); + refreshPresetsCombo(); + + }; + + /*********************************************************************/ + // void : ... + // Refresh the Right export list + function refreshExportMorphList(){ + s_wMorphExportListWidget.clear(); + + for(var i = 0; i < s_aMorphsToExport.length; i++){ + oMorphInfo = s_aMorphsToExport[i] + oItem = DzListViewItem( s_wMorphExportListWidget ) + oItem.setText( 0 ,oMorphInfo.label ); + oItem.addDataItem( "name", oMorphInfo.name ); + }; + savePresetFile( null ); + }; + + /*********************************************************************/ + // void : ... + // Refresh the list of preset csvs from the files in the folder + function refreshPresetsCombo(){ + // Need to understand disconnecting signals + disconnect(s_wPresetCombo, "currentIndexChanged(const QString&)", handlePresetChanged); + var oDir; + var sPath; + + s_wPresetCombo.clear(); + s_wPresetCombo.addItem( "None" ); + + oDir = new DzDir( "" ); + oDir.setPath( s_sPresetPath ); + aPaths = oDir.entryList( "*csv" ); + for( var i = 0; i < aPaths.length; i++ ){ + sPath = aPaths[i] + s_wPresetCombo.addItem( sPath ) + } + connect(s_wPresetCombo, "currentIndexChanged(const QString&)", handlePresetChanged); + }; + + /*********************************************************************/ + // void : ... + // Call when the preset combo is changed by the user + function handlePresetChanged( sCustomName ){ + s_aMorphsToExport = []; + if( sCustomName != undefined ){ + sPresetFilePath = s_sPresetPath + sCustomName; + } + else{ + sPresetName = s_wPresetCombo.currentText; + sPresetFilePath = s_sPresetPath + sPresetName; + }; + oFile = new DzFile( sPresetFilePath ); + if( !oFile.open( DzFile.ReadOnly ) ){ + print( String( "Unable to open \"%1\" for Reading." ).arg( sPresetFilePath ) ); + oFile.close(); + return; + }; + + aMorphLines = oFile.readLines(); + for(var i = 0; i < aMorphLines.length; i++){ + sMorphLine = aMorphLines[i] + if( sMorphLine.indexOf( "\"Export\"" ) > 0 ){ + aItems = sMorphLine.split(","); + sMorphName = aItems[0].replace("\"", "").replace("\"", ""); + if ( sMorphName in s_oMorphs ) + { + s_aMorphsToExport.push( s_oMorphs[sMorphName] ); + }; + }; + }; + + refreshExportMorphList(); + oFile.close(); + }; + + /*********************************************************************/ + // string : ... + // Get the morph string in the format for the Daz FBX Export + function getMorphString(){ + var aMorphNamesToExport; + var sMorphString + + if ( s_aMorphsToExport.length == 0 ) + { + return ""; + } + aMorphNamesToExport = []; + sMorphString = ""; + for( var i = 0; i < s_aMorphsToExport.length; i++ ){ + oMorphInfo = s_aMorphsToExport[i] + aMorphNamesToExport.push( oMorphInfo.name ); + } + sMorphString = aMorphNamesToExport.join("\n1\n"); + sMorphString += "\n1\n.CTRLVS\n2\nAnything\n0"; + return sMorphString; + }; + + /*********************************************************************/ + // string : ... + // Get the morph string in the format used for presets + function getMorphCSVString(){ + var sMorphString; + + s_aMorphList = []; + sMorphString = ""; + for( var i = 0; i < s_aMorphsToExport.length; i++ ){ + oMorphInfo = s_aMorphsToExport[i] + s_aMorphList.push(oMorphInfo.name); + sMorphString += "\"" + oMorphInfo.name + "\",\"Export\"\n"; + } + sMorphString += "\".CTRLVS\", \"Ignore\"\n"; + sMorphString += "\"Anything\", \"Bake\"\n"; + return sMorphString; + }; + + /*********************************************************************/ + function main(){ + var wDlg = new DzBasicDialog(); + initilizeArgs(); + morphSelectionDialog( wDlg ); + prepareDialog(); + // When user Cancels the dialog + if( !wDlg.exec() ){ + return false; + }; + return true + + }; + + /*********************************************************************/ + if(main()){ + return s_aMorphsToExport; + } + else{ + return [] + } + + +})( getArguments() ); +