Frantically optimise remesh and improve gen_perlin
dkl9

dkl9 commited on 2025-172 20:26:01
Showing 5 changed files, with 81 additions and 18 deletions.

... ...
@@ -0,0 +1,11 @@
1
+PROF=profile.log
2
+
3
+run:
4
+	python main.py
5
+
6
+dbg:
7
+	python -m pdb -c 'break debug_mode' main.py
8
+
9
+prof:
10
+	python -m cProfile main.py >$(PROF)
11
+	$(PAGER) $(PROF)
... ...
@@ -16,3 +16,10 @@ GREEN = vec([0.0, 1.0, 0.0, 1.0])
16 16
 def normalize(v):
17 17
     norm = np.linalg.norm(v)
18 18
     return v / norm if norm > 0 else v
19
+
20
+def roll_vec3(l, k):
21
+    match k:
22
+        case 1:
23
+            l[:] = [l[2], l[0], l[1]]
24
+        case 2:
25
+            l[:] = [l[1], l[2], l[0]]
... ...
@@ -26,6 +26,9 @@ void main() {
26 26
 
27 27
 FPS = 240
28 28
 
29
+def debug_mode():
30
+    pass
31
+
29 32
 def click_mesh(self, button, ind):
30 33
     a, p = self.faces[ind]
31 34
     match button:
... ...
@@ -42,7 +45,7 @@ def click_mesh(self, button, ind):
42 45
 
43 46
 def build_scene():
44 47
     box = WorldRegion()
45
-    box.gen_perlin(np.random.rand(2, 2, 2, 3))
48
+    print(f"map generated with {box.gen_perlin(np.random.rand(2, 2, 2, 3))} voxels")
46 49
     box.remesh()
47 50
     box.onclick = click_mesh
48 51
     return [box]
... ...
@@ -69,6 +72,8 @@ def main():
69 72
             if ev.type == pygame.QUIT or ev.type == pygame.KEYUP and ev.unicode == "q":
70 73
                 pygame.quit()
71 74
                 return
75
+            elif ev.type == pygame.KEYUP and ev.unicode == "d":
76
+                debug_mode()
72 77
             cam.handle_event(ev, scene)
73 78
         cam.update_pos()
74 79
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
... ...
@@ -24,10 +24,12 @@ class Player(camera.Camera):
24 24
                 YELLOW, [-1.0, 1.0, 0.0], mode=GL_TRIANGLE_STRIP, hud=True
25 25
             ),
26 26
         }
27
+        self.viewport = (640, 480)
27 28
 
28 29
     def set_focus(self, f): 
29 30
         pygame.event.set_grab(f)
30 31
         pygame.mouse.set_visible(not f)
32
+        pygame.mouse.set_pos([self.viewport[0] / 2, self.viewport[1] / 2])
31 33
         self.hud["crosshair"].pos[0] = 2 * (not f)
32 34
 
33 35
     def get_focus(self):
... ...
@@ -73,3 +75,4 @@ class Player(camera.Camera):
73 75
                         t.click(ev.button, n)
74 76
             case pygame.WINDOWSIZECHANGED | pygame.WINDOWRESIZED:
75 77
                 self.aspect = reshape(ev.x, ev.y)
78
+                self.viewport = (ev.x, ev.y)
... ...
@@ -11,6 +11,7 @@ class WorldRegion(mesh.SquareMesh):
11 11
     def __init__(self, size=16):
12 12
         super().__init__()
13 13
         self.grid = np.zeros((size, size, size), dtype=VOXEL_TYPE)
14
+        self.r = size
14 15
 
15 16
     def add_voxel(self, pos, vt=1):
16 17
         self.grid[*pos] = vt
... ...
@@ -20,30 +21,66 @@ class WorldRegion(mesh.SquareMesh):
20 21
 
21 22
     def remesh(self):
22 23
         offset = vec([0.5, 0.0, 0.0])
23
-        r = self.grid.shape[0]
24
-        self.verts = np.empty((0, 3), dtype=FLOAT)
25 24
         self.faces = []
26
-        for i in range(r):
27
-            for j in range(r):
28
-                for k in range(r):
29
-                    p = [i, j, k]
30
-                    if self.grid[*p]:
25
+        prev, curr = 0, 0
26
+        vl = []
31 27
         for d in range(3):
32
-                            for s in range(2):
33
-                                ts = (-1) ** s
34
-                                if p[d] == [r - 1, 0][s] or not self.grid[*(p + np.roll([ts, 0, 0], d))]:
35
-                                    self.add_sq(ts * (d + 1), 1, p + ts * np.roll(offset, d), p)
28
+            offset = np.array([1, 0, 0])
29
+            roll_vec3(offset, d)
30
+            for i in range(self.r):
31
+                for j in range(self.r):
32
+                    for k in range(self.r + 1):
33
+                        p = np.array([k, i, j])
34
+                        roll_vec3(p, d)
35
+                        prev, curr = curr, (self.grid[*p] if k < self.r else 0)
36
+                        bp, bc = bool(prev), bool(curr)
37
+                        if bp ^ bc:
38
+                            sq = vec([
39
+                                [0, 1, 1], [0, -1, 1], [0, 1, -1],
40
+                                [0, -1, -1], [0, 1, -1], [0, -1, 1]
41
+                            ])
42
+                            sq /= 2 * (bp - bc)
43
+                            for v in sq:
44
+                                roll_vec3(v, d)
45
+                            sq += p - offset / 2
46
+                            vl.extend(sq)
47
+                            if bp:
48
+                                p -= offset
49
+                            for _ in range(2):
50
+                                self.faces.append(((bp - bc) * (d + 1), p))
51
+        self.verts = vec(vl)
52
+
53
+    def prof_min(self):
54
+        self.add_voxel((0, 0, 0))
55
+        self.remesh()
56
+
57
+    def prof_med(self):
58
+        for i in range(self.r // 2):
59
+            for j in range(self.r // 2):
60
+                for k in range(self.r // 2):
61
+                    self.add_voxel((2 * i, 2 * j, 2 * k))
62
+        self.remesh()
63
+
64
+    def prof_max(self):
65
+        for i in range(self.r):
66
+            for j in range(self.r):
67
+                for k in range(self.r):
68
+                    if not (i + j + k) % 2:
69
+                        self.add_voxel((i, j, k))
70
+        self.remesh()
36 71
 
37 72
     def gen_perlin(self, grads):
38
-        r = self.grid.shape[0]
39 73
         corners = np.array([(i, j, k) for i in range(2) for j in range(2) for k in range(2)])
40
-        for i in range(r):
41
-            for j in range(r):
42
-                for k in range(r):
43
-                    w = np.array((i, j, k)) / r
74
+        n = 0
75
+        for i in range(self.r):
76
+            for j in range(self.r):
77
+                for k in range(self.r):
78
+                    w = np.array((i, j, k)) / self.r
44 79
                     d = [np.dot(grads[*c], w) for c in corners]
45 80
                     d = [interp(d[2 * k:2 * (k + 1)], w[2]) for k in range(4)]
46 81
                     d = [interp(d[:2], w[1]), interp(d[2:4], w[1])]
47 82
                     p = interp(d, w[0])
48
-                    if p < 0.6:
83
+                    if p > 2 * w[1] - 0.5:
49 84
                         self.add_voxel((i, j, k))
85
+                        n += 1
86
+        return n
50 87