Skip to content

Commit ed60b96

Browse files
authored
Merge pull request #309 from soupday/Dev
Dev
2 parents 680048d + b2501fa commit ed60b96

File tree

9 files changed

+116
-40
lines changed

9 files changed

+116
-40
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ Links
3535

3636
### 2.2.4
3737
- Rigify face rig fallback to envelope weights if auto weights fail.
38-
- DataLink Import motion will optionally import motion to active character if no matching character.
38+
- DataLink Import motion will optionally (confirmation dialog) import motion to active character if no matching character.
39+
- Rigify head turn expression driver corrected.
40+
- Fixed collision objects being included in export.
41+
- Fixed displacement strength export.
3942

4043
### 2.2.3
4144
- Wrinkle map region strength controls added.

exporter.py

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,30 +1143,20 @@ def get_export_objects(chr_cache, include_selected = True, only_objects=None):
11431143
if obj.parent == arm:
11441144
utils.unhide(obj)
11451145
if obj not in objects:
1146+
utils.log_info(f" Found Character Object: {obj.name}")
11461147
objects.append(obj)
11471148

11481149
child_objects = utils.get_child_objects(arm)
11491150
for obj in child_objects:
11501151
if utils.object_exists_is_mesh(obj):
1151-
# exclude rigid body colliders (parented to armature)
1152-
if collider_collection and obj.name in collider_collection.objects:
1153-
utils.log_info(f" Excluding Rigidbody Collider Object: {obj.name}")
1154-
continue
1155-
# exclude collider proxies
1156-
if chr_cache.is_collision_object(obj):
1157-
utils.log_info(f" Excluding Collider Proxy Object: {obj.name}")
1158-
continue
1159-
# exclude sculpt objects
1160-
if chr_cache.is_sculpt_object(obj):
1161-
utils.log_info(f" Excluding Sculpt Object: {obj.name}")
1162-
continue
11631152
# add child mesh objects
11641153
if obj not in objects:
1165-
utils.log_info(f" Including Child Mesh Object: {obj.name}")
1154+
utils.log_info(f" Found Child Mesh Object: {obj.name}")
11661155
objects.append(obj)
11671156
elif utils.object_exists_is_empty(obj):
1168-
utils.log_info(f" Including Child Empty Transform: {obj.name}")
1157+
utils.log_info(f" Found Child Empty Transform: {obj.name}")
11691158
objects.append(obj)
1159+
11701160
else:
11711161
arm = utils.get_armature_from_objects(objects)
11721162
if arm:
@@ -1178,14 +1168,10 @@ def get_export_objects(chr_cache, include_selected = True, only_objects=None):
11781168
for obj in child_objects:
11791169
if utils.object_exists_is_mesh(obj):
11801170
if obj not in objects:
1181-
# exclude rigid body colliders (parented to armature)
1182-
if collider_collection and obj.name in collider_collection.objects:
1183-
utils.log_info(f" Excluding Rigidbody Collider Object: {obj.name}")
1184-
continue
1185-
utils.log_info(f" Including Child Object: {obj.name}")
1171+
utils.log_info(f" Found Child Object: {obj.name}")
11861172
objects.append(obj)
11871173
elif utils.object_exists_is_empty(obj):
1188-
utils.log_info(f" Including Child Empty Transform: {obj.name}")
1174+
utils.log_info(f" Found Child Empty Transform: {obj.name}")
11891175
objects.append(obj)
11901176

11911177
# include selected objects last
@@ -1194,6 +1180,27 @@ def get_export_objects(chr_cache, include_selected = True, only_objects=None):
11941180
if obj not in objects:
11951181
objects.append(obj)
11961182

1183+
# exclude non-exportable objects
1184+
to_remove = []
1185+
for obj in objects:
1186+
# exclude rigid body colliders (parented to armature)
1187+
if collider_collection and obj.name in collider_collection.objects:
1188+
utils.log_info(f" Excluding Rigidbody Collider Object: {obj.name}")
1189+
to_remove.append(obj)
1190+
continue
1191+
# exclude collider proxies
1192+
if chr_cache and chr_cache.is_collision_object(obj):
1193+
utils.log_info(f" Excluding Collider Proxy Object: {obj.name}")
1194+
to_remove.append(obj)
1195+
continue
1196+
# exclude sculpt objects
1197+
if chr_cache and chr_cache.is_sculpt_object(obj):
1198+
utils.log_info(f" Excluding Sculpt Object: {obj.name}")
1199+
to_remove.append(obj)
1200+
continue
1201+
for o in to_remove:
1202+
objects.remove(o)
1203+
11971204
# make sure all export objects are valid
11981205
clean_objects = [ obj for obj in objects
11991206
if utils.object_exists(obj) and
@@ -1775,6 +1782,7 @@ def export_standard(self, context, chr_cache, file_path, include_selected):
17751782

17761783
# store mode state
17771784
mode_selection_state = utils.store_mode_selection_state()
1785+
rv_state = utils.store_render_visibility_state()
17781786

17791787
utils.log_info("Export to: " + file_path)
17801788
utils.log_info("Exporting as: " + ext)
@@ -1885,6 +1893,7 @@ def export_standard(self, context, chr_cache, file_path, include_selected):
18851893

18861894
# restore mode state
18871895
utils.restore_mode_selection_state(mode_selection_state)
1896+
utils.restore_render_visibility_state(rv_state)
18881897

18891898
utils.log_recess()
18901899
utils.log_timer("Done Character Export.")
@@ -1911,6 +1920,7 @@ def export_non_standard(self, context, file_path, include_selected):
19111920

19121921
# store mode state
19131922
mode_selection_state = utils.store_mode_selection_state()
1923+
rv_state = utils.store_render_visibility_state()
19141924

19151925
# export objects
19161926
objects = get_export_objects(None, include_selected)
@@ -1969,6 +1979,7 @@ def export_non_standard(self, context, file_path, include_selected):
19691979

19701980
# restore mode state
19711981
utils.restore_mode_selection_state(mode_selection_state)
1982+
utils.restore_render_visibility_state(rv_state)
19721983

19731984
utils.log_recess()
19741985
if arp_export:
@@ -2004,6 +2015,7 @@ def export_to_unity(self, context, chr_cache, export_anim, file_path, include_se
20042015

20052016
# store mode state
20062017
mode_selection_state = utils.store_mode_selection_state()
2018+
rv_state = utils.store_render_visibility_state()
20072019

20082020
utils.log_info("Export to: " + file_path)
20092021
utils.log_info("Exporting as: " + ext)
@@ -2117,6 +2129,7 @@ def export_to_unity(self, context, chr_cache, export_anim, file_path, include_se
21172129
bones.restore_armature_settings(arm, armature_settings, include_pose=True)
21182130
# restore mode state
21192131
utils.restore_mode_selection_state(mode_selection_state)
2132+
utils.restore_render_visibility_state(rv_state)
21202133

21212134
utils.log_recess()
21222135
utils.log_timer("Done Character Export.")
@@ -2220,6 +2233,7 @@ def export_rigify(self, context, chr_cache, export_anim, file_path, include_sele
22202233

22212234
# store mode state
22222235
mode_selection_state = utils.store_mode_selection_state()
2236+
rv_state = utils.store_render_visibility_state()
22232237

22242238
utils.log_info("Export to: " + file_path)
22252239
utils.log_info("Exporting as: " + ext)
@@ -2337,6 +2351,7 @@ def export_rigify(self, context, chr_cache, export_anim, file_path, include_sele
23372351

23382352
# restore mode state
23392353
utils.restore_mode_selection_state(mode_selection_state)
2354+
utils.restore_render_visibility_state(rv_state)
23402355

23412356
utils.log_recess()
23422357
utils.log_timer("Done Rigify Export.")
@@ -2603,7 +2618,9 @@ def invoke(self, context, event):
26032618
require_valid_export = (self.param == "EXPORT_CC3" or
26042619
self.param == "EXPORT_NON_STANDARD")
26052620
if require_export_check:
2621+
rv_state = utils.store_render_visibility_state()
26062622
objects = get_export_objects(chr_cache, self.include_selected)
2623+
utils.restore_render_visibility_state(rv_state)
26072624
if export_format == "fbx":
26082625
self.check_valid, self.check_warn, self.check_report = check_valid_export_fbx(chr_cache, objects)
26092626
if require_valid_export:

jsonutils.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ def set_pbr_var(mat_json, var_name, paths, value):
435435
mat_json["Textures"][var_name][paths[2]] = value
436436
else:
437437
# metallic and roughness don't have controllable strength settings, so always set to max
438-
if var_name == "Metallic" or var_name != "Roughness":
438+
if var_name == "Metallic" or var_name == "Roughness":
439439
value = 1.0
440440
mat_json["Textures"][var_name]["Strength"] = value * 100.0
441441
except:
@@ -484,16 +484,16 @@ def get_shader_var_color(mat_json, var_name):
484484
return None
485485

486486

487-
def get_json(json_data, path: str):
487+
def get_json(json_data, path: str, default=None):
488488
if json_data:
489489
keys = path.split("/")
490490
for key in keys:
491491
if key in json_data:
492492
json_data = json_data[key]
493493
else:
494-
return None
494+
return default
495495
return json_data
496-
return None
496+
return default
497497

498498

499499
def set_json(json_data, path: str, value):
@@ -634,3 +634,11 @@ def get_meshes_images(meshes_json, filter=None):
634634
images.add(os.path.normpath(tex_path))
635635
return images
636636

637+
638+
def get_displacement_data(mat_json):
639+
texture_path = get_json(mat_json, "Textures/Displacement/Texture Path", "")
640+
strength = get_json(mat_json, "Textures/Displacement/Strength", 0.0)
641+
level = int(get_json(mat_json, "Textures/Displacement/Tessellation Level", 0))
642+
multiplier = get_json(mat_json, "Textures/Displacement/Multiplier", 1.0)
643+
base = get_json(mat_json, "Textures/Displacement/Gray-scale Base Value", 0.0)
644+
return texture_path, strength, level, multiplier, base

link.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ def remove_datalink_import_rig(actor: LinkActor, apply_contraints=False):
623623

624624
def set_actor_expression_weight(objects, expression_name, weight):
625625
global LINK_DATA
626-
if objects and LINK_DATA.preview_shape_keys:
626+
if objects:
627627
obj: bpy.types.Object
628628
for obj in objects:
629629
if expression_name in obj.data.shape_keys.key_blocks:
@@ -719,6 +719,14 @@ def prep_rig(actor: LinkActor, start_frame, end_frame):
719719
utils.log_info(f"Preparing Character Rig: {actor.name} {rig_id} / {len(actor.bones)} bones")
720720

721721
# set data
722+
723+
if not LINK_DATA.set_keyframes:
724+
# when not setting keyframes remove all actions from the rig
725+
# and let the DataLink set the pose and shape keys directly
726+
utils.safe_set_action(rig, None)
727+
for obj in objects:
728+
utils.safe_set_action(obj.data.shape_keys, None)
729+
722730
if LINK_DATA.set_keyframes:
723731

724732
if LINK_DATA.sequence_type == "POSE":
@@ -1263,10 +1271,14 @@ def recv(self):
12631271
# parse may have received a disconnect notice
12641272
if not self.has_client_sock():
12651273
return
1266-
# if preview sync every frame in sequence
1274+
# if preview frame sync update every frame in sequence
12671275
if op_code == OpCodes.SEQUENCE_FRAME and prefs.datalink_frame_sync:
12681276
self.is_data = True
12691277
return
1278+
# if not key framing, update every frame
1279+
if not LINK_DATA.set_keyframes:
1280+
self.is_data = True
1281+
return
12701282
if op_code == OpCodes.CHARACTER or op_code == OpCodes.PROP:
12711283
# give imports time to process, otherwise bad things happen
12721284
self.is_data = False
@@ -2272,7 +2284,7 @@ def decode_pose_frame_data(self, pose_data):
22722284
for i in range(0, num_weights):
22732285
weight = struct.unpack_from("!f", pose_data, offset)[0]
22742286
offset += 4
2275-
if actor and objects and prefs.datalink_preview_shape_keys:
2287+
if actor and objects and (prefs.datalink_preview_shape_keys or not LINK_DATA.set_keyframes):
22762288
expression_name = actor.expressions[i]
22772289
set_actor_expression_weight(objects, expression_name, weight)
22782290
expression_weights[i] = weight
@@ -2284,7 +2296,7 @@ def decode_pose_frame_data(self, pose_data):
22842296
for i in range(0, num_weights):
22852297
weight = struct.unpack_from("!f", pose_data, offset)[0]
22862298
offset += 4
2287-
if actor and objects and prefs.datalink_preview_shape_keys:
2299+
if actor and objects and (prefs.datalink_preview_shape_keys or not LINK_DATA.set_keyframes):
22882300
viseme_name = actor.visemes[i]
22892301
set_actor_viseme_weight(objects, viseme_name, weight)
22902302
viseme_weights[i] = weight
@@ -2925,7 +2937,8 @@ def receive_sequence_end(self, data):
29252937
bpy.context.scene.frame_current = LINK_DATA.sequence_start_frame
29262938

29272939
# play the recorded sequence
2928-
bpy.ops.screen.animation_play()
2940+
if LINK_DATA.set_keyframes:
2941+
bpy.ops.screen.animation_play()
29292942

29302943
def receive_sequence_ack(self, data):
29312944
prefs = vars.prefs()

modifiers.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -311,16 +311,34 @@ def add_tearline_modifiers(obj):
311311
utils.log_info("Tearline Displacement modifiers applied to: " + obj.name)
312312

313313

314-
def add_decimate_modifier(obj, ratio):
315-
mod : bpy.types.DecimateModifier
316-
mod = get_object_modifier(obj, "DECIMATE", "Decimate_Collision_Body")
314+
def add_decimate_modifier(obj, ratio, name):
315+
mod: bpy.types.DecimateModifier
316+
mod = get_object_modifier(obj, "DECIMATE", name)
317317
if not mod:
318-
mod = obj.modifiers.new(utils.unique_name("Decimate_Collision_Body"), "DECIMATE")
318+
mod = obj.modifiers.new(utils.unique_name(name), "DECIMATE")
319319
mod.decimate_type = 'COLLAPSE'
320320
mod.ratio = ratio
321321
return mod
322322

323323

324+
def add_subdivision(obj: bpy.types.Object, level, name, max_level=3, view_level=1):
325+
mod: bpy.types.SubsurfModifier
326+
mod = get_object_modifier(obj, "SUBSURF", name)
327+
if not mod:
328+
mod = obj.modifiers.new(utils.unique_name(name), "SUBSURF")
329+
level = min(max_level, level)
330+
view_level = min(view_level, level)
331+
mod.render_levels = level
332+
mod.levels = view_level
333+
mod.subdivision_type = "CATMULL_CLARK"
334+
mod.show_only_control_edges = True
335+
mod.uv_smooth = 'PRESERVE_BOUNDARIES'
336+
mod.boundary_smooth = 'PRESERVE_CORNERS'
337+
mod.use_creases = True
338+
mod.use_custom_normals = True
339+
return mod
340+
341+
324342
def add_multi_res_modifier(obj, subdivisions, use_custom_normals = False, uv_smooth = "PRESERVE_BOUNDARIES", quality = 4):
325343
if utils.set_active_object(obj):
326344
mod : bpy.types.MultiresModifier

physics.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,9 @@ def create_collision_proxy(chr_cache, obj_cache, obj):
515515
utils.object_mode_to(collision_proxy)
516516
if obj_cache.collision_proxy_decimate < 1.0:
517517
# add decimate modifier
518-
mod = modifiers.add_decimate_modifier(collision_proxy, obj_cache.collision_proxy_decimate)
518+
mod = modifiers.add_decimate_modifier(collision_proxy,
519+
obj_cache.collision_proxy_decimate,
520+
"Decimate_Collision_Body")
519521
modifiers.move_mod_first(collision_proxy, mod)
520522
# apply decimate modifier
521523
bpy.ops.object.modifier_apply(modifier=mod.name)

properties.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1859,7 +1859,8 @@ def is_sculpt_object(self, obj):
18591859

18601860
def is_collision_object(self, obj):
18611861
source, proxy, is_proxy = self.get_related_physics_objects(obj)
1862-
return ("rl_collision_proxy" in obj or obj.name.endswith(".Collision_Proxy") or is_proxy)
1862+
result = ("rl_collision_proxy" in obj or obj.name.endswith("_Collision_Proxy") or is_proxy)
1863+
return result
18631864

18641865
def get_all_objects(self,
18651866
include_armature=True,

rigify_mapping_data.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,8 +624,8 @@ def OODTR(a):
624624
["Bfr", "Eye_L_Look_Down", ["SCRIPTED", f"min(var, 0)*{-OODTR(22)}"], ["var", "TRANSFORMS", "MCH-eye.L", "ROT_X", "LOCAL_SPACE"]],
625625
["Bfr", "Eye_R_Look_Down", ["SCRIPTED", f"min(var, 0)*{-OODTR(22)}"], ["var", "TRANSFORMS", "MCH-eye.R", "ROT_X", "LOCAL_SPACE"]],
626626
# Head rotation expressions
627-
["", "Head_Turn_Up", ["SCRIPTED", f"max(var, 0)*{-OODTR(-30)}"], ["var", "TRANSFORMS", "ORG-spine.006", "ROT_X", "LOCAL_SPACE"]],
628-
["", "Head_Turn_Down", ["SCRIPTED", f"min(var, 0)*{-OODTR(18)}"], ["var", "TRANSFORMS", "ORG-spine.006", "ROT_X", "LOCAL_SPACE"]],
627+
["", "Head_Turn_Up", ["SCRIPTED", f"min(var, 0)*{OODTR(-30)}"], ["var", "TRANSFORMS", "ORG-spine.006", "ROT_X", "LOCAL_SPACE"]],
628+
["", "Head_Turn_Down", ["SCRIPTED", f"max(var, 0)*{OODTR(18)}"], ["var", "TRANSFORMS", "ORG-spine.006", "ROT_X", "LOCAL_SPACE"]],
629629
["", "Head_Turn_L", ["SCRIPTED", f"max(var, 0)*{OODTR(51)}"], ["var", "TRANSFORMS", "ORG-spine.006", "ROT_Y", "LOCAL_SPACE"]],
630630
["", "Head_Turn_R", ["SCRIPTED", f"min(var, 0)*{OODTR(-51)}"], ["var", "TRANSFORMS", "ORG-spine.006", "ROT_Y", "LOCAL_SPACE"]],
631631
["", "Head_Tilt_L", ["SCRIPTED", f"min(var, 0)*{OODTR(-23.4)}"], ["var", "TRANSFORMS", "ORG-spine.006", "ROT_Z", "LOCAL_SPACE"]],

shaders.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import os
2020
from mathutils import Vector, Color
2121

22-
from . import imageutils, jsonutils, meshutils, materials, wrinkle, nodeutils, params, utils, vars
22+
from . import imageutils, jsonutils, meshutils, materials, modifiers, wrinkle, nodeutils, params, utils, vars
2323

2424

2525
def get_prop_value(mat_cache, prop_name):
@@ -1245,7 +1245,7 @@ def connect_hair_shader(obj_cache, obj, mat, mat_json, processed_images):
12451245
mat.use_sss_translucency = True
12461246

12471247

1248-
def connect_pbr_shader(obj_cache, obj, mat, mat_json, processed_images):
1248+
def connect_pbr_shader(obj_cache, obj, mat: bpy.types.Material, mat_json, processed_images):
12491249
props = vars.props()
12501250
prefs = vars.prefs()
12511251

@@ -1282,6 +1282,20 @@ def connect_pbr_shader(obj_cache, obj, mat, mat_json, processed_images):
12821282
else:
12831283
fix_sss_method(bsdf)
12841284

1285+
texture_path, strength, level, multiplier, base = jsonutils.get_displacement_data(mat_json)
1286+
if texture_path and strength > 0 and level > 0:
1287+
# add a subdivision modifer but set it to zero.
1288+
# lots of clothing in CC/iC uses tesselation and displacement, but
1289+
# subdividing all of it would significantly slow down blender.
1290+
# so the modifiers are added, but the user must then set their levels.
1291+
mod = modifiers.add_subdivision(obj, level, "Displacement_Subdiv", max_level=0, view_level=0)
1292+
if mod:
1293+
modifiers.move_mod_first(obj, mod)
1294+
if utils.B410():
1295+
mat.displacement_method = "BOTH"
1296+
else:
1297+
mat.cycles.displacement_method = "BOTH"
1298+
12851299

12861300
def connect_sss_shader(obj_cache, obj, mat, mat_json, processed_images):
12871301
props = vars.props()

0 commit comments

Comments
 (0)