From d7aa7cc8ca75425d7175c854a67ea42fa34ab2b9 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Sat, 9 Apr 2022 13:20:31 -0700 Subject: [PATCH] Add UV margin setting. It's a little hacky, but mostly works. --- __init__.py | 36 ++++++++++++++++++++++++++++++++---- uv_island_utils.py | 37 ------------------------------------- uv_utils.py | 10 ++++++++++ 3 files changed, 42 insertions(+), 41 deletions(-) delete mode 100644 uv_island_utils.py create mode 100644 uv_utils.py diff --git a/__init__.py b/__init__.py index cf721f9..0d14465 100644 --- a/__init__.py +++ b/__init__.py @@ -36,6 +36,7 @@ from .node_groups import \ ensure_footage_group, \ ensure_camera_project_group, \ ensure_feathered_square_group +from .uv_utils import leftmost_u MAIN_NODE_NAME = "Compify Footage" BAKE_IMAGE_NODE_NAME = "Baked Lighting" @@ -99,6 +100,7 @@ class CompifyPanel(bpy.types.Panel): layout.separator(factor=1.0) layout.use_property_split = True + layout.prop(context.scene.compify_config, "bake_uv_margin") layout.prop(context.scene.compify_config, "bake_image_res") layout.separator(factor=1.0) @@ -301,13 +303,29 @@ class CompifyPrepScene(bpy.types.Operator): bpy.ops.mesh.select_all(action='SELECT') bpy.ops.uv.smart_project( angle_limit=(math.pi/180)*60, # 60 degrees - island_margin=0.005, + island_margin=0.001, area_weight=0.0, correct_aspect=False, - scale_to_bounds=True, + scale_to_bounds=False, ) bpy.ops.object.mode_set(mode='OBJECT') + # We have to do the UV island margins twice, because Blender's + # `island_margin` is stupid beyond belief and corresponds to + # nothing absolute that we can depend on. So what we're doing + # here is saying, "Hey, what was the actual margin achieved + # with `island_margin=0.001`? Okay, now let's redo it based on + # that result." It's still not 100% precise even with this, + # but with a bit of buffer it's close enough. + actual_margin = leftmost_u(context.selected_objects, UV_LAYER_NAME) + actual_margin_pixels = actual_margin * context.scene.compify_config.bake_image_res + target_margin_with_buffer = context.scene.compify_config.bake_uv_margin * (5.0 / 4.0) + correction_factor = target_margin_with_buffer / actual_margin_pixels + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.uv.select_all(action='SELECT') + bpy.ops.uv.pack_islands(rotate=False, margin = 0.001 * correction_factor) + bpy.ops.object.mode_set(mode='OBJECT') + return {'FINISHED'} @@ -333,7 +351,8 @@ class CompifyBake(bpy.types.Operator): and context.scene.compify_config.footage != None \ and context.scene.compify_config.camera != None \ and context.scene.compify_config.geo_collection != None \ - and len(context.scene.compify_config.geo_collection.all_objects) > 0 + and len(context.scene.compify_config.geo_collection.all_objects) > 0 \ + and compify_mat_name(context) in bpy.data.materials def execute(self, context): # Clear operator fields. Not strictly necessary, since they @@ -421,7 +440,7 @@ class CompifyBake(bpy.types.Operator): # filepath='', # width=512, # height=512, - margin=4, + margin=context.scene.compify_config.bake_uv_margin, margin_type='EXTEND', use_selected_to_active=False, max_ray_distance=0.0, @@ -534,6 +553,15 @@ class CompifyFootageConfig(bpy.types.PropertyGroup): type=bpy.types.Collection, name="Footage Lights Collection", ) + bake_uv_margin: bpy.props.IntProperty( + name="Bake UV Margin", + subtype='PIXEL', + options=set(), # Not animatable. + default=4, + min=0, + max=2**16, + soft_max=32, + ) bake_image_res: bpy.props.IntProperty( name="Bake Resolution", subtype='PIXEL', diff --git a/uv_island_utils.py b/uv_island_utils.py deleted file mode 100644 index 4938d59..0000000 --- a/uv_island_utils.py +++ /dev/null @@ -1,37 +0,0 @@ -from math import inf -from bpy_extras.mesh_utils import mesh_linked_uv_islands - - -def uv_island_bbox_area_sum_multi_object(mesh_objects, uv_layer_name): - area_sum = 0.0 - for obj in mesh_objects: - area_sum += uv_island_bbox_area_sum(obj.data, uv_layer_name) - return area_sum - - -def uv_island_bbox_area_sum(mesh, uv_layer_name): - """ Returns the sum of the area of the bounding boxes of all the UV - islands in the given mesh for the given uv layer. - """ - uvs = mesh.uv_layers[uv_layer_name].data - islands = mesh_linked_uv_islands(mesh) - - bbox_area_sum = 0.0 - for island in islands: - # Calculate the island's bounding box. - min_u = inf - max_u = -inf - min_v = inf - max_v = -inf - for face_idx in island: - for loop_idx in mesh.polygons[face_idx].loop_indices: - uv = uvs[mesh.loops[loop_idx].vertex_index].uv - min_u = min(min_u, uv[0]) - max_u = max(max_u, uv[0]) - min_v = min(min_v, uv[1]) - max_v = max(max_v, uv[1]) - - # Add it's area to the sum. - bbox_area_sum += ((max_u - min_u) * (max_v - min_v))**0.5 - - return bbox_area_sum diff --git a/uv_utils.py b/uv_utils.py new file mode 100644 index 0000000..76db207 --- /dev/null +++ b/uv_utils.py @@ -0,0 +1,10 @@ +from math import inf + + +def leftmost_u(mesh_objects, uv_layer_name): + leftmost = inf + for obj in mesh_objects: + uvs = obj.data.uv_layers[uv_layer_name].data + for uv in uvs: + leftmost = min(leftmost, uv.uv[0]) + return leftmost