Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornutti <nutti.metro@gmail.com>2020-10-23 14:18:09 +0300
committernutti <nutti.metro@gmail.com>2020-10-23 14:18:09 +0300
commit40e34a8bbb30c6a4ddc73aa11e92c6bd2095eb80 (patch)
tree5c46bb7af6381407596cab713f21dede0aa65f27 /magic_uv/op/uv_sculpt.py
parentec3c96a37e2daddd5ca9f652c4b018b00a3acc53 (diff)
Magic UV: Release v6.4
* Support multiple objects editing mode * Add snap to point/edge features * Fix bugs
Diffstat (limited to 'magic_uv/op/uv_sculpt.py')
-rw-r--r--magic_uv/op/uv_sculpt.py339
1 files changed, 173 insertions, 166 deletions
diff --git a/magic_uv/op/uv_sculpt.py b/magic_uv/op/uv_sculpt.py
index f40ab253..c9ed4f34 100644
--- a/magic_uv/op/uv_sculpt.py
+++ b/magic_uv/op/uv_sculpt.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.3"
-__date__ = "10 Aug 2020"
+__version__ = "6.4"
+__date__ = "23 Oct 2020"
from math import pi, cos, tan, sin
@@ -51,21 +51,16 @@ else:
def _is_valid_context(context):
- obj = context.object
+ objs = common.get_uv_editable_objects(context)
+ if not objs:
+ return False
# only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
if context.object.mode != 'EDIT':
return False
# only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
+ if not common.is_valid_space(context, ['VIEW_3D']):
return False
return True
@@ -255,7 +250,7 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
bgl.glEnd()
def __init__(self):
- self.__loop_info = []
+ self.__loop_info = {} # { Object: loop_info }
self.__stroking = False
self.current_mco = Vector((0.0, 0.0))
self.__initial_mco = Vector((0.0, 0.0))
@@ -265,52 +260,17 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
self.__initial_mco = self.current_mco
- # get influenced UV
- obj = context.active_object
- world_mat = obj.matrix_world
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- _, region, space = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')
-
- self.__loop_info = []
- for f in bm.faces:
- if not f.select:
- continue
- for i, l in enumerate(f.loops):
- loc_2d = location_3d_to_region_2d_extra(
- region, space.region_3d,
- compat.matmul(world_mat, l.vert.co))
- diff = loc_2d - self.__initial_mco
- if diff.length < sc.muv_uv_sculpt_radius:
- info = {
- "face_idx": f.index,
- "loop_idx": i,
- "initial_vco": l.vert.co.copy(),
- "initial_vco_2d": loc_2d,
- "initial_uv": l[uv_layer].uv.copy(),
- "strength": _get_strength(
- diff.length, sc.muv_uv_sculpt_radius,
- sc.muv_uv_sculpt_strength)
- }
- self.__loop_info.append(info)
+ objs = common.get_uv_editable_objects(context)
- def __stroke_apply(self, context, _):
- sc = context.scene
- obj = context.active_object
- world_mat = obj.matrix_world
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- mco = self.current_mco
-
- if sc.muv_uv_sculpt_tools == 'GRAB':
- for info in self.__loop_info:
- diff_uv = (mco - self.__initial_mco) * info["strength"]
- l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
- l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
-
- elif sc.muv_uv_sculpt_tools == 'PINCH':
+ # get influenced UV
+ self.__loop_info = {}
+ for obj in objs:
+ world_mat = obj.matrix_world
+ bm = bmesh.from_edit_mesh(obj.data)
+ uv_layer = bm.loops.layers.uv.verify()
_, region, space = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')
- loop_info = []
+
+ self.__loop_info[obj] = []
for f in bm.faces:
if not f.select:
continue
@@ -330,123 +290,170 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
diff.length, sc.muv_uv_sculpt_radius,
sc.muv_uv_sculpt_strength)
}
- loop_info.append(info)
-
- # mouse coordinate to UV coordinate
- ray_vec = view3d_utils.region_2d_to_vector_3d(region,
- space.region_3d, mco)
- ray_vec.normalize()
- ray_orig = view3d_utils.region_2d_to_origin_3d(region,
- space.region_3d,
- mco)
- ray_tgt = ray_orig + ray_vec * 1000000.0
- mwi = world_mat.inverted()
- ray_orig_obj = compat.matmul(mwi, ray_orig)
- ray_tgt_obj = compat.matmul(mwi, ray_tgt)
- ray_dir_obj = ray_tgt_obj - ray_orig_obj
- ray_dir_obj.normalize()
- tree = BVHTree.FromBMesh(bm)
- loc, _, fidx, _ = tree.ray_cast(ray_orig_obj, ray_dir_obj)
- if not loc:
- return
- loops = [l for l in bm.faces[fidx].loops]
- uvs = [Vector((l[uv_layer].uv.x, l[uv_layer].uv.y, 0.0))
- for l in loops]
- target_uv = barycentric_transform(
- loc, loops[0].vert.co, loops[1].vert.co, loops[2].vert.co,
- uvs[0], uvs[1], uvs[2])
- target_uv = Vector((target_uv.x, target_uv.y))
-
- # move to target UV coordinate
- for info in loop_info:
- l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
- if sc.muv_uv_sculpt_pinch_invert:
- diff_uv = (l[uv_layer].uv - target_uv) * info["strength"]
- else:
- diff_uv = (target_uv - l[uv_layer].uv) * info["strength"]
- l[uv_layer].uv = l[uv_layer].uv + diff_uv / 10.0
-
- elif sc.muv_uv_sculpt_tools == 'RELAX':
- _, region, space = common.get_space('VIEW_3D', 'WINDOW', 'VIEW_3D')
+ self.__loop_info[obj].append(info)
- # get vertex and loop relation
- vert_db = {}
- for f in bm.faces:
- for l in f.loops:
- if l.vert in vert_db:
- vert_db[l.vert]["loops"].append(l)
- else:
- vert_db[l.vert] = {"loops": [l]}
-
- # get relaxation information
- for k in vert_db.keys():
- d = vert_db[k]
- d["uv_sum"] = Vector((0.0, 0.0))
- d["uv_count"] = 0
-
- for l in d["loops"]:
- ln = l.link_loop_next
- lp = l.link_loop_prev
- d["uv_sum"] = d["uv_sum"] + ln[uv_layer].uv
- d["uv_sum"] = d["uv_sum"] + lp[uv_layer].uv
- d["uv_count"] = d["uv_count"] + 2
- d["uv_p"] = d["uv_sum"] / d["uv_count"]
- d["uv_b"] = d["uv_p"] - d["loops"][0][uv_layer].uv
- for k in vert_db.keys():
- d = vert_db[k]
- d["uv_sum_b"] = Vector((0.0, 0.0))
- for l in d["loops"]:
- ln = l.link_loop_next
- lp = l.link_loop_prev
- dn = vert_db[ln.vert]
- dp = vert_db[lp.vert]
- d["uv_sum_b"] = d["uv_sum_b"] + dn["uv_b"] + dp["uv_b"]
-
- # apply
- for f in bm.faces:
- if not f.select:
- continue
- for i, l in enumerate(f.loops):
- loc_2d = location_3d_to_region_2d_extra(
- region, space.region_3d,
- compat.matmul(world_mat, l.vert.co))
- diff = loc_2d - self.__initial_mco
- if diff.length >= sc.muv_uv_sculpt_radius:
+ def __stroke_apply(self, context, _):
+ sc = context.scene
+ objs = common.get_uv_editable_objects(context)
+
+ for obj in objs:
+ world_mat = obj.matrix_world
+ bm = bmesh.from_edit_mesh(obj.data)
+ uv_layer = bm.loops.layers.uv.verify()
+ mco = self.current_mco
+
+ if sc.muv_uv_sculpt_tools == 'GRAB':
+ for info in self.__loop_info[obj]:
+ diff_uv = (mco - self.__initial_mco) * info["strength"]
+ l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
+ l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
+
+ elif sc.muv_uv_sculpt_tools == 'PINCH':
+ _, region, space = common.get_space(
+ 'VIEW_3D', 'WINDOW', 'VIEW_3D')
+ loop_info = []
+ for f in bm.faces:
+ if not f.select:
continue
- db = vert_db[l.vert]
- strength = _get_strength(diff.length,
- sc.muv_uv_sculpt_radius,
- sc.muv_uv_sculpt_strength)
-
- base = (1.0 - strength) * l[uv_layer].uv
- if sc.muv_uv_sculpt_relax_method == 'HC':
- t = 0.5 * (db["uv_b"] + db["uv_sum_b"] / d["uv_count"])
- diff = strength * (db["uv_p"] - t)
- target_uv = base + diff
- elif sc.muv_uv_sculpt_relax_method == 'LAPLACIAN':
- diff = strength * db["uv_p"]
- target_uv = base + diff
+ for i, l in enumerate(f.loops):
+ loc_2d = location_3d_to_region_2d_extra(
+ region, space.region_3d,
+ compat.matmul(world_mat, l.vert.co))
+ diff = loc_2d - self.__initial_mco
+ if diff.length < sc.muv_uv_sculpt_radius:
+ info = {
+ "face_idx": f.index,
+ "loop_idx": i,
+ "initial_vco": l.vert.co.copy(),
+ "initial_vco_2d": loc_2d,
+ "initial_uv": l[uv_layer].uv.copy(),
+ "strength": _get_strength(
+ diff.length, sc.muv_uv_sculpt_radius,
+ sc.muv_uv_sculpt_strength)
+ }
+ loop_info.append(info)
+
+ # mouse coordinate to UV coordinate
+ ray_vec = view3d_utils.region_2d_to_vector_3d(
+ region, space.region_3d, mco)
+ ray_vec.normalize()
+ ray_orig = view3d_utils.region_2d_to_origin_3d(
+ region, space.region_3d, mco)
+ ray_tgt = ray_orig + ray_vec * 1000000.0
+ mwi = world_mat.inverted()
+ ray_orig_obj = compat.matmul(mwi, ray_orig)
+ ray_tgt_obj = compat.matmul(mwi, ray_tgt)
+ ray_dir_obj = ray_tgt_obj - ray_orig_obj
+ ray_dir_obj.normalize()
+ tree = BVHTree.FromBMesh(bm)
+ loc, _, fidx, _ = tree.ray_cast(ray_orig_obj, ray_dir_obj)
+ if not loc:
+ return
+ loops = [l for l in bm.faces[fidx].loops]
+ uvs = [Vector((l[uv_layer].uv.x, l[uv_layer].uv.y, 0.0))
+ for l in loops]
+ target_uv = barycentric_transform(
+ loc,
+ loops[0].vert.co, loops[1].vert.co, loops[2].vert.co,
+ uvs[0], uvs[1], uvs[2])
+ target_uv = Vector((target_uv.x, target_uv.y))
+
+ # move to target UV coordinate
+ for info in loop_info:
+ l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
+ if sc.muv_uv_sculpt_pinch_invert:
+ diff_uv = \
+ (l[uv_layer].uv - target_uv) * info["strength"]
else:
+ diff_uv = \
+ (target_uv - l[uv_layer].uv) * info["strength"]
+ l[uv_layer].uv = l[uv_layer].uv + diff_uv / 10.0
+
+ elif sc.muv_uv_sculpt_tools == 'RELAX':
+ _, region, space = common.get_space(
+ 'VIEW_3D', 'WINDOW', 'VIEW_3D')
+
+ # get vertex and loop relation
+ vert_db = {}
+ for f in bm.faces:
+ for l in f.loops:
+ if l.vert in vert_db:
+ vert_db[l.vert]["loops"].append(l)
+ else:
+ vert_db[l.vert] = {"loops": [l]}
+
+ # get relaxation information
+ for k in vert_db.keys():
+ d = vert_db[k]
+ d["uv_sum"] = Vector((0.0, 0.0))
+ d["uv_count"] = 0
+
+ for l in d["loops"]:
+ ln = l.link_loop_next
+ lp = l.link_loop_prev
+ d["uv_sum"] = d["uv_sum"] + ln[uv_layer].uv
+ d["uv_sum"] = d["uv_sum"] + lp[uv_layer].uv
+ d["uv_count"] = d["uv_count"] + 2
+ d["uv_p"] = d["uv_sum"] / d["uv_count"]
+ d["uv_b"] = d["uv_p"] - d["loops"][0][uv_layer].uv
+ for k in vert_db.keys():
+ d = vert_db[k]
+ d["uv_sum_b"] = Vector((0.0, 0.0))
+ for l in d["loops"]:
+ ln = l.link_loop_next
+ lp = l.link_loop_prev
+ dn = vert_db[ln.vert]
+ dp = vert_db[lp.vert]
+ d["uv_sum_b"] = d["uv_sum_b"] + dn["uv_b"] + dp["uv_b"]
+
+ # apply
+ for f in bm.faces:
+ if not f.select:
continue
-
- l[uv_layer].uv = target_uv
-
- bmesh.update_edit_mesh(obj.data)
+ for i, l in enumerate(f.loops):
+ loc_2d = location_3d_to_region_2d_extra(
+ region, space.region_3d,
+ compat.matmul(world_mat, l.vert.co))
+ diff = loc_2d - self.__initial_mco
+ if diff.length >= sc.muv_uv_sculpt_radius:
+ continue
+ db = vert_db[l.vert]
+ strength = _get_strength(diff.length,
+ sc.muv_uv_sculpt_radius,
+ sc.muv_uv_sculpt_strength)
+
+ base = (1.0 - strength) * l[uv_layer].uv
+ if sc.muv_uv_sculpt_relax_method == 'HC':
+ t = 0.5 * \
+ (db["uv_b"] + db["uv_sum_b"] / d["uv_count"])
+ diff = strength * (db["uv_p"] - t)
+ target_uv = base + diff
+ elif sc.muv_uv_sculpt_relax_method == 'LAPLACIAN':
+ diff = strength * db["uv_p"]
+ target_uv = base + diff
+ else:
+ continue
+
+ l[uv_layer].uv = target_uv
+
+ bmesh.update_edit_mesh(obj.data)
def __stroke_exit(self, context, _):
sc = context.scene
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- mco = self.current_mco
-
- if sc.muv_uv_sculpt_tools == 'GRAB':
- for info in self.__loop_info:
- diff_uv = (mco - self.__initial_mco) * info["strength"]
- l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
- l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
-
- bmesh.update_edit_mesh(obj.data)
+ objs = common.get_uv_editable_objects(context)
+
+ for obj in objs:
+ bm = bmesh.from_edit_mesh(obj.data)
+ uv_layer = bm.loops.layers.uv.verify()
+ mco = self.current_mco
+
+ if sc.muv_uv_sculpt_tools == 'GRAB':
+ for info in self.__loop_info[obj]:
+ diff_uv = (mco - self.__initial_mco) * info["strength"]
+ l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
+ l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
+
+ bmesh.update_edit_mesh(obj.data)
def modal(self, context, event):
if context.area: