Skip to content

Commit

Permalink
Release 2023.2
Browse files Browse the repository at this point in the history
  • Loading branch information
mrven committed Dec 29, 2023
1 parent e1856cb commit 0f1ef8b
Show file tree
Hide file tree
Showing 13 changed files with 2,858 additions and 2 deletions.
File renamed without changes.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Texel Density Checker simple for use. You need select your mesh (or faces) and t

***Download latest version:***

* ***[(2023.1) Blender 3.6+ (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_2023_1_Bl361.zip)***
* ***[(2023.2) Blender 4.0+ (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_2023_2_Bl400.zip)***
* ***[(2023.2) Blender 3.6+ (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_2023_2_Bl361.zip)***
* ***[(3.4) Blender 3.4+ (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_3_4_341.zip)***
* ***[(3.3.1) Blender 2.91+ (also 3.0+) (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_3_3_1_291.zip)***
* ***[(3.2.1) Blender 2.83-2.90 (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_3_2_1_283.zip)***
Expand Down
3 changes: 2 additions & 1 deletion README_ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ Texel Density Checker – Аддон для Blender, который позвол

***Скачать последнюю версию:***

* ***[(2023.1) Blender 3.6+ (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_2023_1_Bl361.zip)***
* ***[(2023.2) Blender 4.0+ (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_2023_2_Bl400.zip)***
* ***[(2023.2) Blender 3.6+ (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_2023_2_Bl361.zip)***
* ***[(3.4) Blender 3.4+ (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_3_4_341.zip)***
* ***[(3.3.1) Blender 2.91+ (also 3.0+) (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_3_3_1_291.zip)***
* ***[(3.2.1) Blender 2.83-2.90 (Windows, Linux, MacOS)](https://github.com/mrven/Blender-Texel-Density-Checker/raw/master/Releases/Texel_Density_3_2_1_283.zip)***
Expand Down
Binary file added Releases/Texel_Density_2023_2_Bl361.zip
Binary file not shown.
Binary file added Releases/Texel_Density_2023_2_Bl400.zip
Binary file not shown.
41 changes: 41 additions & 0 deletions Texel_Density_2023_2_Bl361/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
bl_info = {
"name": "Texel Density Checker",
"description": "Tools for for checking Texel Density and wasting of uv space",
"author": "Ivan 'mrven' Vostrikov, Toomas Laik",
"wiki_url": "https://gumroad.com/l/CEIOR",
"tracker_url": "https://github.com/mrven/Blender-Texel-Density-Checker/issues",
"doc_url": "https://github.com/mrven/Blender-Texel-Density-Checker#readme",
"version": (2023, 2),
"blender": (3, 6, 1),
"location": "3D View > Toolbox",
"category": "Object",
}

modules_names = ['props', 'preferences', 'utils', 'core_td_operators', 'add_td_operators', 'viz_operators', 'ui']

modules_full_names = {}
for current_module_name in modules_names:
modules_full_names[current_module_name] = ('{}.{}'.format(__name__, current_module_name))

import sys
import importlib


for current_module_full_name in modules_full_names.values():
if current_module_full_name in sys.modules:
importlib.reload(sys.modules[current_module_full_name])
else:
globals()[current_module_full_name] = importlib.import_module(current_module_full_name)
setattr(globals()[current_module_full_name], 'modulesNames', modules_full_names)

def register():
for current_module_name in modules_full_names.values():
if current_module_name in sys.modules:
if hasattr(sys.modules[current_module_name], 'register'):
sys.modules[current_module_name].register()

def unregister():
for current_module_name in modules_full_names.values():
if current_module_name in sys.modules:
if hasattr(sys.modules[current_module_name], 'unregister'):
sys.modules[current_module_name].unregister()
286 changes: 286 additions & 0 deletions Texel_Density_2023_2_Bl361/add_td_operators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
import bpy
import bmesh
from bpy.props import StringProperty
from datetime import datetime
from . import utils

# Copy average TD from object to object
class Texel_Density_Copy(bpy.types.Operator):
"""Copy Density"""
bl_idname = "object.texel_density_copy"
bl_label = "Copy Texel Density"
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):
start_time = datetime.now()
td = context.scene.td

# Save current mode and active object
start_active_obj = bpy.context.active_object
start_selected_obj = bpy.context.selected_objects

# Calculate TD for active object only and copy value to "Set TD Value" field
bpy.ops.object.select_all(action='DESELECT')
start_active_obj.select_set(True)
bpy.context.view_layer.objects.active = start_active_obj
bpy.ops.object.texel_density_check()
td.density_set = td.density

# Set calculated TD for all other selected objects
for x in start_selected_obj:
bpy.ops.object.select_all(action='DESELECT')
if (x.type == 'MESH' and len(x.data.uv_layers) > 0 and len(x.data.polygons) > 0) and not x == start_active_obj:
x.select_set(True)
bpy.context.view_layer.objects.active = x
bpy.ops.object.texel_density_set()

# Select Objects Again
for x in start_selected_obj:
x.select_set(True)
bpy.context.view_layer.objects.active = start_active_obj

utils.Print_Execution_Time("Copy TD", start_time)
return {'FINISHED'}

# Copy last calculated value of TD to "Set TD Value" field
class Calculated_To_Set(bpy.types.Operator):
"""Copy Calc to Set"""
bl_idname = "object.calculate_to_set"
bl_label = "Copy Calculated Value to Set Value Field"
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):
start_time = datetime.now()
td = context.scene.td
td.density_set = td.density

utils.Print_Execution_Time("Calculated TD to Set", start_time)
return {'FINISHED'}

# Copy last calculated value to "Select Value" field
class Calculated_To_Select(bpy.types.Operator):
"""Copy Calc to Set"""
bl_idname = "object.calculate_to_select"
bl_label = "Copy Calculated Value to Select Value Field"
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):
start_time = datetime.now()
td = context.scene.td

# Copying UV area or TD depends on current select mode
if td.select_mode == "ISLANDS_BY_SPACE":
td['select_value'] = td.uv_space[:-2]
else:
td['select_value'] = td.density

utils.Print_Execution_Time("Calculated TD to Select", start_time)
return {'FINISHED'}

# Buttons "Half/Double TD" and presets with values (0.64 - 20.48 px/cm)
class Preset_Set(bpy.types.Operator):
"""Preset Set Density"""
bl_idname = "object.preset_set"
bl_label = "Set Texel Density"
bl_options = {'REGISTER', 'UNDO'}
td_value: StringProperty()

def execute(self, context):
start_time = datetime.now()
td = context.scene.td

# self.td_value is parameter
# It's using in UI like row.operator("object.preset_set", text="20.48").td_value="20.48"
if self.td_value == "Half" or self.td_value == "Double":
# In case using buttons "Half/Double TD"
# Store value from panel, set preset value and call Set TD
saved_td_value = td.density_set
td.density_set = self.td_value
bpy.ops.object.texel_density_set()
# Restore saved value
td.density_set = saved_td_value
else:
td.density_set = self.td_value
bpy.ops.object.texel_density_set()

utils.Print_Execution_Time("Preset TD Set", start_time)
return {'FINISHED'}

# Select polygons or islands with same TD or UV space
class Select_By_TD_Space(bpy.types.Operator):
"""Select Faces with same TD"""
bl_idname = "object.select_by_td_space"
bl_label = "Select Faces with same TD"
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):
start_time = datetime.now()
td = context.scene.td

start_mode = bpy.context.object.mode
start_active_obj = bpy.context.active_object
need_select_again_obj = bpy.context.selected_objects

if start_mode == 'EDIT':
start_selected_obj = bpy.context.objects_in_mode
else:
start_selected_obj = bpy.context.selected_objects

search_value = float(td.select_value)
select_threshold = float(td.select_threshold)

# Set Selection Mode to Face for 3D View and UV Editor
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
bpy.context.scene.tool_settings.uv_select_mode = 'FACE'

bpy.ops.object.mode_set(mode='OBJECT')

# Select polygons
for x in start_selected_obj:
bpy.ops.object.select_all(action='DESELECT')
if (x.type == 'MESH' and len(x.data.uv_layers) > 0) and len(x.data.polygons) > 0:
bpy.context.view_layer.objects.active = x
bpy.context.view_layer.objects.active.select_set(True)
face_count = len(bpy.context.active_object.data.polygons)
searched_faces = []

# Get islands and TD and UV areas of each polygon
islands_list = utils.Get_UV_Islands()
face_td_area_list = utils.Calculate_TD_Area_To_List()

if td.select_mode == "FACES_BY_TD":
for face_id in range(0, face_count):
if td.select_type == "EQUAL":
if (face_td_area_list[face_id][0] >= (search_value - select_threshold)) and (face_td_area_list[face_id][0] <= (search_value + select_threshold)):
searched_faces.append(face_id)

elif td.select_type == "LESS":
if face_td_area_list[face_id][0] <= search_value:
searched_faces.append(face_id)

elif td.select_type == "GREATER":
if face_td_area_list[face_id][0] >= search_value:
searched_faces.append(face_id)

elif td.select_mode == "ISLANDS_BY_TD":
for uv_island in islands_list:
island_td = 0
island_area = 0

# Calculate total island UV area
for face_id in uv_island:
island_area += face_td_area_list[face_id][1]

if island_area == 0:
island_area = 0.000001

# Calculate total island TD
for face_id in uv_island:
island_td += face_td_area_list[face_id][0] * face_td_area_list[face_id][1]/island_area

if td.select_type == "EQUAL":
if (island_td >= (search_value - select_threshold)) and (island_td <= (search_value + select_threshold)):
for face_id in uv_island:
searched_faces.append(face_id)

elif td.select_type == "LESS":
if island_td <= search_value:
for face_id in uv_island:
searched_faces.append(face_id)

elif td.select_type == "GREATER":
if island_td >= search_value:
for face_id in uv_island:
searched_faces.append(face_id)

elif td.select_mode == "ISLANDS_BY_SPACE":
for uv_island in islands_list:
island_area = 0

# Calculate total island UV area
for face_id in uv_island:
island_area += face_td_area_list[face_id][1]

# Convert UV area to percentage
island_area *= 100

if td.select_type == "EQUAL":
if (island_area >= (search_value - select_threshold)) and (island_area <= (search_value + select_threshold)):
for face_id in uv_island:
searched_faces.append(face_id)

if td.select_type == "LESS":
if island_area <= search_value:
for face_id in uv_island:
searched_faces.append(face_id)

if td.select_type == "GREATER":
if island_area >= search_value:
for face_id in uv_island:
searched_faces.append(face_id)

if bpy.context.area.spaces.active.type == "IMAGE_EDITOR" and not bpy.context.scene.tool_settings.use_uv_select_sync:
bpy.ops.object.mode_set(mode='EDIT')

mesh = bpy.context.active_object.data
bm_local = bmesh.from_edit_mesh(mesh)
bm_local.faces.ensure_lookup_table()
uv_layer = bm_local.loops.layers.uv.active

# If called from UV Editor without sync selection deselect all faces
# and select only founded faces in UV Editor
for uv_id in range(0, len(bm_local.faces)):
for loop in bm_local.faces[uv_id].loops:
loop[uv_layer].select = False

for face_id in searched_faces:
for loop in bm_local.faces[face_id].loops:
loop[uv_layer].select = True

bpy.ops.object.mode_set(mode='OBJECT')

else:
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT')

bpy.ops.object.mode_set(mode='OBJECT')

# If called from UV Editor with sync selection or 3D View
# deselect all faces and select only founded faces in 3D View
for face_id in searched_faces:
bpy.context.active_object.data.polygons[face_id].select = True

bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')

if start_mode == 'EDIT':
for o in start_selected_obj:
bpy.context.view_layer.objects.active = o
bpy.ops.object.mode_set(mode='EDIT')

bpy.context.view_layer.objects.active = start_active_obj
for j in need_select_again_obj:
j.select_set(True)

utils.Print_Execution_Time("Select by TD Space", start_time)
return {'FINISHED'}


classes = (
Texel_Density_Copy,
Calculated_To_Set,
Calculated_To_Select,
Preset_Set,
Select_By_TD_Space,
)


def register():
for cls in classes:
bpy.utils.register_class(cls)


def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
Loading

0 comments on commit 0f1ef8b

Please sign in to comment.