Procedural (Perlin) textures for everything
dkl9

dkl9 commited on 2025-183 21:10:06
Showing 5 changed files, with 42 additions and 23 deletions.

... ...
@@ -31,18 +31,21 @@ void main() {{
31 31
     ), 0.0), reflsF.w);
32 32
     float j = texcF.z;
33 33
     vec3 c = colF.xyz;
34
-    if (abs(j) < 1e-3)
35
-        c = texture2D(tex[0], texcF.xy).xyz;
36
-    if (abs(j - 1.0) < 1e-3)
37
-        c = texture2D(tex[1], texcF.xy).xyz;
34
+{"\n".join([
35
+    f"if (abs(j - {i}.0) < 1e-3)" +
36
+        f"c = texture2D(tex[{i}], texcF.xy).xyz;" for i in range(TEX_COUNT)
37
+])}
38 38
     gl_FragColor = vec4((ambient + diffuse + specular) * c, colF.w);
39 39
 }}
40 40
 """
41 41
 
42
-def load_texture(i, fname):
43
-    pli = pygame.image.load(fname).convert()
42
+def load_texture(i, img_data):
43
+    if isinstance(img_data, str):
44
+        pli = pygame.image.load(img_data).convert()
44 45
         (tw, th) = pli.get_size()
45 46
         img_data = np.array(list(pygame.image.tobytes(pli, "RGB")), np.uint8)
47
+    elif isinstance(img_data, np.ndarray):
48
+        (tw, th) = img_data.shape[:2]
46 49
     tex = glGenTextures(1)
47 50
     glActiveTexture(GL_TEXTURE0 + i)
48 51
     glBindTexture(GL_TEXTURE_2D, tex)
... ...
@@ -74,7 +77,7 @@ def init_display():
74 77
     for (k, v) in UNIFORMS.items():
75 78
         v[2] = glGetUniformLocation(sp, k)
76 79
     glUseProgram(sp)
77
-    glUniform1iv(UNIFORMS["tex"][2], 2, np.array([0, 1]))
80
+    glUniform1iv(UNIFORMS["tex"][2], TEX_COUNT, np.array(range(TEX_COUNT)))
78 81
     glEnable(GL_DEPTH_TEST)
79 82
     glEnable(GL_BLEND)
80 83
     glEnable(GL_CULL_FACE)
... ...
@@ -26,14 +26,14 @@ def hand():
26 26
     return h
27 27
 
28 28
 def selection():
29
-    s = mesh.SquareMesh()
29
+    s = mesh.SquareMesh(texi=-1)
30 30
     s.draw_mode = GL_LINE_STRIP
31 31
     s.add_sq(-2, 0.96, [0, 0, 0], 2)
32 32
     s.verts[:] = s.verts[[0, 1, 3, 2, 0, 3]]
33 33
     return s
34 34
 
35 35
 def skybox():
36
-    sb = mesh.SquareMesh(texi=-1)
36
+    sb = mesh.SquareMesh()
37 37
     offset = [0, 0, VIEW_DIST]
38 38
     for d in range(3):
39 39
         roll_vec3(offset, 1)
... ...
@@ -3,18 +3,8 @@ import itertools
3 3
 import numpy as np
4 4
 import pygame
5 5
 
6
-FLOAT = np.float32
7
-VOXEL_TYPE = np.uint8
8
-VERTEX_ATTRS = [
9
-    "vec3 position", "vec4 col", "vec3 normal", "vec4 refls", "vec3 texc"
10
-]
11
-UNIFORMS = {
12
-    "MVP": ["vert", "mat4", None],
13
-    "lightPos": ["frag", "vec4", None],
14
-    "camPos": ["frag", "vec3", None],
15
-    "tex": ["frag", "sampler2D[2]", None]
16
-}
17
-
6
+TEX_COUNT = 7
7
+TEX_RES = 64
18 8
 LIGHT_POS = [5, 30, 10]
19 9
 REGION_SIZE = 8
20 10
 GRAVITY = 1
... ...
@@ -27,6 +17,18 @@ ARROWS = [
27 17
 ]
28 18
 ARROWS = [[getattr(pygame, f"K_{n}") for n in opts] for opts in ARROWS]
29 19
 
20
+FLOAT = np.float32
21
+VOXEL_TYPE = np.uint8
22
+VERTEX_ATTRS = [
23
+    "vec3 position", "vec4 col", "vec3 normal", "vec4 refls", "vec3 texc"
24
+]
25
+UNIFORMS = {
26
+    "MVP": ["vert", "mat4", None],
27
+    "lightPos": ["frag", "vec4", None],
28
+    "camPos": ["frag", "vec3", None],
29
+    "tex": ["frag", f"sampler2D[{TEX_COUNT}]", None]
30
+}
31
+
30 32
 def vec(l):
31 33
     return np.array(l, dtype=FLOAT)
32 34
 
... ...
@@ -1,11 +1,16 @@
1 1
 from libs import *
2
-from display import init_display
2
+import display
3 3
 from mapgen import MapGen
4 4
 from player import Player
5 5
 
6 6
 def debug_mode(mg, cam):
7 7
     pass
8 8
 
9
+def build_texture(i, mg, name, mid, offset, period):
10
+    display.load_texture(i, mg.make_texture(
11
+        name, (TEX_RES, TEX_RES), mid, offset, period
12
+    ))
13
+
9 14
 def in_view(wr, cam):
10 15
     rwrc = wr.pos + wr.r / 2 - cam.pos
11 16
     close = np.linalg.norm(rwrc) < VIEW_DIST
... ...
@@ -15,9 +20,14 @@ def in_view(wr, cam):
15 20
     return close and frust
16 21
 
17 22
 def main():
18
-    init_display()
23
+    display.init_display()
19 24
     glUniform4fv(UNIFORMS["lightPos"][2], 1, vec([*LIGHT_POS, 100]))
20 25
     mg = MapGen()
26
+    build_texture(2, mg, "sky", [0.5, 0.5, 0.8], [0.4, 0.4, 0.1], (20, 8))
27
+    build_texture(3, mg, "stone", [0.7, 0.7, 0.8], [0.1, 0.1, 0.1], (12, 15))
28
+    build_texture(4, mg, "grass", [0.3, 0.6, 0.3], [0.2, 0.1, 0.2], (3, 5))
29
+    build_texture(5, mg, "bark", [0.2, 0.1, 0.0], [0.1, 0.1, 0.0], (2, 8))
30
+    build_texture(6, mg, "leaves", [0.2, 0.5, 0.2], [0.2, 0.4, 0.2], (10, 14))
21 31
     clock = pygame.time.Clock()
22 32
     cam = Player(speed=6/FPS)
23 33
     cam.pos = [4, 8, 4]
... ...
@@ -83,3 +83,7 @@ class MapGen(world.WorldHolder):
83 83
                         wr.grid[i, j, k] = 1
84 84
                         n += 1
85 85
         return n
86
+
87
+    def make_texture(self, name, dims, mid, offset, period):
88
+        mid, offset = vec(mid), vec(offset)
89
+        return np.multiply(256, [[mid + offset * self.perlin(name, vec((i, j)), period) for j in range(dims[1])] for i in range(dims[0])], dtype=FLOAT)
86 90