class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, size=(512, 512), title='Rotating cube', keys='interactive') self.timer = app.Timer('auto', self.on_timer) def on_initialize(self, event): # Build cube data V, I, O = create_cube() vertices = VertexBuffer(V) self.faces = IndexBuffer(I) self.outline = IndexBuffer(O) # Build program # -------------------------------------- self.program = Program(vertex, fragment) self.program.bind(vertices) # Build view, model, projection & normal # -------------------------------------- view = translate((0, 0, -5)) model = np.eye(4, dtype=np.float32) self.program['u_model'] = model self.program['u_view'] = view self.phi, self.theta = 0, 0 # OpenGL initalization # -------------------------------------- gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True, polygon_offset=(1, 1), line_width=0.75, blend_func=('src_alpha', 'one_minus_src_alpha')) self.timer.start() def on_draw(self, event): gloo.clear(color=True, depth=True) # Filled cube gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=True) self.program['u_color'] = 1, 1, 1, 1 self.program.draw('triangles', self.faces) # Outlined cube gloo.set_state(blend=True, depth_mask=False, polygon_offset_fill=False) self.program['u_color'] = 0, 0, 0, 1 self.program.draw('lines', self.outline) gloo.set_state(depth_mask=True) def on_resize(self, event): gloo.set_viewport(0, 0, *event.size) projection = perspective(45.0, event.size[0] / float(event.size[1]), 2.0, 10.0) self.program['u_projection'] = projection def on_timer(self, event): self.theta += .02 self.phi += .02 model = rotate(self.phi, (0, 1, 0)) * rotate(self.theta, (0, 0, 1)) self.program['u_model'] = model self.update()
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, size=(750, 750), title='Textured cube', keys='interactive') self.timer = app.Timer('auto', self.on_timer) self.counter = 0 # Build cube data V, I, _ = create_cube() vertices = VertexBuffer(V) self.indices = IndexBuffer(I) # Build program self.program = Program(vertex, fragment) self.program.bind(vertices) # Build view, model, projection & normal view = translate((0, 0, -5)) model = np.eye(4, dtype=np.float32) self.program['model'] = model self.program['view'] = view self.program['texture'] = cam # checkerboard() self.activate_zoom() self.phi, self.theta = 0, 0 # OpenGL initalization gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True) self.timer.start() self.show() def on_draw(self, event): gloo.clear(color=True, depth=True) self.program.draw('triangles', self.indices) def on_resize(self, event): self.activate_zoom() def activate_zoom(self): gloo.set_viewport(0, 0, *self.physical_size) projection = perspective(45.0, self.size[0] / float(self.size[1]), 2.0, 10.0) self.program['projection'] = projection def on_timer(self, event): self.counter += 1 print("on_timer", self.counter) self.theta += .5 self.phi += .5 self.program['model'] = np.dot(rotate(self.theta, (0, 1, 0)), rotate(self.phi, (0, 1, 0))) # self.program['texture'] = im if self.counter % 200 else checkerboard() self.update()
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, title='Rain [Move mouse]', size=(512, 512), keys='interactive') # Build data # -------------------------------------- n = 500 self.data = np.zeros(n, [('a_position', np.float32, 2), ('a_fg_color', np.float32, 4), ('a_size', np.float32, 1)]) self.index = 0 self.program = Program(vertex, fragment) self.vdata = VertexBuffer(self.data) self.program.bind(self.vdata) self.program['u_antialias'] = 1.00 self.program['u_linewidth'] = 1.00 self.program['u_model'] = np.eye(4, dtype=np.float32) self.program['u_view'] = np.eye(4, dtype=np.float32) self.activate_zoom() gloo.set_clear_color('white') gloo.set_state(blend=True, blend_func=('src_alpha', 'one_minus_src_alpha')) self.timer = app.Timer('auto', self.on_timer, start=True) self.show() def on_draw(self, event): gloo.clear() self.program.draw('points') def on_resize(self, event): self.activate_zoom() def activate_zoom(self): gloo.set_viewport(0, 0, *self.physical_size) projection = ortho(0, self.size[0], 0, self.size[1], -1, +1) self.program['u_projection'] = projection def on_timer(self, event): self.data['a_fg_color'][..., 3] -= 0.01 self.data['a_size'] += 1.0 self.vdata.set_data(self.data) self.update() def on_mouse_move(self, event): x, y = event.pos h = self.size[1] self.data['a_position'][self.index] = x, h - y self.data['a_size'][self.index] = 5 self.data['a_fg_color'][self.index] = 0, 0, 0, 1 self.index = (self.index + 1) % 500
class MyCanvas(app.Canvas): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.timer = app.Timer('auto', connect=self.on_timer, start=True) with open('vertex.glsl') as f: self.vshader = f.read() with open('fragment.glsl') as f: self.fshader = f.read() self.program = Program(self.vshader, self.fshader) v, i, iOutline = create_cube() self.vertices = VertexBuffer(v) self.indices = IndexBuffer(i) self.outlineIndices = IndexBuffer(iOutline) self.program.bind(self.vertices) self.theta, self.phi = 0, 0 self.program['model'] = np.eye(4) self.program['view'] = translate([0, 0, -5]) self.program['texture'] = checkerboard() gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), polygon_offset=(1, 1), blend_func=('src_alpha', 'one_minus_src_alpha'), line_width=5, depth_test=True) def on_resize(self, event): gloo.set_viewport(0, 0, *self.physical_size) proj = perspective(45.0, self.size[0] / self.size[1], 0.01, 1000) self.program['projection'] = proj def on_draw(self, event): gloo.clear(color=True, depth=True) gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=True) self.program['u_color'] = [1, 1, 1, 1] self.program.draw('triangles', self.indices) gloo.set_state(blend=True, depth_mask=False, polygon_offset_fill=False) self.program['u_color'] = [0, 0, 0, 1] self.program.draw('lines', self.outlineIndices) gloo.set_state(depth_mask=True) def on_timer(self, event): self.theta = event.elapsed * 30 self.phi = 0 self.program['model'] = np.dot( rotate(self.phi, [1, 0, 0]), rotate(self.theta, [0, 1, 0]), ) self.update()
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, size=(512, 512), title='Textured cube', keys='interactive') self.timer = app.Timer('auto', self.on_timer) # Build cube data V, I, _ = create_cube() vertices = VertexBuffer(V) self.indices = IndexBuffer(I) # Build program self.program = Program(vertex, fragment) self.program.bind(vertices) # Build view, model, projection & normal view = translate((0, 0, -5)) model = np.eye(4, dtype=np.float32) self.program['model'] = model self.program['view'] = view self.program['texture'] = checkerboard() self.activate_zoom() self.phi, self.theta = 0, 0 # OpenGL initalization gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True) self.timer.start() self.show() def on_draw(self, event): gloo.clear(color=True, depth=True) self.program.draw('triangles', self.indices) def on_resize(self, event): self.activate_zoom() def activate_zoom(self): gloo.set_viewport(0, 0, *self.physical_size) projection = perspective(45.0, self.size[0] / float(self.size[1]), 2.0, 10.0) self.program['projection'] = projection def on_timer(self, event): self.theta += .5 self.phi += .5 self.program['model'] = np.dot(rotate(self.theta, (0, 0, 1)), rotate(self.phi, (0, 1, 0))) self.update()
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, size=(512, 512), title='Textured cube', keys='interactive') self.timer = app.Timer('auto', self.on_timer) def on_initialize(self, event): # Build cube data V, I, _ = create_cube() vertices = VertexBuffer(V) self.indices = IndexBuffer(I) # Build program self.program = Program(vertex, fragment) self.program.bind(vertices) # Build view, model, projection & normal view = np.eye(4, dtype=np.float32) model = np.eye(4, dtype=np.float32) translate(view, 0, 0, -5) self.program['model'] = model self.program['view'] = view self.program['texture'] = checkerboard() self.phi, self.theta = 0, 0 # OpenGL initalization gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True) self.timer.start() def on_draw(self, event): gloo.clear(color=True, depth=True) self.program.draw('triangles', self.indices) def on_resize(self, event): gloo.set_viewport(0, 0, *event.size) projection = perspective(45.0, event.size[0] / float(event.size[1]), 2.0, 10.0) self.program['projection'] = projection def on_timer(self, event): self.theta += .5 self.phi += .5 model = np.eye(4, dtype=np.float32) rotate(model, self.theta, 0, 0, 1) rotate(model, self.phi, 0, 1, 0) self.program['model'] = model self.update()
class GpaphicBlueprint: def __init__(self): self.kind = '' self._color = (0, 0, 0) self._program = None self._indices = None self._mesh = None def getProgram(self): return self._program def getIndices(self): return self._indices def setColor(self, newColor): ''' Mit dieser Methode koennen andere Klassen die Farb-Uniform des _programs setzen. Parameter: newColor Rueckgabewerte: - ''' self._color = newColor self._program['color'] = self._color def buildProgram(self): ''' In dieser Methode wird das Programm samt Indices einer Kugel errechnet. Das Ganze wird mithilfe der Bibliothek vispy.gloo gemacht. Parameter: - Rueckgabewerte: - ''' vertices = np.zeros(self._mesh.getVertices().shape[0], [("position", np.float32, 3)]) vertices["position"] = self._mesh.getVertices() vertices = VertexBuffer(vertices) indices = self._mesh.getIndices() self._indices = IndexBuffer(indices) self._program = Program(vertex, fragment) self._program.bind(vertices) self._program['color'] = self._color self._program['model'] = None self._program['view'] = None self._program['drawHorizon'] = -3
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, size=(512, 512), title='Textured cube', close_keys='escape') self.timer = app.Timer(1./60., self.on_timer) def on_initialize(self, event): # Build cube data V, I, _ = cube() vertices = VertexBuffer(V) self.indices = IndexBuffer(I) # Build program self.program = Program(vertex, fragment) self.program.bind(vertices) # Build view, model, projection & normal view = np.eye(4, dtype=np.float32) model = np.eye(4, dtype=np.float32) translate(view, 0, 0, -5) self.program['model'] = model self.program['view'] = view self.program['texture'] = checkerboard() self.phi, self.theta = 0, 0 # OpenGL initalization gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True) self.timer.start() def on_draw(self, event): gloo.clear(color=True, depth=True) self.program.draw('triangles', self.indices) def on_resize(self, event): gloo.set_viewport(0, 0, *event.size) projection = perspective(45.0, event.size[0] / float(event.size[1]), 2.0, 10.0) self.program['projection'] = projection def on_timer(self, event): self.theta += .5 self.phi += .5 model = np.eye(4, dtype=np.float32) rotate(model, self.theta, 0, 0, 1) rotate(model, self.phi, 0, 1, 0) self.program['model'] = model self.update()
class Example(Drawable): '''Draw a cube''' cube_vertex = """ #version 120 uniform mat4 model; uniform mat4 view; uniform mat4 projection; attribute vec3 position; attribute vec2 texcoord; varying vec2 v_texcoord; void main() { gl_Position = projection * view * model * vec4(position, 1.0); v_texcoord = texcoord; } """ cube_fragment = """ #version 120 uniform sampler2D texture; varying vec2 v_texcoord; void main() { float r = texture2D(texture, v_texcoord).r; gl_FragColor = vec4(0, r, r, 1); } """ def __init__(self): vertices, indices, _ = create_cube() vertices = VertexBuffer(vertices) self.indices = IndexBuffer(indices) self.program = Program(self.cube_vertex, self.cube_fragment) self.model = np.eye(4) self.view = np.eye(4) self.program.bind(vertices) self.program['texture'] = utils.checkerboard() self.program['texture'].interpolation = 'linear' self.program['model'] = self.model self.program['view'] = self.view def draw(self): self.program.draw('triangles', self.indices)
def make_mesh(self): '''mesh() Generates a default mesh (a cube) treat it as though it is a property (i.e. not a function) ex: >>> x = Target((100, 100, 100)) >>> mesh = Target.mesh ''' cube = Program(cube_vertex, cube_fragment) cube.bind(vertices) self.program['model'] = model self.program['view'] = view self.program['projection'] = projection if self.mesh is None: vertices, indices, _ = create_cube() # self.mesh = else: return self.mesh
class Renderer3D(OpenGLRenderer): def __init__(self): super().__init__(src_fbuffer, src_default) self.style = Style3D() self.normal_prog = Program(src_normal.vert, src_normal.frag) self.phong_prog = Program(src_phong.vert, src_phong.frag) self.lookat_matrix = np.identity(4) # Camera position self.camera_pos = np.zeros(3) # Lights self.MAX_LIGHTS_PER_CATEGORY = 8 self.ambient_light_color = GlslList(self.MAX_LIGHTS_PER_CATEGORY, 3, np.float32) self.directional_light_dir = GlslList(self.MAX_LIGHTS_PER_CATEGORY, 3, np.float32) self.directional_light_color = GlslList(self.MAX_LIGHTS_PER_CATEGORY, 3, np.float32) self.directional_light_specular = GlslList( self.MAX_LIGHTS_PER_CATEGORY, 3, np.float32) self.point_light_color = GlslList(self.MAX_LIGHTS_PER_CATEGORY, 3, np.float32) self.point_light_pos = GlslList(self.MAX_LIGHTS_PER_CATEGORY, 3, np.float32) self.point_light_specular = GlslList(self.MAX_LIGHTS_PER_CATEGORY, 3, np.float32) self.const_falloff = GlslList(self.MAX_LIGHTS_PER_CATEGORY, 1, np.float32) self.linear_falloff = GlslList(self.MAX_LIGHTS_PER_CATEGORY, 1, np.float32) self.quadratic_falloff = GlslList(self.MAX_LIGHTS_PER_CATEGORY, 1, np.float32) self.curr_linear_falloff, self.curr_quadratic_falloff, self.curr_constant_falloff = 0.0, 0.0, 0.0 self.light_specular = np.array([0.0] * 3) def initialize_renderer(self): super().initialize_renderer() self.reset_view() def reset_view(self): self.viewport = ( 0, 0, int(builtins.width * builtins.pixel_x_density), int(builtins.height * builtins.pixel_y_density), ) self.texture_viewport = ( 0, 0, builtins.width, builtins.height, ) gloo.set_viewport(*self.viewport) # pylint: disable=no-member cz = (builtins.height / 2) / math.tan(math.radians(30)) self.projection_matrix = matrix.perspective_matrix( math.radians(60), builtins.width / builtins.height, 0.1 * cz, 10 * cz) self.transform_matrix = np.identity(4) self._update_shader_transforms() self.fbuffer_tex_front = Texture2D( (builtins.height, builtins.width, 3)) self.fbuffer_tex_back = Texture2D((builtins.height, builtins.width, 3)) self.fbuffer.depth_buffer = gloo.RenderBuffer( (builtins.height, builtins.width)) for buf in [self.fbuffer_tex_front, self.fbuffer_tex_back]: self.fbuffer.color_buffer = buf with self.fbuffer: self.clear() def clear(self, color=True, depth=True): """Clear the renderer background.""" gloo.set_state(clear_color=self.style.background_color) # pylint: disable=no-member gloo.clear(color=color, depth=depth) # pylint: disable=no-member def clear_lights(self): self.ambient_light_color.clear() self.directional_light_color.clear() self.directional_light_dir.clear() self.directional_light_specular.clear() self.point_light_color.clear() self.point_light_pos.clear() self.point_light_specular.clear() self.const_falloff.clear() self.linear_falloff.clear() self.quadratic_falloff.clear() def _comm_toggles(self, state=True): gloo.set_state(blend=state) # pylint: disable=no-member gloo.set_state(depth_test=state) # pylint: disable=no-member if state: gloo.set_state(blend_func=('src_alpha', 'one_minus_src_alpha')) # pylint: disable=no-member gloo.set_state(depth_func='lequal') # pylint: disable=no-member def _update_shader_transforms(self): # Default shader self.default_prog['projection'] = self.projection_matrix.T.flatten() self.default_prog['perspective_matrix'] = self.lookat_matrix.T.flatten( ) # Normal shader self.normal_prog['projection'] = self.projection_matrix.T.flatten() self.normal_prog['perspective'] = self.lookat_matrix.T.flatten() # This is a no-op, meaning that the normals stay in world space, which # matches the behavior in p5.js normal_transform = np.identity(3) # I think the transformation below takes the vertices to camera space, but # the results are funky, so it's probably incorrect? - ziyaointl, 2020/07/20 # normal_transform = np.linalg.inv(self.projection_matrix[:3, :3] @ self.lookat_matrix[:3, :3]) self.normal_prog['normal_transform'] = normal_transform.flatten() # Blinn-Phong Shader self.phong_prog['projection'] = self.projection_matrix.T.flatten() self.phong_prog['perspective'] = self.lookat_matrix.T.flatten() @contextmanager def draw_loop(self): """The main draw loop context manager. """ self.transform_matrix = np.identity(4) self._update_shader_transforms() self.fbuffer.color_buffer = self.fbuffer_tex_back with self.fbuffer: gloo.set_viewport(*self.texture_viewport) # pylint: disable=no-member self._comm_toggles() self.fbuffer_prog['texture'] = self.fbuffer_tex_front self.fbuffer_prog.draw('triangle_strip') self.clear(color=False, depth=True) self.clear_lights() yield self.flush_geometry() self.transform_matrix = np.identity(4) gloo.set_viewport(*self.viewport) # pylint: disable=no-member self._comm_toggles(False) self.clear() self.fbuffer_prog['texture'] = self.fbuffer_tex_back self.fbuffer_prog.draw('triangle_strip') self.fbuffer_tex_front, self.fbuffer_tex_back = self.fbuffer_tex_back, self.fbuffer_tex_front def _add_to_draw_queue_simple(self, stype, vertices, idx, color): """Adds shape of stype to draw queue """ self.draw_queue.append((stype, (vertices, idx, color, None, None))) def tnormals(self, shape): """Obtain a list of vertex normals in world coordinates """ if isinstance(shape.material, BasicMaterial): # Basic shader doesn't need this return None return shape.vertex_normals @ np.linalg.inv( to_3x3(self.transform_matrix) @ to_3x3(shape.matrix)) def render(self, shape): if isinstance(shape, Geometry): n = len(shape.vertices) # Perform model transform # TODO: Investigate moving model transform from CPU to the GPU tverts = self._transform_vertices( np.hstack([shape.vertices, np.ones((n, 1))]), shape.matrix, self.transform_matrix) tnormals = self.tnormals(shape) edges = shape.edges faces = shape.faces self.add_to_draw_queue('poly', tverts, edges, faces, self.style.fill_color, self.style.stroke_color, tnormals, self.style.material) elif isinstance(shape, PShape): fill = shape.fill.normalized if shape.fill else None stroke = shape.stroke.normalized if shape.stroke else None obj_list = get_render_primitives(shape) for obj in obj_list: stype, vertices, idx = obj # Transform vertices vertices = self._transform_vertices( np.hstack([vertices, np.ones((len(vertices), 1))]), shape._matrix, self.transform_matrix) # Add to draw queue self._add_to_draw_queue_simple( stype, vertices, idx, stroke if stype == 'lines' else fill) def add_to_draw_queue(self, stype, vertices, edges, faces, fill=None, stroke=None, normals=None, material=None): """Add the given vertex data to the draw queue. :param stype: type of shape to be added. Should be one of {'poly', 'path', 'point'} :type stype: str :param vertices: (N, 3) array containing the vertices to be drawn. :type vertices: np.ndarray :param edges: (N, 2) array containing edges as tuples of indices into the vertex array. This can be None when not appropriate (eg. for points) :type edges: None | np.ndarray :param faces: (N, 3) array containing faces as tuples of indices into the vertex array. For 'point' and 'path' shapes, this can be None :type faces: np.ndarray :param fill: Fill color of the shape as a normalized RGBA tuple. When set to `None` the shape doesn't get a fill (default: None) :type fill: None | tuple :param stroke: Stroke color of the shape as a normalized RGBA tuple. When set to `None` the shape doesn't get stroke (default: None) :type stroke: None | tuple // TODO: Update documentation // TODO: Unite style-related attributes for both 2D and 3D under one material class """ fill_shape = self.style.fill_enabled and not (fill is None) stroke_shape = self.style.stroke_enabled and not (stroke is None) if fill_shape and stype not in ['point', 'path']: idx = np.array(faces, dtype=np.uint32).ravel() self.draw_queue.append( ["triangles", (vertices, idx, fill, normals, material)]) if stroke_shape: if stype == 'point': idx = np.arange(0, len(vertices), dtype=np.uint32) self.draw_queue.append( ["points", (vertices, idx, stroke, normals, material)]) else: idx = np.array(edges, dtype=np.uint32).ravel() self.draw_queue.append( ["lines", (vertices, idx, stroke, normals, material)]) def render_with_shaders(self, draw_type, draw_obj): vertices, idx, color, normals, material = draw_obj """Like render_default but is aware of shaders other than the basic one""" # 0. If material does not need normals nor extra info, strip them out # and use the method from superclass if material is None or isinstance( material, BasicMaterial) or draw_type in ['points', 'lines']: OpenGLRenderer.render_default(self, draw_type, [draw_obj[:3]]) return # 1. Get the number of vertices num_vertices = len(vertices) # 2. Create empty buffers based on the number of vertices. # data = np.zeros(num_vertices, dtype=[('position', np.float32, 3), ('normal', np.float32, 3)]) # 3. Loop through all the shapes in the geometry queue adding # it's information to the buffer. # draw_indices = [] data['position'][0:num_vertices, ] = np.array(vertices) draw_indices.append(idx) data['normal'][0:num_vertices, ] = np.array(normals) self.vertex_buffer.set_data(data) self.index_buffer.set_data(np.hstack(draw_indices)) if isinstance(material, NormalMaterial): # 4. Bind the buffer to the shader. # self.normal_prog.bind(self.vertex_buffer) # 5. Draw the shape using the proper shape type and get rid of # the buffers. # self.normal_prog.draw(draw_type, indices=self.index_buffer) elif isinstance(material, BlinnPhongMaterial): self.phong_prog.bind(self.vertex_buffer) self.phong_prog['u_cam_pos'] = self.camera_pos # Material attributes self.phong_prog['u_ambient_color'] = material.ambient self.phong_prog['u_diffuse_color'] = material.diffuse self.phong_prog['u_specular_color'] = material.specular self.phong_prog['u_shininess'] = material.shininess # Directional lights self.phong_prog[ 'u_directional_light_count'] = self.directional_light_color.size self.phong_prog[ 'u_directional_light_dir'] = self.directional_light_dir.data self.phong_prog[ 'u_directional_light_color'] = self.directional_light_color.data self.phong_prog[ 'u_directional_light_specular'] = self.directional_light_specular.data # Ambient lights self.phong_prog[ 'u_ambient_light_count'] = self.ambient_light_color.size self.phong_prog[ 'u_ambient_light_color'] = self.ambient_light_color.data # Point lights self.phong_prog[ 'u_point_light_count'] = self.point_light_color.size self.phong_prog[ 'u_point_light_color'] = self.point_light_color.data self.phong_prog['u_point_light_pos'] = self.point_light_pos.data self.phong_prog[ 'u_point_light_specular'] = self.point_light_specular.data # Point light falloffs self.phong_prog['u_const_falloff'] = self.const_falloff.data self.phong_prog['u_linear_falloff'] = self.linear_falloff.data self.phong_prog[ 'u_quadratic_falloff'] = self.quadratic_falloff.data # Draw self.phong_prog.draw(draw_type, indices=self.index_buffer) else: raise NotImplementedError("Material not implemented") def flush_geometry(self): """Flush all the shape geometry from the draw queue to the GPU. """ for index, shape in enumerate(self.draw_queue): current_shape, current_obj = self.draw_queue[index][ 0], self.draw_queue[index][1] # If current_shape is lines, bring it to the front by epsilon # to resolve z-fighting if current_shape == 'lines': # line_transform is used whenever we render lines to break ties in depth # We transform the points to camera space, move them by # Z_EPSILON, and them move them back to world space line_transform = inv(self.lookat_matrix).dot( translation_matrix(0, 0, Z_EPSILON).dot(self.lookat_matrix)) vertices = current_obj[0] current_obj = (np.hstack([ vertices, np.ones((vertices.shape[0], 1)) ]).dot(line_transform.T)[:, :3], *current_obj[1:]) self.render_with_shaders(current_shape, current_obj) self.draw_queue = [] def cleanup(self): super(Renderer3D, self).cleanup() self.normal_prog.delete() self.phong_prog.delete() def add_ambient_light(self, r, g, b): self.ambient_light_color.add(np.array((r, g, b))) def add_directional_light(self, r, g, b, x, y, z): self.directional_light_color.add(np.array((r, g, b))) self.directional_light_dir.add(np.array((x, y, z))) self.directional_light_specular.add(self.light_specular) def add_point_light(self, r, g, b, x, y, z): self.point_light_color.add(np.array((r, g, b))) self.point_light_pos.add(np.array((x, y, z))) self.point_light_specular.add(self.light_specular) self.const_falloff.add(self.curr_constant_falloff) self.linear_falloff.add(self.curr_linear_falloff) self.quadratic_falloff.add(self.curr_quadratic_falloff)
vertices = VertexBuffer(V) I = [ 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 1, 1, 6, 7, 1, 7, 2, 7, 4, 3, 7, 3, 2, 4, 7, 6, 4, 6, 5 ] indices = IndexBuffer(I) O = [0, 1, 1, 2, 2, 3, 3, 0, 4, 7, 7, 6, 6, 5, 5, 4, 0, 5, 1, 6, 2, 7, 3, 4] outline = IndexBuffer(O) # Build program # -------------------------------------- program = Program(vertex, fragment) program.bind(vertices) # Build view, model, projection & normal # -------------------------------------- view = np.eye(4, dtype=np.float32) rotate(view, 20, 1, 0, 0) translate(view, 0, 1, -8) model = np.eye(4, dtype=np.float32) projection = np.eye(4, dtype=np.float32) program['model'] = model program['view'] = view program['o_projection'] = ortho(-10, 10, -10, 10, -10, 20) phi, theta = 0, 0 program2 = Program(vertex, ilio.read('black.frag'), count=4) program2['model'] = model
vertices = VertexBuffer(V) I = [0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,1, 1,6,7, 1,7,2, 7,4,3, 7,3,2, 4,7,6, 4,6,5] indices = IndexBuffer(I) O = [0,1, 1,2, 2,3, 3,0, 4,7, 7,6, 6,5, 5,4, 0,5, 1,6, 2,7, 3,4 ] outline = IndexBuffer(O) # Build program # -------------------------------------- program = Program(vertex, fragment) program.bind(vertices) # Build view, model, projection & normal # -------------------------------------- view = np.eye(4,dtype=np.float32) rotate(view, 20, 1, 0, 0) translate(view, 0,1 ,-8) model = np.eye(4,dtype=np.float32) projection = np.eye(4,dtype=np.float32) program['model'] = model program['view'] = view program['o_projection'] = ortho(-10, 10, -10, 10, -10, 20) phi, theta = 0,0 program2 = Program(vertex, ilio.read('black.frag'), count=4) program2['model'] = model
vertices = VertexBuffer(V) faces = IndexBuffer(F) outline = IndexBuffer(O) # Build view, model, projection & normal # -------------------------------------- view = np.eye(4, dtype=np.float32) model = np.eye(4, dtype=np.float32) projection = np.eye(4, dtype=np.float32) translate(view, 0, 0, -5) normal = np.array(np.matrix(np.dot(view, model)).I.T) # Build program # -------------------------------------- program = Program(vertex, fragment) program.bind(vertices) program["u_light_position"] = 2, 2, 2 program["u_light_intensity"] = 1, 1, 1 program["u_model"] = model program["u_view"] = view program["u_normal"] = normal phi, theta = 0, 0 # OpenGL initalization # -------------------------------------- gl.glClearColor(1, 1, 1, 1) gl.glEnable(gl.GL_DEPTH_TEST) gl.glPolygonOffset(1, 1) gl.glEnable(gl.GL_LINE_SMOOTH) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) gl.glLineWidth(0.75)
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, title='Framebuffer post-processing', keys='interactive', size=(512, 512)) def on_initialize(self, event): # Build cube data # -------------------------------------- vertices, indices, _ = create_cube() vertices = VertexBuffer(vertices) self.indices = IndexBuffer(indices) # Build program # -------------------------------------- view = np.eye(4, dtype=np.float32) model = np.eye(4, dtype=np.float32) translate(view, 0, 0, -7) self.phi, self.theta = 60, 20 rotate(model, self.theta, 0, 0, 1) rotate(model, self.phi, 0, 1, 0) self.cube = Program(cube_vertex, cube_fragment) self.cube.bind(vertices) self.cube["texture"] = checkerboard() self.cube["texture"].interpolation = 'linear' self.cube['model'] = model self.cube['view'] = view color = Texture2D((512, 512, 3), interpolation='linear') self.framebuffer = FrameBuffer(color, RenderBuffer((512, 512))) self.quad = Program(quad_vertex, quad_fragment, count=4) self.quad['texcoord'] = [(0, 0), (0, 1), (1, 0), (1, 1)] self.quad['position'] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)] self.quad['texture'] = color # OpenGL and Timer initalization # -------------------------------------- set_state(clear_color=(.3, .3, .35, 1), depth_test=True) self.timer = app.Timer('auto', connect=self.on_timer, start=True) self._set_projection(self.size) def on_draw(self, event): with self.framebuffer: set_viewport(0, 0, 512, 512) clear(color=True, depth=True) set_state(depth_test=True) self.cube.draw('triangles', self.indices) set_viewport(0, 0, *self.size) clear(color=True) set_state(depth_test=False) self.quad.draw('triangle_strip') def on_resize(self, event): self._set_projection(event.size) def _set_projection(self, size): width, height = size set_viewport(0, 0, width, height) projection = perspective(30.0, width / float(height), 2.0, 10.0) self.cube['projection'] = projection def on_timer(self, event): self.theta += .5 self.phi += .5 model = np.eye(4, dtype=np.float32) rotate(model, self.theta, 0, 0, 1) rotate(model, self.phi, 0, 1, 0) self.cube['model'] = model self.update()
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, size=(512, 512), title="Lighted cube", keys="interactive") self.timer = app.Timer("auto", self.on_timer) # Build cube data V, F, O = create_cube() vertices = VertexBuffer(V) self.faces = IndexBuffer(F) self.outline = IndexBuffer(O) # Build view, model, projection & normal # -------------------------------------- self.view = np.eye(4, dtype=np.float32) model = np.eye(4, dtype=np.float32) translate(self.view, 0, 0, -5) normal = np.array(np.matrix(np.dot(self.view, model)).I.T) # Build program # -------------------------------------- self.program = Program(vertex, fragment) self.program.bind(vertices) self.program["u_light_position"] = 2, 2, 2 self.program["u_light_intensity"] = 1, 1, 1 self.program["u_model"] = model self.program["u_view"] = self.view self.program["u_normal"] = normal self.phi, self.theta = 0, 0 # OpenGL initalization # -------------------------------------- gloo.set_state( clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True, polygon_offset=(1, 1), blend_func=("src_alpha", "one_minus_src_alpha"), line_width=0.75, ) self.timer.start() def on_draw(self, event): gloo.clear(color=True, depth=True) # program.draw(gl.GL_TRIANGLES, indices) # Filled cube gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=True) self.program["u_color"] = 1, 1, 1, 1 self.program.draw("triangles", self.faces) # Outlined cube gloo.set_state(polygon_offset_fill=False, blend=True, depth_mask=False) self.program["u_color"] = 0, 0, 0, 1 self.program.draw("lines", self.outline) gloo.set_state(depth_mask=True) def on_resize(self, event): gloo.set_viewport(0, 0, *event.size) projection = perspective(45.0, event.size[0] / float(event.size[1]), 2.0, 10.0) self.program["u_projection"] = projection def on_timer(self, event): self.theta += 0.5 self.phi += 0.5 model = np.eye(4, dtype=np.float32) rotate(model, self.theta, 0, 0, 1) rotate(model, self.phi, 0, 1, 0) normal = np.array(np.matrix(np.dot(self.view, model)).I.T) self.program["u_model"] = model self.program["u_normal"] = normal self.update()
class Renderer2D: def __init__(self): self.default_prog = None self.fbuffer_prog = None self.texture_prog = None self.line_prog = None self.fbuffer = None self.fbuffer_tex_front = None self.fbuffer_tex_back = None self.vertex_buffer = None self.index_buffer = None ## Renderer Globals: USEFUL CONSTANTS self.COLOR_WHITE = (1, 1, 1, 1) self.COLOR_BLACK = (0, 0, 0, 1) self.COLOR_DEFAULT_BG = (0.8, 0.8, 0.8, 1.0) ## Renderer Globals: STYLE/MATERIAL PROPERTIES ## self.background_color = self.COLOR_DEFAULT_BG self.fill_color = self.COLOR_WHITE self.fill_enabled = True self.stroke_color = self.COLOR_BLACK self.stroke_enabled = True self.tint_color = self.COLOR_BLACK self.tint_enabled = False ## Renderer Globals: Curves self.stroke_weight = 1 self.stroke_cap = 2 self.stroke_join = 0 ## Renderer Globals ## VIEW MATRICES, ETC ## self.viewport = None self.texture_viewport = None self.transform_matrix = np.identity(4) self.modelview_matrix = np.identity(4) self.projection_matrix = np.identity(4) ## Renderer Globals: RENDERING self.draw_queue = [] def initialize_renderer(self): self.fbuffer = FrameBuffer() vertices = np.array( [[-1.0, -1.0], [+1.0, -1.0], [-1.0, +1.0], [+1.0, +1.0]], np.float32) texcoords = np.array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]], dtype=np.float32) self.fbuf_vertices = VertexBuffer(data=vertices) self.fbuf_texcoords = VertexBuffer(data=texcoords) self.fbuffer_prog = Program(src_fbuffer.vert, src_fbuffer.frag) self.fbuffer_prog['texcoord'] = self.fbuf_texcoords self.fbuffer_prog['position'] = self.fbuf_vertices self.vertex_buffer = VertexBuffer() self.index_buffer = IndexBuffer() self.default_prog = Program(src_default.vert, src_default.frag) self.texture_prog = Program(src_texture.vert, src_texture.frag) self.texture_prog['texcoord'] = self.fbuf_texcoords self.reset_view() def reset_view(self): self.viewport = ( 0, 0, int(builtins.width * builtins.pixel_x_density), int(builtins.height * builtins.pixel_y_density), ) self.texture_viewport = ( 0, 0, builtins.width, builtins.height, ) gloo.set_viewport(*self.viewport) cz = (builtins.height / 2) / math.tan(math.radians(30)) self.projection_matrix = matrix.perspective_matrix( math.radians(60), builtins.width / builtins.height, 0.1 * cz, 10 * cz) self.modelview_matrix = matrix.translation_matrix(-builtins.width / 2, \ builtins.height / 2, \ -cz) self.modelview_matrix = self.modelview_matrix.dot( matrix.scale_transform(1, -1, 1)) self.transform_matrix = np.identity(4) self.default_prog['modelview'] = self.modelview_matrix.T.flatten() self.default_prog['projection'] = self.projection_matrix.T.flatten() self.texture_prog['modelview'] = self.modelview_matrix.T.flatten() self.texture_prog['projection'] = self.projection_matrix.T.flatten() self.line_prog = Program(src_line.vert, src_line.frag) self.line_prog['modelview'] = self.modelview_matrix.T.flatten() self.line_prog['projection'] = self.projection_matrix.T.flatten() self.line_prog["height"] = builtins.height self.fbuffer_tex_front = Texture2D( (builtins.height, builtins.width, 3)) self.fbuffer_tex_back = Texture2D((builtins.height, builtins.width, 3)) for buf in [self.fbuffer_tex_front, self.fbuffer_tex_back]: self.fbuffer.color_buffer = buf with self.fbuffer: self.clear() def clear(self, color=True, depth=True): """Clear the renderer background.""" gloo.set_state(clear_color=self.background_color) gloo.clear(color=color, depth=depth) def _comm_toggles(self, state=True): gloo.set_state(blend=state) gloo.set_state(depth_test=state) if state: gloo.set_state(blend_func=('src_alpha', 'one_minus_src_alpha')) gloo.set_state(depth_func='lequal') @contextmanager def draw_loop(self): """The main draw loop context manager. """ self.transform_matrix = np.identity(4) self.default_prog['modelview'] = self.modelview_matrix.T.flatten() self.default_prog['projection'] = self.projection_matrix.T.flatten() self.fbuffer.color_buffer = self.fbuffer_tex_back with self.fbuffer: gloo.set_viewport(*self.texture_viewport) self._comm_toggles() self.fbuffer_prog['texture'] = self.fbuffer_tex_front self.fbuffer_prog.draw('triangle_strip') yield self.flush_geometry() self.transform_matrix = np.identity(4) gloo.set_viewport(*self.viewport) self._comm_toggles(False) self.clear() self.fbuffer_prog['texture'] = self.fbuffer_tex_back self.fbuffer_prog.draw('triangle_strip') self.fbuffer_tex_front, self.fbuffer_tex_back = self.fbuffer_tex_back, self.fbuffer_tex_front def _transform_vertices(self, vertices, local_matrix, global_matrix): return np.dot(np.dot(vertices, local_matrix.T), global_matrix.T)[:, :3] def _add_to_draw_queue_simple(self, stype, vertices, idx, fill, stroke, stroke_weight, stroke_cap, stroke_join): """Adds shape of stype to draw queue """ if stype == 'lines': self.draw_queue.append( (stype, (vertices, idx, stroke, stroke_weight, stroke_cap, stroke_join))) else: self.draw_queue.append((stype, (vertices, idx, fill))) def render(self, shape): fill = shape.fill.normalized if shape.fill else None stroke = shape.stroke.normalized if shape.stroke else None stroke_weight = shape.stroke_weight stroke_cap = shape.stroke_cap stroke_join = shape.stroke_join obj_list = get_render_primitives(shape) for obj in obj_list: stype, vertices, idx = obj # Transform vertices vertices = self._transform_vertices( np.hstack([vertices, np.ones((len(vertices), 1))]), shape._matrix, self.transform_matrix) # Add to draw queue self._add_to_draw_queue_simple(stype, vertices, idx, fill, stroke, stroke_weight, stroke_cap, stroke_join) def flush_geometry(self): """Flush all the shape geometry from the draw queue to the GPU. """ current_queue = [] for index, shape in enumerate(self.draw_queue): current_shape = self.draw_queue[index][0] current_queue.append(self.draw_queue[index][1]) if current_shape == "lines": self.render_line(current_queue) else: self.render_default(current_shape, current_queue) current_queue = [] self.draw_queue = [] def render_default(self, draw_type, draw_queue): # 1. Get the maximum number of vertices persent in the shapes # in the draw queue. # if len(draw_queue) == 0: return num_vertices = 0 for vertices, _, _ in draw_queue: num_vertices = num_vertices + len(vertices) # 2. Create empty buffers based on the number of vertices. # data = np.zeros(num_vertices, dtype=[('position', np.float32, 3), ('color', np.float32, 4)]) # 3. Loop through all the shapes in the geometry queue adding # it's information to the buffer. # sidx = 0 draw_indices = [] for vertices, idx, color in draw_queue: num_shape_verts = len(vertices) data['position'][sidx:(sidx + num_shape_verts), ] = vertices color_array = np.array([color] * num_shape_verts) data['color'][sidx:sidx + num_shape_verts, :] = color_array draw_indices.append(sidx + idx) sidx += num_shape_verts self.vertex_buffer.set_data(data) self.index_buffer.set_data(np.hstack(draw_indices)) # 4. Bind the buffer to the shader. # self.default_prog.bind(self.vertex_buffer) # 5. Draw the shape using the proper shape type and get rid of # the buffers. # self.default_prog.draw(draw_type, indices=self.index_buffer) def render_line(self, queue): ''' This rendering algorithm works by tesselating the line into multiple triangles. Reference: https://blog.mapbox.com/drawing-antialiased-lines-with-opengl-8766f34192dc ''' if len(queue) == 0: return pos = [] posPrev = [] posCurr = [] posNext = [] markers = [] side = [] linewidth = [] join_type = [] cap_type = [] color = [] for line in queue: if len(line[1]) == 0: continue for segment in line[1]: for i in range( len(segment) - 1): # the data is sent to renderer in line segments for j in [0, 0, 1, 0, 1, 1]: # all the vertices of triangles if i + j - 1 >= 0: posPrev.append(line[0][segment[i + j - 1]]) else: posPrev.append(line[0][segment[i + j]]) if i + j + 1 < len(segment): posNext.append(line[0][segment[i + j + 1]]) else: posNext.append(line[0][segment[i + j]]) posCurr.append(line[0][segment[i + j]]) markers.extend( [1.0, -1.0, -1.0, -1.0, 1.0, -1.0]) # Is the vertex up/below the line segment side.extend([1.0, 1.0, -1.0, 1.0, -1.0, -1.0]) # Left or right side of the segment pos.extend([line[0][segment[i]]] * 6) # Left vertex of each segment linewidth.extend([line[3]] * 6) join_type.extend([line[5]] * 6) cap_type.extend([line[4]] * 6) color.extend([line[2]] * 6) if len(pos) == 0: return posPrev = np.array(posPrev, np.float32) posCurr = np.array(posCurr, np.float32) posNext = np.array(posNext, np.float32) markers = np.array(markers, np.float32) side = np.array(side, np.float32) pos = np.array(pos, np.float32) linewidth = np.array(linewidth, np.float32) join_type = np.array(join_type, np.float32) cap_type = np.array(cap_type, np.float32) color = np.array(color, np.float32) self.line_prog['pos'] = gloo.VertexBuffer(pos) self.line_prog['posPrev'] = gloo.VertexBuffer(posPrev) self.line_prog['posCurr'] = gloo.VertexBuffer(posCurr) self.line_prog['posNext'] = gloo.VertexBuffer(posNext) self.line_prog['marker'] = gloo.VertexBuffer(markers) self.line_prog['side'] = gloo.VertexBuffer(side) self.line_prog['linewidth'] = gloo.VertexBuffer(linewidth) self.line_prog['join_type'] = gloo.VertexBuffer(join_type) self.line_prog['cap_type'] = gloo.VertexBuffer(cap_type) self.line_prog["color"] = gloo.VertexBuffer(color) self.line_prog.draw('triangles') def render_image(self, image, location, size): """Render the image. :param image: image to be rendered :type image: builtins.Image :param location: top-left corner of the image :type location: tuple | list | builtins.Vector :param size: target size of the image to draw. :type size: tuple | list | builtins.Vector """ self.flush_geometry() self.texture_prog[ 'fill_color'] = self.tint_color if self.tint_enabled else self.COLOR_WHITE self.texture_prog['transform'] = self.transform_matrix.T.flatten() x, y = location sx, sy = size imx, imy = image.size data = np.zeros(4, dtype=[('position', np.float32, 2), ('texcoord', np.float32, 2)]) data['texcoord'] = np.array( [[0.0, 1.0], [1.0, 1.0], [0.0, 0.0], [1.0, 0.0]], dtype=np.float32) data['position'] = np.array( [[x, y + sy], [x + sx, y + sy], [x, y], [x + sx, y]], dtype=np.float32) self.texture_prog['texture'] = image._texture self.texture_prog.bind(VertexBuffer(data)) self.texture_prog.draw('triangle_strip') def cleanup(self): """Run the clean-up routine for the renderer. This method is called when all drawing has been completed and the program is about to exit. """ self.default_prog.delete() self.fbuffer_prog.delete() self.line_prog.delete() self.fbuffer.delete()
class Map2D(app.Canvas): def __init__(self, data_handler, parent): app.Canvas.__init__(self, size=(512, 512), title='map', keys='interactive') self.__parent__ = parent self.__data_handler = data_handler ##read building data ##fetch single building #building1 = self.__sh.get_single_at_id(1595) #nya #building2 = self.__sh.get_single_at_id(1999) #stryk #building3 = self.__sh.get_single_at_id(1886) #strykbrada #building4 = self.__sh.get_single_at_id(1722) #Gula vid bron #building5 = self.__sh.get_single_at_id(1723) # ##and its vertices #verts1 = building1.gl_ready_vertices() #verts2 = building2.gl_ready_vertices() #verts3 = building3.gl_ready_vertices() #verts4 = building4.gl_ready_vertices() #verts5 = building5.gl_ready_vertices() self.all_buildings = self.__data_handler.get_all_buildings() all_pos = self.all_buildings[0].gl_ready_vertices() for building in self.all_buildings[1:]: all_pos = np.vstack((all_pos, building.gl_ready_vertices())) abets = self.__data_handler.get_single_at_id(1886) abets = abets.gl_ready_vertices() #Problem: 977, 1061, 1342(tva stora hal), 1389(hal), 1393(hal), 1434(hal), 1327(rese) #Error 1072, 1327(rese). 1472(?!?!?), 1504(!?!?!) #for j in range(100000): # for i in range(1503, 1504): #print("----------------\n----------------",i) #all_pos = all_buildings[i].gl_ready_vertices() self.translate_by = np.mean(abets[:], 0) self.scale = 1.0 all_pos = (all_pos - self.translate_by) * self.scale allverts = np.zeros(len(all_pos), [('position', np.float32, 2)]) allverts['position'] = all_pos self.selectedverts = np.zeros(len(abets), [('position', np.float32, 2)]) self.selectedverts['position'] = (abets - self.translate_by) * self.scale self.vertices = VertexBuffer(allverts) self.selectedvertices = VertexBuffer(self.selectedverts) #self.indices = IndexBuffer(I) # Build program self.program = Program(vertex, fragment) self.program.bind(self.vertices) self.cam2 = Cam3D.Camera([0, 0, 250], [0, 0, 0], [0, 1, 0], 45.0, self.size[0] / float(self.size[1]), 0.001, 10000.0, is_2d=True) # Build view, model, projection & normal self.program['model'] = np.eye( 4, dtype=np.float32) #models are at palce from beginnings? self.program['model'] = np.transpose(vut.rotx(-10)) self.program['view'] = self.cam2.view projection = perspective(45.0, self.size[0] / float(self.size[1]), 1.0, 1000.0) self.program['projection'] = projection self.phi, self.theta = 0, 0 gloo.set_state(clear_color=(0.70, 0.70, 0.7, 1.00), depth_test=True) self.set_selected([1999]) self.activate_zoom() self.timer = app.Timer('auto', self.on_timer, start=True) self.show() def set_selected(self, ids): #building = self.__data_handler.get_single_at_id(id) #verts2 = building.gl_ready_vertices() self.selectedverts = np.zeros(0, [('position', np.float32, 2)]) for id in ids: building = self.__data_handler.get_single_at_id(id) verts = building.gl_ready_vertices() data = np.zeros(len(verts), [('position', np.float32, 2)]) data['position'] = (verts - self.translate_by) * self.scale self.selectedverts = np.concatenate([self.selectedverts, data]) #self.selectedverts['position'] = (verts2 - self.translate_by) * self.scale self.selectedvertices = VertexBuffer(self.selectedverts) selected_pos = np.mean(self.all_buildings[id].points, 0) - self.translate_by self.cam2.translate_to(selected_pos) self.program['view'] = self.cam2.view self.update() def on_mouse_press(self, event): if event.button == 1: self.cam2.is_move = True self.cam2.is_rotate = False if event.button == 2: self.cam2.is_move = False self.cam2.is_rotate = True self.cam2.prev_mouse_pos = event.pos def on_mouse_release(self, event): self.cam2.is_move = False self.cam2.is_rotate = False def on_mouse_move(self, event): if self.cam2.is_move: self.cam2.translate2d(-1 * np.array( event.pos - self.cam2.prev_mouse_pos, dtype=np.float32)) self.program['view'] = self.cam2.view self.update() elif self.cam2.is_rotate: self.cam2.rotx(-1 * np.array( (event.pos - self.cam2.prev_mouse_pos))[1:2]) self.cam2.roty(-1 * np.array( (event.pos - self.cam2.prev_mouse_pos))[0:1]) self.program['view'] = self.cam2.view self.update() self.cam2.prev_mouse_pos = event.pos def on_mouse_wheel(self, event): self.cam2.scale(event.delta[1]) self.program['view'] = self.cam2.view self.update() def on_draw(self, event): gloo.clear(color=True, depth=True) self.program.set_shaders(vertex, fragment_active) self.program.bind(self.selectedvertices) self.program.draw('triangles') self.program.set_shaders(vertex, fragment) self.program.bind(self.vertices) self.program.draw('triangles') def on_resize(self, event): self.activate_zoom() def activate_zoom(self): gloo.set_viewport(0, 0, *self.physical_size) projection = perspective(45.0, self.size[0] / float(self.size[1]), 1.0, 10000.0) self.program['projection'] = projection self.update() def on_timer(self, event): self.update() def on_resize(self, event): self.activate_zoom() def on_key_press(self, event): modifiers = [key.name for key in event.modifiers] print('Key pressed - text: %r, key: %s, modifiers: %r' % (event.text, event.key.name, modifiers)) def on_key_release(self, event): modifiers = [key.name for key in event.modifiers] print('Key released - text: %r, key: %s, modifiers: %r' % (event.text, event.key.name, modifiers))
class Canvas(app.Canvas): def __init__(self, image_acquisition_manager=None, width=640, height=480, fps=50., background_color='gray', vertex_shader=None, fragment_shader=None): """ NOTE: fps should be smaller than or equal to 50 fps. If it's exceed VisPy drags down the acquisition performance. This is the issue we have to investigate. """ self._vertex_shader = vertex_shader if vertex_shader else """ // Uniforms uniform mat4 u_model; uniform mat4 u_view; uniform mat4 u_projection; // Attributes attribute vec2 a_position; attribute vec2 a_texcoord; // Varyings varying vec2 v_texcoord; // Main void main (void) { v_texcoord = a_texcoord; gl_Position = u_projection * u_view * u_model * vec4(a_position, 0.0, 1.0); } """ self._fragment_shader = fragment_shader if fragment_shader else """ varying vec2 v_texcoord; uniform sampler2D texture; void main() { gl_FragColor = texture2D(texture, v_texcoord); } """ # self._iaa = image_acquisition_manager # app.Canvas.__init__(self, size=(width, height), vsync=True, autoswap=True) # self._program = None self._data = None self._coordinate = None self._origin = None self._translate = 0. self._latest_translate = self._translate self._magnification = 1. # self._background_color = background_color self._has_filled_texture = False self._width, self._height = width, height # self._is_dragging = False # If it's True , the canvas keeps image acquisition but do not # draw images on the canvas. self._pause_drawing = False # Apply shaders. self.set_shaders(vertex_shader=self._vertex_shader, fragment_shader=self._fragment_shader) # self._timer = app.Timer(1. / fps, connect=self.update, start=True) @property def iaa(self): return self._iaa @iaa.setter def iaa(self, value): self._iaa = value def set_shaders(self, vertex_shader=None, fragment_shader=None): # vs = vertex_shader if vertex_shader else self._vertex_shader fs = fragment_shader if fragment_shader else self._fragment_shader self._program = Program(vs, fs, count=4) # self._data = np.zeros(4, dtype=[('a_position', np.float32, 2), ('a_texcoord', np.float32, 2)]) # self._data['a_texcoord'] = np.array([[0., 1.], [1., 1.], [0., 0.], [1., 0.]]) # self._program['u_model'] = np.eye(4, dtype=np.float32) self._program['u_view'] = np.eye(4, dtype=np.float32) # self._coordinate = [0, 0] self._origin = [0, 0] # self._program['texture'] = np.zeros((self._height, self._width), dtype='uint8') # self.apply_magnification() def set_rect(self, width, height): # self._has_filled_texture = False # updated = False # if self._width != width or self._height != height: self._width = width self._height = height updated = True # if updated: self.apply_magnification() def on_draw(self, event): # Clear the canvas in gray. gloo.clear(color=self._background_color) self._update_texture() def _update_texture(self): # Fetch a buffer. try: with self._iaa.fetch_buffer_manager(timeout_ms=0.1) as bm: # Set the image as the texture of our canvas. if not self._pause_drawing and bm: # Update the canvas size if needed. self.set_rect(bm.buffer.width, bm.buffer.height) # update = True power = 0 # pixel_format = bm.pixel_format if pixel_format in component_8bit_formats: payload = bm.payload else: if pixel_format in component_10bit_formats: power = 2 elif pixel_format in component_12bit_formats: power = 4 elif pixel_format in component_14bit_formats: power = 6 elif pixel_format in component_16bit_formats: power = 8 else: update = False if update: payload = bm.payload / (2**power) # Explicitly cast the payload to an uint8 array. payload = payload.astype(np.uint8) if update: self._program['texture'] = payload # Draw the texture. self._draw() except AttributeError: # Harvester Core has not started image acquisition so # calling fetch_buffer() raises AttributeError because # None object is used for the with statement. # Update on June 15th, 2018: # According to a VisPy developer, they have not finished # porting VisPy to PyQt5. Once they finished the development # we should try it out if it gives us the maximum refresh rate. # See the following URL to check the latest information: # # https://github.com/vispy/vispy/issues/1394 # Draw the texture. self._draw() def _draw(self): self._program.draw('triangle_strip') def on_resize(self, event): self.apply_magnification() def apply_magnification(self): # canvas_w, canvas_h = self.physical_size gloo.set_viewport(0, 0, canvas_w, canvas_h) # ratio = self._magnification w, h = self._width, self._height self._program['u_projection'] = ortho( self._coordinate[0], canvas_w * ratio + self._coordinate[0], self._coordinate[1], canvas_h * ratio + self._coordinate[1], -1, 1) x, y = int((canvas_w * ratio - w) / 2), int( (canvas_h * ratio - h) / 2) # centering x & y # self._data['a_position'] = np.array([[x, y], [x + w, y], [x, y + h], [x + w, y + h]]) # self._program.bind(gloo.VertexBuffer(self._data)) def on_mouse_wheel(self, event): self._translate += event.delta[1] power = 7. if is_running_on_macos() else 5. # 2 ** power stride = 4. if is_running_on_macos() else 7. translate = self._translate translate = min(power * stride, translate) translate = max(-power * stride, translate) self._translate = translate self._magnification = 2**-(self._translate / stride) if self._latest_translate != self._translate: self.apply_magnification() self._latest_translate = self._translate def on_mouse_press(self, event): self._is_dragging = True self._origin = event.pos def on_mouse_release(self, event): self._is_dragging = False def on_mouse_move(self, event): if self._is_dragging: adjustment = 2. if is_running_on_macos() else 1. ratio = self._magnification * adjustment delta = event.pos - self._origin self._origin = event.pos self._coordinate[0] -= (delta[0] * ratio) self._coordinate[1] += (delta[1] * ratio) self.apply_magnification() def pause_drawing(self, pause=True): self._pause_drawing = pause def toggle_drawing(self): self._pause_drawing = False if self._pause_drawing else True @property def is_pausing(self): return True if self._pause_drawing else False def resume_drawing(self): self._pause_drawing = False @property def background_color(self): return self._background_color @background_color.setter def background_color(self, color): self._background_color = color
class Drawable(object): name = "Default Drawable" skip = False def __init__(self, *args, **kwargs): '''Drawable(*args, **kwargs) -> Drawable Everything is tracked internally, different drawables will handle things differently Inherit from this for all drawables. Inheriting: You must define a make_mesh, make_shaders, and draw method. If you do not make shaders, you will get a default If you do not make a mesh, you'll get a square that takes up the screen ''' self.model = np.eye(4) self.view = np.eye(4) self.projection = np.eye(4) self.mesh = self.make_mesh() self.vert_shader, self.frag_shader = self.make_shaders() self.program = Program(self.vert_shader, self.frag_shader) self.program.bind(VertexBuffer(self.mesh)) if hasattr(self, make_texture): self.texture = self.make_texture() assert isinstance(self.texture, Texture2D), "Texture passed is not a texture!" self.program['texture'] = self.texture cube["texture"].interpolation = 'linear' def __setitem__(self, key, value): self.bind(key, value) def translate(self, *args): translate(self.model, *args) self.program['model'] = self.model def rotate(self, *args): rotate(self.model, *args) self.program['model'] = self.model def bind(self, key, value): '''Rebind a single program item to a value''' self.program[key] = value def bind_multiple(self, **kwargs): '''rebind multiple things!''' for key, value in kwargs: self.bind(key, value) def make_mesh(self): '''mesh() Generates a default mesh (a cube) treat it as though it is a property (i.e. not a function) ex: >>> x = Target((100, 100, 100)) >>> mesh = Target.mesh ''' cube = Program(cube_vertex, cube_fragment) cube.bind(vertices) self.program['model'] = model self.program['view'] = view self.program['projection'] = projection if self.mesh is None: vertices, indices, _ = create_cube() # self.mesh = else: return self.mesh def make_shaders(self): '''shader -> (vertex, fragment) Returns vertex and fragment shaders as 2-tuple of strings THIS IS A DEFAULT SHADER ''' fragment = '' vertex = '' return vertex, fragment def make_texture(self): '''Make a texture THIS IS A DEFAULT TEXTURE ''' texture = utils.checkerboard() return texture def update(self): pass def draw(self): self.program.draw()
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, size=(512, 512), title='Lighted cube', keys='interactive') self.timer = app.Timer('auto', self.on_timer) # Build cube data V, F, outline = create_cube() vertices = VertexBuffer(V) self.faces = IndexBuffer(F) self.outline = IndexBuffer(outline) # Build view, model, projection & normal # -------------------------------------- self.view = translate((0, 0, -5)) model = np.eye(4, dtype=np.float32) normal = np.array(np.matrix(np.dot(self.view, model)).I.T) # Build program # -------------------------------------- self.program = Program(vertex, fragment) self.program.bind(vertices) self.program["u_light_position"] = 2, 2, 2 self.program["u_light_intensity"] = 1, 1, 1 self.program["u_model"] = model self.program["u_view"] = self.view self.program["u_normal"] = normal self.phi, self.theta = 0, 0 self.activate_zoom() # OpenGL initialization # -------------------------------------- gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True, polygon_offset=(1, 1), blend_func=('src_alpha', 'one_minus_src_alpha'), line_width=0.75) self.timer.start() self.show() def on_draw(self, event): gloo.clear(color=True, depth=True) # program.draw(gl.GL_TRIANGLES, indices) # Filled cube gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=True) self.program['u_color'] = 1, 1, 1, 1 self.program.draw('triangles', self.faces) # Outlined cube gloo.set_state(polygon_offset_fill=False, blend=True, depth_mask=False) self.program['u_color'] = 0, 0, 0, 1 self.program.draw('lines', self.outline) gloo.set_state(depth_mask=True) def on_resize(self, event): self.activate_zoom() def activate_zoom(self): gloo.set_viewport(0, 0, *self.physical_size) projection = perspective(45.0, self.size[0] / float(self.size[1]), 2.0, 10.0) self.program['u_projection'] = projection def on_timer(self, event): self.theta += .5 self.phi += .5 model = np.dot(rotate(self.theta, (0, 0, 1)), rotate(self.phi, (0, 1, 0))) normal = np.linalg.inv(np.dot(self.view, model)).T self.program['u_model'] = model self.program['u_normal'] = normal self.update()
class VispyRenderer2D(OpenGLRenderer): def __init__(self): super().__init__(src_fbuffer, src_default) self.texture_prog = None self.line_prog = None self.modelview_matrix = np.identity(4) def initialize_renderer(self): super().initialize_renderer() self.texture_prog = Program(src_texture.vert, src_texture.frag) self.texture_prog['texcoord'] = self.fbuf_texcoords self.reset_view() def reset_view(self): self.viewport = ( 0, 0, int(builtins.width * builtins.pixel_x_density), int(builtins.height * builtins.pixel_y_density), ) self.texture_viewport = ( 0, 0, builtins.width, builtins.height, ) gloo.set_viewport(*self.viewport) # pylint: disable=no-member cz = (builtins.height / 2) / math.tan(math.radians(30)) self.projection_matrix = matrix.perspective_matrix( math.radians(60), builtins.width / builtins.height, 0.1 * cz, 10 * cz) self.modelview_matrix = matrix.translation_matrix( -builtins.width / 2, builtins.height / 2, -cz) self.modelview_matrix = self.modelview_matrix.dot( matrix.scale_transform(1, -1, 1)) self.transform_matrix = np.identity(4) self.default_prog['modelview'] = self.modelview_matrix.T.flatten() self.default_prog['projection'] = self.projection_matrix.T.flatten() self.texture_prog['modelview'] = self.modelview_matrix.T.flatten() self.texture_prog['projection'] = self.projection_matrix.T.flatten() self.line_prog = Program(src_line.vert, src_line.frag) self.line_prog['modelview'] = self.modelview_matrix.T.flatten() self.line_prog['projection'] = self.projection_matrix.T.flatten() self.line_prog["height"] = builtins.height self.fbuffer_tex_front = Texture2D( (builtins.height, builtins.width, 3)) self.fbuffer_tex_back = Texture2D((builtins.height, builtins.width, 3)) for buf in [self.fbuffer_tex_front, self.fbuffer_tex_back]: self.fbuffer.color_buffer = buf with self.fbuffer: self.clear() def clear(self, color=True, depth=True): """Clear the renderer background.""" gloo.set_state(clear_color=self.style.background_color) # pylint: disable=no-member gloo.clear(color=color, depth=depth) # pylint: disable=no-member def _comm_toggles(self, state=True): gloo.set_state(blend=state) # pylint: disable=no-member gloo.set_state(depth_test=state) # pylint: disable=no-member if state: gloo.set_state(blend_func=('src_alpha', 'one_minus_src_alpha')) # pylint: disable=no-member gloo.set_state(depth_func='lequal') # pylint: disable=no-member @contextmanager def draw_loop(self): """The main draw loop context manager. """ self.transform_matrix = np.identity(4) self.default_prog['modelview'] = self.modelview_matrix.T.flatten() self.default_prog['projection'] = self.projection_matrix.T.flatten() self.fbuffer.color_buffer = self.fbuffer_tex_back with self.fbuffer: gloo.set_viewport(*self.texture_viewport) # pylint: disable=no-member self._comm_toggles() self.fbuffer_prog['texture'] = self.fbuffer_tex_front self.fbuffer_prog.draw('triangle_strip') yield self.flush_geometry() self.transform_matrix = np.identity(4) gloo.set_viewport(*self.viewport) # pylint: disable=no-member self._comm_toggles(False) self.clear() self.fbuffer_prog['texture'] = self.fbuffer_tex_back self.fbuffer_prog.draw('triangle_strip') self.fbuffer_tex_front, self.fbuffer_tex_back = self.fbuffer_tex_back, self.fbuffer_tex_front def _add_to_draw_queue(self, stype, vertices, idx, fill, stroke, stroke_weight, stroke_cap, stroke_join): """Adds shape of stype to draw queue """ if stype == 'lines': self.draw_queue.append( (stype, (vertices, idx, stroke, stroke_weight, stroke_cap, stroke_join))) else: self.draw_queue.append((stype, (vertices, idx, fill))) def render(self, shape): fill = shape.fill.normalized if shape.fill else None stroke = shape.stroke.normalized if shape.stroke else None stroke_weight = shape.stroke_weight stroke_cap = shape.stroke_cap stroke_join = shape.stroke_join obj_list = get_render_primitives(shape) for obj in obj_list: stype, vertices, idx = obj # Convert 2D vertices to 3D by adding "0" column, needed for further transformations if len(vertices[0]) == 2: vertices = np.hstack([vertices, np.zeros((len(vertices), 1))]) # Transform vertices vertices = self._transform_vertices( np.hstack([vertices, np.ones((len(vertices), 1))]), shape._matrix, self.transform_matrix) # Add to draw queue self._add_to_draw_queue(stype, vertices, idx, fill, stroke, stroke_weight, stroke_cap, stroke_join) def flush_geometry(self): """Flush all the shape geometry from the draw queue to the GPU. """ current_queue = [] for index, shape in enumerate(self.draw_queue): current_shape = self.draw_queue[index][0] current_queue.append(self.draw_queue[index][1]) if current_shape == "lines": self.render_line(current_queue) else: self.render_default(current_shape, current_queue) current_queue = [] self.draw_queue = [] def render_line(self, queue): ''' This rendering algorithm works by tesselating the line into multiple triangles. Reference: https://blog.mapbox.com/drawing-antialiased-lines-with-opengl-8766f34192dc ''' if len(queue) == 0: return pos = [] posPrev = [] posCurr = [] posNext = [] markers = [] side = [] linewidth = [] join_type = [] cap_type = [] color = [] stroke_cap_codes = {'PROJECT': 0, 'SQUARE': 1, 'ROUND': 2} stroke_join_codes = {'MITER': 0, 'BEVEL': 1, 'ROUND': 2} for line in queue: if len(line[1]) == 0: continue for segment in line[1]: for i in range( len(segment) - 1): # the data is sent to renderer in line segments for j in [0, 0, 1, 0, 1, 1]: # all the vertices of triangles if i + j - 1 >= 0: posPrev.append(line[0][segment[i + j - 1]]) else: posPrev.append(line[0][segment[i + j]]) if i + j + 1 < len(segment): posNext.append(line[0][segment[i + j + 1]]) else: posNext.append(line[0][segment[i + j]]) posCurr.append(line[0][segment[i + j]]) # Is the vertex up/below the line segment markers.extend([1.0, -1.0, -1.0, -1.0, 1.0, -1.0]) # Left or right side of the segment side.extend([1.0, 1.0, -1.0, 1.0, -1.0, -1.0]) # Left vertex of each segment pos.extend([line[0][segment[i]]] * 6) linewidth.extend([line[3]] * 6) join_type.extend([stroke_join_codes[line[5]]] * 6) cap_type.extend([stroke_cap_codes[line[4]]] * 6) color.extend([line[2]] * 6) if len(pos) == 0: return posPrev = np.array(posPrev, np.float32) posCurr = np.array(posCurr, np.float32) posNext = np.array(posNext, np.float32) markers = np.array(markers, np.float32) side = np.array(side, np.float32) pos = np.array(pos, np.float32) linewidth = np.array(linewidth, np.float32) join_type = np.array(join_type, np.float32) cap_type = np.array(cap_type, np.float32) color = np.array(color, np.float32) self.line_prog['pos'] = gloo.VertexBuffer(pos) self.line_prog['posPrev'] = gloo.VertexBuffer(posPrev) self.line_prog['posCurr'] = gloo.VertexBuffer(posCurr) self.line_prog['posNext'] = gloo.VertexBuffer(posNext) self.line_prog['marker'] = gloo.VertexBuffer(markers) self.line_prog['side'] = gloo.VertexBuffer(side) self.line_prog['linewidth'] = gloo.VertexBuffer(linewidth) self.line_prog['join_type'] = gloo.VertexBuffer(join_type) self.line_prog['cap_type'] = gloo.VertexBuffer(cap_type) self.line_prog["color"] = gloo.VertexBuffer(color) self.line_prog.draw('triangles') def render_image(self, image, location, size): """Render the image. :param image: image to be rendered :type image: builtins.Image :param location: top-left corner of the image :type location: tuple | list | builtins.Vector :param size: target size of the image to draw. :type size: tuple | list | builtins.Vector """ self.flush_geometry() self.texture_prog[ 'fill_color'] = self.style.tint_color if self.style.tint_enabled else COLOR_WHITE self.texture_prog['transform'] = self.transform_matrix.T.flatten() x, y = location sx, sy = size imx, imy = image.size data = np.zeros(4, dtype=[('position', np.float32, 2), ('texcoord', np.float32, 2)]) data['texcoord'] = np.array( [[0.0, 1.0], [1.0, 1.0], [0.0, 0.0], [1.0, 0.0]], dtype=np.float32) data['position'] = np.array( [[x, y + sy], [x + sx, y + sy], [x, y], [x + sx, y]], dtype=np.float32) self.texture_prog['texture'] = image._texture self.texture_prog.bind(VertexBuffer(data)) self.texture_prog.draw('triangle_strip') def cleanup(self): """Run the clean-up routine for the renderer. This method is called when all drawing has been completed and the program is about to exit. """ OpenGLRenderer.cleanup(self) self.line_prog.delete() def render_shape(self, shape): self.render(shape) for child_shape in shape.children: self.render_shape(child_shape) def line(self, *args): path = args[0] self.render_shape(PShape(vertices=path, shape_type=SType.LINES)) def bezier(self, *args): vertices = args[0] self.render_shape( PShape(vertices=vertices, shape_type=SType.LINE_STRIP)) def curve(self, *args): vertices = args[0] self.render_shape( PShape(vertices=vertices, shape_type=SType.LINE_STRIP)) def triangle(self, *args): path = args[0] self.render_shape(PShape(vertices=path, shape_type=SType.TRIANGLES)) def quad(self, *args): path = args[0] self.render_shape(PShape(vertices=path, shape_type=SType.QUADS)) def arc(self, *args): center = args[0] dim = args[1] start_angle = args[2] stop_angle = args[3] mode = args[4] self.render_shape(Arc(center, dim, start_angle, stop_angle, mode)) def shape(self, vertices, contours, shape_type, *args): """Render a Pshape""" self.render_shape( PShape(vertices=vertices, contours=contours, shape_type=shape_type))
class Canvas(app.Canvas): def __init__(self, sensor=None, i=0, yaw=False, title='Rotating Cube'): app.Canvas.__init__(self, size=(640, 640), title=title, keys='interactive') self.timer = app.Timer('auto', self.on_timer) self.sensor = sensor self.i = i self.yaw = yaw # Build cube data V, I, O = create_cube() vertices = VertexBuffer(V) self.faces = IndexBuffer(I) self.outline = IndexBuffer(O) # Build program # -------------------------------------- self.program = Program(vertex, fragment) self.program.bind(vertices) # Build view, model, projection & normal # -------------------------------------- view = translate((0, 0, -5)) model = np.eye(4, dtype=np.float32) self.program['u_model'] = model self.program['u_view'] = view self.theta, self.psi, self.phi = 0, 0, 0 self.activate_zoom() # OpenGL initialization # -------------------------------------- gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True, polygon_offset=(1, 1), line_width=0.75, blend_func=('src_alpha', 'one_minus_src_alpha')) self.timer.start() self.show() def on_draw(self, event): gloo.clear(color=True, depth=True) # Filled cube gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=True) self.program['u_color'] = 1, 1, 1, 1 self.program.draw('triangles', self.faces) # Outlined cube gloo.set_state(blend=True, depth_mask=False, polygon_offset_fill=False) self.program['u_color'] = 0, 0, 0, 1 self.program.draw('lines', self.outline) gloo.set_state(depth_mask=True) def on_resize(self, event): self.activate_zoom() def activate_zoom(self): gloo.set_viewport(0, 0, *self.physical_size) projection = perspective(45.0, self.size[0] / float(self.size[1]), 2.0, 10.0) self.program['u_projection'] = projection def on_timer(self, event): if self.sensor is not None: data = next(self.sensor) self.theta, self.psi, self.phi = data[self.i] self.theta = -self.theta # read yaw from gyro if self.yaw: self.phi = data[2][2] else: self.phi = 0 else: self.theta += .5 self.phi += .5 # self.program['u_model'] = np.dot(rotate(self.theta, (1, 0, 0)), # rotate(self.psi, (0, 0, 1))) self.program['u_model'] = np.dot( rotate(self.theta, (1, 0, 0)), np.dot(rotate(self.phi, (0, 1, 0)), rotate(self.psi, (0, 0, 1)))) self.update()
class Renderer3D: def __init__(self): self.default_prog = None self.fbuffer = None self.fbuffer_tex_front = None self.fbuffer_tex_back = None self.vertex_buffer = None self.index_buffer = None ## Renderer Globals: USEFUL CONSTANTS self.COLOR_WHITE = (1, 1, 1, 1) self.COLOR_BLACK = (0, 0, 0, 1) self.COLOR_DEFAULT_BG = (0.8, 0.8, 0.8, 1.0) ## Renderer Globals: STYLE/MATERIAL PROPERTIES ## self.background_color = self.COLOR_DEFAULT_BG self.fill_color = self.COLOR_WHITE self.fill_enabled = True self.stroke_color = self.COLOR_BLACK self.stroke_enabled = True self.tint_color = self.COLOR_BLACK self.tint_enabled = False ## Renderer Globals: Curves self.stroke_weight = 1 self.stroke_cap = 2 self.stroke_join = 0 ## Renderer Globals ## VIEW MATRICES, ETC ## self.viewport = None self.texture_viewport = None self.transform_matrix = np.identity(4) self.projection_matrix = np.identity(4) self.lookat_matrix = np.identity(4) ## Renderer Globals: RENDERING self.draw_queue = [] def initialize_renderer(self): self.fbuffer = FrameBuffer() vertices = np.array( [[-1.0, -1.0], [+1.0, -1.0], [-1.0, +1.0], [+1.0, +1.0]], np.float32) texcoords = np.array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]], dtype=np.float32) self.fbuf_vertices = VertexBuffer(data=vertices) self.fbuf_texcoords = VertexBuffer(data=texcoords) self.fbuffer_prog = Program(src_fbuffer.vert, src_fbuffer.frag) self.fbuffer_prog['texcoord'] = self.fbuf_texcoords self.fbuffer_prog['position'] = self.fbuf_vertices self.vertex_buffer = VertexBuffer() self.index_buffer = IndexBuffer() self.default_prog = Program(src_default.vert, src_default.frag) self.reset_view() def reset_view(self): self.viewport = ( 0, 0, int(builtins.width * builtins.pixel_x_density), int(builtins.height * builtins.pixel_y_density), ) self.texture_viewport = ( 0, 0, builtins.width, builtins.height, ) gloo.set_viewport(*self.viewport) cz = (builtins.height / 2) / math.tan(math.radians(30)) self.projection_matrix = matrix.perspective_matrix( math.radians(60), builtins.width / builtins.height, 0.1 * cz, 10 * cz) self.transform_matrix = np.identity(4) self.default_prog['projection'] = self.projection_matrix.T.flatten() self.default_prog['perspective_matrix'] = self.lookat_matrix.T.flatten( ) self.fbuffer_tex_front = Texture2D( (builtins.height, builtins.width, 3)) self.fbuffer_tex_back = Texture2D((builtins.height, builtins.width, 3)) for buf in [self.fbuffer_tex_front, self.fbuffer_tex_back]: self.fbuffer.color_buffer = buf with self.fbuffer: self.clear() self.fbuffer.depth_buffer = gloo.RenderBuffer( (builtins.height, builtins.width)) def clear(self, color=True, depth=True): """Clear the renderer background.""" gloo.set_state(clear_color=self.background_color) gloo.clear(color=color, depth=depth) def _comm_toggles(self, state=True): gloo.set_state(blend=state) gloo.set_state(depth_test=state) if state: gloo.set_state(blend_func=('src_alpha', 'one_minus_src_alpha')) gloo.set_state(depth_func='lequal') @contextmanager def draw_loop(self): """The main draw loop context manager. """ self.transform_matrix = np.identity(4) self.default_prog['projection'] = self.projection_matrix.T.flatten() self.default_prog['perspective_matrix'] = self.lookat_matrix.T.flatten( ) self.fbuffer.color_buffer = self.fbuffer_tex_back with self.fbuffer: gloo.set_viewport(*self.texture_viewport) self._comm_toggles() self.fbuffer_prog['texture'] = self.fbuffer_tex_front self.fbuffer_prog.draw('triangle_strip') yield self.flush_geometry() self.transform_matrix = np.identity(4) gloo.set_viewport(*self.viewport) self._comm_toggles(False) self.clear() self.fbuffer_prog['texture'] = self.fbuffer_tex_back self.fbuffer_prog.draw('triangle_strip') self.fbuffer_tex_front, self.fbuffer_tex_back = self.fbuffer_tex_back, self.fbuffer_tex_front def _transform_vertices(self, vertices, local_matrix, global_matrix): return np.dot(np.dot(vertices, local_matrix.T), global_matrix.T)[:, :3] def render(self, shape): if isinstance(shape, Geometry): n = len(shape.vertices) tverts = self._transform_vertices( np.hstack([shape.vertices, np.ones((n, 1))]), shape.matrix, self.transform_matrix) edges = shape.edges faces = shape.faces self.add_to_draw_queue('poly', tverts, edges, faces, self.fill_color, self.stroke_color) elif isinstance(shape, PShape): vertices = shape._draw_vertices n, _ = vertices.shape tverts = self._transform_vertices( np.hstack([vertices, np.zeros((n, 1)), np.ones((n, 1))]), shape._matrix, self.transform_matrix) fill = shape.fill.normalized if shape.fill else None stroke = shape.stroke.normalized if shape.stroke else None edges = shape._draw_edges faces = shape._draw_faces if edges is None: print(vertices) print("whale") exit() if 'open' in shape.attribs: overtices = shape._draw_outline_vertices no, _ = overtices.shape toverts = self._transform_vertices( np.hstack([overtices, np.zeros((no, 1)), np.ones((no, 1))]), shape._matrix, self.transform_matrix) self.add_to_draw_queue('poly', tverts, edges, faces, fill, None) self.add_to_draw_queue('path', toverts, edges[:-1], None, None, stroke) else: self.add_to_draw_queue(shape.kind, tverts, edges, faces, fill, stroke) def add_to_draw_queue(self, stype, vertices, edges, faces, fill=None, stroke=None): """Add the given vertex data to the draw queue. :param stype: type of shape to be added. Should be one of {'poly', 'path', 'point'} :type stype: str :param vertices: (N, 3) array containing the vertices to be drawn. :type vertices: np.ndarray :param edges: (N, 2) array containing edges as tuples of indices into the vertex array. This can be None when not appropriate (eg. for points) :type edges: None | np.ndarray :param faces: (N, 3) array containing faces as tuples of indices into the vertex array. For 'point' and 'path' shapes, this can be None :type faces: np.ndarray :param fill: Fill color of the shape as a normalized RGBA tuple. When set to `None` the shape doesn't get a fill (default: None) :type fill: None | tuple :param stroke: Stroke color of the shape as a normalized RGBA tuple. When set to `None` the shape doesn't get stroke (default: None) :type stroke: None | tuple """ fill_shape = self.fill_enabled and not (fill is None) stroke_shape = self.stroke_enabled and not (stroke is None) if fill_shape and stype not in ['point', 'path']: idx = np.array(faces, dtype=np.uint32).ravel() self.draw_queue.append(["triangles", (vertices, idx, fill)]) if stroke_shape: if stype == 'point': idx = np.arange(0, len(vertices), dtype=np.uint32) self.draw_queue.append(["points", (vertices, idx, stroke)]) else: idx = np.array(edges, dtype=np.uint32).ravel() self.draw_queue.append(["lines", (vertices, idx, stroke)]) def flush_geometry(self): """Flush all the shape geometry from the draw queue to the GPU. """ current_queue = [] for index, shape in enumerate(self.draw_queue): current_shape, current_obj = self.draw_queue[index][ 0], self.draw_queue[index][1] # If current_shape is lines, bring it to the front by epsilon # to resolve z-fighting if current_shape == 'lines': # line_transform is used whenever we render lines to break ties in depth # We transform the points to camera space, move them by Z_EPSILON, and them move them back to world space line_transform = inv(self.lookat_matrix).dot( translation_matrix(0, 0, Z_EPSILON).dot(self.lookat_matrix)) vertices = current_obj[0] current_obj = (np.hstack( [vertices, np.ones( (vertices.shape[0], 1))]).dot(line_transform.T)[:, :3], current_obj[1], current_obj[2]) current_queue.append(current_obj) if index < len(self.draw_queue) - 1: if self.draw_queue[index][0] == self.draw_queue[index + 1][0]: continue self.render_default(current_shape, current_queue) current_queue = [] self.draw_queue = [] def render_default(self, draw_type, draw_queue): # 1. Get the maximum number of vertices persent in the shapes # in the draw queue. # if len(draw_queue) == 0: return num_vertices = 0 for vertices, _, _ in draw_queue: num_vertices = num_vertices + len(vertices) # 2. Create empty buffers based on the number of vertices. # data = np.zeros(num_vertices, dtype=[('position', np.float32, 3), ('color', np.float32, 4)]) # 3. Loop through all the shapes in the geometry queue adding # it's information to the buffer. # sidx = 0 draw_indices = [] for vertices, idx, color in draw_queue: num_shape_verts = len(vertices) data['position'][sidx:(sidx + num_shape_verts), ] = np.array(vertices) color_array = np.array([color] * num_shape_verts) data['color'][sidx:sidx + num_shape_verts, :] = color_array draw_indices.append(sidx + idx) sidx += num_shape_verts self.vertex_buffer.set_data(data) self.index_buffer.set_data(np.hstack(draw_indices)) # 4. Bind the buffer to the shader. # self.default_prog.bind(self.vertex_buffer) # 5. Draw the shape using the proper shape type and get rid of # the buffers. # self.default_prog.draw(draw_type, indices=self.index_buffer) def cleanup(self): """Run the clean-up routine for the renderer. This method is called when all drawing has been completed and the program is about to exit. """ self.default_prog.delete() self.fbuffer_prog.delete() self.fbuffer.delete()
glut.glutPassiveMotionFunc(on_passive_motion) glut.glutTimerFunc(1000 / 60, timer, 60) # Build data # -------------------------------------- n = 500 data = np.zeros(n, [('a_position', np.float32, 2), ('a_fg_color', np.float32, 4), ('a_size', np.float32, 1)]) index = 0 # Build program # -------------------------------------- program = Program(vertex, fragment) vdata = VertexBuffer(data) program.bind(vdata) program['u_antialias'] = 1.00 program['u_linewidth'] = 1.00 # Build view, model, projection # -------------------------------------- program['u_model'] = np.eye(4, dtype=np.float32) program['u_view'] = np.eye(4, dtype=np.float32) # OpenGL initalization # -------------------------------------- gloo.set_clear_color((1.0, 1.0, 1.0, 1.0)) gloo.set_state(blend=True, blend_func=('src_alpha', 'one_minus_src_alpha')) gloo.gl_initialize() # Start
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, title='Framebuffer post-processing', keys='interactive', size=(512, 512)) # Build cube data # -------------------------------------- vertices, indices, _ = create_cube() vertices = VertexBuffer(vertices) self.indices = IndexBuffer(indices) # Build program # -------------------------------------- view = np.eye(4, dtype=np.float32) model = np.eye(4, dtype=np.float32) translate(view, 0, 0, -7) self.phi, self.theta = 60, 20 rotate(model, self.theta, 0, 0, 1) rotate(model, self.phi, 0, 1, 0) self.cube = Program(cube_vertex, cube_fragment) self.cube.bind(vertices) self.cube["texture"] = checkerboard() self.cube["texture"].interpolation = 'linear' self.cube['model'] = model self.cube['view'] = view color = Texture2D((512, 512, 3), interpolation='linear') self.framebuffer = FrameBuffer(color, RenderBuffer((512, 512))) self.quad = Program(quad_vertex, quad_fragment, count=4) self.quad['texcoord'] = [(0, 0), (0, 1), (1, 0), (1, 1)] self.quad['position'] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)] self.quad['texture'] = color # OpenGL and Timer initalization # -------------------------------------- set_state(clear_color=(.3, .3, .35, 1), depth_test=True) self.timer = app.Timer('auto', connect=self.on_timer, start=True) self._set_projection(self.size) def on_draw(self, event): with self.framebuffer: set_viewport(0, 0, 512, 512) clear(color=True, depth=True) set_state(depth_test=True) self.cube.draw('triangles', self.indices) set_viewport(0, 0, *self.size) clear(color=True) set_state(depth_test=False) self.quad.draw('triangle_strip') def on_resize(self, event): self._set_projection(event.size) def _set_projection(self, size): width, height = size set_viewport(0, 0, width, height) projection = perspective(30.0, width / float(height), 2.0, 10.0) self.cube['projection'] = projection def on_timer(self, event): self.theta += .5 self.phi += .5 model = np.eye(4, dtype=np.float32) rotate(model, self.theta, 0, 0, 1) rotate(model, self.phi, 0, 1, 0) self.cube['model'] = model self.update()
glut.glutReshapeWindow(512, 512) glut.glutReshapeFunc(reshape) glut.glutKeyboardFunc(keyboard) glut.glutDisplayFunc(display) glut.glutTimerFunc(1000 / 60, timer, 60) # Build cube data # -------------------------------------- V, I, _ = cube() vertices = VertexBuffer(V) indices = IndexBuffer(I) # Build program # -------------------------------------- program = Program(vertex, fragment) program.bind(vertices) # Build view, model, projection & normal # -------------------------------------- view = np.eye(4, dtype=np.float32) model = np.eye(4, dtype=np.float32) projection = np.eye(4, dtype=np.float32) translate(view, 0, 0, -5) program["model"] = model program["view"] = view phi, theta = 0, 0 # OpenGL initalization # -------------------------------------- gl.glClearColor(0.30, 0.30, 0.35, 1.00) gl.glEnable(gl.GL_DEPTH_TEST)
class Canvas3D(app.Canvas): def __init__(self, data_handler, parent, currentdata): app.Canvas.__init__(self, size=(512, 512), title='3d view', keys='interactive') self.current_data = currentdata self.render_params = { 'transparent': False, 'top_dogs_only': False, 'draw_polygons': True, 'draw_points': True, 'debug_colors': True } self.__parent__ = parent self.__data_handler = data_handler self.__inliers, self.__outliers = 0, 0 self.__render_points_params = {'inliers': False, 'outliers': False} self.setupCanvas() #Render objects self.render_objects = [] #Data... SLICE self.__bfps = 0 self.__points = 0 self.__solids = 0 self.__property_area = 0 self.__mbb = 0 self.__offset = 0 self.__top_dogs = 0 #self.__parent__.set_slice(1343) self.show() def setupCanvas(self): #Create the camera self.__camera = Cam3D.Camera([0, -200, 150], [0, 0, 0], [0, 0, 1], 45.0, self.size[0] / float(self.size[1]), 0.01, 1000.0, is_2d=False) #Build and setup the glprogram for rendering the models self.program_solids = Program(vertex, fragment) self.program_solids['model'] = vut.rotx(90) self.program_solids['model'] = np.eye(4, dtype=np.float32) self.program_solids['view'] = self.__camera.view self.program_solids['u_alpha'] = np.float32(0.6) # build and setup glprogram for rendering the points self.program_points = gloo.Program(vert, frag) self.program_points['u_linewidth'] = 1.0 self.program_points['u_antialias'] = 1.0 self.program_points['u_model'] = np.eye(4, dtype=np.float32) self.program_points['u_view'] = self.__camera.view self.program_points['u_size'] = 0.3 + 0.8 / self.__camera.zoom_factor #Some aditional drawing variables/setups self.__draw_model_transparent = False self.context.set_clear_color(Color([0.7, 0.7, 0.7, 1.0])) self.__theta = 0 self.__phi = 0 self.timer = app.Timer('auto', self.on_timer, start=True) self.activate_zoom() def readTheData(self): self.__bfps = self.current_data['bfps'] self.__points = np.array(self.current_data['points'], copy=True) self.__solids = self.current_data['solids'] self.__property_area = self.current_data['property_area'] self.__mbb = self.current_data['mbb'] self.__top_dogs = self.current_data['top_dogs'] self.__top_dog_points = self.current_data['top_dog_points'] self.__offset = np.mean(self.__property_area.points, 0) def setCanvasData(self): #self.__bfps, self.__points, self.__solids, self.__property_area, self.__mbb, self.__top_dogs = self.__data_handler.get_slice_from_property(property_id) self.readTheData() for points in self.__points: points[:, 0:2] -= self.__offset self.setup_points_selected = self.setup_points self.setup_polygons_selected = self.setup_bfps self.updateCanvas() self.reset_camera() self.update() self.__parent__.focus_building_id = self.__top_dogs def updateCanvas(self): self.setup_points_selected() self.setup_polygons_selected() self.update() def points(self): self.setup_points_selected = self.setup_points self.readTheData() self.setup_points() def bfps(self): self.setup_polygons_selected = self.setup_bfps def features(self): self.setup_polygons_selected = self.setup_features self.setup_polygons_selected() self.update() def regions(self): self.setup_points_selected = self.setup_regions self.slice_regions = self.current_data['regions'] self.top_dogs_regions = self.current_data['top_dog_regions'] self.setup_regions() def planes(self): self.setup_points_selected = self.setup_regions self.all_planes = self.current_data['planes'] self.top_dog_planes = self.current_data['top_dog_planes'] self.setup_planes() def clearPoints(self): print("Clear Points") verts = np.zeros(0, [('position', np.float32, 3), ('normal', np.float32, 3), ('color', np.float32, 3)]) #start empty... self.program_points.bind(VertexBuffer(verts)) self.update() def setup_bfps(self): verts = np.zeros( 0, [('position', np.float32, 3), ('normal', np.float32, 3), ('color', np.float32, 3)]) #start with an empty array colors = distinct_colors(2) for i in range(len(self.__solids)): if self.render_params['top_dogs_only']: if self.__bfps[i].id in self.__top_dogs: get_verts = self.__solids[i].get_gl_vertex_data( self.__offset) data = np.zeros(len(get_verts), [('position', np.float32, 3), ('normal', np.float32, 3), ('color', np.float32, 3)]) data['position'] = get_verts['position'] data['normal'] = get_verts['normal'] data['color'] = colors[1] verts = np.concatenate([verts, data]) else: get_verts = self.__solids[i].get_gl_vertex_data(self.__offset) data = np.zeros(len(get_verts), [('position', np.float32, 3), ('normal', np.float32, 3), ('color', np.float32, 3)]) data['position'] = get_verts['position'] data['normal'] = get_verts['normal'] if self.__bfps[i].id in self.__top_dogs: data['color'] = colors[1] else: data['color'] = colors[0] verts = np.concatenate([verts, data]) self.program_solids.bind(VertexBuffer(verts)) def setup_features(self): verts = np.zeros( 0, [('position', np.float32, 3), ('normal', np.float32, 3), ('color', np.float32, 3)]) #start with an empty array all_feature_groups = self.current_data['features'] if self.render_params['top_dogs_only'] or all_feature_groups == None: all_feature_groups = self.current_data['top_dog_features'] colors = distinct_colors(2) base_roof_color = [0.35, 0.35, 0.35] wallcolor = [0.72, 0.72, 0.72] yellow = [1, 0.76, 0] topwallcolor = [0.94, 0.94, 0.99] origin = [0, 0] for feature_group, gid in zip(all_feature_groups, range(len(all_feature_groups))): feature_group_wall_color = yellow feature_roof_color = base_roof_color top_roof_colors = distinct_colors(len(feature_group)) if self.render_params['top_dogs_only'] or self.__bfps[ gid].id in self.__top_dogs: feature_group_wall_color = topwallcolor for feature, fid in zip(feature_group, range(len(feature_group))): get_verts = feature['roof'].get_gl_vertex_data(origin) data = np.zeros(len(get_verts), [('position', np.float32, 3), ('normal', np.float32, 3), ('color', np.float32, 3)]) data['position'] = get_verts['position'] data['normal'] = get_verts['normal'] data['color'] = feature_roof_color if self.render_params['top_dogs_only'] or self.__bfps[ gid].id in self.__top_dogs: data['color'] = top_roof_colors[fid] if self.render_params['debug_colors']: data['color'] = top_roof_colors[fid] verts = np.concatenate([verts, data]) get_verts = feature['walls'].get_gl_vertex_data(origin) data = np.zeros(len(get_verts), [('position', np.float32, 3), ('normal', np.float32, 3), ('color', np.float32, 3)]) data['position'] = get_verts['position'] data['normal'] = get_verts['normal'] data['color'] = feature_group_wall_color if self.render_params['debug_colors']: data['color'] = [i * 1.3 for i in top_roof_colors[fid]] verts = np.concatenate([verts, data]) self.program_solids.bind(VertexBuffer(verts)) def setup_points(self): self.setup_points_selected = self.setup_points if self.render_params['top_dogs_only']: all_points = np.array(self.__top_dog_points) else: all_points = np.array(self.__points) total_n = sum([len(points) for points in all_points]) data = np.zeros(total_n, [('a_position', np.float32, 3), ('a_bg_color', np.float32, 4), ('a_fg_color', np.float32, 4), ('a_size', np.float32, 1)]) start = 0 for i in range(len(all_points)): points = all_points[i] n = len(points) if self.__bfps[i].id in self.__top_dogs: data[start:start + n]['a_bg_color'] = np.array( [0.6, 0.92, 0.8, 0.5], dtype=np.float32) else: data[start:start + n]['a_bg_color'] = np.array( [0.7, 0.7, 0.9, 0.5], dtype=np.float32) data[start:start + n]['a_fg_color'] = 0, 0, 0, 1 data[start:start + n]['a_size'] = 10 data[start:start + n]['a_position'] = points start += n self.program_points.bind(gloo.VertexBuffer(data)) self.update() def setup_planes(self): self.setup_points_selected = self.setup_regions all_points = np.array(self.__points) self.selected_planes = self.all_planes if self.render_params['top_dogs_only']: self.selected_planes = self.top_dog_planes #all_points = copy.copy(all_points) all_plane_points = copy.deepcopy(all_points) print("running setup planes with {} points".format( len(all_plane_points))) n_regions = len(self.selected_regions) #PREPARE DATA ARRAY total_n = 0 current_regions = 0 for i in range(len(all_plane_points)): points = all_plane_points[i] if self.render_params['top_dogs_only']: if self.__bfps[i].id in self.__top_dogs: n_in_region = sum([ len(region) for region in self.selected_regions[current_regions] ]) total_n += len(points) current_regions += 1 else: total_n += len(points) ##PREPARE DATA ARRAY #total_n = 0 #current_regions = 0 #for i in range(len(all_plane_points)): # points = all_plane_points[i] # if self.__bfps[i].id in self.__top_dogs : # n_in_region = sum([len(region) for region in self.selected_regions[current_regions]]) # total_n += len(points) # current_regions += 1 # elif self.render_params['top_dogs_only'] == False: # total_n += len(points) data = np.zeros(total_n, [('a_position', np.float32, 3), ('a_bg_color', np.float32, 4), ('a_fg_color', np.float32, 4), ('a_size', np.float32, 1)]) #POPULATE DATA ARRAY start = 0 current_regions = 0 for i in range(len(all_plane_points)): points = all_plane_points[i] if self.render_params['top_dogs_only']: if self.__bfps[i].id in self.__top_dogs: regions = self.selected_regions[current_regions] m = sum([len(region) for region in regions]) n = len(points) #assert(m == n) m innehåller inte alla points då de kan ha försvunnit i små regions for j in range(len(regions)): #plane = pf.fitPlane(points[regions[j]]) plane = self.selected_planes[current_regions][j] points[regions[j]] = elevatePointsToPlane( points[regions[j]], plane) datapoints = data[start:start + n] self.setupRegionData(datapoints, regions, points) current_regions += 1 start += n else: regions = self.selected_regions[current_regions] m = sum([len(region) for region in regions]) n = len(points) #assert(m == n) m innehåller inte alla points då de kan ha försvunnit i små regions for j in range(len(regions)): #plane = pf.fitPlane(points[regions[j]]) plane = self.selected_planes[current_regions][j] points[regions[j]] = elevatePointsToPlane( points[regions[j]], plane) datapoints = data[start:start + n] self.setupRegionData(datapoints, regions, points) current_regions += 1 start += n ##POPULATE DATA ARRAY #start = 0 #current_regions = 0 #for i in range(len(all_plane_points)): # points = all_plane_points[i] # n = len(points) # if self.__bfps[i].id in self.__top_dogs : # regions = self.selected_regions[current_regions] # datapoints = data[start:start+n] # for j in range(len(regions)): # plane = pf.fitPlane(points[regions[j]]) # points[regions[j]] = elevatePointsToPlane(points[regions[j]], plane) # #region_points = elevatePointsToPlane(points[:,0:2], self.all_planes[current_regions]) # self.setupRegionData(datapoints, regions, points) # current_regions += 1 # start += n # elif self.render_params['top_dogs_only'] == False: # n = len(points) # data[start:start+n]['a_bg_color'] = np.array([0.7,0.7,0.9,0.5], dtype=np.float32) # data[start:start+n]['a_position'] = points # start += n data[0:total_n]['a_fg_color'] = 0, 0, 0, 1 data[0:total_n]['a_size'] = 10 #BIND DATA TO GL PROGRAM self.program_points.bind(gloo.VertexBuffer(data)) self.update() def setup_regions(self): self.setup_points_selected = self.setup_regions all_points = np.array(self.__points) all_points = copy.copy(all_points) self.selected_regions = self.slice_regions if self.render_params['top_dogs_only']: self.selected_regions = self.top_dogs_regions if self.selected_regions == None: self.__parent__.pipelineWidget.cluster_layout.setRegions() self.selected_regions = self.slice_regions n_regions = len(self.selected_regions) #PREPARE DATA ARRAY total_n = 0 current_regions = 0 for i in range(len(all_points)): points = all_points[i] if self.render_params['top_dogs_only']: if self.__bfps[i].id in self.__top_dogs: n_in_region = sum([ len(region) for region in self.selected_regions[current_regions] ]) total_n += len(points) current_regions += 1 else: total_n += len(points) data = np.zeros(total_n, [('a_position', np.float32, 3), ('a_bg_color', np.float32, 4), ('a_fg_color', np.float32, 4), ('a_size', np.float32, 1)]) #POPULATE DATA ARRAY start = 0 current_regions = 0 for i in range(len(all_points)): points = all_points[i] if self.render_params['top_dogs_only']: if self.__bfps[i].id in self.__top_dogs: regions = self.selected_regions[current_regions] m = sum([len(region) for region in regions]) n = len(points) #assert(m == n) m innehåller inte alla points då de kan ha försvunnit i små regions datapoints = data[start:start + n] self.setupRegionData(datapoints, regions, points) current_regions += 1 start += n else: regions = self.selected_regions[current_regions] m = sum([len(region) for region in regions]) n = len(points) #assert(m == n) m innehåller inte alla points då de kan ha försvunnit i små regions datapoints = data[start:start + n] self.setupRegionData(datapoints, regions, points) current_regions += 1 start += n #else: # n = len(points) # data[start:start+n]['a_bg_color'] = np.array([0.7,0.7,0.9,0.5], dtype=np.float32) # data[start:start+n]['a_position'] = points # start += n data[0:total_n]['a_fg_color'] = 0, 0, 0, 1 data[0:total_n]['a_size'] = 10 #BIND DATA TO GL PROGRAM self.program_points.bind(gloo.VertexBuffer(data)) self.update() def setupRegionData(self, datapoints, regions, points): n_regions = len(regions) colors = distinct_colors(n_regions) for region_idx in range(n_regions): n_points_in_region = len(regions[region_idx]) r, g, b = colors[region_idx] for point_idx in regions[region_idx]: datapoints[point_idx]['a_bg_color'] = np.array( [r, g, b, 0.5], dtype=np.float32) datapoints[point_idx]['a_position'] = np.array( points[point_idx], dtype=np.float32) def reset_camera(self): #Create the camera self.__camera = Cam3D.Camera([0, -100, 50], [0, 0, 0], [0, 0, 1], 45.0, self.size[0] / float(self.size[1]), 0.01, 1000.0, is_2d=False) self.program_solids['view'] = self.__camera.view self.program_points['u_view'] = self.__camera.view self.program_points['u_size'] = 0.3 + 0.8 / self.__camera.zoom_factor self.activate_zoom() def update_render_points_params(self, attr: str, value): self.__render_points_params[attr] = value self.setup_points() def on_mouse_press(self, event): if event.button == 1: self.__camera.is_move = True self.__camera.is_rotate = False if event.button == 2: self.__camera.is_move = False self.__camera.is_rotate = True self.__camera.prev_mouse_pos = event.pos def on_mouse_release(self, event): self.__camera.is_move = False self.__camera.is_rotate = False def on_mouse_move(self, event): if self.__camera.is_move: self.__camera.translate2d(-1 * np.array( event.pos - self.__camera.prev_mouse_pos, dtype=np.float32)) self.program_solids['view'] = self.__camera.view self.program_points['u_view'] = self.__camera.view self.update() elif self.__camera.is_rotate: self.__camera.rotx(-1 * np.array( (event.pos - self.__camera.prev_mouse_pos))[1:2]) self.__camera.roty(-1 * np.array( (event.pos - self.__camera.prev_mouse_pos))[0:1]) self.program_solids['view'] = self.__camera.view self.program_points['u_view'] = self.__camera.view self.update() self.__camera.prev_mouse_pos = event.pos def on_mouse_wheel(self, event): self.__camera.scale(event.delta[1]) self.program_solids['view'] = self.__camera.view self.program_points['u_view'] = self.__camera.view self.program_points[ 'u_size'] = 0.3 + 0.8 / self.__camera.zoom_factor #magicnumber zoom on the poor camera self.update() def draw_model(self): gl.glEnable(gl.GL_DEPTH_TEST) gl.glDepthMask(gl.GL_TRUE) gl.glFrontFace(gl.GL_CCW) gl.glDisable(gl.GL_BLEND) gl.glBlendFunc(gl.GL_ZERO, gl.GL_ZERO) if self.render_params['transparent']: gl.glEnable(gl.GL_BLEND) gl.glDepthMask(gl.GL_FALSE) gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) self.program_solids.draw('triangles') def draw_points(self): gl.glDisable(gl.GL_BLEND) gl.glEnable(gl.GL_DEPTH_TEST) gl.glDepthMask(gl.GL_TRUE) self.program_points.draw('points') def on_draw(self, event): gl.glClear(gl.GL_COLOR_BUFFER_BIT) gl.glClear(gl.GL_DEPTH_BUFFER_BIT) if self.render_params['draw_polygons']: self.draw_model() if self.render_params['draw_points']: self.draw_points() def on_resize(self, event): self.activate_zoom() def activate_zoom(self): gloo.set_viewport(0, 0, *self.physical_size) projection = perspective(45.0, self.size[0] / float(self.size[1]), 1.0, 1000.0) self.program_solids['projection'] = projection self.program_points['u_projection'] = projection def on_timer(self, event): self.__theta += .5 self.__phi += .5 self.__camera.roty(.0) self.program_solids['view'] = self.__camera.view self.program_points['u_view'] = self.__camera.view self.update()
class Canvas(app.Canvas): _visible_payloads = [ PAYLOADTYPE_INFO_IDS.PAYLOAD_TYPE_IMAGE, PAYLOADTYPE_INFO_IDS.PAYLOAD_TYPE_CHUNK_DATA, PAYLOADTYPE_INFO_IDS.PAYLOAD_TYPE_MULTI_PART, ] def __init__(self, image_acquisition_manager=None, width=640, height=480, fps=30, background_color='gray', vertex_shader=None, fragment_shader=None): """ NOTE: fps should be smaller than or equal to 50 fps. If it's exceed VisPy drags down the acquisition performance. This is the issue we have to investigate. """ """ As far as we know, Vispy refreshes the canvas every 1/30 sec at the fastest no matter which faster number is specified. If we set any value which is greater than 30, then Vispy's callback is randomly called. """ self._vertex_shader = vertex_shader if vertex_shader else """ // Uniforms uniform mat4 u_model; uniform mat4 u_view; uniform mat4 u_projection; // Attributes attribute vec2 a_position; attribute vec2 a_texcoord; // Varyings varying vec2 v_texcoord; // Main void main (void) { v_texcoord = a_texcoord; gl_Position = u_projection * u_view * u_model * vec4(a_position, 0.0, 1.0); } """ self._fragment_shader = fragment_shader if fragment_shader else """ varying vec2 v_texcoord; uniform sampler2D texture; void main() { gl_FragColor = texture2D(texture, v_texcoord); } """ # self._iam = image_acquisition_manager # app.Canvas.__init__(self, size=(width, height), vsync=True, autoswap=True) # self._program = None self._data = None self._coordinate = None self._origin = None self._translate = 0. self._latest_translate = self._translate self._magnification = 1. # self._background_color = background_color self._has_filled_texture = False self._width, self._height = width, height # self._is_dragging = False # If it's True , the canvas keeps image acquisition but do not # draw images on the canvas. self._pause_drawing = False # Apply shaders. self.set_shaders(vertex_shader=self._vertex_shader, fragment_shader=self._fragment_shader) # self._timer = app.Timer(1. / fps, connect=self.update, start=True) @property def iam(self): return self._iam @iam.setter def iam(self, value): self._iam = value def set_shaders(self, vertex_shader=None, fragment_shader=None): # vs = vertex_shader if vertex_shader else self._vertex_shader fs = fragment_shader if fragment_shader else self._fragment_shader self._program = Program(vs, fs, count=4) # self._data = np.zeros(4, dtype=[('a_position', np.float32, 2), ('a_texcoord', np.float32, 2)]) # self._data['a_texcoord'] = np.array([[0., 1.], [1., 1.], [0., 0.], [1., 0.]]) # self._program['u_model'] = np.eye(4, dtype=np.float32) self._program['u_view'] = np.eye(4, dtype=np.float32) # self._coordinate = [0, 0] self._origin = [0, 0] # self._program['texture'] = np.zeros((self._height, self._width), dtype='uint8') # self.apply_magnification() def set_rect(self, width, height): # self._has_filled_texture = False # updated = False # if self._width != width or self._height != height: self._width = width self._height = height updated = True # if updated: self.apply_magnification() def on_draw(self, event): # Clear the canvas in gray. gloo.clear(color=self._background_color) self._update_texture() def _update_texture(self): # Fetch a buffer. try: with self.iam.fetch_buffer(timeout_ms=0.1) as buffer: update = True if buffer.payload_type not in self._visible_payloads: update = False # Set the image as the texture of our canvas. if not self._pause_drawing and buffer: # Update the canvas size if needed. self.set_rect(buffer.payload.components[0].width, buffer.payload.components[0].height) # exponent = 0 # data_format_value = buffer.payload.components[ 0].data_format_value if is_custom(data_format_value): update = False else: data_format = buffer.payload.components[0].data_format bpp = get_bits_per_pixel(data_format) if bpp is not None: exponent = bpp - 8 else: update = False if update: # Convert each data to an 8bit. content = buffer.payload.components[0].data if exponent > 0: # The following code may affect to the rendering # performance: content = (content / (2**exponent)) # Then cast each array element to an uint8: content = content.astype(np.uint8) self._program['texture'] = content # Draw the texture. self._draw() except AttributeError: # Harvester Core has not started image acquisition so # calling fetch_buffer() raises AttributeError because # None object is used for the with statement. # Update on June 15th, 2018: # According to a VisPy developer, they have not finished # porting VisPy to PyQt5. Once they finished the development # we should try it out if it gives us the maximum refresh rate. # See the following URL to check the latest information: # # https://github.com/vispy/vispy/issues/1394 # Draw the texture. self._draw() def _draw(self): self._program.draw('triangle_strip') def on_resize(self, event): self.apply_magnification() def apply_magnification(self): # canvas_w, canvas_h = self.physical_size gloo.set_viewport(0, 0, canvas_w, canvas_h) # ratio = self._magnification w, h = self._width, self._height self._program['u_projection'] = ortho( self._coordinate[0], canvas_w * ratio + self._coordinate[0], self._coordinate[1], canvas_h * ratio + self._coordinate[1], -1, 1) x, y = int((canvas_w * ratio - w) / 2), int( (canvas_h * ratio - h) / 2) # centering x & y # self._data['a_position'] = np.array([[x, y], [x + w, y], [x, y + h], [x + w, y + h]]) # self._program.bind(gloo.VertexBuffer(self._data)) def on_mouse_wheel(self, event): self._translate += event.delta[1] power = 7. if is_running_on_macos() else 5. # 2 ** power stride = 4. if is_running_on_macos() else 7. translate = self._translate translate = min(power * stride, translate) translate = max(-power * stride, translate) self._translate = translate self._magnification = 2**-(self._translate / stride) if self._latest_translate != self._translate: self.apply_magnification() self._latest_translate = self._translate def on_mouse_press(self, event): self._is_dragging = True self._origin = event.pos def on_mouse_release(self, event): self._is_dragging = False def on_mouse_move(self, event): if self._is_dragging: adjustment = 2. if is_running_on_macos() else 1. ratio = self._magnification * adjustment delta = event.pos - self._origin self._origin = event.pos self._coordinate[0] -= (delta[0] * ratio) self._coordinate[1] += (delta[1] * ratio) self.apply_magnification() def pause_drawing(self, pause=True): self._pause_drawing = pause def toggle_drawing(self): self._pause_drawing = False if self._pause_drawing else True @property def is_pausing(self): return True if self._pause_drawing else False def resume_drawing(self): self._pause_drawing = False @property def background_color(self): return self._background_color @background_color.setter def background_color(self, color): self._background_color = color
class Canvas2D(CanvasBase): _visible_payloads = [ PAYLOADTYPE_INFO_IDS.PAYLOAD_TYPE_IMAGE, PAYLOADTYPE_INFO_IDS.PAYLOAD_TYPE_CHUNK_DATA, PAYLOADTYPE_INFO_IDS.PAYLOAD_TYPE_MULTI_PART, ] def __init__( self, *, image_acquirer=None, width=640, height=480, background_color='gray', vsync=True, display_rate=30. ): # super().__init__( image_acquirer=image_acquirer, width=width, height=height, display_rate=display_rate, background_color=background_color, vsync=vsync ) # self._vertex_shader = """ // Uniforms uniform mat4 u_model; uniform mat4 u_view; uniform mat4 u_projection; // Attributes attribute vec2 a_position; attribute vec2 a_texcoord; // Varyings varying vec2 v_texcoord; // Main void main (void) { v_texcoord = a_texcoord; gl_Position = u_projection * u_view * u_model * vec4(a_position, 0.0, 1.0); } """ self._fragment_shader = """ varying vec2 v_texcoord; uniform sampler2D texture; void main() { gl_FragColor = texture2D(texture, v_texcoord); } """ # self._program = None self._data = None self._coordinate = None self._translate = 0. self._latest_translate = self._translate self._magnification = 1. # Apply shaders. self._program = Program( self._vertex_shader, self._fragment_shader, count=4 ) # self._data = np.zeros( 4, dtype=[ ('a_position', np.float32, 2), ('a_texcoord', np.float32, 2) ] ) # self._data['a_texcoord'] = np.array( [[0., 1.], [1., 1.], [0., 0.], [1., 0.]] ) # self._program['u_model'] = np.eye(4, dtype=np.float32) self._program['u_view'] = np.eye(4, dtype=np.float32) # self._coordinate = [0, 0] # self._program['texture'] = np.zeros( (self._height, self._width), dtype='uint8' ) # self.apply_magnification() def _prepare_texture(self, buffer): update = True if buffer.payload_type not in self._visible_payloads: update = False # Set the image as the texture of our canvas. if buffer: # payload = buffer.payload component = payload.components[0] width = component.width height = component.height # Update the canvas size if needed. self.set_canvas_size(width, height) # exponent = 0 data_format = None # data_format_value = component.data_format_value if is_custom(data_format_value): update = False else: data_format = component.data_format bpp = get_bits_per_pixel(data_format) if bpp is not None: exponent = bpp - 8 else: update = False if update: # Reshape the image so that it can be drawn on the # VisPy canvas: if data_format in mono_location_formats or \ data_format in bayer_location_formats: # Reshape the 1D NumPy array into a 2D so that VisPy # can display it as a mono image: content = component.data.reshape(height, width) else: # The image requires you to reshape it to draw it on the # canvas: if data_format in rgb_formats or \ data_format in rgba_formats or \ data_format in bgr_formats or \ data_format in bgra_formats: # Reshape the 1D NumPy array into a 2D so that VisPy # can display it as an RGB image: content = component.data.reshape( height, width, int(component.num_components_per_pixel) ) # if data_format in bgr_formats: # Swap every R and B so that VisPy can display # it as an RGB image: content = content[:, :, ::-1] else: return # Convert each data to an 8bit. if exponent > 0: # The following code may affect to the rendering # performance: content = (content / (2 ** exponent)) # Then cast each array element to an uint8: content = content.astype(np.uint8) self._program['texture'] = content def _draw(self): self._program.draw('triangle_strip') def apply_magnification(self): # canvas_w, canvas_h = self.physical_size gloo.set_viewport(0, 0, canvas_w, canvas_h) # ratio = self._magnification w, h = self._width, self._height self._program['u_projection'] = ortho( self._coordinate[0], canvas_w * ratio + self._coordinate[0], self._coordinate[1], canvas_h * ratio + self._coordinate[1], -1, 1 ) x, y = int((canvas_w * ratio - w) / 2), int((canvas_h * ratio - h) / 2) # centering x & y # self._data['a_position'] = np.array( [[x, y], [x + w, y], [x, y + h], [x + w, y + h]] ) # self._program.bind(gloo.VertexBuffer(self._data)) def on_mouse_wheel(self, event): self._translate += event.delta[1] power = 7. if is_running_on_macos() else 5. # 2 ** exponent stride = 4. if is_running_on_macos() else 7. translate = self._translate translate = min(power * stride, translate) translate = max(-power * stride, translate) self._translate = translate self._magnification = 2 ** -(self._translate / stride) if self._latest_translate != self._translate: self.apply_magnification() self._latest_translate = self._translate def on_mouse_move(self, event): if self._is_dragging: adjustment = 2. if is_running_on_macos() else 1. ratio = self._magnification * adjustment delta = event.pos - self._origin self._origin = event.pos self._coordinate[0] -= (delta[0] * ratio) self._coordinate[1] += (delta[1] * ratio) self.apply_magnification()
class OpenGLRenderer(ABC): def __init__(self, src_fbuffer, src_default): self.default_prog = None self.fbuffer_prog = None self.fbuffer = None self.fbuffer_tex_front = None self.fbuffer_tex_back = None self.vertex_buffer = None self.index_buffer = None # Renderer Globals: STYLE/MATERIAL PROPERTIES # self.style = Style() # Renderer Globals: Curves self.stroke_weight = 1 self.stroke_cap = ROUND self.stroke_join = MITER # Renderer Globals # VIEW MATRICES, ETC # self.viewport = None self.texture_viewport = None self.transform_matrix = np.identity(4) self.projection_matrix = np.identity(4) # Renderer Globals: RENDERING self.draw_queue = [] # Shaders self.fbuffer_prog = Program(src_fbuffer.vert, src_fbuffer.frag) self.default_prog = Program(src_default.vert, src_default.frag) def initialize_renderer(self): self.fbuffer = FrameBuffer() vertices = np.array( [[-1.0, -1.0], [+1.0, -1.0], [-1.0, +1.0], [+1.0, +1.0]], np.float32) texcoords = np.array([[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0]], dtype=np.float32) self.fbuf_vertices = VertexBuffer(data=vertices) self.fbuf_texcoords = VertexBuffer(data=texcoords) self.fbuffer_prog['texcoord'] = self.fbuf_texcoords self.fbuffer_prog['position'] = self.fbuf_vertices self.vertex_buffer = VertexBuffer() self.index_buffer = IndexBuffer() def render_default(self, draw_type, draw_queue): # 1. Get the maximum number of vertices persent in the shapes # in the draw queue. # if len(draw_queue) == 0: return num_vertices = 0 for vertices, _, _ in draw_queue: num_vertices = num_vertices + len(vertices) # 2. Create empty buffers based on the number of vertices. # data = np.zeros(num_vertices, dtype=[('position', np.float32, 3), ('color', np.float32, 4)]) # 3. Loop through all the shapes in the geometry queue adding # it's information to the buffer. # sidx = 0 draw_indices = [] for vertices, idx, color in draw_queue: num_shape_verts = len(vertices) data['position'][sidx:(sidx + num_shape_verts), ] = np.array(vertices) color_array = np.array([color] * num_shape_verts) data['color'][sidx:sidx + num_shape_verts, :] = color_array draw_indices.append(sidx + idx) sidx += num_shape_verts self.vertex_buffer.set_data(data) self.index_buffer.set_data(np.hstack(draw_indices)) # 4. Bind the buffer to the shader. # self.default_prog.bind(self.vertex_buffer) # 5. Draw the shape using the proper shape type and get rid of # the buffers. # self.default_prog.draw(draw_type, indices=self.index_buffer) def cleanup(self): """Run the clean-up routine for the renderer. This method is called when all drawing has been completed and the program is about to exit. """ self.default_prog.delete() self.fbuffer_prog.delete() self.fbuffer.delete() def _transform_vertices(self, vertices, local_matrix, global_matrix): return np.dot(np.dot(vertices, local_matrix.T), global_matrix.T)[:, :3]
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, title='Visualize Mesh', keys='interactive', size=(1920, 1080)) def on_initialize(self, event): self.rho = 0.0 # Build cube data # -------------------------------------- self.checker = Program(cube_vertex, cube_fragment) self.checker['texture'] = checkerboard() self.checker['position'] = [(-1, -1), (-1, +1), (+1, -1), (+1, +1)] self.checker['texcoord'] = [(0, 0), (0, 1), (1, 0), (1, 1)] # sheet, indices = make_sheet((960, 1080)) # sheet_buffer = VertexBuffer(sheet) left_eye = Texture2D((960, 1080, 3), interpolation='linear') self.left_eye_buffer = FrameBuffer(left_eye, RenderBuffer((960, 1080))) # Build program # -------------------------------------- self.view = np.eye(4, dtype=np.float32) self.program = Program(vertex, fragment) distortion_buffer = VertexBuffer(make_distortion()) self.program.bind(distortion_buffer) self.program['rotation'] = self.view self.program['texture'] = left_eye # OpenGL and Timer initalization # -------------------------------------- set_state(clear_color=(.3, .3, .35, 1), depth_test=True) self.timer = app.Timer('auto', connect=self.on_timer, start=True) self._set_projection(self.size) def on_draw(self, event): with self.left_eye_buffer: set_viewport(0, 0, *self.size) clear(color=True) set_state(depth_test=False) self.checker.draw('triangle_strip') set_viewport(0, 0, *self.size) clear(color=True) set_state(depth_test=True) self.program.draw('points') def on_resize(self, event): self._set_projection(event.size) def on_mouse_move(self, event): pos = np.array(event.pos) def on_key_press(self, event): if event.text == 'q': sys.exit() def _set_projection(self, size): width, height = size set_viewport(0, 0, width, height) projection = perspective(30.0, width / float(height), 2.0, 10.0) # self.program['projection'] = projection def on_timer(self, event): self.rho = 0.1 if self.rho >= 30: self.rho = 0 self.update()
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, size=(512, 512), title='Rotating cube', keys='interactive') self.timer = app.Timer('auto', self.on_timer) # Build cube data V, I, O = create_cube() vertices = VertexBuffer(V) self.faces = IndexBuffer(I) self.outline = IndexBuffer(O) # Build program # -------------------------------------- self.program = Program(vertex, fragment) self.program.bind(vertices) # Build view, model, projection & normal # -------------------------------------- view = np.eye(4, dtype=np.float32) model = np.eye(4, dtype=np.float32) translate(view, 0, 0, -5) self.program['u_model'] = model self.program['u_view'] = view self.phi, self.theta = 0, 0 # OpenGL initalization # -------------------------------------- gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True, polygon_offset=(1, 1), line_width=0.75, blend_func=('src_alpha', 'one_minus_src_alpha')) self.timer.start() def on_draw(self, event): gloo.clear(color=True, depth=True) # Filled cube gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=True) self.program['u_color'] = 1, 1, 1, 1 self.program.draw('triangles', self.faces) # Outlined cube gloo.set_state(blend=True, depth_mask=False, polygon_offset_fill=False) self.program['u_color'] = 0, 0, 0, 1 self.program.draw('lines', self.outline) gloo.set_state(depth_mask=True) def on_resize(self, event): gloo.set_viewport(0, 0, *event.size) projection = perspective(45.0, event.size[0] / float(event.size[1]), 2.0, 10.0) self.program['u_projection'] = projection def on_timer(self, event): self.theta += .5 self.phi += .5 model = np.eye(4, dtype=np.float32) rotate(model, self.theta, 0, 0, 1) rotate(model, self.phi, 0, 1, 0) self.program['u_model'] = model self.update()
class Canvas(app.Canvas): def __init__(self): app.Canvas.__init__(self, size=(512, 512), title='Lighted cube', keys='interactive') self.timer = app.Timer('auto', self.on_timer) # Build cube data V, F, O = create_cube() vertices = VertexBuffer(V) self.faces = IndexBuffer(F) self.outline = IndexBuffer(O) # Build view, model, projection & normal # -------------------------------------- self.view = translate((0, 0, -5)) model = np.eye(4, dtype=np.float32) normal = np.array(np.matrix(np.dot(self.view, model)).I.T) # Build program # -------------------------------------- self.program = Program(vertex, fragment) self.program.bind(vertices) self.program["u_light_position"] = 2, 2, 2 self.program["u_light_intensity"] = 1, 1, 1 self.program["u_model"] = model self.program["u_view"] = self.view self.program["u_normal"] = normal self.phi, self.theta = 0, 0 self.activate_zoom() # OpenGL initialization # -------------------------------------- gloo.set_state(clear_color=(0.30, 0.30, 0.35, 1.00), depth_test=True, polygon_offset=(1, 1), blend_func=('src_alpha', 'one_minus_src_alpha'), line_width=0.75) self.timer.start() self.show() def on_draw(self, event): gloo.clear(color=True, depth=True) # program.draw(gl.GL_TRIANGLES, indices) # Filled cube gloo.set_state(blend=False, depth_test=True, polygon_offset_fill=True) self.program['u_color'] = 1, 1, 1, 1 self.program.draw('triangles', self.faces) # Outlined cube gloo.set_state(polygon_offset_fill=False, blend=True, depth_mask=False) self.program['u_color'] = 0, 0, 0, 1 self.program.draw('lines', self.outline) gloo.set_state(depth_mask=True) def on_resize(self, event): self.activate_zoom() def activate_zoom(self): gloo.set_viewport(0, 0, *self.physical_size) projection = perspective(45.0, self.size[0] / float(self.size[1]), 2.0, 10.0) self.program['u_projection'] = projection def on_timer(self, event): self.theta += .5 self.phi += .5 model = np.dot(rotate(self.theta, (0, 0, 1)), rotate(self.phi, (0, 1, 0))) normal = np.linalg.inv(np.dot(self.view, model)).T self.program['u_model'] = model self.program['u_normal'] = normal self.update()