forked from franMarz/TexTools-Blender
-
Notifications
You must be signed in to change notification settings - Fork 0
/
op_texel_density_set.py
189 lines (146 loc) · 5.23 KB
/
op_texel_density_set.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import bpy
import bmesh
import operator
import math
from mathutils import Vector
from collections import defaultdict
from . import utilities_texel
from . import utilities_uv
class op(bpy.types.Operator):
bl_idname = "uv.textools_texel_density_set"
bl_label = "Set Texel size"
bl_description = "Apply texel density by scaling the UV's to match the ratio"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
if not bpy.context.active_object:
return False
if len(bpy.context.selected_objects) == 0:
return False
if bpy.context.active_object.type != 'MESH':
return False
#Only in UV editor mode
if bpy.context.area.type != 'IMAGE_EDITOR':
return False
#Requires UV map
if not bpy.context.object.data.uv_layers:
return False
# if bpy.context.object.mode == 'EDIT':
# # In edit mode requires face select mode
# if bpy.context.scene.tool_settings.mesh_select_mode[2] == False:
# return False
return True
def execute(self, context):
set_texel_density(
self,
context,
bpy.context.scene.texToolsSettings.texel_mode_scale,
bpy.context.scene.texToolsSettings.texel_density
)
return {'FINISHED'}
def set_texel_density(self, context, mode, density):
print("Set texel density!")
is_edit = bpy.context.object.mode == 'EDIT'
is_sync = bpy.context.scene.tool_settings.use_uv_select_sync
object_faces = utilities_texel.get_selected_object_faces()
# Warning: No valid input objects
if len(object_faces) == 0:
self.report({'ERROR_INVALID_INPUT'}, "No valid meshes or UV maps" )
return
# Collect Images / textures
object_images = {}
for obj in object_faces:
image = utilities_texel.get_object_texture_image(obj)
if image:
object_images[obj] = image
# Warning: No valid images
if len(object_images) == 0:
self.report({'ERROR_INVALID_INPUT'}, "No Texture found. Assign Checker map or texture." )
return
for obj in object_faces:
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = obj
obj.select_set( state = True, view_layer = None)
# Find image of object
image = object_images[obj]
if image:
bpy.ops.object.mode_set(mode='EDIT')
bpy.context.scene.tool_settings.use_uv_select_sync = False
# Store selection
utilities_uv.selection_store()
bm = bmesh.from_edit_mesh(obj.data)
uv_layers = bm.loops.layers.uv.verify()
# Collect groups of faces to scale together
group_faces = []
if is_edit:
# Collect selected faces as islands
bm.faces.ensure_lookup_table()
bpy.ops.uv.select_all(action='SELECT')
group_faces = utilities_uv.getSelectionIslands()
elif mode == 'ALL':
# Scale all UV's together
group_faces = [bm.faces]
elif mode == 'ISLAND':
# Scale each UV idland centered
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.uv.select_all(action='SELECT')
group_faces = utilities_uv.getSelectionIslands()
print("group_faces {}x".format(len(group_faces)))
for group in group_faces:
# Get triangle areas
sum_area_vt = 0
sum_area_uv = 0
for face in group:
# Triangle Verts
triangle_uv = [loop[uv_layers].uv for loop in face.loops ]
triangle_vt = [obj.matrix_world @ vert.co for vert in face.verts]
#Triangle Areas
face_area_vt = utilities_texel.get_area_triangle(
triangle_vt[0],
triangle_vt[1],
triangle_vt[2]
)
face_area_uv = utilities_texel.get_area_triangle_uv(
triangle_uv[0],
triangle_uv[1],
triangle_uv[2],
image.size[0],
image.size[1]
)
sum_area_vt+= math.sqrt( face_area_vt )
sum_area_uv+= math.sqrt( face_area_uv ) * min(image.size[0], image.size[1])
# Apply scale to group
print("scale: {:.2f} {:.2f} {:.2f} ".format(density, sum_area_uv, sum_area_vt))
scale = 0
if density > 0 and sum_area_uv > 0 and sum_area_vt > 0:
scale = density / (sum_area_uv / sum_area_vt)
# Set Scale Origin to Island or top left
if mode == 'ISLAND':
bpy.context.tool_settings.transform_pivot_point = 'MEDIAN_POINT'
elif mode == 'ALL':
bpy.context.tool_settings.transform_pivot_point = 'CURSOR'
bpy.ops.uv.cursor_set(location=(0, 1))
# Select Face loops and scale
bpy.ops.uv.select_all(action='DESELECT')
bpy.context.scene.tool_settings.uv_select_mode = 'VERTEX'
for face in group:
for loop in face.loops:
loop[uv_layers].select = True
print("Scale: {} {}x".format(scale, len(group)))
bpy.ops.transform.resize(value=(scale, scale, 1), use_proportional_edit=False)
# Restore selection
utilities_uv.selection_restore()
# Restore selection
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')
for obj in object_faces:
obj.select_set( state = True, view_layer = None)
bpy.context.view_layer.objects.active = list(object_faces.keys())[0]
# Restore edit mode
if is_edit:
bpy.ops.object.mode_set(mode='EDIT')
# Restore sync mode
if is_sync:
bpy.context.scene.tool_settings.use_uv_select_sync = True
bpy.utils.register_class(op)