ModelTranslator: _unwrap_seam 加松弛+纹素均衡,seam 角度参数化
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
788122b271
commit
c23ab2508f
@@ -116,6 +116,8 @@ PACK_MARGIN = 0.002 # 岛间距 ≈ 2048 图 4px
|
|||||||
UVPM_EXT = "bl_ext.user_default.uvpackmaster4" # UVPackmaster 4 扩展模块名
|
UVPM_EXT = "bl_ext.user_default.uvpackmaster4" # UVPackmaster 4 扩展模块名
|
||||||
UVPM_PIXEL_MARGIN = 4 # UVPM 岛间距(像素),与 PACK_MARGIN * UVPM_TEX_SIZE 同口径
|
UVPM_PIXEL_MARGIN = 4 # UVPM 岛间距(像素),与 PACK_MARGIN * UVPM_TEX_SIZE 同口径
|
||||||
UVPM_TEX_SIZE = 2048
|
UVPM_TEX_SIZE = 2048
|
||||||
|
SEAM_ANGLE_SWEEP = (55.0, 45.0, 35.0) # 首选 66° 不过门时依次下探的 seam 角度
|
||||||
|
STRETCH_ITERS = 30 # minimize_stretch 松弛迭代次数
|
||||||
|
|
||||||
|
|
||||||
def _clear_uv_layers(mesh):
|
def _clear_uv_layers(mesh):
|
||||||
@@ -135,18 +137,22 @@ def _unwrap_smart(obj):
|
|||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
|
|
||||||
def _unwrap_seam(obj, warnings):
|
def _unwrap_seam(obj, warnings, seam_angle_deg=SEAM_ANGLE_DEG):
|
||||||
"""锐边标 seam -> MINIMUM_STRETCH/ANGLE_BASED 展开 -> pack。碎岛远少于投影式。"""
|
"""锐边标 seam -> MINIMUM_STRETCH/ANGLE_BASED 展开 -> 松弛 -> 纹素均衡 -> pack。
|
||||||
|
seam_angle_deg 可变以支持角度扫描;重跑前清掉上一档残留 seam。"""
|
||||||
import bpy
|
import bpy
|
||||||
import math
|
import math
|
||||||
_clear_uv_layers(obj.data)
|
_clear_uv_layers(obj.data)
|
||||||
obj.data.uv_layers.new()
|
obj.data.uv_layers.new()
|
||||||
bpy.context.view_layer.objects.active = obj
|
bpy.context.view_layer.objects.active = obj
|
||||||
bpy.ops.object.mode_set(mode='EDIT')
|
bpy.ops.object.mode_set(mode='EDIT')
|
||||||
# 锐边标 seam:接缝只落在硬边处,平滑区域保持整岛
|
|
||||||
bpy.ops.mesh.select_mode(type='EDGE')
|
bpy.ops.mesh.select_mode(type='EDGE')
|
||||||
|
# 清掉上一档角度残留 seam(同一对象多角度扫描时必须)
|
||||||
|
bpy.ops.mesh.select_all(action='SELECT')
|
||||||
|
bpy.ops.mesh.mark_seam(clear=True)
|
||||||
|
# 锐边标 seam:接缝只落在硬边处,平滑区域保持整岛
|
||||||
bpy.ops.mesh.select_all(action='DESELECT')
|
bpy.ops.mesh.select_all(action='DESELECT')
|
||||||
bpy.ops.mesh.edges_select_sharp(sharpness=math.radians(SEAM_ANGLE_DEG))
|
bpy.ops.mesh.edges_select_sharp(sharpness=math.radians(seam_angle_deg))
|
||||||
bpy.ops.mesh.mark_seam(clear=False)
|
bpy.ops.mesh.mark_seam(clear=False)
|
||||||
bpy.ops.mesh.select_all(action='SELECT')
|
bpy.ops.mesh.select_all(action='SELECT')
|
||||||
try:
|
try:
|
||||||
@@ -154,6 +160,14 @@ def _unwrap_seam(obj, warnings):
|
|||||||
except TypeError: # 老版本无 SLIM 枚举
|
except TypeError: # 老版本无 SLIM 枚举
|
||||||
warnings.append("MINIMUM_STRETCH 不可用,展开改用 ANGLE_BASED")
|
warnings.append("MINIMUM_STRETCH 不可用,展开改用 ANGLE_BASED")
|
||||||
bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=PACK_MARGIN)
|
bpy.ops.uv.unwrap(method='ANGLE_BASED', margin=PACK_MARGIN)
|
||||||
|
try: # 角度松弛:压翻转/拉伸
|
||||||
|
bpy.ops.uv.minimize_stretch(iterations=STRETCH_ITERS)
|
||||||
|
except (RuntimeError, TypeError) as e:
|
||||||
|
warnings.append("minimize_stretch 不可用(%s),跳过松弛" % e)
|
||||||
|
try: # 统一纹素密度,避免大岛霸占分辨率
|
||||||
|
bpy.ops.uv.average_islands_scale()
|
||||||
|
except RuntimeError as e:
|
||||||
|
warnings.append("average_islands_scale 不可用(%s),跳过纹素均衡" % e)
|
||||||
try:
|
try:
|
||||||
bpy.ops.uv.pack_islands(rotate=True, margin=PACK_MARGIN)
|
bpy.ops.uv.pack_islands(rotate=True, margin=PACK_MARGIN)
|
||||||
except RuntimeError: # headless 上下文不满足时靠 unwrap 自带打包
|
except RuntimeError: # headless 上下文不满足时靠 unwrap 自带打包
|
||||||
|
|||||||
Reference in New Issue
Block a user