Skip to content

Commit

Permalink
Merge pull request #67 from soupday/Dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
soupday authored Oct 4, 2024
2 parents 317f2f2 + d3fb129 commit a3b33f1
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 63 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ Known Issues
Changelog
=========

### 2.1.10
- Support for exporting MDProps.
- Update materials through the datalink will use exact name matching and will no longer update materials on partial name matches.

### 2.1.9
- Some UI Restructure.
- Fix to exporting Lite Avatars.
Expand Down
83 changes: 57 additions & 26 deletions btp/cc.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ def parse(self):
def json(self):
return self.mesh_json

def find_material_name(self, search_mat_name):
def find_material_name(self, search_mat_name, exact=False):
try_names = set()
try_names.add(search_mat_name)
try_names.add(safe_export_name(search_mat_name))
Expand All @@ -275,6 +275,8 @@ def find_material_name(self, search_mat_name):
trunc_mat_name = json_mat_name[:-13]
if json_mat_name in try_names or (trunc_mat_name and trunc_mat_name in try_names):
return json_mat_name
if exact:
return None
# try a partial match, but only if there is only one result
partial_mat_name = None
partial_mat_count = 0
Expand All @@ -293,8 +295,8 @@ def find_material_name(self, search_mat_name):
return partial_mat_name
return None

def find_material(self, search_mat_name):
mat_name = self.find_material_name(search_mat_name)
def find_material(self, search_mat_name, exact=False):
mat_name = self.find_material_name(search_mat_name, exact=exact)
cc_mat_json: CCMaterialJson = None
if mat_name:
cc_mat_json = self.materials[mat_name]
Expand Down Expand Up @@ -347,7 +349,7 @@ def parse(self):
def json(self):
return self.physics_mesh_json

def find_material_name(self, search_mat_name):
def find_material_name(self, search_mat_name, exact=False):
try_names = set()
try_names.add(search_mat_name)
try_names.add(safe_export_name(search_mat_name))
Expand All @@ -359,6 +361,8 @@ def find_material_name(self, search_mat_name):
trunc_mat_name = json_mat_name[:-13]
if json_mat_name in try_names or (trunc_mat_name and trunc_mat_name in try_names):
return json_mat_name
if exact:
return None
# try a partial match, but only if there is only one result
partial_mat_name = None
partial_mat_count = 0
Expand All @@ -377,8 +381,8 @@ def find_material_name(self, search_mat_name):
return partial_mat_name
return None

def find_material(self, search_mat_name):
mat_name = self.find_material_name(search_mat_name)
def find_material(self, search_mat_name, exact=False):
mat_name = self.find_material_name(search_mat_name, exact=exact)
cc_mat_json: CCPhysicsMaterialJson = None
if mat_name:
cc_mat_json = self.materials[mat_name]
Expand Down Expand Up @@ -531,7 +535,7 @@ def get_character_json(self):
utils.log("Could not find character json: " + self.character_id)
return None

def find_source_mesh_name(self, imported_mesh_name, imported_obj_name, rl_meshes):
def find_source_mesh_name(self, imported_mesh_name, imported_obj_name, rl_meshes, exact=False):
try_names = set()
try_names.add(imported_mesh_name)
try_names.add(safe_export_name(imported_mesh_name))
Expand All @@ -544,6 +548,8 @@ def find_source_mesh_name(self, imported_mesh_name, imported_obj_name, rl_meshes
for mesh_name in rl_meshes:
if mesh_name in try_names:
return mesh_name
if exact:
return None
# try a partial match, but only if there is only one result
partial_mesh_match = None
partial_mesh_count = 0
Expand All @@ -559,17 +565,14 @@ def find_source_mesh_name(self, imported_mesh_name, imported_obj_name, rl_meshes
return partial_mesh_match
return None

def find_mesh_name(self, search_mesh_name, search_obj_name = None):
return self.find_source_mesh_name(search_mesh_name, search_obj_name, self.meshes)

def find_mesh(self, search_mesh_name, search_obj_name = None):
mesh_name = self.find_mesh_name(search_mesh_name, search_obj_name)
def find_mesh(self, search_mesh_name, search_obj_name=None, exact=False):
mesh_name = self.find_source_mesh_name(search_mesh_name, search_obj_name, self.meshes, exact=exact)
cc_mesh_json: CCMeshJson = None
if mesh_name:
cc_mesh_json = self.meshes[mesh_name]
return cc_mesh_json

def find_physics_mesh_name(self, search_mesh_name, search_obj_name = None):
def find_physics_mesh_name(self, search_mesh_name, search_obj_name, rl_meshes, exact=False):
try_names = set()
if search_mesh_name:
try_names.add(search_mesh_name)
Expand All @@ -580,10 +583,25 @@ def find_physics_mesh_name(self, search_mesh_name, search_obj_name = None):
for mesh_name in self.physics_meshes:
if mesh_name in try_names:
return mesh_name
if exact:
return None
# try a partial match, but only if there is only one result
partial_mesh_match = None
partial_mesh_count = 0
for mesh_name in rl_meshes:
for try_name in try_names:
if try_name in mesh_name:
partial_mesh_count += 1
if not partial_mesh_match:
partial_mesh_match = mesh_name
# only count 1 match per try set
break
if partial_mesh_count == 1:
return partial_mesh_match
return None

def find_physics_mesh(self, search_mesh_name, search_obj_name = None):
mesh_name = self.find_physics_mesh_name(search_mesh_name, search_obj_name)
def find_physics_mesh(self, search_mesh_name, search_obj_name=None, exact=False):
mesh_name = self.find_physics_mesh_name(search_mesh_name, search_obj_name, self.physics_meshes, exact=exact)
cc_physics_mesh_json: CCPhysicsMeshJson = None
if mesh_name:
cc_physics_mesh_json = self.physics_meshes[mesh_name]
Expand Down Expand Up @@ -615,7 +633,8 @@ class CCMeshMaterial():
def __init__(self, actor = None, obj = None,
mesh_name = None, mat_name = None,
duf_mesh = None, duf_material = None,
physx_object = None, cc_json_data = None):
physx_object = None, cc_json_data = None,
exact=False):
self.actor = actor
self.obj = obj
self.actor_name = actor.GetName()
Expand All @@ -628,7 +647,7 @@ def __init__(self, actor = None, obj = None,
self.duf_material = duf_material
self.json_data = cc_json_data
if self.json_data:
self.find_json_data()
self.find_json_data(exact)

def material_component(self):
if not self.mat_component and self.actor:
Expand Down Expand Up @@ -866,20 +885,20 @@ def set_physics_param(self, json_param_name, param_value, folder = None):
else:
PC.SetSoftPhysXProperty(self.mesh_name, self.mat_name, phys_param_name, float(param_value))

def find_json_data(self):
def find_json_data(self, exact):
if self.json_data:
self.mesh_json = self.json_data.find_mesh(self.mesh_name, self.obj_name)
self.mesh_json = self.json_data.find_mesh(self.mesh_name, self.obj_name, exact=exact)
if self.mesh_json:
self.json_mesh_name = self.mesh_json.name
self.mat_json = self.mesh_json.find_material(self.mat_name)
self.mat_json = self.mesh_json.find_material(self.mat_name, exact=exact)
if self.mat_json:
self.json_mat_name = self.mat_json.name
else:
utils.log_warn(f"Material JSON {self.mat_name} not found!")
if self.physx_object:
self.physx_mesh_json = self.json_data.find_physics_mesh(self.json_mesh_name)
self.physx_mesh_json = self.json_data.find_physics_mesh(self.json_mesh_name, exact=exact)
if self.physx_mesh_json:
self.physx_mat_json = self.physx_mesh_json.find_material(self.json_mat_name)
self.physx_mat_json = self.physx_mesh_json.find_material(self.json_mat_name, exact=exact)
else:
utils.log_warn(f"Mesh JSON {self.obj_name}/{self.mesh_name} not found!")

Expand Down Expand Up @@ -933,7 +952,8 @@ def get_selected_mesh_materials(exclude_mesh_names=None, exclude_material_names=


def get_avatar_mesh_materials(avatar, exclude_mesh_names=None, exclude_material_names=None,
mesh_filter=None, material_filter=None, json_data=None):
mesh_filter=None, material_filter=None, json_data=None,
exact=False):

mesh_materials = []

Expand Down Expand Up @@ -976,7 +996,8 @@ def get_avatar_mesh_materials(avatar, exclude_mesh_names=None, exclude_material_
physics_object = get_actor_physics_object(avatar, mesh_name, mat_name)

M = CCMeshMaterial(actor=avatar, obj=obj, mesh_name=mesh_name, mat_name=mat_name,
physx_object=physics_object, cc_json_data=json_data)
physx_object=physics_object, cc_json_data=json_data,
exact=exact)

mesh_materials.append(M)

Expand Down Expand Up @@ -1366,7 +1387,7 @@ def get_object_type(obj):
T = type(obj)
if T is RIAvatar or T is RILightAvatar:
return "AVATAR"
elif T is RIProp:
elif T is RIProp or T is RIMDProp:
return "PROP"
elif T is RIAccessory:
return "ACCESSORY"
Expand Down Expand Up @@ -1728,6 +1749,16 @@ def print_node_tree(obj):
print_nodes(node)


def is_prop(obj):
T = type(obj)
return (T is RIProp or T is RIMDProp)


def is_avatar(obj):
T = type(obj)
return (T is RIAvatar or T is RILightAvatar)


IGNORE_NODES = ["RL_BoneRoot", "IKSolverDummy", "NodeForExpressionLookAtSolver"]

def get_actor_objects(actor):
Expand All @@ -1746,7 +1777,7 @@ def get_actor_objects(actor):
if avatar.GetAvatarType() != EAvatarType_Standard:
objects.append(avatar)

elif actor and type(actor) is RIProp:
elif actor and (T is RIProp or T is RIMDProp):
child_objects = RScene.FindChildObjects(actor, EObjectType_Avatar)
for obj in child_objects:
name = obj.GetName()
Expand Down
9 changes: 5 additions & 4 deletions btp/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ def __init__(self, objects, no_window=False):
self.create_options_window()

def collect_objects(self, objects):
self.avatars = [ o for o in objects if (type(o) is RIAvatar or type(o) is RILightAvatar) ]
self.props = [ o for o in objects if type(o) is RIProp ]
self.avatars = [ o for o in objects if cc.is_avatar(o) ]
self.props = [ o for o in objects if cc.is_prop(o) ]

def clear_objects(self):
self.avatars = []
Expand Down Expand Up @@ -181,8 +181,7 @@ def set_base_path(self, file_path, create=False, show=False):
def set_multi_paths(self, object, motion_only=False):
base_path = self.base_path
ext = ".iCCX"
T = type(object)
if T is RIAvatar or T is RILightAvatar or T is RIProp:
if cc.is_avatar(object) or cc.is_prop(object):
ext = ".Fbx"
name = object.GetName()
if motion_only:
Expand Down Expand Up @@ -672,6 +671,8 @@ def export_fbx(self):
export = "ANIMATION"
elif self.option_current_animation and num_frames > 0:
export = "CURRENT_POSE"
elif self.option_current_pose:
export = "CURRENT_POSE"
else:
export = "BIND"

Expand Down
41 changes: 22 additions & 19 deletions btp/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,21 +304,22 @@ def import_fbx(self):
return objects

def update_materials(self, obj):
if type(obj) is RLPy.RIAvatar or type(obj) is RLPy.RILightAvatar:
# NOTE: RILightAvatars and RIMDProps do not have material components so can't be updated.
if type(obj) is RLPy.RIAvatar:
self.avatar = obj
self.rebuild_materials()
self.rebuild_materials(update=True)
elif type(obj) is RLPy.RIProp:
objects = set()
objects.add(obj)
child_objects = RLPy.RGlobal.FindChildObjects(obj, RLPy.EObjectType_Prop)
for obj in child_objects:
if type(obj) is RLPy.RIProp:
objects.add(obj)
for child in child_objects:
if cc.is_prop(child):
objects.add(child)
for obj in objects:
self.avatar = obj
self.rebuild_materials()
self.rebuild_materials(update=True)

def rebuild_materials(self):
def rebuild_materials(self, update=False):
"""Material reconstruction process.
"""

Expand All @@ -328,7 +329,7 @@ def rebuild_materials(self):
utils.start_timer()

self.create_progress_window()
cc_mesh_materials = cc.get_avatar_mesh_materials(avatar, json_data=json_data)
cc_mesh_materials = cc.get_avatar_mesh_materials(avatar, json_data=json_data, exact=update)
utils.log("Rebuilding character materials and texures:")
self.update_shaders(cc_mesh_materials)
self.update_progress(0, "Done Initializing!", True)
Expand All @@ -338,19 +339,21 @@ def rebuild_materials(self):
self.import_custom_textures(cc_mesh_materials)
self.import_physics(cc_mesh_materials)

if self.character_type == "HUMANOID":
self.option_import_hik = True
self.option_import_profile = True
# user optional for importing custom facial expressions as the import profile will load the old ones.
# and it's slow...
#self.option_import_expressions = True
if not update: # do not update HIK / facial profiles on material updates

if self.option_import_hik:
self.import_hik_profile()
if self.character_type == "HUMANOID":
self.option_import_hik = True
self.option_import_profile = True
# user optional for importing custom facial expressions as the import profile will load the old ones.
# and it's slow...
#self.option_import_expressions = True

if self.character_type == "STANDARD" or self.character_type == "HUMANOID":
if self.option_import_profile or self.option_import_expressions:
self.import_facial_profile()
if self.option_import_hik:
self.import_hik_profile()

if self.character_type == "STANDARD" or self.character_type == "HUMANOID":
if self.option_import_profile or self.option_import_expressions:
self.import_facial_profile()

self.final(cc_mesh_materials)

Expand Down
Loading

0 comments on commit a3b33f1

Please sign in to comment.