from libs import * # https://iquilezles.org/articles/intersectors/ def intersect_tri(ro, rd, tv): e1 = tv[1] - tv[0] e2 = tv[2] - tv[0] to = ro - tv[0] n = np.cross(e1, e2) q = np.cross(to, rd) d = 1.0 / np.dot(rd, n) u = d * np.dot(-q, e2) v = d * np.dot(q, e1) t = d * np.dot(-n, to) if u > 0.0 and v > 0.0 and u + v < 1.0 and t > 1e-3: return t class Camera: def __init__(self, **kwargs): self.pos = vec([0, 0, 0]) self.theta = 0 self.phi = 0 self.fovy = kwargs.get("fovy", 90) self.aspect = 1 def looking(self): return vec([ np.cos(self.phi) * np.sin(self.theta), np.sin(self.phi), np.cos(self.phi) * np.cos(self.theta) ]) def up(self): return vec([0, 1, 0]) def view_mat(self): f = normalize(self.looking()) s = normalize(np.cross(f, self.up())) u = np.cross(s, f) m = np.identity(4, dtype=FLOAT) m[:3, :3] = [s, u, -f] m[:3, 3] = [-np.dot(s, self.pos), -np.dot(u, self.pos), np.dot(f, self.pos)] return m def persp_mat(self): near = 0.1 far = 100 f = 1.0 / np.tan(np.radians(self.fovy) / 2) depth = near - far return vec([ [f / self.aspect, 0, 0, 0], [0, f, 0, 0], [0, 0, (near + far) / depth, (2 * near * far) / depth], [0, 0, -1, 0] ]) def mvp(self, ent): if ent.hud: am = np.identity(4, dtype=FLOAT) am[0, 0] = 1 / self.aspect return ent.translate() @ am @ ent.orient else: return self.persp_mat() @ self.view_mat() @ ent.translate() @ ent.orient def draw(self, ent, loc_mvp): if not ent.vao: ent.build_vao() glUniformMatrix4fv(loc_mvp, 1, GL_TRUE, self.mvp(ent)) glBindVertexArray(ent.vao) glDrawArrays(ent.draw_mode, 0, len(ent.verts)) def target(self, scene): l = self.looking() d, c, n = None, None, None for ent in scene: if ent.hud: continue elif ent.draw_mode == GL_TRIANGLE_STRIP: tl = ((i, ent.verts[i:i + 3]) for i in range(len(ent.verts) - 2)) elif ent.draw_mode == GL_TRIANGLES: tl = ((i, ent.verts[3 * i:3 * (i + 1)]) for i in range(len(ent.verts) // 3)) else: raise NotImplementedError for (i, t) in tl: r = intersect_tri(self.pos, l, np.dot(t, ent.orient[:3, :3].T) + ent.pos) if r and (d is None or r < d): d, c, n = r, ent, i return c, n