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
This commit is contained in:
parent
c875244331
commit
117faa96af
|
@ -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",
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
aspect = tex_aspect
|
||||
|
||||
# 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)
|
||||
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)
|
||||
)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)")
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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__', {})
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue