from libs import * 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.viewport = (640, 480) 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 aspect(self): return self.viewport[0] / self.viewport[1] 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: r, i = ent.raycast(self.pos, l) if r and (d is None or r < d): d, c, n = r, ent, i return c, n