109 lines
3.9 KiB
Python
109 lines
3.9 KiB
Python
import bpy
|
|
from bpy.types import Context, Object, Mesh, Scene
|
|
|
|
def assert_mirror_modifier(obj: Object, target: Object = None):
|
|
modifier = next((modifier for modifier in obj.modifiers if modifier.type == "MIRROR"), None)
|
|
if modifier is None:
|
|
modifier = obj.modifiers.new("Mirror", "MIRROR")
|
|
modifier.use_clip = True
|
|
|
|
if target is not None and modifier.mirror_object is None:
|
|
modifier.mirror_object = target
|
|
|
|
|
|
def assert_shrinkwrap_modifier(obj: Object, target: Object = None):
|
|
modifier = next((modifier for modifier in obj.modifiers if modifier.type == "SHRINKWRAP"), None)
|
|
if modifier is None:
|
|
modifier = obj.modifiers.new("Shrinkwrap", "SHRINKWRAP")
|
|
|
|
modifier.show_viewport = False
|
|
modifier.wrap_method = "PROJECT"
|
|
modifier.wrap_mode = "ABOVE_SURFACE"
|
|
modifier.project_limit = 0.0
|
|
modifier.use_negative_direction = True
|
|
modifier.use_positive_direction = True
|
|
|
|
|
|
vgroup = next((group for group in obj.vertex_groups if "no_shrinkwrap" in group.name), None)
|
|
if vgroup is None:
|
|
vgroup = obj.vertex_groups.new(name="no_shrinkwrap")
|
|
|
|
|
|
modifier.vertex_group = vgroup.name
|
|
modifier.invert_vertex_group = True
|
|
|
|
if target is not None and modifier.target is None:
|
|
modifier.target = target
|
|
|
|
|
|
|
|
def assert_retopo_modifiers(ctx: Context, target: Object = None):
|
|
active = ctx.active_object
|
|
assert_mirror_modifier(active, target)
|
|
assert_shrinkwrap_modifier(active, target)
|
|
|
|
def setup_project_snap_settings(scene: Scene):
|
|
scene.tool_settings.use_snap = True
|
|
scene.tool_settings.snap_elements = {"FACE"}
|
|
scene.tool_settings.use_snap_self = True
|
|
scene.tool_settings.use_snap_edit = True
|
|
scene.tool_settings.use_snap_nonedit = True
|
|
scene.tool_settings.use_snap_selectable = True
|
|
scene.tool_settings.use_snap_align_rotation = False
|
|
scene.tool_settings.use_snap_backface_culling = True
|
|
scene.tool_settings.use_snap_project = True
|
|
scene.tool_settings.use_snap_translate = True
|
|
scene.tool_settings.use_snap_rotate = True
|
|
scene.tool_settings.use_snap_scale = True
|
|
|
|
def setup_vertex_snap_settings(scene: Scene):
|
|
scene.tool_settings.use_snap = True
|
|
scene.tool_settings.snap_elements = {"VERTEX"}
|
|
scene.tool_settings.use_snap_self = True
|
|
scene.tool_settings.use_snap_edit = True
|
|
scene.tool_settings.use_snap_nonedit = False
|
|
scene.tool_settings.use_snap_selectable = True
|
|
scene.tool_settings.use_snap_align_rotation = False
|
|
scene.tool_settings.use_snap_backface_culling = True
|
|
scene.tool_settings.use_snap_translate = True
|
|
scene.tool_settings.use_snap_rotate = True
|
|
scene.tool_settings.use_snap_scale = True
|
|
|
|
def get_context_target(ctx: Context):
|
|
if len(ctx.selected_objects) != 2:
|
|
return None
|
|
return next(obj for obj in ctx.selected_objects if obj is not ctx.active_object)
|
|
|
|
class RetopoProjectModeOperator(bpy.types.Operator):
|
|
bl_idname = "object.retopoprojectmode"
|
|
bl_label = "RetopoProjectMode"
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
@classmethod
|
|
def poll(Cls, context: Context):
|
|
return context.active_object is not None and type(context.active_object.data) is Mesh
|
|
|
|
def execute(self, context: Context):
|
|
bpy.ops.object.mode_set(mode="EDIT")
|
|
target = get_context_target(context)
|
|
assert_retopo_modifiers(context, target)
|
|
setup_project_snap_settings(context.scene)
|
|
self.report({"INFO"}, "Project Mode")
|
|
return {'FINISHED'}
|
|
|
|
|
|
class RetopoVertexModeOperator(bpy.types.Operator):
|
|
bl_idname = "object.retopovertexmode"
|
|
bl_label = "RetopoVertexMode"
|
|
|
|
def execute(self, context):
|
|
bpy.ops.object.mode_set(mode="EDIT")
|
|
target = get_context_target(context)
|
|
assert_retopo_modifiers(context, target)
|
|
setup_vertex_snap_settings(context.scene)
|
|
self.report({"INFO"}, "Vertex Mode")
|
|
return {'FINISHED'}
|
|
|
|
|
|
|