UV: improve performance for lightmap unwrap
Replaces this search by representing the 3 edge lengths of each triangle as 3d points and searching with a KD-tree. On a mesh with ~20k Tris the old method runs in 40s while the new method takes 0.23s with a difference of <0.001%. Ref !113720
This commit is contained in:
committed by
Campbell Barton
parent
7fa2a1071e
commit
406a2fde91
@@ -302,28 +302,52 @@ def lightmap_uvpack(
|
||||
tri_lengths = [trylens(f) for f in face_sel if f.loop_total == 3]
|
||||
del trylens
|
||||
|
||||
def trilensdiff(t1, t2):
|
||||
return (abs(t1[1][t1[2][0]] - t2[1][t2[2][0]]) +
|
||||
abs(t1[1][t1[2][1]] - t2[1][t2[2][1]]) +
|
||||
abs(t1[1][t1[2][2]] - t2[1][t2[2][2]]))
|
||||
# To add triangles into the light-map pack triangles are grouped in pairs to fill rectangular areas.
|
||||
# In the following for each triangle we add the sorted triangle edge lengths (3d point) into a KD-Tree
|
||||
# then iterate over all triangles and search for pairs of triangles by looking for the closest
|
||||
# sorted triangle point.
|
||||
# Additionally clusters of similar/equal triangles are parsed by searching for ranges in a second step.
|
||||
kd = mathutils.kdtree.KDTree(len(tri_lengths))
|
||||
for i, (f, lens, o) in enumerate(tri_lengths):
|
||||
vector = (lens[o[0]], lens[o[1]], lens[o[2]])
|
||||
kd.insert(vector, i)
|
||||
kd.balance()
|
||||
|
||||
while tri_lengths:
|
||||
tri1 = tri_lengths.pop()
|
||||
added_ids = [False] * len(tri_lengths)
|
||||
pairs_added = 0
|
||||
tri_equality_threshold = 0.00001 # Add multiple pairs at once that are within this threshold.
|
||||
for i in range(len(tri_lengths)):
|
||||
if added_ids[i]:
|
||||
continue
|
||||
tri1 = tri_lengths[i]
|
||||
f1, lens1, lo1 = tri1
|
||||
|
||||
if not tri_lengths:
|
||||
sorted_l = (lens1[lo1[0]], lens1[lo1[1]], lens1[lo1[2]])
|
||||
added_ids[i] = True
|
||||
vec, nearest, dist = kd.find(sorted_l, filter=lambda idx: not added_ids[idx])
|
||||
if not nearest or nearest < 0:
|
||||
pretty_faces.append(prettyface((tri1, None)))
|
||||
break
|
||||
tri2 = tri_lengths[nearest]
|
||||
pretty_faces.append(prettyface((tri1, tri2)))
|
||||
pairs_added = pairs_added + 1
|
||||
added_ids[nearest] = True
|
||||
|
||||
best_tri_index = -1
|
||||
best_tri_diff = 100000000.0
|
||||
# Look in threshold proximity to add all similar/equal triangles in one go.
|
||||
# This code is not necessary but acts as a shortcut (~9% performance improvement).
|
||||
if dist < tri_equality_threshold:
|
||||
cluster_tri_ids = [
|
||||
idx for _, idx, _ in kd.find_range(sorted_l, tri_equality_threshold)
|
||||
if not added_ids[idx]
|
||||
]
|
||||
|
||||
for i, tri2 in enumerate(tri_lengths):
|
||||
diff = trilensdiff(tri1, tri2)
|
||||
if diff < best_tri_diff:
|
||||
best_tri_index = i
|
||||
best_tri_diff = diff
|
||||
|
||||
pretty_faces.append(prettyface((tri1, tri_lengths.pop(best_tri_index))))
|
||||
if len(cluster_tri_ids) > 1:
|
||||
for ci in range(0, len(cluster_tri_ids) - (len(cluster_tri_ids) % 2), 2):
|
||||
pretty_faces.append(
|
||||
prettyface((tri_lengths[cluster_tri_ids[ci]], tri_lengths[cluster_tri_ids[ci + 1]]))
|
||||
)
|
||||
added_ids[cluster_tri_ids[ci]] = added_ids[cluster_tri_ids[ci + 1]] = True
|
||||
pairs_added = pairs_added + 1
|
||||
|
||||
# Get the min, max and total areas
|
||||
max_area = 0.0
|
||||
|
||||
Reference in New Issue
Block a user