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>2021-03-06 11:54:33 +0300
committernutti <nutti.metro@gmail.com>2021-03-06 11:54:33 +0300
commit117faa96af35685d72e5e01f9a386d163d874133 (patch)
treeb4378f8ca2e91c93ab035ab37b05e018f601ff54 /magic_uv
parentc8752443311b133f8783a6b9b2152eb7c92d06a7 (diff)
Magic UV: Release v6.5
Updated Features * Texture Projection * Add option "Scaling", "Rotation", "Translation" * Select UV * Add Zoom Selected UV feature * Add option "Same Polygon Threshold" * Add option "Selection Method" * Add option "Sync Mesh Selection" * UV Inspection * Add option "Same Polygon Threshold" * Add option "Display View3D" * Mirror UV * Add option "Origin" * UVW * Add option "Force Axis" Other Updates * Fix bugs
Diffstat (limited to 'magic_uv')
-rw-r--r--magic_uv/__init__.py6
-rw-r--r--magic_uv/common.py112
-rw-r--r--magic_uv/lib/__init__.py4
-rw-r--r--magic_uv/lib/bglx.py12
-rw-r--r--magic_uv/op/__init__.py4
-rw-r--r--magic_uv/op/align_uv.py4
-rw-r--r--magic_uv/op/align_uv_cursor.py4
-rw-r--r--magic_uv/op/clip_uv.py4
-rw-r--r--magic_uv/op/copy_paste_uv.py4
-rw-r--r--magic_uv/op/copy_paste_uv_object.py4
-rw-r--r--magic_uv/op/copy_paste_uv_uvedit.py4
-rw-r--r--magic_uv/op/flip_rotate_uv.py4
-rw-r--r--magic_uv/op/mirror_uv.py96
-rw-r--r--magic_uv/op/move_uv.py4
-rw-r--r--magic_uv/op/pack_uv.py15
-rw-r--r--magic_uv/op/preserve_uv_aspect.py4
-rw-r--r--magic_uv/op/select_uv.py203
-rw-r--r--magic_uv/op/smooth_uv.py4
-rw-r--r--magic_uv/op/texture_lock.py4
-rw-r--r--magic_uv/op/texture_projection.py136
-rw-r--r--magic_uv/op/texture_wrap.py4
-rw-r--r--magic_uv/op/transfer_uv.py4
-rw-r--r--magic_uv/op/unwrap_constraint.py4
-rw-r--r--magic_uv/op/uv_bounding_box.py4
-rw-r--r--magic_uv/op/uv_inspection.py110
-rw-r--r--magic_uv/op/uv_sculpt.py4
-rw-r--r--magic_uv/op/uvw.py232
-rw-r--r--magic_uv/op/world_scale_uv.py49
-rw-r--r--magic_uv/preferences.py36
-rw-r--r--magic_uv/properites.py4
-rw-r--r--magic_uv/ui/IMAGE_MT_uvs.py17
-rw-r--r--magic_uv/ui/VIEW3D_MT_object.py4
-rw-r--r--magic_uv/ui/VIEW3D_MT_uv_map.py4
-rw-r--r--magic_uv/ui/__init__.py4
-rw-r--r--magic_uv/ui/uvedit_copy_paste_uv.py4
-rw-r--r--magic_uv/ui/uvedit_editor_enhancement.py8
-rw-r--r--magic_uv/ui/uvedit_uv_manipulation.py21
-rw-r--r--magic_uv/ui/view3d_copy_paste_uv_editmode.py4
-rw-r--r--magic_uv/ui/view3d_copy_paste_uv_objectmode.py4
-rw-r--r--magic_uv/ui/view3d_uv_manipulation.py6
-rw-r--r--magic_uv/ui/view3d_uv_mapping.py18
-rw-r--r--magic_uv/updater.py7
-rw-r--r--magic_uv/utils/__init__.py4
-rw-r--r--magic_uv/utils/addon_updater.py4
-rw-r--r--magic_uv/utils/bl_class_registry.py4
-rw-r--r--magic_uv/utils/compatibility.py8
-rw-r--r--magic_uv/utils/property_class_registry.py4
47 files changed, 976 insertions, 232 deletions
diff --git a/magic_uv/__init__.py b/magic_uv/__init__.py
index e9c95f24..d0b8ae45 100644
--- a/magic_uv/__init__.py
+++ b/magic_uv/__init__.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
bl_info = {
@@ -29,7 +29,7 @@ bl_info = {
"author": "Nutti, Mifth, Jace Priester, kgeogeo, mem, imdjs"
"Keith (Wahooney) Boshoff, McBuff, MaxRobinot, "
"Alexander Milovsky, Dusan Stevanovic, MatthiasThDs",
- "version": (6, 4, 0),
+ "version": (6, 5, 0),
"blender": (2, 80, 0),
"location": "See Add-ons Preferences",
"description": "UV Toolset. See Add-ons Preferences for details",
diff --git a/magic_uv/common.py b/magic_uv/common.py
index 3817486c..1d9d55cf 100644
--- a/magic_uv/common.py
+++ b/magic_uv/common.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from collections import defaultdict
from pprint import pprint
@@ -333,7 +333,7 @@ def get_uvimg_editor_board_size(area):
return (255.0, 255.0)
-def calc_polygon_2d_area(points):
+def calc_tris_2d_area(points):
area = 0.0
for i, p1 in enumerate(points):
p2 = points[(i + 1) % len(points)]
@@ -345,7 +345,7 @@ def calc_polygon_2d_area(points):
return fabs(0.5 * area)
-def calc_polygon_3d_area(points):
+def calc_tris_3d_area(points):
area = 0.0
for i, p1 in enumerate(points):
p2 = points[(i + 1) % len(points)]
@@ -395,6 +395,23 @@ def get_faces_list(bm, method, only_selected):
return faces_list
+def measure_all_faces_mesh_area(bm):
+ if compat.check_version(2, 80, 0) >= 0:
+ triangle_loops = bm.calc_loop_triangles()
+ else:
+ triangle_loops = bm.calc_tessface()
+
+ areas = {face: 0.0 for face in bm.faces}
+
+ for loops in triangle_loops:
+ face = loops[0].face
+ area = areas[face]
+ area += calc_tris_3d_area([l.vert.co for l in loops])
+ areas[face] = area
+
+ return areas
+
+
def measure_mesh_area(obj, calc_method, only_selected):
bm = bmesh.from_edit_mesh(obj.data)
if check_version(2, 73, 0) >= 0:
@@ -406,17 +423,18 @@ def measure_mesh_area(obj, calc_method, only_selected):
areas = []
for faces in faces_list:
- areas.append(measure_mesh_area_from_faces(faces))
+ areas.append(measure_mesh_area_from_faces(bm, faces))
return areas
-def measure_mesh_area_from_faces(faces):
+def measure_mesh_area_from_faces(bm, faces):
+ face_areas = measure_all_faces_mesh_area(bm)
+
mesh_area = 0.0
for f in faces:
- verts = [l.vert.co for l in f.loops]
- f_mesh_area = calc_polygon_3d_area(verts)
- mesh_area = mesh_area + f_mesh_area
+ if f in face_areas:
+ mesh_area += face_areas[f]
return mesh_area
@@ -486,12 +504,34 @@ def find_images(obj, face=None, tex_layer=None):
return images
-def measure_uv_area_from_faces(obj, faces, uv_layer, tex_layer,
+def measure_all_faces_uv_area(bm, uv_layer):
+ if compat.check_version(2, 80, 0) >= 0:
+ triangle_loops = bm.calc_loop_triangles()
+ else:
+ triangle_loops = bm.calc_tessface()
+
+ areas = {face: 0.0 for face in bm.faces}
+
+ for loops in triangle_loops:
+ face = loops[0].face
+ area = areas[face]
+ area += calc_tris_2d_area([l[uv_layer].uv for l in loops])
+ areas[face] = area
+
+ return areas
+
+
+def measure_uv_area_from_faces(obj, bm, faces, uv_layer, tex_layer,
tex_selection_method, tex_size):
+
+ face_areas = measure_all_faces_uv_area(bm, uv_layer)
+
uv_area = 0.0
for f in faces:
- uvs = [l[uv_layer].uv for l in f.loops]
- f_uv_area = calc_polygon_2d_area(uvs)
+ if f not in face_areas:
+ continue
+
+ f_uv_area = face_areas[f]
# user specified
if tex_selection_method == 'USER_SPECIFIED' and tex_size is not None:
@@ -547,8 +587,8 @@ def measure_uv_area_from_faces(obj, faces, uv_layer, tex_layer,
return uv_area
-def measure_uv_area(obj, calc_method, tex_selection_method, tex_size,
- only_selected):
+def measure_uv_area(obj, calc_method, tex_selection_method,
+ tex_size, only_selected):
bm = bmesh.from_edit_mesh(obj.data)
if check_version(2, 73, 0) >= 0:
bm.verts.ensure_lookup_table()
@@ -565,7 +605,8 @@ def measure_uv_area(obj, calc_method, tex_selection_method, tex_size,
uv_areas = []
for faces in faces_list:
uv_area = measure_uv_area_from_faces(
- obj, faces, uv_layer, tex_layer, tex_selection_method, tex_size)
+ obj, bm, faces, uv_layer, tex_layer,
+ tex_selection_method, tex_size)
if uv_area is None:
return None
uv_areas.append(uv_area)
@@ -946,7 +987,8 @@ class RingBuffer:
# clip: reference polygon
# subject: tested polygon
-def __do_weiler_atherton_cliping(clip_uvs, subject_uvs, mode):
+def __do_weiler_atherton_cliping(clip_uvs, subject_uvs, mode,
+ same_polygon_threshold):
clip_uvs = RingBuffer(clip_uvs)
if __is_polygon_flipped(clip_uvs):
@@ -961,7 +1003,7 @@ def __do_weiler_atherton_cliping(clip_uvs, subject_uvs, mode):
debug_print(subject_uvs)
# check if clip and subject is overlapped completely
- if __is_polygon_same(clip_uvs, subject_uvs):
+ if __is_polygon_same(clip_uvs, subject_uvs, same_polygon_threshold):
polygons = [subject_uvs.as_list()]
debug_print("===== Polygons Overlapped Completely =====")
debug_print(polygons)
@@ -1193,26 +1235,31 @@ def get_uv_editable_objects(context):
return objs
-def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list, mode):
+def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list,
+ mode, same_polygon_threshold=0.0000001):
# at first, check island overlapped
isl = []
for bm, uv_layer, faces in zip(bm_list, uv_layer_list, faces_list):
info = get_island_info_from_faces(bm, faces, uv_layer)
- isl.extend([(i, uv_layer) for i in info])
+ isl.extend([(i, uv_layer, bm) for i in info])
overlapped_isl_pairs = []
overlapped_uv_layer_pairs = []
- for i, (i1, uv_layer_1) in enumerate(isl):
- for i2, uv_layer_2 in isl[i + 1:]:
+ overlapped_bm_paris = []
+ for i, (i1, uv_layer_1, bm_1) in enumerate(isl):
+ for i2, uv_layer_2, bm_2 in isl[i + 1:]:
if (i1["max"].x < i2["min"].x) or (i2["max"].x < i1["min"].x) or \
(i1["max"].y < i2["min"].y) or (i2["max"].y < i1["min"].y):
continue
overlapped_isl_pairs.append([i1, i2])
overlapped_uv_layer_pairs.append([uv_layer_1, uv_layer_2])
+ overlapped_bm_paris.append([bm_1, bm_2])
# next, check polygon overlapped
overlapped_uvs = []
- for oip, uvlp in zip(overlapped_isl_pairs, overlapped_uv_layer_pairs):
+ for oip, uvlp, bmp in zip(overlapped_isl_pairs,
+ overlapped_uv_layer_pairs,
+ overlapped_bm_paris):
for clip in oip[0]["faces"]:
f_clip = clip["face"]
clip_uvs = [l[uvlp[0]].uv.copy() for l in f_clip.loops]
@@ -1228,11 +1275,13 @@ def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list, mode):
subject_uvs = [l[uvlp[1]].uv.copy() for l in f_subject.loops]
# slow operation, apply Weiler-Atherton cliping algorithm
- result, polygons = __do_weiler_atherton_cliping(clip_uvs,
- subject_uvs,
- mode)
+ result, polygons = \
+ __do_weiler_atherton_cliping(clip_uvs, subject_uvs,
+ mode, same_polygon_threshold)
if result:
- overlapped_uvs.append({"clip_face": f_clip,
+ overlapped_uvs.append({"clip_bmesh": bmp[0],
+ "subject_bmesh": bmp[1],
+ "clip_face": f_clip,
"subject_face": f_subject,
"clip_uv_layer": uvlp[0],
"subject_uv_layer": uvlp[1],
@@ -1242,14 +1291,15 @@ def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list, mode):
return overlapped_uvs
-def get_flipped_uv_info(faces_list, uv_layer_list):
+def get_flipped_uv_info(bm_list, faces_list, uv_layer_list):
flipped_uvs = []
- for faces, uv_layer in zip(faces_list, uv_layer_list):
+ for bm, faces, uv_layer in zip(bm_list, faces_list, uv_layer_list):
for f in faces:
polygon = RingBuffer([l[uv_layer].uv.copy() for l in f.loops])
if __is_polygon_flipped(polygon):
uvs = [l[uv_layer].uv.copy() for l in f.loops]
- flipped_uvs.append({"face": f,
+ flipped_uvs.append({"bmesh": bm,
+ "face": f,
"uv_layer": uv_layer,
"uvs": uvs,
"polygons": [polygon.as_list()]})
@@ -1257,7 +1307,7 @@ def get_flipped_uv_info(faces_list, uv_layer_list):
return flipped_uvs
-def __is_polygon_same(points1, points2):
+def __is_polygon_same(points1, points2, threshold):
if len(points1) != len(points2):
return False
@@ -1267,7 +1317,7 @@ def __is_polygon_same(points1, points2):
for p1 in pts1:
for p2 in pts2:
diff = p2 - p1
- if diff.length < 0.0000001:
+ if diff.length < threshold:
pts2.remove(p2)
break
else:
diff --git a/magic_uv/lib/__init__.py b/magic_uv/lib/__init__.py
index 8bed4656..68d1843a 100644
--- a/magic_uv/lib/__init__.py
+++ b/magic_uv/lib/__init__.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
if "bpy" in locals():
import importlib
diff --git a/magic_uv/lib/bglx.py b/magic_uv/lib/bglx.py
index 6bc885c6..e72cd734 100644
--- a/magic_uv/lib/bglx.py
+++ b/magic_uv/lib/bglx.py
@@ -159,6 +159,11 @@ def glEnd():
#shader = gpu.shader.from_builtin('2D_IMAGE')
vert_shader, frag_shader = _get_transparency_shader()
shader = gpu.types.GPUShader(vert_shader, frag_shader)
+ elif inst.get_dims() == 3:
+ if len(tex_coords) == 0:
+ shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
+ else:
+ raise NotImplemented("Texture is not supported in get_dims() == 3")
else:
raise NotImplemented("get_dims() != 2")
@@ -223,6 +228,12 @@ def glVertex2f(x, y):
inst.set_dims(2)
+def glVertex3f(x, y, z):
+ inst = InternalData.get_instance()
+ inst.add_vert([x, y, z])
+ inst.set_dims(3)
+
+
def glTexCoord2f(u, v):
inst = InternalData.get_instance()
inst.add_tex_coord([u, v])
@@ -234,6 +245,7 @@ GL_INT = bgl.GL_INT
GL_SCISSOR_BOX = bgl.GL_SCISSOR_BOX
GL_TEXTURE_2D = bgl.GL_TEXTURE_2D
GL_TEXTURE0 = bgl.GL_TEXTURE0
+GL_DEPTH_TEST = bgl.GL_DEPTH_TEST
GL_TEXTURE_MIN_FILTER = 0
GL_TEXTURE_MAG_FILTER = 0
diff --git a/magic_uv/op/__init__.py b/magic_uv/op/__init__.py
index 459a37e0..702ee452 100644
--- a/magic_uv/op/__init__.py
+++ b/magic_uv/op/__init__.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
if "bpy" in locals():
import importlib
diff --git a/magic_uv/op/align_uv.py b/magic_uv/op/align_uv.py
index cb68bf25..0cc3bcda 100644
--- a/magic_uv/op/align_uv.py
+++ b/magic_uv/op/align_uv.py
@@ -20,8 +20,8 @@
__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import math
from math import atan2, tan, sin, cos
diff --git a/magic_uv/op/align_uv_cursor.py b/magic_uv/op/align_uv_cursor.py
index 08c90db7..10f19a71 100644
--- a/magic_uv/op/align_uv_cursor.py
+++ b/magic_uv/op/align_uv_cursor.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
from mathutils import Vector
diff --git a/magic_uv/op/clip_uv.py b/magic_uv/op/clip_uv.py
index 990d35a6..b1532a36 100644
--- a/magic_uv/op/clip_uv.py
+++ b/magic_uv/op/clip_uv.py
@@ -20,8 +20,8 @@
__author__ = "Dusan Stevanovic, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import math
diff --git a/magic_uv/op/copy_paste_uv.py b/magic_uv/op/copy_paste_uv.py
index 0410ee8d..761aa36b 100644
--- a/magic_uv/op/copy_paste_uv.py
+++ b/magic_uv/op/copy_paste_uv.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>, Jace Priester"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bmesh
import bpy.utils
diff --git a/magic_uv/op/copy_paste_uv_object.py b/magic_uv/op/copy_paste_uv_object.py
index 2130ea38..37706c37 100644
--- a/magic_uv/op/copy_paste_uv_object.py
+++ b/magic_uv/op/copy_paste_uv_object.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bmesh
import bpy
diff --git a/magic_uv/op/copy_paste_uv_uvedit.py b/magic_uv/op/copy_paste_uv_uvedit.py
index abfb69a8..5ee7d62c 100644
--- a/magic_uv/op/copy_paste_uv_uvedit.py
+++ b/magic_uv/op/copy_paste_uv_uvedit.py
@@ -20,8 +20,8 @@
__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import math
from math import atan2, sin, cos
diff --git a/magic_uv/op/flip_rotate_uv.py b/magic_uv/op/flip_rotate_uv.py
index 7e6dbdf9..246e5fbf 100644
--- a/magic_uv/op/flip_rotate_uv.py
+++ b/magic_uv/op/flip_rotate_uv.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
import bmesh
diff --git a/magic_uv/op/mirror_uv.py b/magic_uv/op/mirror_uv.py
index a893ab83..969c26dc 100644
--- a/magic_uv/op/mirror_uv.py
+++ b/magic_uv/op/mirror_uv.py
@@ -20,8 +20,8 @@
__author__ = "Keith (Wahooney) Boshoff, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
from bpy.props import (
@@ -30,7 +30,7 @@ from bpy.props import (
BoolProperty,
)
import bmesh
-from mathutils import Vector
+from mathutils import Vector, Euler
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
@@ -65,15 +65,15 @@ def _is_vector_similar(v1, v2, error):
return within_err_x and within_err_y and within_err_z
-def _mirror_uvs(uv_layer, src, dst, axis, error):
+def _mirror_uvs(uv_layer, src, dst, axis, error, transformed):
"""
Copy UV coordinates from one UV face to another
"""
for sl in src.loops:
suv = sl[uv_layer].uv.copy()
- svco = sl.vert.co.copy()
+ svco = transformed[sl.vert].copy()
for dl in dst.loops:
- dvco = dl.vert.co.copy()
+ dvco = transformed[dl.vert].copy()
if axis == 'X':
dvco.x = -dvco.x
elif axis == 'Y':
@@ -85,13 +85,14 @@ def _mirror_uvs(uv_layer, src, dst, axis, error):
dl[uv_layer].uv = suv.copy()
-def _get_face_center(face):
+def _get_face_center(face, transformed):
"""
Get center coordinate of the face
"""
center = Vector((0.0, 0.0, 0.0))
for v in face.verts:
- center = center + v.co
+ tv = transformed[v]
+ center = center + tv
return center / len(face.verts)
@@ -117,11 +118,22 @@ class _Properties:
description="Mirror Axis",
default='X'
)
+ scene.muv_mirror_uv_origin = EnumProperty(
+ items=(
+ ('WORLD', "World", "World"),
+ ("GLOBAL", "Global", "Global"),
+ ('LOCAL', "Local", "Local"),
+ ),
+ name="Origin",
+ description="Origin of the mirror operation",
+ default='LOCAL'
+ )
@classmethod
def del_props(cls, scene):
del scene.muv_mirror_uv_enabled
del scene.muv_mirror_uv_axis
+ del scene.muv_mirror_uv_origin
@BlClassRegistry()
@@ -154,6 +166,16 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
soft_min=0.0,
soft_max=1.0
)
+ origin = EnumProperty(
+ items=(
+ ('WORLD', "World", "World"),
+ ("GLOBAL", "Global", "Global"),
+ ('LOCAL', "Local", "Local"),
+ ),
+ name="Origin",
+ description="Origin of the mirror operation",
+ default='LOCAL'
+ )
@classmethod
def poll(cls, context):
@@ -162,6 +184,51 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
return True
return _is_valid_context(context)
+ def _get_world_vertices(self, obj, bm):
+ # Get world orientation matrix.
+ world_orientation_mat = obj.matrix_world
+
+ # Move to local to world.
+ transformed = {}
+ for v in bm.verts:
+ transformed[v] = compat.matmul(world_orientation_mat, v.co)
+
+ return transformed
+
+ def _get_global_vertices(self, obj, bm):
+ # Get world rotation matrix.
+ eular = Euler(obj.rotation_euler)
+ rotation_mat = eular.to_matrix()
+
+ # Get center location of all verticies.
+ center_location = Vector((0.0, 0.0, 0.0))
+ for v in bm.verts:
+ center_location += v.co
+ center_location /= len(bm.verts)
+
+ # Move to local to global.
+ transformed = {}
+ for v in bm.verts:
+ transformed[v] = compat.matmul(rotation_mat, v.co)
+ transformed[v] -= center_location
+
+ return transformed
+
+ def _get_local_vertices(self, _, bm):
+ transformed = {}
+
+ # Get center location of all verticies.
+ center_location = Vector((0.0, 0.0, 0.0))
+ for v in bm.verts:
+ center_location += v.co
+ center_location /= len(bm.verts)
+
+ for v in bm.verts:
+ transformed[v] = v.co.copy()
+ transformed[v] -= center_location
+
+ return transformed
+
def execute(self, context):
objs = common.get_uv_editable_objects(context)
@@ -180,6 +247,13 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
return {'CANCELLED'}
uv_layer = bm.loops.layers.uv.verify()
+ if self.origin == 'WORLD':
+ transformed_verts = self._get_world_vertices(obj, bm)
+ elif self.origin == 'GLOBAL':
+ transformed_verts = self._get_global_vertices(obj, bm)
+ elif self.origin == 'LOCAL':
+ transformed_verts = self._get_local_vertices(obj, bm)
+
faces = [f for f in bm.faces if f.select]
for f_dst in faces:
count = len(f_dst.verts)
@@ -191,8 +265,8 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
continue
# test if the vertices x values are the same sign
- dst = _get_face_center(f_dst)
- src = _get_face_center(f_src)
+ dst = _get_face_center(f_dst, transformed_verts)
+ src = _get_face_center(f_src, transformed_verts)
if (dst.x > 0 and src.x > 0) or (dst.x < 0 and src.x < 0):
continue
@@ -207,7 +281,7 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
# do mirror UV
if _is_vector_similar(dst, src, error):
_mirror_uvs(uv_layer, f_src, f_dst,
- self.axis, self.error)
+ self.axis, self.error, transformed_verts)
bmesh.update_edit_mesh(obj.data)
diff --git a/magic_uv/op/move_uv.py b/magic_uv/op/move_uv.py
index fb7c287d..210169ab 100644
--- a/magic_uv/op/move_uv.py
+++ b/magic_uv/op/move_uv.py
@@ -20,8 +20,8 @@
__author__ = "kgeogeo, mem, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
from bpy.props import BoolProperty
diff --git a/magic_uv/op/pack_uv.py b/magic_uv/op/pack_uv.py
index 75fc760c..dd4a74d3 100644
--- a/magic_uv/op/pack_uv.py
+++ b/magic_uv/op/pack_uv.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from math import fabs
@@ -151,7 +151,7 @@ class _Properties:
name="Allowable Center Deviation",
description="Allowable center deviation to judge same UV island",
min=0.000001,
- max=0.1,
+ max=10.0,
default=(0.001, 0.001),
size=2
)
@@ -159,7 +159,7 @@ class _Properties:
name="Allowable Size Deviation",
description="Allowable sizse deviation to judge same UV island",
min=0.000001,
- max=0.1,
+ max=10.0,
default=(0.001, 0.001),
size=2
)
@@ -196,12 +196,13 @@ class MUV_OT_PackUV(bpy.types.Operator):
description="Margin used by default pack UV function",
min=0,
max=1,
- default=0.001)
+ default=0.001
+ )
allowable_center_deviation = FloatVectorProperty(
name="Allowable Center Deviation",
description="Allowable center deviation to judge same UV island",
min=0.000001,
- max=0.1,
+ max=10.0,
default=(0.001, 0.001),
size=2
)
@@ -209,7 +210,7 @@ class MUV_OT_PackUV(bpy.types.Operator):
name="Allowable Size Deviation",
description="Allowable sizse deviation to judge same UV island",
min=0.000001,
- max=0.1,
+ max=10.0,
default=(0.001, 0.001),
size=2
)
diff --git a/magic_uv/op/preserve_uv_aspect.py b/magic_uv/op/preserve_uv_aspect.py
index 270bc7ec..f1404b10 100644
--- a/magic_uv/op/preserve_uv_aspect.py
+++ b/magic_uv/op/preserve_uv_aspect.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
from bpy.props import StringProperty, EnumProperty, BoolProperty
diff --git a/magic_uv/op/select_uv.py b/magic_uv/op/select_uv.py
index a405e66d..cf8195f2 100644
--- a/magic_uv/op/select_uv.py
+++ b/magic_uv/op/select_uv.py
@@ -20,16 +20,17 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
-from bpy.props import BoolProperty
+from bpy.props import BoolProperty, FloatProperty, EnumProperty
import bmesh
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
+from ..utils import compatibility as compat
def _is_valid_context(context):
@@ -61,13 +62,38 @@ class _Properties:
description="Select UV is enabled",
default=False
)
+ scene.muv_select_uv_same_polygon_threshold = FloatProperty(
+ name="Same Polygon Threshold",
+ description="Threshold to distinguish same polygons",
+ default=0.000001,
+ min=0.000001,
+ max=0.01,
+ step=0.00001
+ )
+ scene.muv_select_uv_selection_method = EnumProperty(
+ name="Selection Method",
+ description="How to select faces which have overlapped UVs",
+ items=[
+ ('EXTEND', "Extend",
+ "Select faces without unselecting selected faces"),
+ ('RESET', "Reset", "Select faces and unselect selected faces"),
+ ],
+ default='RESET'
+ )
+ scene.muv_select_uv_sync_mesh_selection = BoolProperty(
+ name="Sync Mesh Selection",
+ description="Select the mesh's faces as well as UV's faces",
+ default=False
+ )
@classmethod
def del_props(cls, scene):
del scene.muv_select_uv_enabled
+ del scene.muv_select_uv_same_polygon_threshold
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
"""
Operation class: Select faces which have overlapped UVs
@@ -78,6 +104,30 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
bl_description = "Select faces which have overlapped UVs"
bl_options = {'REGISTER', 'UNDO'}
+ same_polygon_threshold = FloatProperty(
+ name="Same Polygon Threshold",
+ description="Threshold to distinguish same polygons",
+ default=0.000001,
+ min=0.000001,
+ max=0.01,
+ step=0.00001
+ )
+ selection_method = EnumProperty(
+ name="Selection Method",
+ description="How to select faces which have overlapped UVs",
+ items=[
+ ('EXTEND', "Extend",
+ "Select faces without unselecting selected faces"),
+ ('RESET', "Reset", "Select faces and unselect selected faces"),
+ ],
+ default='RESET'
+ )
+ sync_mesh_selection = BoolProperty(
+ name="Sync Mesh Selection",
+ description="Select mesh's faces as well as UV's faces",
+ default=False
+ )
+
@classmethod
def poll(cls, context):
# we can not get area/space/region from console
@@ -85,6 +135,12 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
return True
return _is_valid_context(context)
+ @staticmethod
+ def setup_argument(ops, scene):
+ ops.same_polygon_threshold = scene.muv_select_uv_same_polygon_threshold
+ ops.selection_method = scene.muv_select_uv_selection_method
+ ops.sync_mesh_selection = scene.muv_select_uv_sync_mesh_selection
+
def execute(self, context):
objs = common.get_uv_editable_objects(context)
@@ -105,13 +161,29 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
uv_layer_list.append(uv_layer)
faces_list.append(sel_faces)
- overlapped_info = common.get_overlapped_uv_info(bm_list, faces_list,
- uv_layer_list, 'FACE')
+ overlapped_info = common.get_overlapped_uv_info(
+ bm_list, faces_list, uv_layer_list, 'FACE',
+ self.same_polygon_threshold)
+
+ if self.selection_method == 'RESET':
+ if context.tool_settings.use_uv_select_sync:
+ for faces in faces_list:
+ for f in faces:
+ f.select = False
+ else:
+ for uv_layer, faces in zip(uv_layer_list, faces_list):
+ for f in faces:
+ if self.sync_mesh_selection:
+ f.select = False
+ for l in f.loops:
+ l[uv_layer].select = False
for info in overlapped_info:
if context.tool_settings.use_uv_select_sync:
info["subject_face"].select = True
else:
+ if self.sync_mesh_selection:
+ info["subject_face"].select = True
for l in info["subject_face"].loops:
l[info["subject_uv_layer"]].select = True
@@ -122,6 +194,7 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
"""
Operation class: Select faces which have flipped UVs
@@ -132,6 +205,22 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
bl_description = "Select faces which have flipped UVs"
bl_options = {'REGISTER', 'UNDO'}
+ selection_method = EnumProperty(
+ name="Selection Method",
+ description="How to select faces which have overlapped UVs",
+ items=[
+ ('EXTEND', "Extend",
+ "Select faces without unselecting selected faces"),
+ ('RESET', "Reset", "Select faces and unselect selected faces"),
+ ],
+ default='RESET'
+ )
+ sync_mesh_selection = BoolProperty(
+ name="Sync Mesh Selection",
+ description="Select mesh's faces as well as UV's faces",
+ default=False
+ )
+
@classmethod
def poll(cls, context):
# we can not get area/space/region from console
@@ -139,6 +228,11 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
return True
return _is_valid_context(context)
+ @staticmethod
+ def setup_argument(ops, scene):
+ ops.selection_method = scene.muv_select_uv_selection_method
+ ops.sync_mesh_selection = scene.muv_select_uv_sync_mesh_selection
+
def execute(self, context):
objs = common.get_uv_editable_objects(context)
@@ -159,12 +253,28 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
uv_layer_list.append(uv_layer)
faces_list.append(sel_faces)
- flipped_info = common.get_flipped_uv_info(faces_list, uv_layer_list)
+ flipped_info = common.get_flipped_uv_info(
+ bm_list, faces_list, uv_layer_list)
+
+ if self.selection_method == 'RESET':
+ if context.tool_settings.use_uv_select_sync:
+ for faces in faces_list:
+ for f in faces:
+ f.select = False
+ else:
+ for uv_layer, faces in zip(uv_layer_list, faces_list):
+ for f in faces:
+ if self.sync_mesh_selection:
+ f.select = False
+ for l in f.loops:
+ l[uv_layer].select = False
for info in flipped_info:
if context.tool_settings.use_uv_select_sync:
info["face"].select = True
else:
+ if self.sync_mesh_selection:
+ info["face"].select = True
for l in info["face"].loops:
l[info["uv_layer"]].select = True
@@ -172,3 +282,84 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
bmesh.update_edit_mesh(obj.data)
return {'FINISHED'}
+
+
+@BlClassRegistry()
+class MUV_OT_SelectUV_ZoomSelectedUV(bpy.types.Operator):
+ """
+ Operation class: Zoom selected UV in View3D space
+ """
+
+ bl_idname = "uv.muv_select_uv_zoom_selected_uv"
+ bl_label = "Zoom Selected UV"
+ bl_description = "Zoom selected UV in View3D space"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
+
+ def _get_override_context(self, context):
+ for window in context.window_manager.windows:
+ screen = window.screen
+ for area in screen.areas:
+ if area.type == 'VIEW_3D':
+ for region in area.regions:
+ if region.type == 'WINDOW':
+ return {'window': window, 'screen': screen,
+ 'area': area, 'region': region}
+ return None
+
+ def execute(self, context):
+ objs = common.get_uv_editable_objects(context)
+
+ bm_list = []
+ uv_layer_list = []
+ verts_list = []
+ for obj in objs:
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ uv_layer = bm.loops.layers.uv.verify()
+
+ sel_verts = [v for v in bm.verts if v.select]
+ bm_list.append(bm)
+ uv_layer_list.append(uv_layer)
+ verts_list.append(sel_verts)
+
+ # Get all selected UV vertices in UV Editor.
+ sel_uv_verts = []
+ for vlist, uv_layer in zip(verts_list, uv_layer_list):
+ for v in vlist:
+ for l in v.link_loops:
+ if l[uv_layer].select or \
+ context.tool_settings.use_uv_select_sync:
+ sel_uv_verts.append(v)
+ break
+
+ # Select vertices only selected in UV Editor.
+ for bm in bm_list:
+ for v in bm.verts:
+ v.select = False
+ for v in sel_uv_verts:
+ v.select = True
+ for obj in objs:
+ bmesh.update_edit_mesh(obj.data)
+
+ # Zoom.
+ override_context = self._get_override_context(context)
+ if override_context is None:
+ self.report({'WARNING'}, "More than one 'VIEW_3D' area must exist")
+ return {'CANCELLED'}
+ bpy.ops.view3d.view_selected(override_context, use_all_regions=False)
+
+ # Revert selection of verticies.
+ for v in sel_verts:
+ v.select = True
+ for obj in objs:
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
diff --git a/magic_uv/op/smooth_uv.py b/magic_uv/op/smooth_uv.py
index 9b721615..232d6ccc 100644
--- a/magic_uv/op/smooth_uv.py
+++ b/magic_uv/op/smooth_uv.py
@@ -20,8 +20,8 @@
__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
from bpy.props import BoolProperty, FloatProperty
diff --git a/magic_uv/op/texture_lock.py b/magic_uv/op/texture_lock.py
index fb9ac4c7..6873cc4a 100644
--- a/magic_uv/op/texture_lock.py
+++ b/magic_uv/op/texture_lock.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import math
from math import atan2, cos, sqrt, sin, fabs
diff --git a/magic_uv/op/texture_projection.py b/magic_uv/op/texture_projection.py
index 694fac0d..9ce3cdc4 100644
--- a/magic_uv/op/texture_projection.py
+++ b/magic_uv/op/texture_projection.py
@@ -20,10 +20,11 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from collections import namedtuple
+from math import sin, cos
import bpy
import bmesh
@@ -32,6 +33,7 @@ from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
+ FloatVectorProperty,
)
import mathutils
@@ -56,7 +58,7 @@ def _get_loaded_texture_name(_, __):
return items
-def _get_canvas(context, magnitude):
+def _get_canvas(context):
"""
Get canvas to be renderred texture
"""
@@ -88,11 +90,11 @@ def _get_canvas(context, magnitude):
len_y = canvas_h
else:
if sc.muv_texture_projection_apply_tex_aspect:
- len_x = tex_w * magnitude
- len_y = tex_h * magnitude
+ len_x = tex_w
+ len_y = tex_h
else:
- len_x = region_w * magnitude
- len_y = region_h * magnitude
+ len_x = region_w
+ len_y = region_h
x0 = int(center_x - len_x * 0.5)
y0 = int(center_y - len_y * 0.5)
@@ -123,6 +125,35 @@ def _region_to_canvas(rg_vec, canvas):
return cv_vec
+def _create_affine_matrix(identity, scale, rotate, translate):
+ if identity:
+ return mathutils.Matrix.Identity(3)
+
+ sx = scale[0]
+ sy = scale[1]
+ theta = rotate
+ tx = translate[0]
+ ty = translate[1]
+
+ mat_scale = mathutils.Matrix((
+ (sx, 0.0, 0.0),
+ (0.0, sy, 0.0),
+ (0.0, 0.0, 1.0)
+ ))
+ mat_rotate = mathutils.Matrix((
+ (cos(theta), sin(theta), 0.0),
+ (-sin(theta), cos(theta), 0.0),
+ (0.0, 0.0, 1.0)
+ ))
+ mat_translate = mathutils.Matrix((
+ (1.0, 0.0, tx),
+ (0.0, 1.0, ty),
+ (0.0, 0.0, 1.0)
+ ))
+
+ return compat.matmul(compat.matmul(mat_translate, mat_rotate), mat_scale)
+
+
def _is_valid_context(context):
objs = common.get_uv_editable_objects(context)
if not objs:
@@ -167,12 +198,31 @@ class _Properties:
set=set_func,
update=update_func
)
- scene.muv_texture_projection_tex_magnitude = FloatProperty(
- name="Magnitude",
- description="Texture Magnitude",
- default=0.5,
- min=0.0,
- max=100.0
+ scene.muv_texture_projection_tex_scaling = FloatVectorProperty(
+ name="Scaling",
+ description="Texture Scale",
+ default=(0.5, 0.5),
+ min=-100.0,
+ max=100.0,
+ size=2,
+ subtype='XYZ'
+ )
+ scene.muv_texture_projection_tex_rotation = FloatProperty(
+ name="Rotation",
+ description="Texture Rotate",
+ default=0.0,
+ min=-360.0,
+ max=360.0,
+ subtype='ANGLE'
+ )
+ scene.muv_texture_projection_tex_translation = FloatVectorProperty(
+ name="Translation",
+ description="Texture Translate",
+ default=(0.0, 0.0),
+ min=-2000.0,
+ max=2000.0,
+ size=2,
+ subtype='XYZ'
)
scene.muv_texture_projection_tex_image = EnumProperty(
name="Image",
@@ -188,7 +238,7 @@ class _Properties:
)
scene.muv_texture_projection_adjust_window = BoolProperty(
name="Adjust Window",
- description="Size of renderered texture is fitted to window",
+ description="Scale of renderered texture is fitted to window",
default=True
)
scene.muv_texture_projection_apply_tex_aspect = BoolProperty(
@@ -205,7 +255,9 @@ class _Properties:
@classmethod
def del_props(cls, scene):
del scene.muv_texture_projection_enabled
- del scene.muv_texture_projection_tex_magnitude
+ del scene.muv_texture_projection_tex_scaling
+ del scene.muv_texture_projection_tex_rotation
+ del scene.muv_texture_projection_tex_translation
del scene.muv_texture_projection_tex_image
del scene.muv_texture_projection_tex_transparency
del scene.muv_texture_projection_adjust_window
@@ -264,12 +316,33 @@ class MUV_OT_TextureProjection(bpy.types.Operator):
img = bpy.data.images[sc.muv_texture_projection_tex_image]
# setup rendering region
- rect = _get_canvas(context, sc.muv_texture_projection_tex_magnitude)
+ rect = _get_canvas(context)
+
+ # Apply affine transformation.
+ center = mathutils.Vector((
+ (rect.x1 + rect.x0) / 2.0,
+ (rect.y1 + rect.y0) / 2.0,
+ 0.0,
+ ))
+ p1 = mathutils.Vector((rect.x0 - center.x, rect.y0 - center.y, 1.0))
+ p2 = mathutils.Vector((rect.x0 - center.x, rect.y1 - center.y, 1.0))
+ p3 = mathutils.Vector((rect.x1 - center.x, rect.y1 - center.y, 1.0))
+ p4 = mathutils.Vector((rect.x1 - center.x, rect.y0 - center.y, 1.0))
+ mat_affine = _create_affine_matrix(
+ sc.muv_texture_projection_adjust_window,
+ sc.muv_texture_projection_tex_scaling,
+ sc.muv_texture_projection_tex_rotation,
+ sc.muv_texture_projection_tex_translation)
+ p1 = compat.matmul(mat_affine, p1) + center
+ p2 = compat.matmul(mat_affine, p2) + center
+ p3 = compat.matmul(mat_affine, p3) + center
+ p4 = compat.matmul(mat_affine, p4) + center
+
positions = [
- [rect.x0, rect.y0],
- [rect.x0, rect.y1],
- [rect.x1, rect.y1],
- [rect.x1, rect.y0]
+ [p1.x, p1.y],
+ [p2.x, p2.y],
+ [p3.x, p3.y],
+ [p4.x, p4.y]
]
tex_coords = [
[0.0, 0.0],
@@ -384,13 +457,30 @@ class MUV_OT_TextureProjection_Project(bpy.types.Operator):
for f in sel_faces for l in f.loops
]
+ # Apply affine transformation.
+ rect = _get_canvas(bpy.context)
+ center = mathutils.Vector((
+ (rect.x1 + rect.x0) / 2.0,
+ (rect.y1 + rect.y0) / 2.0,
+ 0.0,
+ ))
+ v_screen_transformed = []
+ for v in v_screen:
+ p1 = mathutils.Vector((v.x - center.x, v.y - center.y, 1.0))
+ mat_affine = _create_affine_matrix(
+ sc.muv_texture_projection_adjust_window,
+ sc.muv_texture_projection_tex_scaling,
+ sc.muv_texture_projection_tex_rotation,
+ sc.muv_texture_projection_tex_translation)
+ p1 = compat.matmul(mat_affine.inverted(), p1) + center
+ v_screen_transformed.append(p1)
+
# transform screen region to canvas
v_canvas = [
_region_to_canvas(
v,
- _get_canvas(bpy.context,
- sc.muv_texture_projection_tex_magnitude)
- ) for v in v_screen
+ rect
+ ) for v in v_screen_transformed
]
# assign image
diff --git a/magic_uv/op/texture_wrap.py b/magic_uv/op/texture_wrap.py
index 5fd0cfe6..9a706fd7 100644
--- a/magic_uv/op/texture_wrap.py
+++ b/magic_uv/op/texture_wrap.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
from bpy.props import (
diff --git a/magic_uv/op/transfer_uv.py b/magic_uv/op/transfer_uv.py
index bcf9fab9..da308816 100644
--- a/magic_uv/op/transfer_uv.py
+++ b/magic_uv/op/transfer_uv.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>, Mifth, MaxRobinot"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from collections import OrderedDict
diff --git a/magic_uv/op/unwrap_constraint.py b/magic_uv/op/unwrap_constraint.py
index dcaa79b4..489c3b69 100644
--- a/magic_uv/op/unwrap_constraint.py
+++ b/magic_uv/op/unwrap_constraint.py
@@ -18,8 +18,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
from bpy.props import (
diff --git a/magic_uv/op/uv_bounding_box.py b/magic_uv/op/uv_bounding_box.py
index fc3455b4..d7b9badb 100644
--- a/magic_uv/op/uv_bounding_box.py
+++ b/magic_uv/op/uv_bounding_box.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from enum import IntEnum
import math
diff --git a/magic_uv/op/uv_inspection.py b/magic_uv/op/uv_inspection.py
index 49525b98..7ee1633d 100644
--- a/magic_uv/op/uv_inspection.py
+++ b/magic_uv/op/uv_inspection.py
@@ -20,14 +20,14 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import random
from math import fabs
import bpy
-from bpy.props import BoolProperty, EnumProperty
+from bpy.props import BoolProperty, EnumProperty, FloatProperty
import bmesh
from .. import common
@@ -64,6 +64,7 @@ def _update_uvinsp_info(context):
props = sc.muv_props.uv_inspection
objs = common.get_uv_editable_objects(context)
+ bm_to_obj = {} # { Object: BMesh }
bm_list = []
uv_layer_list = []
faces_list = []
@@ -77,13 +78,35 @@ def _update_uvinsp_info(context):
sel_faces = [f for f in bm.faces]
else:
sel_faces = [f for f in bm.faces if f.select]
+ bm_to_obj[bm] = obj
bm_list.append(bm)
uv_layer_list.append(uv_layer)
faces_list.append(sel_faces)
props.overlapped_info = common.get_overlapped_uv_info(
- bm_list, faces_list, uv_layer_list, sc.muv_uv_inspection_show_mode)
- props.flipped_info = common.get_flipped_uv_info(faces_list, uv_layer_list)
+ bm_list, faces_list, uv_layer_list, sc.muv_uv_inspection_show_mode,
+ sc.muv_uv_inspection_same_polygon_threshold)
+ props.flipped_info = common.get_flipped_uv_info(
+ bm_list, faces_list, uv_layer_list)
+
+ if sc.muv_uv_inspection_display_in_v3d:
+ props.overlapped_info_for_v3d = {}
+ for info in props.overlapped_info:
+ bm = info["subject_bmesh"]
+ face = info["subject_face"]
+ obj = bm_to_obj[bm]
+ if obj not in props.overlapped_info_for_v3d:
+ props.overlapped_info_for_v3d[obj] = []
+ props.overlapped_info_for_v3d[obj].append(face.index)
+
+ props.filpped_info_for_v3d = {}
+ for info in props.flipped_info:
+ bm = info["bmesh"]
+ face = info["face"]
+ obj = bm_to_obj[bm]
+ if obj not in props.filpped_info_for_v3d:
+ props.filpped_info_for_v3d[obj] = []
+ props.filpped_info_for_v3d[obj].append(face.index)
@PropertyClassRegistry()
@@ -95,6 +118,8 @@ class _Properties:
class Props():
overlapped_info = []
flipped_info = []
+ overlapped_info_for_v3d = {} # { Object: [face_indices] }
+ filpped_info_for_v3d = {} # { Object: [face_indices] }
scene.muv_props.uv_inspection = Props()
@@ -130,6 +155,11 @@ class _Properties:
description="Show flipped UVs",
default=False
)
+ scene.muv_uv_inspection_display_in_v3d = BoolProperty(
+ name="Display View3D",
+ description="Display overlapped/flipped faces on View3D",
+ default=True
+ )
scene.muv_uv_inspection_show_mode = EnumProperty(
name="Mode",
description="Show mode",
@@ -139,6 +169,14 @@ class _Properties:
],
default='PART'
)
+ scene.muv_uv_inspection_same_polygon_threshold = FloatProperty(
+ name="Same Polygon Threshold",
+ description="Threshold to distinguish same polygons",
+ default=0.000001,
+ min=0.000001,
+ max=0.01,
+ step=0.00001
+ )
@classmethod
def del_props(cls, scene):
@@ -147,7 +185,9 @@ class _Properties:
del scene.muv_uv_inspection_show
del scene.muv_uv_inspection_show_overlapped
del scene.muv_uv_inspection_show_flipped
+ del scene.muv_uv_inspection_display_in_v3d
del scene.muv_uv_inspection_show_mode
+ del scene.muv_uv_inspection_same_polygon_threshold
@BlClassRegistry()
@@ -162,6 +202,7 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
bl_label = "Overlapped/Flipped UV renderer"
__handle = None
+ __handle_v3d = None
@classmethod
def poll(cls, context):
@@ -181,6 +222,11 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
MUV_OT_UVInspection_Render.draw, (obj, context),
'WINDOW', 'POST_PIXEL')
+ sv3d = bpy.types.SpaceView3D
+ cls.__handle_v3d = sv3d.draw_handler_add(
+ MUV_OT_UVInspection_Render.draw_v3d, (obj, context),
+ 'WINDOW', 'POST_VIEW')
+
@classmethod
def handle_remove(cls):
if cls.__handle is not None:
@@ -188,6 +234,60 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
cls.__handle, 'WINDOW')
cls.__handle = None
+ if cls.__handle_v3d is not None:
+ bpy.types.SpaceView3D.draw_handler_remove(
+ cls.__handle_v3d, 'WINDOW')
+
+ @staticmethod
+ def draw_v3d(_, context):
+ sc = context.scene
+ props = sc.muv_props.uv_inspection
+ user_prefs = compat.get_user_preferences(context)
+ prefs = user_prefs.addons["magic_uv"].preferences
+
+ if not MUV_OT_UVInspection_Render.is_running(context):
+ return
+
+ if not sc.muv_uv_inspection_display_in_v3d:
+ return
+
+ # OpenGL configuration.
+ bgl.glEnable(bgl.GL_BLEND)
+ bgl.glEnable(bgl.GL_DEPTH_TEST)
+
+ # Render faces whose UV is overlapped.
+ if sc.muv_uv_inspection_show_overlapped:
+ color = prefs.uv_inspection_overlapped_color_for_v3d
+ for obj, findices in props.overlapped_info_for_v3d.items():
+ world_mat = obj.matrix_world
+ bm = bmesh.from_edit_mesh(obj.data)
+
+ for fidx in findices:
+ bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+ bgl.glColor4f(color[0], color[1], color[2], color[3])
+ for l in bm.faces[fidx].loops:
+ co = compat.matmul(world_mat, l.vert.co)
+ bgl.glVertex3f(co[0], co[1], co[2])
+ bgl.glEnd()
+
+ # Render faces whose UV is flipped.
+ if sc.muv_uv_inspection_show_flipped:
+ color = prefs.uv_inspection_flipped_color_for_v3d
+ for obj, findices in props.filpped_info_for_v3d.items():
+ world_mat = obj.matrix_world
+ bm = bmesh.from_edit_mesh(obj.data)
+
+ for fidx in findices:
+ bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+ bgl.glColor4f(color[0], color[1], color[2], color[3])
+ for l in bm.faces[fidx].loops:
+ co = compat.matmul(world_mat, l.vert.co)
+ bgl.glVertex3f(co[0], co[1], co[2])
+ bgl.glEnd()
+
+ bgl.glDisable(bgl.GL_DEPTH_TEST)
+ bgl.glDisable(bgl.GL_BLEND)
+
@staticmethod
def draw(_, context):
sc = context.scene
diff --git a/magic_uv/op/uv_sculpt.py b/magic_uv/op/uv_sculpt.py
index c9ed4f34..0821f0bc 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.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from math import pi, cos, tan, sin
diff --git a/magic_uv/op/uvw.py b/magic_uv/op/uvw.py
index 42918dd5..3b155b89 100644
--- a/magic_uv/op/uvw.py
+++ b/magic_uv/op/uvw.py
@@ -20,8 +20,8 @@
__author__ = "Alexander Milovsky, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from math import sin, cos, pi
@@ -30,7 +30,8 @@ import bmesh
from bpy.props import (
FloatProperty,
FloatVectorProperty,
- BoolProperty
+ BoolProperty,
+ EnumProperty
)
from mathutils import Vector
@@ -70,7 +71,9 @@ def _get_uv_layer(ops_obj, bm, assign_uvmap):
return uv_layer
-def _apply_box_map(bm, uv_layer, size, offset, rotation, tex_aspect):
+def _apply_box_map(bm, uv_layer, size, offset, rotation,
+ tex_aspect, force_axis, force_axis_tex_aspect_correction,
+ force_axis_rotation):
scale = 1.0 / size
sx = 1.0 * scale
@@ -82,7 +85,10 @@ def _apply_box_map(bm, uv_layer, size, offset, rotation, tex_aspect):
rx = rotation[0] * pi / 180.0
ry = rotation[1] * pi / 180.0
rz = rotation[2] * pi / 180.0
- aspect = tex_aspect
+
+ farx = force_axis_rotation[0] * pi / 180.0
+ fary = force_axis_rotation[1] * pi / 180.0
+ farz = force_axis_rotation[2] * pi / 180.0
sel_faces = [f for f in bm.faces if f.select]
@@ -94,37 +100,116 @@ def _apply_box_map(bm, uv_layer, size, offset, rotation, tex_aspect):
x = co.x * sx
y = co.y * sy
z = co.z * sz
-
- # X-plane
- if abs(n[0]) >= abs(n[1]) and abs(n[0]) >= abs(n[2]):
- if n[0] >= 0.0:
- u = (y - ofy) * cos(rx) + (z - ofz) * sin(rx)
- v = -(y * aspect - ofy) * sin(rx) + \
- (z * aspect - ofz) * cos(rx)
- else:
- u = -(y - ofy) * cos(rx) + (z - ofz) * sin(rx)
- v = (y * aspect - ofy) * sin(rx) + \
- (z * aspect - ofz) * cos(rx)
- # Y-plane
- elif abs(n[1]) >= abs(n[0]) and abs(n[1]) >= abs(n[2]):
- if n[1] >= 0.0:
- u = -(x - ofx) * cos(ry) + (z - ofz) * sin(ry)
- v = (x * aspect - ofx) * sin(ry) + \
- (z * aspect - ofz) * cos(ry)
- else:
- u = (x - ofx) * cos(ry) + (z - ofz) * sin(ry)
- v = -(x * aspect - ofx) * sin(ry) + \
- (z * aspect - ofz) * cos(ry)
- # Z-plane
- else:
- if n[2] >= 0.0:
- u = (x - ofx) * cos(rz) + (y - ofy) * sin(rz)
- v = -(x * aspect - ofx) * sin(rz) + \
- (y * aspect - ofy) * cos(rz)
- else:
- u = -(x - ofx) * cos(rz) - (y + ofy) * sin(rz)
- v = -(x * aspect + ofx) * sin(rz) + \
- (y * aspect - ofy) * cos(rz)
+ aspect = tex_aspect
+
+ transformed = False
+ if force_axis == 'X':
+ # Use Y-plane
+ if abs(n[1]) < abs(n[0]) and abs(n[1]) >= abs(n[2]):
+ aspect *= force_axis_tex_aspect_correction
+ if n[1] >= 0.0:
+ u = -(x - ofx) * cos(fary) + (z - ofz) * sin(fary)
+ v = (x * aspect - ofx) * sin(fary) + \
+ (z * aspect - ofz) * cos(fary)
+ else:
+ u = (x - ofx) * cos(fary) + (z - ofz) * sin(fary)
+ v = -(x * aspect - ofx) * sin(fary) + \
+ (z * aspect - ofz) * cos(fary)
+ transformed = True
+ # Use Z-plane
+ elif abs(n[2]) < abs(n[0]) and abs(n[2]) >= abs(n[1]):
+ aspect *= force_axis_tex_aspect_correction
+ if n[2] >= 0.0:
+ u = (x - ofx) * cos(farz) + (y - ofy) * sin(farz)
+ v = -(x * aspect - ofx) * sin(farz) + \
+ (y * aspect - ofy) * cos(farz)
+ else:
+ u = -(x - ofx) * cos(farz) - (y + ofy) * sin(farz)
+ v = -(x * aspect + ofx) * sin(farz) + \
+ (y * aspect - ofy) * cos(farz)
+ transformed = True
+ elif force_axis == 'Y':
+ # Use X-plane
+ if abs(n[0]) < abs(n[1]) and abs(n[0]) >= abs(n[2]):
+ aspect *= force_axis_tex_aspect_correction
+ if n[0] >= 0.0:
+ u = (y - ofy) * cos(farx) + (z - ofz) * sin(farx)
+ v = -(y * aspect - ofy) * sin(farx) + \
+ (z * aspect - ofz) * cos(farx)
+ else:
+ u = -(y - ofy) * cos(farx) + (z - ofz) * sin(farx)
+ v = (y * aspect - ofy) * sin(farx) + \
+ (z * aspect - ofz) * cos(farx)
+ transformed = True
+ # Use Z-plane
+ elif abs(n[2]) >= abs(n[0]) and abs(n[2]) < abs(n[1]):
+ aspect *= force_axis_tex_aspect_correction
+ if n[2] >= 0.0:
+ u = (x - ofx) * cos(farz) + (y - ofy) * sin(farz)
+ v = -(x * aspect - ofx) * sin(farz) + \
+ (y * aspect - ofy) * cos(farz)
+ else:
+ u = -(x - ofx) * cos(farz) - (y + ofy) * sin(farz)
+ v = -(x * aspect + ofx) * sin(farz) + \
+ (y * aspect - ofy) * cos(farz)
+ transformed = True
+ elif force_axis == 'Z':
+ # Use X-plane
+ if abs(n[0]) >= abs(n[1]) and abs(n[0]) < abs(n[2]):
+ aspect *= force_axis_tex_aspect_correction
+ if n[0] >= 0.0:
+ u = (y - ofy) * cos(farx) + (z - ofz) * sin(farx)
+ v = -(y * aspect - ofy) * sin(farx) + \
+ (z * aspect - ofz) * cos(farx)
+ else:
+ u = -(y - ofy) * cos(farx) + (z - ofz) * sin(farx)
+ v = (y * aspect - ofy) * sin(farx) + \
+ (z * aspect - ofz) * cos(farx)
+ transformed = True
+ # Use Y-plane
+ elif abs(n[1]) >= abs(n[0]) and abs(n[1]) < abs(n[2]):
+ aspect *= force_axis_tex_aspect_correction
+ if n[1] >= 0.0:
+ u = -(x - ofx) * cos(fary) + (z - ofz) * sin(fary)
+ v = (x * aspect - ofx) * sin(fary) + \
+ (z * aspect - ofz) * cos(fary)
+ else:
+ u = (x - ofx) * cos(fary) + (z - ofz) * sin(fary)
+ v = -(x * aspect - ofx) * sin(fary) + \
+ (z * aspect - ofz) * cos(fary)
+ transformed = True
+
+ if not transformed:
+ # X-plane
+ if abs(n[0]) >= abs(n[1]) and abs(n[0]) >= abs(n[2]):
+ if n[0] >= 0.0:
+ u = (y - ofy) * cos(rx) + (z - ofz) * sin(rx)
+ v = -(y * aspect - ofy) * sin(rx) + \
+ (z * aspect - ofz) * cos(rx)
+ else:
+ u = -(y - ofy) * cos(rx) + (z - ofz) * sin(rx)
+ v = (y * aspect - ofy) * sin(rx) + \
+ (z * aspect - ofz) * cos(rx)
+ # Y-plane
+ elif abs(n[1]) >= abs(n[0]) and abs(n[1]) >= abs(n[2]):
+ if n[1] >= 0.0:
+ u = -(x - ofx) * cos(ry) + (z - ofz) * sin(ry)
+ v = (x * aspect - ofx) * sin(ry) + \
+ (z * aspect - ofz) * cos(ry)
+ else:
+ u = (x - ofx) * cos(ry) + (z - ofz) * sin(ry)
+ v = -(x * aspect - ofx) * sin(ry) + \
+ (z * aspect - ofz) * cos(ry)
+ # Z-plane
+ elif abs(n[2]) >= abs(n[0]) and abs(n[2]) >= abs(n[1]):
+ if n[2] >= 0.0:
+ u = (x - ofx) * cos(rz) + (y - ofy) * sin(rz)
+ v = -(x * aspect - ofx) * sin(rz) + \
+ (y * aspect - ofy) * cos(rz)
+ else:
+ u = -(x - ofx) * cos(rz) - (y + ofy) * sin(rz)
+ v = -(x * aspect + ofx) * sin(rz) + \
+ (y * aspect - ofy) * cos(rz)
l[uv_layer].uv = Vector((u, v))
@@ -196,14 +281,16 @@ class MUV_OT_UVW_BoxMap(bpy.types.Operator):
precision=4
)
rotation = FloatVectorProperty(
- name="XYZ Rotation",
+ name="Rotation",
size=3,
- default=(0.0, 0.0, 0.0)
+ default=(0.0, 0.0, 0.0),
+ subtype='XYZ'
)
offset = FloatVectorProperty(
- name="XYZ Offset",
+ name="Offset",
size=3,
- default=(0.0, 0.0, 0.0)
+ default=(0.0, 0.0, 0.0),
+ subtype='XYZ'
)
tex_aspect = FloatProperty(
name="Texture Aspect",
@@ -215,6 +302,30 @@ class MUV_OT_UVW_BoxMap(bpy.types.Operator):
description="Assign UVMap when no UVmaps are available",
default=True
)
+ force_axis = EnumProperty(
+ name="Force Axis",
+ description="Axis to force the mapping",
+ items=[
+ ('NONE', "None", "None"),
+ ('X', "X", "Axis X"),
+ ('Y', "Y", "Axis Y"),
+ ('Z', "Z", "Axis Z")
+ ],
+ default='NONE'
+ )
+ force_axis_tex_aspect_correction = FloatProperty(
+ name="Texture Aspect Correction (Force Axis)",
+ description="Texture Aspect correction for the faces mapped forcibly",
+ default=3.14,
+ precision=4
+ )
+ force_axis_rotation = FloatVectorProperty(
+ name="Rotation (Force Axis)",
+ description="Rotation for the faces mapped forcibly",
+ size=3,
+ default=(0.0, 0.0, 0.0),
+ subtype='XYZ'
+ )
@classmethod
def poll(cls, context):
@@ -223,6 +334,39 @@ class MUV_OT_UVW_BoxMap(bpy.types.Operator):
return True
return _is_valid_context(context)
+ def draw(self, _):
+ layout = self.layout
+
+ col = layout.column()
+ row = col.row()
+ row.label(text="Size:")
+ row.prop(self, "size", text="")
+
+ layout.label(text="Rotation:")
+ layout.row().prop(self, "rotation", text="")
+
+ layout.label(text="Offset:")
+ layout.row().prop(self, "offset", text="")
+
+ col = layout.column()
+ row = col.row()
+ row.label(text="Texture Aspect:")
+ row.prop(self, "tex_aspect", text="")
+
+ layout.prop(self, "assign_uvmap")
+
+ layout.separator(factor=2.0)
+
+ layout.prop(self, "force_axis")
+ if self.force_axis != 'NONE':
+ col = layout.column()
+ row = col.row()
+ row.label(text="Texture Aspect Correction (Force Axis)")
+ row.prop(self, "force_axis_tex_aspect_correction", text="")
+
+ layout.label(text="Rotation (Force Axis)")
+ layout.row().prop(self, "force_axis_rotation", text="")
+
def execute(self, context):
objs = common.get_uv_editable_objects(context)
@@ -237,7 +381,9 @@ class MUV_OT_UVW_BoxMap(bpy.types.Operator):
return {'CANCELLED'}
_apply_box_map(bm, uv_layer, self.size, self.offset, self.rotation,
- self.tex_aspect)
+ self.tex_aspect, self.force_axis,
+ self.force_axis_tex_aspect_correction,
+ self.force_axis_rotation)
bmesh.update_edit_mesh(obj.data)
return {'FINISHED'}
@@ -256,11 +402,11 @@ class MUV_OT_UVW_BestPlanerMap(bpy.types.Operator):
precision=4
)
rotation = FloatProperty(
- name="XY Rotation",
+ name="Rotation",
default=0.0
)
offset = FloatVectorProperty(
- name="XY Offset",
+ name="Offset",
size=2,
default=(0.0, 0.0)
)
diff --git a/magic_uv/op/world_scale_uv.py b/magic_uv/op/world_scale_uv.py
index a2806db5..dd42ed3d 100644
--- a/magic_uv/op/world_scale_uv.py
+++ b/magic_uv/op/world_scale_uv.py
@@ -20,8 +20,8 @@
__author__ = "McBuff, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from math import sqrt
@@ -97,11 +97,11 @@ def _measure_wsuv_info(obj, calc_method='MESH',
return uv_areas, mesh_areas, densities
-def _measure_wsuv_info_from_faces(obj, faces, uv_layer, tex_layer,
+def _measure_wsuv_info_from_faces(obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='FIRST', tex_size=None):
- mesh_area = common.measure_mesh_area_from_faces(faces)
+ mesh_area = common.measure_mesh_area_from_faces(bm, faces)
uv_area = common.measure_uv_area_from_faces(
- obj, faces, uv_layer, tex_layer, tex_selection_method, tex_size)
+ obj, bm, faces, uv_layer, tex_layer, tex_selection_method, tex_size)
if not uv_area:
return None, mesh_area, None
@@ -376,7 +376,12 @@ class MUV_OT_WorldScaleUV_Measure(bpy.types.Operator):
@staticmethod
def setup_argument(ops, scene):
- ops.tgt_texture = scene.muv_world_scale_uv_measure_tgt_texture
+ try:
+ ops.tgt_texture = scene.muv_world_scale_uv_measure_tgt_texture
+ except TypeError:
+ # Workaround for the error raised when the items of EnumProperty
+ # are deleted.
+ ops.tgt_texture = "[Average]"
ops.only_selected = scene.muv_world_scale_uv_measure_only_selected
def execute(self, context):
@@ -524,7 +529,7 @@ class MUV_OT_WorldScaleUV_ApplyManual(bpy.types.Operator):
factors = []
for faces in faces_list:
uv_area, _, density = _measure_wsuv_info_from_faces(
- obj, faces, uv_layer, tex_layer,
+ obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='USER_SPECIFIED', tex_size=tex_size)
if not uv_area:
@@ -659,7 +664,12 @@ class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
ops.src_density = scene.muv_world_scale_uv_src_density
ops.same_density = False
ops.show_dialog = False
- ops.tgt_texture = scene.muv_world_scale_uv_apply_tgt_texture
+ try:
+ ops.tgt_texture = scene.muv_world_scale_uv_apply_tgt_texture
+ except TypeError:
+ # Workaround for the error raised when the items of EnumProperty
+ # are deleted.
+ ops.tgt_texture = "[Average]"
ops.tgt_area_calc_method = \
scene.muv_world_scale_uv_tgt_area_calc_method
ops.only_selected = scene.muv_world_scale_uv_apply_only_selected
@@ -688,20 +698,20 @@ class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
for faces in faces_list:
if self.tgt_texture == "[Average]":
uv_area, _, density = _measure_wsuv_info_from_faces(
- obj, faces, uv_layer, tex_layer,
+ obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='AVERAGE')
elif self.tgt_texture == "[Max]":
uv_area, _, density = _measure_wsuv_info_from_faces(
- obj, faces, uv_layer, tex_layer,
+ obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='MAX')
elif self.tgt_texture == "[Min]":
uv_area, _, density = _measure_wsuv_info_from_faces(
- obj, faces, uv_layer, tex_layer,
+ obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='MIN')
else:
tgt_texture = bpy.data.images[self.tgt_texture]
uv_area, _, density = _measure_wsuv_info_from_faces(
- obj, faces, uv_layer, tex_layer,
+ obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='USER_SPECIFIED',
tex_size=tgt_texture.size)
@@ -859,7 +869,12 @@ class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
ops.src_uv_area = scene.muv_world_scale_uv_src_uv_area
ops.src_mesh_area = scene.muv_world_scale_uv_src_mesh_area
ops.show_dialog = False
- ops.tgt_texture = scene.muv_world_scale_uv_apply_tgt_texture
+ try:
+ ops.tgt_texture = scene.muv_world_scale_uv_apply_tgt_texture
+ except TypeError:
+ # Workaround for the error raised when the items of EnumProperty
+ # are deleted.
+ ops.tgt_texture = "[Average]"
ops.tgt_area_calc_method = \
scene.muv_world_scale_uv_tgt_area_calc_method
ops.only_selected = scene.muv_world_scale_uv_apply_only_selected
@@ -889,23 +904,23 @@ class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
if self.tgt_texture == "[Average]":
uv_area, mesh_area, density = \
_measure_wsuv_info_from_faces(
- obj, faces, uv_layer, tex_layer,
+ obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='AVERAGE')
elif self.tgt_texture == "[Max]":
uv_area, mesh_area, density = \
_measure_wsuv_info_from_faces(
- obj, faces, uv_layer, tex_layer,
+ obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='MAX')
elif self.tgt_texture == "[Min]":
uv_area, mesh_area, density = \
_measure_wsuv_info_from_faces(
- obj, faces, uv_layer, tex_layer,
+ obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='MIN')
else:
tgt_texture = bpy.data.images[self.tgt_texture]
uv_area, mesh_area, density = \
_measure_wsuv_info_from_faces(
- obj, faces, uv_layer, tex_layer,
+ obj, bm, faces, uv_layer, tex_layer,
tex_selection_method='USER_SPECIFIED',
tex_size=tgt_texture.size)
if not uv_area:
diff --git a/magic_uv/preferences.py b/magic_uv/preferences.py
index ea8e7434..21f70508 100644
--- a/magic_uv/preferences.py
+++ b/magic_uv/preferences.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
from bpy.props import (
@@ -241,6 +241,15 @@ class MUV_Preferences(AddonPreferences):
size=4,
subtype='COLOR'
)
+ uv_inspection_overlapped_color_for_v3d = FloatVectorProperty(
+ name="Color (View3D)",
+ description="Color in View3D",
+ default=(0.0, 0.0, 1.0, 0.5),
+ min=0.0,
+ max=1.0,
+ size=4,
+ subtype='COLOR'
+ )
# for Flipped UV
uv_inspection_flipped_color = FloatVectorProperty(
@@ -252,6 +261,15 @@ class MUV_Preferences(AddonPreferences):
size=4,
subtype='COLOR'
)
+ uv_inspection_flipped_color_for_v3d = FloatVectorProperty(
+ name="Color (View3D)",
+ description="Color in View3D",
+ default=(1.0, 0.0, 0.0, 0.5),
+ min=0.0,
+ max=1.0,
+ size=4,
+ subtype='COLOR'
+ )
# for Texture Projection
texture_projection_canvas_padding = FloatVectorProperty(
@@ -458,6 +476,20 @@ class MUV_Preferences(AddonPreferences):
col = sp.column()
col.label(text="Flipped UV Color:")
col.prop(self, "uv_inspection_flipped_color", text="")
+
+ sp = compat.layout_split(layout, 0.05)
+ col = sp.column() # spacer
+ sp = compat.layout_split(sp, 0.3)
+ col = sp.column()
+ col.label(text="Overlapped UV Color (View3D):")
+ col.prop(self, "uv_inspection_overlapped_color_for_v3d",
+ text="")
+ sp = compat.layout_split(sp, 0.45)
+ col = sp.column()
+ col.label(text="Flipped UV Color (View3D):")
+ col.prop(self, "uv_inspection_flipped_color_for_v3d",
+ text="")
+
layout.separator()
layout.prop(
diff --git a/magic_uv/properites.py b/magic_uv/properites.py
index 28b9216d..a301d64f 100644
--- a/magic_uv/properites.py
+++ b/magic_uv/properites.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from .utils.property_class_registry import PropertyClassRegistry
diff --git a/magic_uv/ui/IMAGE_MT_uvs.py b/magic_uv/ui/IMAGE_MT_uvs.py
index 3984c20f..79199cfd 100644
--- a/magic_uv/ui/IMAGE_MT_uvs.py
+++ b/magic_uv/ui/IMAGE_MT_uvs.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
@@ -123,13 +123,16 @@ class MUV_MT_SelectUV(bpy.types.Menu):
bl_label = "Select UV"
bl_description = "Select UV"
- def draw(self, _):
+ def draw(self, context):
+ sc = context.scene
layout = self.layout
- layout.operator(MUV_OT_SelectUV_SelectOverlapped.bl_idname,
- text="Overlapped")
- layout.operator(MUV_OT_SelectUV_SelectFlipped.bl_idname,
- text="Flipped")
+ ops = layout.operator(MUV_OT_SelectUV_SelectOverlapped.bl_idname,
+ text="Overlapped")
+ MUV_OT_SelectUV_SelectOverlapped.setup_argument(ops, sc)
+ ops = layout.operator(MUV_OT_SelectUV_SelectFlipped.bl_idname,
+ text="Flipped")
+ MUV_OT_SelectUV_SelectFlipped.setup_argument(ops, sc)
@BlClassRegistry()
diff --git a/magic_uv/ui/VIEW3D_MT_object.py b/magic_uv/ui/VIEW3D_MT_object.py
index c8980592..e4255c3a 100644
--- a/magic_uv/ui/VIEW3D_MT_object.py
+++ b/magic_uv/ui/VIEW3D_MT_object.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
diff --git a/magic_uv/ui/VIEW3D_MT_uv_map.py b/magic_uv/ui/VIEW3D_MT_uv_map.py
index e6574f4d..a795ad48 100644
--- a/magic_uv/ui/VIEW3D_MT_uv_map.py
+++ b/magic_uv/ui/VIEW3D_MT_uv_map.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy.utils
diff --git a/magic_uv/ui/__init__.py b/magic_uv/ui/__init__.py
index 083590a6..ebf11949 100644
--- a/magic_uv/ui/__init__.py
+++ b/magic_uv/ui/__init__.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
if "bpy" in locals():
import importlib
diff --git a/magic_uv/ui/uvedit_copy_paste_uv.py b/magic_uv/ui/uvedit_copy_paste_uv.py
index 5f029f6f..2f652460 100644
--- a/magic_uv/ui/uvedit_copy_paste_uv.py
+++ b/magic_uv/ui/uvedit_copy_paste_uv.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
diff --git a/magic_uv/ui/uvedit_editor_enhancement.py b/magic_uv/ui/uvedit_editor_enhancement.py
index a0eba3a9..3d1e9ba3 100644
--- a/magic_uv/ui/uvedit_editor_enhancement.py
+++ b/magic_uv/ui/uvedit_editor_enhancement.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
@@ -143,6 +143,10 @@ class MUV_PT_UVEdit_EditorEnhancement(bpy.types.Panel):
row.prop(sc, "muv_uv_inspection_show_overlapped")
row.prop(sc, "muv_uv_inspection_show_flipped")
row = box.row()
+ row.prop(sc, "muv_uv_inspection_display_in_v3d", text="3D")
row.prop(sc, "muv_uv_inspection_show_mode")
+ if sc.muv_uv_inspection_show_overlapped:
+ row = box.row()
+ row.prop(sc, "muv_uv_inspection_same_polygon_threshold")
box.separator()
box.operator(MUV_OT_UVInspection_PaintUVIsland.bl_idname)
diff --git a/magic_uv/ui/uvedit_uv_manipulation.py b/magic_uv/ui/uvedit_uv_manipulation.py
index 1b05cb00..4a4358da 100644
--- a/magic_uv/ui/uvedit_uv_manipulation.py
+++ b/magic_uv/ui/uvedit_uv_manipulation.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
@@ -41,6 +41,7 @@ from ..op.smooth_uv import (
from ..op.select_uv import (
MUV_OT_SelectUV_SelectOverlapped,
MUV_OT_SelectUV_SelectFlipped,
+ MUV_OT_SelectUV_ZoomSelectedUV,
)
from ..op.pack_uv import MUV_OT_PackUV
from ..op.clip_uv import MUV_OT_ClipUV
@@ -176,8 +177,20 @@ class MUV_PT_UVEdit_UVManipulation(bpy.types.Panel):
box.prop(sc, "muv_select_uv_enabled", text="Select UV")
if sc.muv_select_uv_enabled:
row = box.row(align=True)
- row.operator(MUV_OT_SelectUV_SelectOverlapped.bl_idname)
- row.operator(MUV_OT_SelectUV_SelectFlipped.bl_idname)
+ ops = row.operator(MUV_OT_SelectUV_SelectOverlapped.bl_idname)
+ MUV_OT_SelectUV_SelectOverlapped.setup_argument(ops, sc)
+ ops = row.operator(MUV_OT_SelectUV_SelectFlipped.bl_idname)
+ MUV_OT_SelectUV_SelectFlipped.setup_argument(ops, sc)
+
+ col = box.column()
+ col.label(text="Same Polygon Threshold:")
+ col.prop(sc, "muv_select_uv_same_polygon_threshold", text="")
+ col.prop(sc, "muv_select_uv_selection_method")
+ col.prop(sc, "muv_select_uv_sync_mesh_selection")
+
+ box.separator()
+
+ box.operator(MUV_OT_SelectUV_ZoomSelectedUV.bl_idname)
box = layout.box()
box.prop(sc, "muv_pack_uv_enabled", text="Pack UV (Extension)")
diff --git a/magic_uv/ui/view3d_copy_paste_uv_editmode.py b/magic_uv/ui/view3d_copy_paste_uv_editmode.py
index 762fd9d9..6a458aff 100644
--- a/magic_uv/ui/view3d_copy_paste_uv_editmode.py
+++ b/magic_uv/ui/view3d_copy_paste_uv_editmode.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
diff --git a/magic_uv/ui/view3d_copy_paste_uv_objectmode.py b/magic_uv/ui/view3d_copy_paste_uv_objectmode.py
index 71d30755..b4fb3934 100644
--- a/magic_uv/ui/view3d_copy_paste_uv_objectmode.py
+++ b/magic_uv/ui/view3d_copy_paste_uv_objectmode.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
diff --git a/magic_uv/ui/view3d_uv_manipulation.py b/magic_uv/ui/view3d_uv_manipulation.py
index 6d0fce6d..dde58266 100644
--- a/magic_uv/ui/view3d_uv_manipulation.py
+++ b/magic_uv/ui/view3d_uv_manipulation.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
@@ -94,7 +94,9 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
row = box.row()
ops = row.operator(MUV_OT_MirrorUV.bl_idname, text="Mirror")
ops.axis = sc.muv_mirror_uv_axis
+ ops.origin = sc.muv_mirror_uv_origin
row.prop(sc, "muv_mirror_uv_axis", text="")
+ box.prop(sc, "muv_mirror_uv_origin")
box = layout.box()
box.prop(sc, "muv_move_uv_enabled", text="Move UV")
diff --git a/magic_uv/ui/view3d_uv_mapping.py b/magic_uv/ui/view3d_uv_mapping.py
index 6a4217c0..22d20b4f 100644
--- a/magic_uv/ui/view3d_uv_mapping.py
+++ b/magic_uv/ui/view3d_uv_mapping.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
@@ -92,8 +92,18 @@ class MUV_PT_View3D_UVMapping(bpy.types.Panel):
row.prop(sc, "muv_texture_projection_adjust_window",
text="Adjust Window")
if not sc.muv_texture_projection_adjust_window:
- row.prop(sc, "muv_texture_projection_tex_magnitude",
- text="Magnitude")
+ sp = compat.layout_split(col, factor=0.5)
+ sub = sp.column()
+ sub.prop(sc, "muv_texture_projection_tex_scaling",
+ text="Scaling")
+ sp = compat.layout_split(sp, factor=1.0)
+ sub = sp.column()
+ sub.prop(sc, "muv_texture_projection_tex_translation",
+ text="Translation")
+ row = col.row()
+ row.label(text="Rotation:")
+ row.prop(sc, "muv_texture_projection_tex_rotation", text="")
+ col.separator()
col.prop(sc, "muv_texture_projection_apply_tex_aspect",
text="Texture Aspect Ratio")
col.prop(sc, "muv_texture_projection_assign_uvmap",
diff --git a/magic_uv/updater.py b/magic_uv/updater.py
index a9e09bfa..72d85766 100644
--- a/magic_uv/updater.py
+++ b/magic_uv/updater.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import os
@@ -131,7 +131,7 @@ def register_updater(bl_info):
config.owner = "nutti"
config.repository = "Magic-UV"
config.current_addon_path = os.path.dirname(os.path.realpath(__file__))
- config.branches = ["master", "develop"]
+ config.branches = ["master"]
config.addon_directory = \
config.current_addon_path[
:config.current_addon_path.rfind(get_separator())]
@@ -139,7 +139,6 @@ def register_updater(bl_info):
config.default_target_addon_path = "magic_uv"
config.target_addon_path = {
"master": "src{}magic_uv".format(get_separator()),
- "develop": "src{}magic_uv".format(get_separator()),
}
updater = AddonUpdaterManager.get_instance()
updater.init(bl_info, config)
diff --git a/magic_uv/utils/__init__.py b/magic_uv/utils/__init__.py
index 918bc207..776c7564 100644
--- a/magic_uv/utils/__init__.py
+++ b/magic_uv/utils/__init__.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
if "bpy" in locals():
import importlib
diff --git a/magic_uv/utils/addon_updater.py b/magic_uv/utils/addon_updater.py
index 813813eb..8c1601b8 100644
--- a/magic_uv/utils/addon_updater.py
+++ b/magic_uv/utils/addon_updater.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from threading import Lock
import urllib
diff --git a/magic_uv/utils/bl_class_registry.py b/magic_uv/utils/bl_class_registry.py
index 080a1a45..93f29244 100644
--- a/magic_uv/utils/bl_class_registry.py
+++ b/magic_uv/utils/bl_class_registry.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
diff --git a/magic_uv/utils/compatibility.py b/magic_uv/utils/compatibility.py
index 517c33af..d17f2c66 100644
--- a/magic_uv/utils/compatibility.py
+++ b/magic_uv/utils/compatibility.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
import bpy
import bgl
@@ -47,7 +47,9 @@ def make_annotations(cls):
return cls
# make annotation from attributes
- props = {k: v for k, v in cls.__dict__.items() if isinstance(v, tuple)}
+ props = {k: v
+ for k, v in cls.__dict__.items()
+ if isinstance(v, getattr(bpy.props, '_PropertyDeferred', tuple))}
if props:
if '__annotations__' not in cls.__dict__:
setattr(cls, '__annotations__', {})
diff --git a/magic_uv/utils/property_class_registry.py b/magic_uv/utils/property_class_registry.py
index f107aed3..ef4f5872 100644
--- a/magic_uv/utils/property_class_registry.py
+++ b/magic_uv/utils/property_class_registry.py
@@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
-__version__ = "6.4"
-__date__ = "23 Oct 2020"
+__version__ = "6.5"
+__date__ = "6 Mar 2021"
from .. import common