def take_screenshot(self, quick): """ takes a screenshot of the OpenGLWidget. saves it in the screenshots folder with . :return: """ GL.glReadBuffer(GL.GL_FRONT) pixels = GL.glReadPixels(0, 0, self.width(), self.height(), GL.GL_RGB, GL.GL_UNSIGNED_BYTE) i = Image.frombytes('RGB', (self.width(), self.height()), pixels, 'raw') # if quick, save at screenshots/date_screenshot.jpg # else ask for location if not os.path.exists("outputs/screenshots") or not os.path.isdir( "outputs/screenshots"): os.mkdir("outputs/screenshots") if quick: # if the screenshot folder exists save it, else print an error. if os.path.exists("outputs/screenshots") and os.path.isdir( "outputs/screenshots"): now = datetime.datetime.now() filename = str( "outputs/screenshots/%d-%d-%d_%d-%d-%d_screenshot.jpg" % (now.year, now.month, now.day, now.hour, now.minute, now.second)) i.save(filename, "JPEG") # checks if the file exists. If not, some unknown error occured in the Image library. if not os.path.exists(filename) or not os.path.isfile( filename): raise VisualizationError( "Screenshot couldn't be saved due to an unknown reason.", Level.WARNING) else: raise VisualizationError( "Couldn't create the screenshot folder.", Level.WARNING) else: directory = "." if os.path.exists("outputs/screenshots") and os.path.isdir( "outputs/screenshots"): directory = "outputs/screenshots" path = TopQFileDialog( self.world.vis.get_main_window()).getSaveFileName( options=(TopQFileDialog.Options()), filter="*.jpg;;*.png;;*.bmp", directory=directory) if path[0] == '': return if path[0].endswith(".jpg") or path[0].endswith(".jpeg") or \ path[0].endswith(".png") or path[0].endswith(".bmp"): i.save(path[0]) else: i.save(path[0] + path[1].replace('*', ''))
def __init__(self, vertex_file, fragment_file, model_file): """ Superclass for Opengl Programs. compiles the given shader source files, gives access to the shared uniform variables of the shaders, loads the model mesh and calls the abstract init_buffer function with the loaded data :param vertex_file: file path to the vertex shader :param fragment_file: file path to the fragment shader :param model_file: file path to the .obj file """ # creating GL Program self._program = GL.glCreateProgram() # loading shader source files self._vertex = GL.glCreateShader(GL.GL_VERTEX_SHADER) self._fragment = GL.glCreateShader(GL.GL_FRAGMENT_SHADER) self.amount = 0 try: vert_source = open(vertex_file).read() except IOError as e: raise VisualizationError( "Vertex shader file couldn't be loaded:\n%s" % str(e), Level.CRITICAL) try: frag_source = open(fragment_file).read() except IOError as e: raise VisualizationError( "Fragment shader file couldn't be loaded:\n%s" % str(e), Level.CRITICAL) self.vbos = [] self._init_shaders(vert_source, frag_source) GL.glUseProgram(self._program) self.light_angle = 0 v, n, t = load_obj_file("components/models/" + model_file) self.size = len(v) self._vao = GL.glGenVertexArrays(1) self.use() self._init_buffers(v, n, t) GL.glBindVertexArray(0) self._init_uniforms()
def _init_shaders(self, vert, frag): """ compiles and links shaders :param vert: vertex shader source string :param frag: fragment shader source string :return: """ # set the sources GL.glShaderSource(self._vertex, vert) GL.glShaderSource(self._fragment, frag) # compile vertex shader GL.glCompileShader(self._vertex) if not GL.glGetShaderiv(self._vertex, GL.GL_COMPILE_STATUS): e = GL.glGetShaderInfoLog(self._vertex).decode() raise VisualizationError( "Vertex shader couldn't be compiled:\n%s" % str(e), Level.CRITICAL) # compile fragment shader GL.glCompileShader(self._fragment) if not GL.glGetShaderiv(self._fragment, GL.GL_COMPILE_STATUS): e = GL.glGetShaderInfoLog(self._fragment).decode() raise VisualizationError( "Fragment shader couldn't be compiled:\n%s" % str(e), Level.CRITICAL) # attach the shaders to the matter program GL.glAttachShader(self._program, self._vertex) GL.glAttachShader(self._program, self._fragment) # link the shaders to the matter program GL.glLinkProgram(self._program) if not GL.glGetProgramiv(self._program, GL.GL_LINK_STATUS): e = GL.glGetProgramInfoLog(self._program) raise VisualizationError( "The shaders couldn't be linked to program:\n%s" % str(e), Level.CRITICAL) # detach the shaders from matter program GL.glDetachShader(self._program, self._vertex) GL.glDetachShader(self._program, self._fragment)
def set_color(self, color: tuple): """ Sets the matter color :param color: matter color :return: None """ if len(color) != 4: raise VisualizationError( "Invalid color format!\ncolor has to be in rgba format => (float, float, float, float)", Level.WARNING) else: self.color = color
def get_attribute_location(self, name: str): """ gets and checks the attribute location with given name :param name: variable name (string) :return: location (int) """ loc = GL.glGetAttribLocation(self._program, name) if loc < 0: raise VisualizationError( "Attribute \"%s\" doesn't exist!\n" "(Maybe the compilation optimized the shader by removing the unused attribute?)" % name, Level.WARNING) else: return loc
def set_line_scaling(self, scaling): """ sets the line_scaling uniform in the vertex shader :param scaling: the scaling vector :return: """ self.use() gpu_data = np.array(scaling, dtype=np.float32).flatten() if len(gpu_data) != 3: raise VisualizationError( "Length of set_line_scaling parameter not correct, expected 3 got %d " % len(gpu_data), Level.WARNING) loc = self.get_uniform_location("line_scaling") GL.glUniform3f(loc, *gpu_data)
def set_model_color(self, color): """ sets the model_color uniform in the grid vertex shader :param color: the color (rgba) :return: """ self.use() gpu_data = np.array(color, dtype=np.float32).flatten() if len(gpu_data) != 4: raise VisualizationError( "Length of set_model_color parameter not correct, expected 4 got %d " % len(gpu_data), Level.WARNING) loc = self.get_uniform_location("model_color") GL.glUniform4f(loc, *gpu_data)
def set_light_color(self, light_color): """ sets the color of the light :param light_color: tuple/array, rgba format :return: """ self.use() gpu_data = np.array(light_color, dtype=np.float32).flatten() if len(gpu_data) != 4: raise VisualizationError( "Length of set_light_color parameter not correct, expected 4 got %d " % len(gpu_data), Level.WARNING) else: loc = self.get_uniform_location("light_color") GL.glUniform4f(loc, *light_color)
def set_model_scaling(self, scaling): """ sets the size scaling of the model :param scaling: 3d float tuple/array :return: """ self.use() gpu_data = np.array(scaling, dtype=np.float32).flatten() if len(gpu_data) != 3: raise VisualizationError( "Length of set_model_scaling parameter not correct, expected 3 got %d " % len(gpu_data), Level.WARNING) else: loc = self.get_uniform_location("model_scaling") GL.glUniform3f(loc, *gpu_data)
def set_world_matrix(self, world_matrix): """ sets the world matrix in the vertex shader :param world_matrix: 4x4 float32 :return: """ self.use() gpu_data = np.array(world_matrix, dtype=np.float32).flatten() if len(gpu_data) != 16: raise VisualizationError( "Length of set_world_matrix parameter not correct, expected 16 got %d " % len(gpu_data), Level.WARNING) else: loc = self.get_uniform_location("world") GL.glUniformMatrix4fv(loc, 1, False, world_matrix)
def set_projection_matrix(self, projection_matrix): """ sets the projection matrix in the vertex shader program :param projection_matrix: 4x4 float32 projection matrix :return: """ self.use() gpu_data = np.array(projection_matrix, dtype=np.float32).flatten() if len(gpu_data) != 16: raise VisualizationError( "Length of set_projection_matrix parameter not correct, expected 16 got %d " % len(gpu_data), Level.CRITICAL) else: loc = self.get_uniform_location("projection") GL.glUniformMatrix4fv(loc, 1, False, projection_matrix)
def update_previous_positions(self, data): """ updates the previous positions data (VBO 3) :param data: array of 3d positions """ self.use() gpu_data = np.array(data, dtype=np.float32).flatten() GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vbos[3]) GL.glBufferData(GL.GL_ARRAY_BUFFER, gpu_data.nbytes, gpu_data, GL.GL_DYNAMIC_DRAW) if len(gpu_data) % 3.0 != 0.0: raise VisualizationError( "Invalid previous positions data! Amount of coordinate " "components not dividable by 3 (not in xyz format?)!", Level.WARNING)
def update_colors(self, data): """ updates the color data (VBO2) :param data: list/array of rgba values. (dimensions are irrelevant) :return: """ self.use() gpu_data = np.array(data, dtype=np.float32).flatten() GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vbos[2]) GL.glBufferData(GL.GL_ARRAY_BUFFER, gpu_data.nbytes, gpu_data, GL.GL_DYNAMIC_DRAW) if len(gpu_data) % 4.0 != 0.0: raise VisualizationError( "Invalid color data! Amount of color components not dividable by 4 (not in rgba format?)!", Level.WARNING)
def _update_projection(self): if self._projection_type == "perspective": self.projection_matrix = get_perspetive_projection_matrix( self._fov, self._aspect, 1, self._render_distance) elif self._projection_type == "ortho": self.projection_matrix = get_orthographic_projection_matrix( -self._radius * self._aspect, self._radius * self._aspect, -self._radius, self._radius, 0.001, self._render_distance) else: self._projection_type = "perspective" self.projection_matrix = get_perspetive_projection_matrix( self._fov, self._aspect, 1, self._render_distance) raise VisualizationError( "Unknown projection type: \"" + self._projection_type + "\"! Setting projection to perspective.", Level.INFO)
def update_offsets(self, data): """ updates the offsets/positions data (VBO 1) :param data: array of 3d positions :return: """ self.use() gpu_data = np.array(data, dtype=np.float32).flatten() GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.vbos[1]) GL.glBufferData(GL.GL_ARRAY_BUFFER, gpu_data.nbytes, gpu_data, GL.GL_DYNAMIC_DRAW) self.amount = len(gpu_data) / 3.0 if len(gpu_data) % 3.0 != 0.0: raise VisualizationError( "Invalid offset data! Amount of coordinate components not dividable by 3 (not in xyz format?)!", Level.WARNING) self.amount = int(self.amount)