Ship the WeChat hot-update catalogs and the camp, TideWhale T2, UI atlas, and animation-lab work.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""Weld coincident geometry, retain corner UV seams, then collapse to target.
|
||||
|
||||
Studio GLBs split vertices at normals and UV seams. Decimating those as loose
|
||||
triangles drops patches rather than simplifying a continuous surface.
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import bpy
|
||||
import bmesh
|
||||
|
||||
source, target, requested = sys.argv[sys.argv.index('--') + 1:][:3]
|
||||
source, target, requested = Path(source), Path(target), int(requested)
|
||||
bpy.ops.wm.read_factory_settings(use_empty=True)
|
||||
bpy.ops.import_scene.gltf(filepath=str(source), merge_vertices=False)
|
||||
objects = [o for o in bpy.context.scene.objects if o.type == 'MESH']
|
||||
assert len(objects) == 1
|
||||
obj = objects[0]
|
||||
bpy.context.view_layer.objects.active = obj
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
obj.select_set(True)
|
||||
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
|
||||
assert obj.data.uv_layers.active
|
||||
|
||||
|
||||
def corners():
|
||||
# Reordering by bmesh is harmless; the (position, per-corner UV) multiset
|
||||
# must stay the same through welding, including UV seam discontinuities.
|
||||
uv = obj.data.uv_layers.active.data
|
||||
return sorted(tuple(round(c, 6) for c in (*obj.data.vertices[l.vertex_index].co, *uv[l.index].uv)) for l in obj.data.loops)
|
||||
|
||||
|
||||
before_corners = corners()
|
||||
vertices_before = len(obj.data.vertices)
|
||||
bm = bmesh.new()
|
||||
bm.from_mesh(obj.data)
|
||||
bmesh.ops.remove_doubles(bm, verts=list(bm.verts), dist=max(obj.dimensions) * 1e-7)
|
||||
bm.to_mesh(obj.data)
|
||||
bm.free()
|
||||
obj.data.update()
|
||||
assert before_corners == corners(), 'Welding changed the existing corner UV mapping'
|
||||
vertices_welded = len(obj.data.vertices)
|
||||
tri = obj.modifiers.new('Triangulate', 'TRIANGULATE')
|
||||
bpy.ops.object.modifier_apply(modifier=tri.name)
|
||||
before = len(obj.data.polygons)
|
||||
area_before = sum(p.area for p in obj.data.polygons)
|
||||
modifier = obj.modifiers.new('PreserveCornerUVDecimate', 'DECIMATE')
|
||||
modifier.decimate_type = 'COLLAPSE'
|
||||
modifier.use_collapse_triangulate = True
|
||||
lower, upper = 0.0, 1.0
|
||||
candidate = min(1.0, requested / before)
|
||||
best = None
|
||||
for _ in range(22):
|
||||
modifier.ratio = candidate
|
||||
bpy.context.view_layer.update()
|
||||
count = len(obj.evaluated_get(bpy.context.evaluated_depsgraph_get()).data.polygons)
|
||||
rank = (abs(count - requested), count > requested)
|
||||
if best is None or rank < best[0]: best = (rank, candidate)
|
||||
if count == requested: break
|
||||
if count > requested: upper = candidate
|
||||
else: lower = candidate
|
||||
candidate = (lower + upper) / 2
|
||||
modifier.ratio = best[1]
|
||||
bpy.ops.object.modifier_apply(modifier=modifier.name)
|
||||
after = len(obj.data.polygons)
|
||||
area_after = sum(p.area for p in obj.data.polygons)
|
||||
print('Final faces', after, 'target', requested, 'best', best, flush=True)
|
||||
assert after <= requested * 1.30, (after, requested, best)
|
||||
assert area_after >= area_before * .80, 'Reduction lost too much surface area'
|
||||
assert obj.data.uv_layers.active
|
||||
bpy.ops.export_scene.gltf(filepath=str(target), export_format='GLB', use_selection=True,
|
||||
export_materials='EXPORT', export_image_format='AUTO')
|
||||
report = dict(faces_before=before, faces_after=after, target_faces=requested,
|
||||
vertices_before=vertices_before, vertices_after_weld=vertices_welded,
|
||||
cornerUVPreservedDuringWeld=True, uv_mode='preserved_no_unwrap',
|
||||
area_before=area_before, area_after=area_after, area_ratio=area_after / area_before,
|
||||
ratio=best[1], threshold_percent=30, triggered=True)
|
||||
target.with_suffix('.json').write_text(json.dumps(report, indent=2), encoding='utf-8')
|
||||
print('MT_SUMMARY ' + json.dumps(report), flush=True)
|
||||
Reference in New Issue
Block a user