Single multicoloured cube demo
dkl9

dkl9 commited on 2025-170 16:55:37
Showing 4 changed files, with 46 additions and 44 deletions.

... ...
@@ -56,11 +56,10 @@ class Camera:
56 56
     def mvp(self, ent):
57 57
         return self.persp_mat() @ self.view_mat() @ ent.translate() @ ent.orient
58 58
 
59
-    def draw(self, ent, loc_mvp, loc_col):
59
+    def draw(self, ent, loc_mvp):
60 60
         if not ent.vao:
61 61
             ent.build_vao()
62 62
         glUniformMatrix4fv(loc_mvp, 1, GL_TRUE, self.mvp(ent))
63
-        glUniform4fv(loc_col, 1, ent.col)
64 63
         glBindVertexArray(ent.vao)
65 64
         glDrawArrays(ent.draw_mode, 0, len(ent.verts))
66 65
 
... ...
@@ -75,7 +74,7 @@ class Camera:
75 74
             else:
76 75
                 raise NotImplementedError
77 76
             for t in tl:
78
-                r = intersect_tri(self.pos, l, ent.pos + np.dot(ent.orient[:3, :3].T, t))
77
+                r = intersect_tri(self.pos, l, np.dot(t, ent.orient[:3, :3].T) + ent.pos)
79 78
                 if r and (d is None or r < d):
80 79
                     d, c = r, ent
81 80
         return c
... ...
@@ -7,17 +7,32 @@ class Entity:
7 7
         self.pos = vec(pos)
8 8
         self.draw_mode = mode
9 9
         self.orient = np.identity(4, dtype=FLOAT)
10
-        self.vao = None
11 10
         self.onclick = lambda s, b: print(f"clicked {s} with button {b}")
11
+        self.vao = None
12
+        self.vbos = [[None, 0], [None, 0]]
13
+
14
+    def col_list(self):
15
+        return np.repeat(vec([self.col]), len(self.verts), 0)
16
+
17
+    def update_attr(self, i, l=None):
18
+        if l is None:
19
+            l = self.verts if i == 0 else self.col_list()
20
+        if self.vao:
21
+            glBindBuffer(GL_ARRAY_BUFFER, self.vbos[i][0])
22
+            if l.shape[0] > self.vbos[i][1]:
23
+                glBufferData(GL_ARRAY_BUFFER, l.nbytes, l, GL_DYNAMIC_DRAW)
24
+                self.vbos[i][1] = l.shape[0]
25
+            else:
26
+                glBufferSubData(GL_ARRAY_BUFFER, 0, l.nbytes, l)
12 27
 
13 28
     def build_vao(self):
14 29
         self.vao = glGenVertexArrays(1)
15 30
         glBindVertexArray(self.vao)
16
-        vbo = glGenBuffers(1)
17
-        glBindBuffer(GL_ARRAY_BUFFER, vbo)
18
-        glBufferData(GL_ARRAY_BUFFER, self.verts.nbytes, self.verts, GL_STATIC_DRAW)
19
-        glEnableVertexAttribArray(0)
20
-        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
31
+        for (i, l) in enumerate((self.verts, self.col_list())):
32
+            self.vbos[i][0] = glGenBuffers(1)
33
+            self.update_attr(i, l)
34
+            glEnableVertexAttribArray(i)
35
+            glVertexAttribPointer(i, l.shape[1], GL_FLOAT, GL_FALSE, 0, None)
21 36
 
22 37
     def translate(self):
23 38
         m = np.identity(4, dtype=FLOAT)
... ...
@@ -2,53 +2,37 @@ from OpenGL.GL import shaders
2 2
 from libs import *
3 3
 from player import Player
4 4
 from entity import Entity
5
+from mesh import SquareMesh
5 6
 
6 7
 VS = """
7 8
 #version 120
8 9
 attribute vec3 position;
10
+attribute vec4 colIn;
11
+varying vec4 colOut;
9 12
 uniform mat4 MVP;
10 13
 void main() {
11 14
     gl_Position = MVP * vec4(position, 1.0);
15
+    colOut = colIn;
12 16
 }
13 17
 """
14 18
 
15 19
 FS = """
16 20
 #version 120
17
-uniform vec4 matCol;
21
+varying vec4 colOut;
18 22
 void main() {
19
-    gl_FragColor = matCol;
23
+    gl_FragColor = colOut;
20 24
 }
21 25
 """
22 26
 
23
-def weaken(self, button):
24
-    if button == 1:
25
-        self.col *= 0.9
26
-
27
-def toggle_spin(self, button):
28
-    if button == 3:
29
-        self.spin = not self.spin
30
-
31 27
 def build_scene():
32
-    ot = Entity(
33
-        [[-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [0.0, 0.5, 0.0]],
34
-        [1.0, 0.5, 0.2, 1.0],
35
-        [0.0, 0.0, 3.0]
36
-    )
37
-    ot.spin = True
38
-    ot.onclick = toggle_spin
39
-    cr = Entity(
40
-        [[-0.8, -0.4, 0.0], [-0.8, 0.4, 0.0], [0.8, -0.4, 0.0], [0.8, 0.4, 0.0]],
41
-        [0.2, 0.5, 1.0, 1.0],
42
-        [3.0, -0.5, 0.0]
43
-    )
44
-    cr.rotate(np.radians(90), [0.0, 1.0, 0.0])
45
-    cr.onclick = weaken
46
-    return [ot, cr]
28
+    box = SquareMesh()
29
+    box.add_cube(2, [0, 0, 0])
30
+    return [box]
47 31
 
48 32
 def main():
49 33
     pygame.init()
50 34
     pygame.display.set_mode((640, 480), pygame.DOUBLEBUF | pygame.OPENGL | pygame.RESIZABLE)
51
-    pygame.display.set_caption("OpenGL!")
35
+    pygame.display.set_caption("OpenGL")
52 36
     sp = shaders.compileProgram(
53 37
         shaders.compileShader(VS, GL_VERTEX_SHADER),
54 38
         shaders.compileShader(FS, GL_FRAGMENT_SHADER)
... ...
@@ -56,25 +40,26 @@ def main():
56 40
     glUseProgram(sp)
57 41
     glEnable(GL_DEPTH_TEST)
58 42
     loc_mvp = glGetUniformLocation(sp, "MVP")
59
-    loc_matcol = glGetUniformLocation(sp, "matCol")
60 43
     glClearColor(0.1, 0.1, 0.1, 1.0)
61 44
     scene = build_scene()
62 45
     clock = pygame.time.Clock()
63 46
     cam = Player()
64 47
     cam.set_focus(True)
48
+    n = 0
65 49
     while True:
66 50
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
67 51
         for ent in scene:
68
-            cam.draw(ent, loc_mvp, loc_matcol)
52
+            cam.draw(ent, loc_mvp)
69 53
         for ev in pygame.event.get():
70 54
             if ev.type == pygame.QUIT or ev.type == pygame.KEYUP and ev.unicode == "q":
71 55
                 pygame.quit()
72 56
                 return
73 57
             cam.handle_event(ev, scene)
74 58
         cam.update_pos()
75
-        if scene[0].spin:
76
-            scene[0].rotate(0.03 / np.linalg.norm(scene[0].pos - cam.pos) ** 2, [0.0, 1.0, 0.0])
77 59
         pygame.display.flip()
78
-        clock.tick(60)
60
+        clock.tick(240)
61
+        n += 1
62
+        if n % 120 == 0:
63
+            pygame.display.set_caption(f"fps {round(clock.get_fps())}")
79 64
 
80 65
 main()
... ...
@@ -1,7 +1,7 @@
1 1
 from libs import *
2 2
 import camera
3 3
 
4
-ARROWS = [pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT]
4
+ARROWS = [pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT, pygame.K_SPACE, pygame.K_LSHIFT]
5 5
 
6 6
 def reshape(w, h):
7 7
     glViewport(0, 0, w, h)
... ...
@@ -26,8 +26,11 @@ class Player(camera.Camera):
26 26
         self.phi = min(np.pi / 2, max(-np.pi / 2, self.phi + self.sensitivity * dy))
27 27
                 
28 28
     def update_motion(self, pk):
29
-        self.rv[0] = pk[pygame.K_RIGHT] - pk[pygame.K_LEFT]
30
-        self.rv[2] = pk[pygame.K_UP] - pk[pygame.K_DOWN]
29
+        self.rv = vec([
30
+            pk[pygame.K_RIGHT] - pk[pygame.K_LEFT],
31
+            pk[pygame.K_SPACE] - pk[pygame.K_LSHIFT],
32
+            pk[pygame.K_UP] - pk[pygame.K_DOWN]
33
+        ])
31 34
 
32 35
     def vdof(self):
33 36
         l = self.looking()
... ...
@@ -54,6 +57,6 @@ class Player(camera.Camera):
54 57
             case pygame.MOUSEBUTTONDOWN:
55 58
                 t = self.target(scene)
56 59
                 if t:
57
-                    t.onclick(ev.button)
60
+                    t.click(ev.button)
58 61
             case pygame.WINDOWSIZECHANGED | pygame.WINDOWRESIZED:
59 62
                 self.aspect = reshape(ev.x, ev.y)
60 63