TexTools is a UV and Texture tool set for 3dsMax created several years ago. This open repository will port in time several of the UV tools to Blender in python. http://renderhjs.net/textools/blender
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

358 lines
11 KiB

import bpy
import os
import bmesh
import math
import operator
from mathutils import Vector
from collections import defaultdict
from itertools import chain # 'flattens' collection of iterables
from . import utilities_uv
class op(bpy.types.Operator):
bl_idname = "uv.textools_edge_split_bevel"
bl_label = "Split Bevel"
bl_description = "..."
bl_options = {'REGISTER', 'UNDO'}
radius: bpy.props.FloatProperty(
name="Space",
description="Space for split bevel",
default=0.015,
min=0,
max=0.35
)
@classmethod
def poll(cls, context):
if not bpy.context.active_object:
return False
# Only in Edit mode
if bpy.context.active_object.mode != 'EDIT':
return False
# Requires UV map
if not bpy.context.object.data.uv_layers:
return False
if bpy.context.scene.tool_settings.use_uv_select_sync:
return False
# Only in UV editor mode
if bpy.context.area.type != 'IMAGE_EDITOR':
return False
return True
def execute(self, context):
main(self, self.radius)
return {'FINISHED'}
def main(self, radius):
# Store selection
utilities_uv.selection_store()
print("____________\nedge split UV sharp edges {}".format(radius))
obj = bpy.context.object
bm = bmesh.from_edit_mesh(bpy.context.active_object.data)
uv_layers = bm.loops.layers.uv.verify()
islands = utilities_uv.getSelectionIslands()
# Collect UV to Vert
vert_to_uv = utilities_uv.get_vert_to_uv(bm, uv_layers)
uv_to_vert = utilities_uv.get_uv_to_vert(bm, uv_layers)
# Collect hard edges
edges = []
for edge in bm.edges:
if edge.select and not edge.smooth:
# edge.link_faces
# print("Hard edge: {} - {}".format(edge.verts[0].index, edge.verts[1].index))
edges.append(edge)
# Get vert rails to slide
vert_rails = get_vert_edge_rails(edges)
# Get left and right faces
edge_face_pairs = get_edge_face_pairs(edges)
print("Vert rails: {}x".format(len(vert_rails)))
# for vert in vert_rails:
# print(".. v.idx {} = {}x".format(vert.index, len(vert_rails[vert]) ))
vert_processed = []
vert_uv_pos = []
for edge in edges:
if len(edge_face_pairs[edge]) == 2:
v0 = edge.verts[0]
v1 = edge.verts[1]
f0 = edge_face_pairs[edge][0]
f1 = edge_face_pairs[edge][1]
# v0
if v0 not in vert_processed:
vert_processed.append(v0)
faces, origin, delta = slide_uvs(
v0, edge, f0, edges, vert_rails, vert_to_uv)
vert_uv_pos.append(
{"v": v0, "f": f0, "origin": origin, "delta": delta, "faces": faces})
faces, origin, delta = slide_uvs(
v0, edge, f1, edges, vert_rails, vert_to_uv)
vert_uv_pos.append(
{"v": v0, "f": f1, "origin": origin, "delta": delta, "faces": faces})
# V1
if v1 not in vert_processed:
vert_processed.append(v1)
faces, origin, delta = slide_uvs(
v1, edge, f0, edges, vert_rails, vert_to_uv)
vert_uv_pos.append(
{"v": v1, "f": f0, "origin": origin, "delta": delta, "faces": faces})
faces, origin, delta = slide_uvs(
v1, edge, f1, edges, vert_rails, vert_to_uv)
vert_uv_pos.append(
{"v": v1, "f": f1, "origin": origin, "delta": delta, "faces": faces})
# ...
for item in vert_uv_pos:
v = item["v"]
for face in item["faces"]:
if v in face.verts:
for loop in face.loops:
if loop.vert == v:
loop[uv_layers].uv = item["origin"] + \
item["delta"] * (radius/2)
# for f in faces:
# for loop in f.loops:
# if loop.vert == vert:
# loop[uv_layers].uv= vert_to_uv[vert][0].uv + item["delta"] * radius/2
# for loop in face.loops:
# if loop.vert == vert:
# loop[uv_layers].uv+= avg_uv_delta
# Restore selection
utilities_uv.selection_restore()
def slide_uvs(vert, edge, face, edges, vert_rails, vert_to_uv):
def IS_DEBUG():
return vert.index == 64 and edge.verts[0].index == 64 and edge.verts[1].index == 63
A = edge.verts[0]
B = edge.verts[1]
A_links, B_links = get_edge_prev_next(edge, edges)
verts_edges = {edge.verts[0], edge.verts[1]}
for v in A_links:
verts_edges.add(v)
for v in B_links:
verts_edges.add(v)
if IS_DEBUG():
print("\r")
print(
"Edge {} <--> {} ({})".format(edge.verts[0].index, edge.verts[1].index, vert.index))
# Collect faces of this side
'''
faces = [face]
face_edges_used = [e for e in face.edges if e in edges]
for e in face.edges:
if e not in face_edges_used:
for f in e.link_faces:
if f != face:
faces.append(f)
'''
faces = [face]
edges_main_used = [edge]
for i in range(2):
append = []
for f in faces:
for e in f.edges:
if e not in edges_main_used:
if e in edges:
edges_main_used.append(e)
for f_link in e.link_faces:
if f_link not in faces:
append.append(f_link)
faces.extend(append)
if IS_DEBUG():
print(" Faces {}x = {}".format(len(faces), [f.index for f in faces]))
# Get all face edges that could be valid rails
face_edges = list(
set([e for f in faces for e in f.edges if e not in edges]))
# The verts influencing the offset
verts = [A, B]
if vert == A:
verts.extend(B_links)
elif vert == B:
verts.extend(A_links)
# verts = [vert]
if IS_DEBUG():
print(" Verts: {}x = {}".format(len(verts), [v.index for v in verts]))
print(" Rails:")
delta = Vector((0, 0))
count = 0.0
for v in verts:
rails = [e for e in vert_rails[v] if e in face_edges]
if IS_DEBUG():
print(" #{} rails = {}".format(v.index, [
("{} - {}".format(e.verts[0].index, e.verts[1].index)) for e in rails]))
for e in rails:
# determine order
v0 = None
v1 = None
if e.verts[0] in verts_edges:
v0 = e.verts[0]
v1 = e.verts[1]
elif e.verts[1] in verts_edges:
v0 = e.verts[1]
v1 = e.verts[0]
uv0 = vert_to_uv[v0][0].uv
uv1 = vert_to_uv[v1][0].uv
delta += (uv1-uv0).normalized()
count += 1.0
delta /= count
if IS_DEBUG():
print("\r")
return faces, vert_to_uv[vert][0].uv.copy(), delta.normalized()
# print(" V{} = {}".format(v.index, avg_uv_delta))
# for loop in face.loops:
# if loop.vert == vert:
# loop[uv_layers].uv+= avg_uv_delta
'''
def slide_face_uvs(uv_layers, edge, vert, face, radius, vert_to_uv):
avg_target = Vector((0,0))
avg_count = 0
for e in face.edges:
if e != edge and vert in e.verts:
vert_B = e.verts[0]
if vert == e.verts[0]:
vert_B = e.verts[1]
A = vert_to_uv[vert][0].uv
B = vert_to_uv[vert_B][0].uv
avg_target+= A +(B - A).normalized() * radius
avg_count+=1
avg_target/=avg_count
avg_target = vert_to_uv[vert][0].uv +(avg_target - vert_to_uv[vert][0].uv).normalized() * radius
for loop in face.loops:
if loop.vert == vert:
loop[uv_layers].uv = avg_target
'''
'''
# Get all rails (max 3x: current, before and after)
rails = [e for v in verts_edges for e in vert_rails[v]]
for x in rails:
print(" raail: {} x {}".format(x.verts[0].index, x.verts[1].index))
# Keep only rails shared with faces
rails = [e for e in rails if e in face_edges]
# print("...... v{} with {}x rails ".format(vert.index, len(rails)))
# Filter rails on same side
'''
def get_edge_prev_next(edge, edges):
A = edge.verts[0]
B = edge.verts[1]
# print(" get_edge_prev_next {}x edges".format(len(edges)))
# v0_extends = []
# v0_extends = [v for e in edges for v in e.verts if v in edge.verts and e != edge and v != v0]
# v1_extends = [v for e in edges for v in e.verts if v in edge.verts and e != edge and v != v1]
# v0_extends = [v_nest for v in edge.verts for e in v.link_edges for v_nest in e.verts if e != edge and if e in edges]
A_extends = [v2 for v1 in edge.verts for e in v1.link_edges for v2 in e.verts if e !=
edge and e in edges and v2 not in edge.verts and v1 != A]
B_extends = [v2 for v1 in edge.verts for e in v1.link_edges for v2 in e.verts if e !=
edge and e in edges and v2 not in edge.verts and v1 != B]
return A_extends, B_extends
def get_edge_face_pairs(edges):
edge_faces = {}
for edge in edges:
v0 = edge.verts[0]
v1 = edge.verts[1]
faces = []
for face in edge.link_faces:
if v0 in face.verts and v1 in face.verts:
faces.append(face)
edge_faces[edge] = faces
return edge_faces
def get_vert_edge_rails(edges):
vert_rails = {}
for edge in edges:
v0 = edge.verts[0]
v1 = edge.verts[1]
faces = []
for face in edge.link_faces:
if v0 in face.verts and v1 in face.verts:
faces.append(face)
for face in faces:
for e in face.edges:
if e not in edges and len(e.link_faces) > 0:
if v0 not in vert_rails:
vert_rails[v0] = []
if v1 not in vert_rails:
vert_rails[v1] = []
if v0 in e.verts and e not in vert_rails[v0]:
vert_rails[v0].append(e)
if v1 in e.verts and e not in vert_rails[v1]:
vert_rails[v1].append(e)
return vert_rails
bpy.utils.register_class(op)