Skip to content

Commit 72533e5

Browse files
committed
Wrap 0 longitude line with uvremap=:sphere
Inserts a seam on the 0–90° side of faces that straddle 0° and adds 1 to the U coordinated of the new vertex. Works best with `repeat=true` texture mapping. Fixes #57
1 parent 84747e5 commit 72533e5

File tree

2 files changed

+50
-7
lines changed

2 files changed

+50
-7
lines changed

src/flitter/render/window/models.pyx

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -829,8 +829,10 @@ cdef class UVRemap(UnaryOperation):
829829
@cython.wraparound(False)
830830
cdef object remap_sphere(self, vertex_array, index_array, Vector bounds):
831831
vertex_array = vertex_array.copy()
832+
index_array = index_array.copy()
832833
cdef float[:, :] vertex_data = vertex_array
833-
cdef int64_t i, n=len(vertex_array)
834+
cdef int32_t[:, :] index_data = index_array
835+
cdef int64_t i, n=len(vertex_data), m=len(index_data)
834836
cdef float x, y, z, u
835837
for i in range(n):
836838
x, y, z = vertex_data[i, 0], vertex_data[i, 1], vertex_data[i, 2]
@@ -839,7 +841,39 @@ cdef class UVRemap(UnaryOperation):
839841
u += 1
840842
vertex_data[i, 6] = u
841843
vertex_data[i, 7] = atan2(z, sqrt(x*x + y*y)) / Tau * 2 + 0.5
842-
return vertex_array
844+
cdef float u0, u1, u2, u_max
845+
cdef int32_t a, b, c, j=n
846+
cdef list extra_vertices = []
847+
for i in range(m):
848+
a = index_data[i, 0]
849+
b = index_data[i, 1]
850+
c = index_data[i, 2]
851+
u0 = vertex_data[a, 6]
852+
u1 = vertex_data[b, 6]
853+
u2 = vertex_data[c, 6]
854+
u_max = max(u0, u1, u2)
855+
if u_max > 0.75:
856+
if u0 < 0.25:
857+
index_data[i, 0] = j
858+
extra_vertices.append([vertex_data[a, 0], vertex_data[a, 1], vertex_data[a, 2],
859+
vertex_data[a, 3], vertex_data[a, 4], vertex_data[a, 5],
860+
u0 + 1, vertex_data[a, 7]])
861+
j += 1
862+
if u1 < 0.25:
863+
index_data[i, 1] = j
864+
extra_vertices.append([vertex_data[b, 0], vertex_data[b, 1], vertex_data[b, 2],
865+
vertex_data[b, 3], vertex_data[b, 4], vertex_data[b, 5],
866+
u1 + 1, vertex_data[b, 7]])
867+
j += 1
868+
if u2 < 0.25:
869+
index_data[i, 2] = j
870+
extra_vertices.append([vertex_data[c, 0], vertex_data[c, 1], vertex_data[c, 2],
871+
vertex_data[c, 3], vertex_data[c, 4], vertex_data[c, 5],
872+
u2 + 1, vertex_data[c, 7]])
873+
j += 1
874+
if extra_vertices:
875+
vertex_array = np.vstack((vertex_array, extra_vertices), dtype='f4')
876+
return vertex_array, index_array
843877

844878
@cython.cdivision(True)
845879
@cython.boundscheck(False)
@@ -854,7 +888,7 @@ cdef class UVRemap(UnaryOperation):
854888
x, y = vertex_data[i, 0], vertex_data[i, 1]
855889
vertex_data[i, 6] = (x - x0) / width
856890
vertex_data[i, 7] = (y - y0) / height
857-
return vertex_array
891+
return vertex_array, index_array
858892

859893
cpdef tuple build_arrays(self):
860894
cdef tuple arrays = self.original.get_arrays()
@@ -863,9 +897,9 @@ cdef class UVRemap(UnaryOperation):
863897
cdef Vector bounds = self.original.get_bounds()
864898
vertex_array, index_array = arrays
865899
if self.mapping is 'sphere':
866-
vertex_array = self.remap_sphere(vertex_array, index_array, bounds)
900+
vertex_array, index_array = self.remap_sphere(vertex_array, index_array, bounds)
867901
elif self.mapping is 'plane':
868-
vertex_array = self.remap_plane(vertex_array, index_array, bounds)
902+
vertex_array, index_array = self.remap_plane(vertex_array, index_array, bounds)
869903
return vertex_array, index_array
870904

871905
cpdef object build_manifold(self):

tests/test_models.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,11 +489,20 @@ def tearDown(self):
489489
def test_uv_remap_sphere(self):
490490
model = Model.box()
491491
mesh = model.uv_remap('sphere').get_trimesh()
492-
for (x, y, z), uv in zip(mesh.vertices, mesh.visual.uv):
492+
m = 0
493+
n = 0
494+
for (x, y, z), (uu, vv) in zip(mesh.vertices, mesh.visual.uv):
493495
u = math.atan2(y, x) / (2*math.pi) % 1
494496
r = math.sqrt(x*x + y*y)
495497
v = (math.atan2(z, r) / math.pi + 0.5) % 1
496-
self.assertAllAlmostEqual(uv, [u, v])
498+
if uu >= 1:
499+
self.assertAllAlmostEqual((uu, vv), (u + 1, v))
500+
n += 1
501+
else:
502+
self.assertAllAlmostEqual((uu, vv), (u, v))
503+
m += 1
504+
self.assertEqual(m, 24)
505+
self.assertEqual(n, 5)
497506

498507
def test_flatten(self):
499508
model = Model.sphere()

0 commit comments

Comments
 (0)