def plot(self): # Specify shader to be used glUseProgram(self.gls_pgr.program_id) # Bind VAO - this will automatically # bind all the vbo's saving us a bunch # of calls #glBindVertexArray(self.vao_id) glUniform4fv(self.gls_id_xy_color,1, self.plot_color) # Modern GL makes the draw call really simple # All the complexity has been pushed elsewhere glEnableVertexAttribArray(self.vertIndex) # set buffers glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer) glVertexAttribPointer(self.vertIndex,2, GL_FLOAT, GL_FALSE, 0, None) glDrawArrays(GL_LINE_STRIP, 0, self.data_points-1) # Lets unbind the shader and vertex array state glUseProgram(0) # disable arrays glDisableVertexAttribArray(self.vertIndex) glBindVertexArray(0)
def draw(self): """Draw test object.""" glBindBuffer(GL_ARRAY_BUFFER, self.vbo) glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) glDrawArrays(GL_TRIANGLES, 0, 6) glDisableVertexAttribArray(0) glBindBuffer(GL_ARRAY_BUFFER, 0)
def add_attribute(self, vid, data, name): """Add array vertex attribute for shaders.""" if data.ndim > 1: data = data.flatten() glBindBuffer(GL_ARRAY_BUFFER, self.__vbo_id[vid]) glBufferData(GL_ARRAY_BUFFER, data.nbytes, data, GL_STATIC_DRAW) glVertexAttribPointer(glGetAttribLocation(self.__program, name), 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(vid) self.__attributes.append(data)
def bind_attributes(self, buffer_objects, attribute_inputs): # TODO for attr_name, attr_index in self._attributes.items(): data = attribute_inputs[attr_name] bufname = data['buffer'] buf = buffer_objects[bufname] buf.bind() glEnableVertexAttribArray(attr_index) # TODO buf.bind_to_attribute(attr_index, data['buffer_view'])
def render(self): """Render game world.""" for vbo in self.vbos: if vbo.render: glBindBuffer(GL_ARRAY_BUFFER, vbo.name) glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) glDrawArrays( GL_TRIANGLES, 0, vbo.vertexes_count) glDisableVertexAttribArray(0) glBindBuffer(GL_ARRAY_BUFFER, 0)
def setup(self, actor): ''' Setup the shader uniforms / attributes. Assumes actor.vbo is already bound ''' # Bind the shader shaders.glUseProgram(self.program) # Enable vertex attribute arrays glEnableVertexAttribArray(self.attrib_position) # Set the Attribute pointers glVertexAttribPointer(self.attrib_position, 4, GL_FLOAT, False, 0, actor.vbo) # Apply uniforms glUniformMatrix4fv(self.uniform_modelCamera, 1, GL_TRUE, actor.modelCamera_matrix) glUniformMatrix4fv(self.uniform_projection, 1, GL_TRUE, actor.projection_matrix) glUniform1f(self.uniform_alpha, actor.alpha) # Bind to the correct texture glBindTexture(GL_TEXTURE_2D, actor.texid)
def setup(self, actor): ''' Setup the shader uniforms / attributes. Assumes actor.vbo is already bound ''' # Bind the shader shaders.glUseProgram(self.program) # Enable vertex attribute arrays glEnableVertexAttribArray(self.attrib_position) glEnableVertexAttribArray(self.attrib_color) # colorOffset is sizeof float (4) * floats per point (4) * num of points (vbo/2) colorOffset = 4 * 4 * (len(actor.vbo) / 2) # Set the Attribute pointers glVertexAttribPointer(self.attrib_position, 4, GL_FLOAT, False, 0, actor.vbo) glVertexAttribPointer(self.attrib_color, 4, GL_FLOAT, False, 0, actor.vbo + colorOffset) # Apply uniforms glUniformMatrix4fv(self.uniform_modelCamera, 1, GL_TRUE, actor.modelCamera_matrix) glUniformMatrix4fv(self.uniform_projection, 1, GL_TRUE, actor.projection_matrix) glUniform1f(self.uniform_alpha, actor.alpha)
def buff_vertices(verts: list, indes: list=None) -> int: """Given a list of vertex-like objects, an optional list of indices, returns a VAO handle. Format (all should be floats): [[pX, pY, pZ, nX, nY, nZ, cR, cR, cB, tU, tV]] * len.""" vao = glGenVertexArrays(1) glBindVertexArray(vao) v = vbo.VBO(array(verts, 'f')) v.bind() glVertexAttribPointer(0, 3, GL_FLOAT, False, 44, v) glVertexAttribPointer(1, 3, GL_FLOAT, False, 44, v+12) glVertexAttribPointer(2, 3, GL_FLOAT, False, 44, v+24) glVertexAttribPointer(3, 2, GL_FLOAT, False, 44, v+36) glEnableVertexAttribArray(0) glEnableVertexAttribArray(1) glEnableVertexAttribArray(2) glEnableVertexAttribArray(3) # Maybe you want to include the vertices verbatim? Go for it. if indes is not None: ebo = glGenBuffers(1) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo) glBufferData(GL_ELEMENT_ARRAY_BUFFER, len(indes)*8, array(indes, 'i'), GL_STATIC_DRAW) glBindVertexArray(0) return vao
def enable(self): " Enable the shader attribute " glEnableVertexAttribArray(self.loc)
# Bind a buffer before we can use it glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]) # Now go ahead and fill this bound buffer with some data glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(vertex_data), vertex_data, GL_STATIC_DRAW) # Now specify how the shader program will be receiving this data # In this case the data from this buffer will be # available in the shader as the vin_position vertex attribute glVertexAttribPointer(program.attribute_location('vin_position'), 3, GL_FLOAT, GL_FALSE, 0, None) # Turn on this vertex attribute in the shader glEnableVertexAttribArray(0) # Now do the same for the other vertex buffer glBindBuffer(GL_ARRAY_BUFFER, vbo_id[1]) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(color_data), color_data, GL_STATIC_DRAW) glVertexAttribPointer(program.attribute_location('vin_color'), 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(1) # Lets unbind our vbo and vao state # We will bind these again in the draw loop glBindBuffer(GL_ARRAY_BUFFER, 0) glBindVertexArray(0)
def render_thing(thing, position_location, normal_location, color_location, modelview_location, context_matrix): try: translate = np.array(matrix_translate(thing["position"]), 'f') except: print "render_thing can't translate thing: ", thing exit() #print "render_thing type: ", thing["type"], thing["position"] context_matrix = np.dot(context_matrix, translate) rotates = thing["rotates"] if len(rotates) == 2: rotate0 = np.array(matrix_rotate_ortho(rotates[0]["angle"], rotates[0]["axis"]), 'f') tmp_matrix = np.dot(context_matrix, rotate0) rotate1 = np.array(matrix_rotate_ortho(rotates[1]["angle"], rotates[1]["axis"]), 'f') context_matrix = np.dot(tmp_matrix, rotate1) #print "render_thing:\n {}\n{}\n{}".format(translate, rotate0, rotate1) #print "context_matrix:\n", context_matrix glUniformMatrix4fv(modelview_location, 1, True, context_matrix) geometry = thing["geometry"] if geometry != None: if geometry["static"]: key = int(float(geometry["id"])) #print "thing type: {}, key: {}".format(thing["type"], key) if not key in vbos: vertices = geometry["vertices"] #print "adding geometry:\n{}".format(vertices[0]) #vbos[key] = (vbo.VBO(np.array(vertices, 'f')), len(vertices)) vbos[key] = (vbo.VBO(vertices), len(vertices)) buffer_object, buffer_size = vbos[key] else: vertices = geometry["vertices"] buffer_object = vbo.VBO(vertices) buffer_size = len(vertices) #print "rendering type: {}, size: {}".format(buffer_object, buffer_size) #pdb.set_trace() buffer_object.bind() try: glEnableVertexAttribArray( position_location ) glEnableVertexAttribArray( normal_location ) glEnableVertexAttribArray( color_location ) stride = 10*4 glVertexAttribPointer( position_location, 3, GL_FLOAT,False, stride, buffer_object ) glVertexAttribPointer( normal_location, 3, GL_FLOAT,False, stride, buffer_object+12 ) glVertexAttribPointer( color_location, 4, GL_FLOAT,False, stride, buffer_object+24 ) glDrawArrays(GL_TRIANGLES, 0, buffer_size) #print 'buffer size: ', buffer_size finally: buffer_object.unbind() glDisableVertexAttribArray( position_location ) glDisableVertexAttribArray( color_location ) else: for child in thing["children"]: render_thing(child, position_location, normal_location, color_location, modelview_location, context_matrix)
def __init__(self, vertices, indices, normals=None, uvs=None): """Constructor. Creates and initializes corresponding OpenGL objects with given data. :param vertices: Vertex data, specified as a contiguous list of X,Y,Z floating point values. :type vertices: list :param indices: Indices which identify model faces. The only supported geometry primitive is the triangle, thus, the size of indices list must be a multiple of 3. :type indices: list :param normals: Normals data, specified as a contiguos list of Xn,Yn,Zn floating point values. List length must be a multiple of 3. :type normals: list :param uvs: List of texture coordinates, specified as a contigous array of U,V floating pont values.. List length must be a multiple of 2. :type uvs: list """ if len(vertices) < 3 or len(vertices) % 3: raise ValueError( 'Vertex data must be an array of floats, which length is a ' 'positive multiple of 3') if len(indices) < 3 or len(indices) % 3: raise ValueError('Indices count must be a positive multiple of 3') if normals and (len(normals) < 3 or len(normals) % 3): raise ValueError( 'Normals data must be an array of floats, which length is a ' 'positive multiple of 3') if uvs is not None and len(uvs) % 2: raise ValueError('UVs count must be a positive multiple of 2') self.num_elements = len(indices) # generate vertex array object and make it active self.vao = glGenVertexArrays(1) glBindVertexArray(self.vao) # generate buffers self.buffers = glGenBuffers(2) vbo, ibo = self.buffers # initialize vertex buffer vertex_data = np.array(vertices, np.float32) # append normals data, if provided normals_offset = 0 if normals: normals_offset = vertex_data.nbytes vertex_data = np.append(vertex_data, np.array(normals, np.float32)) # append UVs data, if provided uvs_offset = 0 if uvs: uvs_offset = vertex_data.nbytes vertex_data = np.append(vertex_data, np.array(uvs, np.float32)) glBindBuffer(GL_ARRAY_BUFFER, vbo) glBufferData(GL_ARRAY_BUFFER, vertex_data.nbytes, vertex_data, GL_STATIC_DRAW) # initialize index buffer index_data = np.array(indices, np.uint32) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo) glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_data.nbytes, index_data, GL_STATIC_DRAW) # specify first attribute as vertex data glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) # if provided, specify normals as second attribute if normals is not None: glEnableVertexAttribArray(1) glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(normals_offset)) # if provided, specify UVs as third attribute if uvs is not None: glEnableVertexAttribArray(2) glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(uvs_offset)) # unbind the vertex array object glBindVertexArray(0)
def run(): #Start OpenGL and ask it for an OpenGL context pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode(SCREEN_SIZE, pygame.HWSURFACE|pygame.OPENGL|pygame.DOUBLEBUF) #The first thing we do is print some OpenGL details and check that we have a good enough version print("OpenGL Implementation Details:") if glGetString(GL_VENDOR): print("\tGL_VENDOR: {}".format(glGetString(GL_VENDOR).decode())) if glGetString(GL_RENDERER): print("\tGL_RENDERER: {}".format(glGetString(GL_RENDERER).decode())) if glGetString(GL_VERSION): print("\tGL_VERSION: {}".format(glGetString(GL_VERSION).decode())) if glGetString(GL_SHADING_LANGUAGE_VERSION): print("\tGL_SHADING_LANGUAGE_VERSION: {}".format(glGetString(GL_SHADING_LANGUAGE_VERSION).decode())) major_version = int(glGetString(GL_VERSION).decode().split()[0].split('.')[0]) minor_version = int(glGetString(GL_VERSION).decode().split()[0].split('.')[1]) if major_version < 3 or (major_version < 3 and minor_version < 0): print("OpenGL version must be at least 3.0 (found {0})".format(glGetString(GL_VERSION).decode().split()[0])) #Now onto the OpenGL initialisation #Set up depth culling glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) glDepthFunc(GL_LEQUAL) glDepthRange(0.0, 1.0) #We create out shaders which do little more than set a flat colour for each face VERTEX_SHADER = shaders.compileShader(b""" #version 130 in vec4 position; in vec4 normal; uniform mat4 projectionMatrix; uniform mat4 viewMatrix; uniform mat4 modelMatrix; flat out float theColor; void main() { vec4 temp = modelMatrix * position; temp = viewMatrix * temp; gl_Position = projectionMatrix * temp; theColor = clamp(abs(dot(normalize(normal.xyz), normalize(vec3(0.9,0.1,0.5)))), 0, 1); } """, GL_VERTEX_SHADER) FRAGMENT_SHADER = shaders.compileShader(b""" #version 130 flat in float theColor; out vec4 outputColor; void main() { outputColor = vec4(1.0, 0.5, theColor, 1.0); } """, GL_FRAGMENT_SHADER) shader = shaders.compileProgram(VERTEX_SHADER, FRAGMENT_SHADER) #And then grab our attribute locations from it glBindAttribLocation(shader, 0, b"position") glBindAttribLocation(shader, 1, b"normal") #Create the Vertex Array Object to hold our volume mesh vertexArrayObject = GLuint(0) glGenVertexArrays(1, vertexArrayObject) glBindVertexArray(vertexArrayObject) #Create the index buffer object indexPositions = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER, usage=GL_STATIC_DRAW) #Create the VBO vertexPositions = vbo.VBO(vertices, usage=GL_STATIC_DRAW) #Bind our VBOs and set up our data layout specifications with indexPositions, vertexPositions: glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, False, 6*vertices.dtype.itemsize, vertexPositions+(0*vertices.dtype.itemsize)) glEnableVertexAttribArray(1) glVertexAttribPointer(1, 3, GL_FLOAT, False, 6*vertices.dtype.itemsize, vertexPositions+(3*vertices.dtype.itemsize)) glBindVertexArray(0) glDisableVertexAttribArray(0) #Now grab out transformation martix locations modelMatrixUnif = glGetUniformLocation(shader, b"modelMatrix") viewMatrixUnif = glGetUniformLocation(shader, b"viewMatrix") projectionMatrixUnif = glGetUniformLocation(shader, b"projectionMatrix") modelMatrix = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f') viewMatrix = np.array([[1.0,0.0,0.0,0.0],[0.0,1.0,0.0,0.0],[0.0,0.0,1.0,-50.0],[0.0,0.0,0.0,1.0]], dtype='f') projectionMatrix = np.array([[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0]], dtype='f') #These next few lines just set up our camera frustum fovDeg = 45.0 frustumScale = 1.0 / tan(radians(fovDeg) / 2.0) zNear = 1.0 zFar = 1000.0 projectionMatrix[0][0] = frustumScale projectionMatrix[1][1] = frustumScale projectionMatrix[2][2] = (zFar + zNear) / (zNear - zFar) projectionMatrix[2][3] = -1.0 projectionMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar) #viewMatrix and projectionMatrix don't change ever so just set them once here with shader: glUniformMatrix4fv(projectionMatrixUnif, 1, GL_TRUE, projectionMatrix) glUniformMatrix4fv(viewMatrixUnif, 1, GL_TRUE, viewMatrix) #These are used to track the rotation of the volume LastFrameMousePos = (0,0) CurrentMousePos = (0,0) xRotation = 0 yRotation = 0 while True: clock.tick() for event in pygame.event.get(): if event.type == pygame.QUIT: return if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: return if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: CurrentMousePos = event.pos LastFrameMousePos = CurrentMousePos if event.type == pygame.MOUSEMOTION and 1 in event.buttons: CurrentMousePos = event.pos diff = (CurrentMousePos[0] - LastFrameMousePos[0], CurrentMousePos[1] - LastFrameMousePos[1]) xRotation += event.rel[0] yRotation += event.rel[1] LastFrameMousePos = CurrentMousePos glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #Perform the rotation of the mesh moveToOrigin = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f') rotateAroundX = np.array([[1.0,0.0,0.0,0.0],[0.0,cos(radians(yRotation)),-sin(radians(yRotation)),0.0],[0.0,sin(radians(yRotation)),cos(radians(yRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f') rotateAroundY = np.array([[cos(radians(xRotation)),0.0,sin(radians(xRotation)),0.0],[0.0,1.0,0.0,0.0],[-sin(radians(xRotation)),0.0,cos(radians(xRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f') modelMatrix = rotateAroundY.dot(rotateAroundX.dot(moveToOrigin)) with shader: glUniformMatrix4fv(modelMatrixUnif, 1, GL_TRUE, modelMatrix) glBindVertexArray(vertexArrayObject) glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None) glBindVertexArray(0) # Show the screen pygame.display.flip()
def create_field(rows, cols, size, fun, gen_textures, gen_relief=False): normals_vec = np.zeros((rows * cols, 3), dtype=np.float32) vertices_list = [] texcoords_list = [] faces_list = [] indices_list = [] if not gen_relief: for z in range(0, rows): for x in range(0, cols): # if (x**2 + z**2)**(1/2) <= cols: xx = -size / 2 + x * size / cols zz = -size / 2 + z * size / rows try: yy = fun(xx, zz) if yy < -size / 2: yy = -size / 2 if yy > size / 2: yy = size / 2 except (ArithmeticError, ValueError): yy = 0.0 vertices_list.append([xx, yy, zz]) if gen_textures: texcoords_list.append( [x / float(cols - 1), z / float(rows - 1)]) else: buff1 = [] vertices_list_mountain = [] for z in range(0, rows): del buff1[:] for x in range(0, cols): xx = -size / 2 + x * size / cols zz = -size / 2 + z * size / rows yy = 0.0 buff1.append([xx, yy, zz]) vertices_list_mountain.append(buff1[:]) for i in range(0, 250): radius = 12 z = randint(0, rows - 1) x = randint(0, cols - 1) for iz in range(z - radius, z + radius): if iz < 0 or iz > rows - 1: continue else: for ix in range(x - radius, x + radius): if ix < 0 or ix > cols - 1: continue else: if radius**2 - ( (z - iz + 10)**2 + (x - ix) ) > vertices_list_mountain[iz][ix][1]**(2): vertices_list_mountain[iz][ix][1] = ( radius**2 - ((z - iz + 10)**2 + (x - ix)))**(1 / 2) else: continue v = vertices_list_mountain[:] vec_lines = [] for ii in range(0, 10): i = 2 * ii for z in range(0, rows - 1): for x in range(0, cols - 1): xx = -size / 2 + x * size / cols zz = -size / 2 + z * size / rows if v[z][x][1] < i and v[z][x + 1][1] < i and v[z + 1][x][1] < i and v[z + 1][x + 1][1] < i or \ v[z][x][1] >= i and v[z][x + 1][1] >= i and v[z + 1][x][1] >= i and v[z + 1][x + 1][1] >= i: continue elif v[z][x][1] >= i and v[z][x + 1][1] < i and v[ z + 1][x][1] < i and v[z + 1][x + 1][1] < i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] >= i and v[ z + 1][x][1] < i and v[z + 1][x + 1][1] < i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] < i and v[ z + 1][x][1] >= i and v[z + 1][x + 1][1] < i: vec_lines.append([xx + 0.25, i, zz + 0.5]) vec_lines.append([xx, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] < i and v[ z + 1][x][1] < i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz + 0.5]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] >= i and v[ z + 1][x][1] >= i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx, i, zz + 0.25]) elif v[z][x][1] >= i and v[z][x + 1][1] < i and v[ z + 1][x][1] >= i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] >= i and v[z][x + 1][1] >= i and v[ z + 1][x][1] < i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz + 0.5]) vec_lines.append([xx, i, zz + 0.25]) elif v[z][x][1] >= i and v[z][x + 1][1] >= i and v[ z + 1][x][1] >= i and v[z + 1][x + 1][1] < i: vec_lines.append([xx + 0.25, i, zz + 0.5]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] < i and v[z + 1][x][1] >= i and v[z + 1][x + 1][1] >= i or \ v[z][x][1] >= i and v[z][x + 1][1] >= i and v[z + 1][x][1] < i and v[z + 1][x + 1][1] < i: vec_lines.append([xx, i, zz + 0.25]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] >= i and v[z][x + 1][1] < i and v[z + 1][x][1] >= i and v[z + 1][x + 1][1] < i or \ v[z][x][1] < i and v[z][x + 1][1] >= i and v[z + 1][x][1] < i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx + 0.25, i, zz + 0.5]) elif v[z][x][1] >= i and v[z][x + 1][1] < i and v[z + 1][x][1] < i and v[z + 1][x + 1][1] >= i or \ v[z][x][1] < i and v[z][x + 1][1] >= i and v[z + 1][x][1] >= i and v[z + 1][x + 1][1] < i: vec_lines.append([xx, i, zz + 0.25]) vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx + 0.5, i, zz + 0.25]) vec_lines.append([xx + 0.25, i, zz + 0.5]) index_lines = [it for it in range(0, len(vec_lines))] vector_lines = np.array(vec_lines, dtype=np.float32) vector_line_indexes = np.array(index_lines, dtype=np.uint32) for z in range(0, rows): for x in range(0, cols): vertices_list.append(vertices_list_mountain[z][x]) primRestart = rows * cols vertices_vec = np.array(vertices_list, dtype=np.float32) print(len(vertices_list)) print(vertices_vec.size) print(len(indices_list)) print(size) if gen_textures: texcoords_vec = np.array(texcoords_list, dtype=np.float32) for x in range(0, cols - 1): for z in range(0, rows - 1): if ((50 - x)**2 + (50 - z)**2)**(1 / 2) <= (rows - 1) / 2 or gen_relief == True: offset = x * cols + z if z == 0: indices_list.append(offset) indices_list.append(offset + rows) indices_list.append(offset + 1) indices_list.append(offset + rows + 1) else: indices_list.append(offset + 1) indices_list.append(offset + rows + 1) if z == rows - 2: indices_list.append(primRestart) print(len(indices_list)) indices_vec = np.array(indices_list, dtype=np.uint32) print(indices_vec.size) currFace = 1 for i in range(0, indices_vec.size - 2): index0 = indices_vec[i] index1 = indices_vec[i + 1] index2 = indices_vec[i + 2] face = np.array([0, 0, 0], dtype=np.int32) if (index0 != primRestart) and (index1 != primRestart) and ( index2 != primRestart): if currFace % 2 != 0: face[0] = indices_vec[i] face[1] = indices_vec[i + 1] face[2] = indices_vec[i + 2] currFace += 1 else: face[0] = indices_vec[i] face[1] = indices_vec[i + 2] face[2] = indices_vec[i + 1] currFace += 1 faces_list.append(face) faces = np.reshape(faces_list, newshape=(len(faces_list), 3)) for i in range(0, faces.shape[0]): A = np.array([ vertices_vec[faces[i, 0], 0], vertices_vec[faces[i, 0], 1], vertices_vec[faces[i, 0], 2] ], dtype=np.float32) B = np.array([ vertices_vec[faces[i, 1], 0], vertices_vec[faces[i, 1], 1], vertices_vec[faces[i, 1], 2] ], dtype=np.float32) C = np.array([ vertices_vec[faces[i, 2], 0], vertices_vec[faces[i, 2], 1], vertices_vec[faces[i, 2], 2] ], dtype=np.float32) edge1A = normalize(B - A) edge2A = normalize(C - A) face_normal = np.cross(edge1A, edge2A) normals_vec[faces[i, 0]] += face_normal normals_vec[faces[i, 1]] += face_normal normals_vec[faces[i, 2]] += face_normal for i in range(0, normals_vec.shape[0]): normals_vec[i] = normalize(normals_vec[i]) vao = glGenVertexArrays(1) vbo_vertices = glGenBuffers(1) vbo_normals = glGenBuffers(1) if gen_textures: vbo_texcoords = glGenBuffers(1) vbo_indices = glGenBuffers(1) glBindVertexArray(vao) glBindBuffer(GL_ARRAY_BUFFER, vbo_vertices) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(vertices_vec), vertices_vec.flatten(), GL_STATIC_DRAW) # glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(0) glBindBuffer(GL_ARRAY_BUFFER, vbo_normals) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(normals_vec), normals_vec.flatten(), GL_STATIC_DRAW) # glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(1) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_indices) glBufferData(GL_ELEMENT_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(indices_vec), indices_vec.flatten(), GL_STATIC_DRAW) if gen_textures: glBindBuffer(GL_ARRAY_BUFFER, vbo_texcoords) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(texcoords_vec), texcoords_vec.flatten(), GL_STATIC_DRAW) glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(2) glEnable(GL_PRIMITIVE_RESTART) glPrimitiveRestartIndex(primRestart) glBindVertexArray(0) if gen_relief: return (vao, indices_vec.size, vector_lines, vector_line_indexes) else: return (vao, indices_vec.size)
vbo_id = glGenBuffers(2) # Bind a buffer before we can use it glBindBuffer(GL_ARRAY_BUFFER, vbo_id[0]) # Now go ahead and fill this bound buffer with some data glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(vertex_data), vertex_data, GL_STATIC_DRAW) # Now specify how the shader program will be receiving this data # In this case the data from this buffer will be available in the shader as the vin_position vertex attribute glVertexAttribPointer(program.attribute_location('vin_position'), 3, GL_FLOAT, GL_FALSE, 0, None) # Turn on this vertex attribute in the shader glEnableVertexAttribArray(0) # Now do the same for the other vertex buffer glBindBuffer(GL_ARRAY_BUFFER, vbo_id[1]) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(color_data), color_data, GL_STATIC_DRAW) glVertexAttribPointer(program.attribute_location('vin_color'), 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(1) # Lets unbind our vbo and vao state # We will bind these again in the draw loop glBindBuffer(GL_ARRAY_BUFFER, 0) glBindVertexArray(0) running = True
def build(self) -> bool: """ Build OpenGL Vertex Array for the object This function gets automatically called if `self._vao` does not exists in the first render cycle. Once the vba is built, geometry changes or material display mode changes will not be automatically effected. So, in every geometry or display mode change, a `build` call is necessary. If `self.static` is `True`, then the system assumes that another update call is not expected, thus frees `_normals`, `_textcoords`, `_vertices` and `_indices` lists to free memory. So in this case, calling `build` function twice will result in an invisible object (will not be drawn). Returns: bool """ if len(self._indices) == 0: return False # If we don't have a VAO yet, we need to create one if not self.has_vao: # Generate Vertex Array self._vao = glGenVertexArrays(1) # We need 5 buffers (vertex, normal, texcoord, color, indices) self._vbos = glGenBuffers(5) glBindVertexArray(self._vao) # Material shader must be built when there is an active binding # to vertex array self.material.build_shader() else: # Ok, we already have vertex array object, just bind it to modify glBindVertexArray(self._vao) # Turn python arrays into C type arrays using Numpy. # This is required for OpenGL. Python memory model is a bit # different than raw memory model of C (OpenGL) vertices = np.array(self._vertices, dtype=np.float32).flatten() normals = np.array(self._normals, dtype=np.float32).flatten() texcoords = np.array(self._texcoords, dtype=np.float32).flatten() colors = np.array(self._vertex_colors, dtype=np.float32).flatten() indices = np.array(self._indices, dtype=np.int32).flatten() self._calc_bounds() # OpenGL allocates buffers in different mechanisms between # STATIC and DYNAMIC draw modes. If you select STATIC, then OpenGL # will assume that object buffer will not change and allocate it in a # more suitable way. draw = GL_STATIC_DRAW if not self.static: draw = GL_DYNAMIC_DRAW # Buffer overflow, we need more space. if self._buffer_size < vertices.nbytes: self._buffer_size = vertices.nbytes self._buffer_size_changed = True if self._t_buffer_size < texcoords.nbytes: self._t_buffer_size = texcoords.nbytes self._t_buffer_size_changed = True # Bind Vertices glBindBuffer(GL_ARRAY_BUFFER, self._vbos[0]) glEnableVertexAttribArray(0) # shader layout location glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, ctypes.c_void_p(0)) if self._buffer_size_changed: # glBufferData creates a new data area glBufferData(GL_ARRAY_BUFFER, self._buffer_size, vertices, draw) else: # glBufferSubData just replaces memory area in buffer so it is # much more efficient way to handle things. glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.nbytes, vertices) # Bind Normals glBindBuffer(GL_ARRAY_BUFFER, self._vbos[1]) glEnableVertexAttribArray(1) # shader layout location glVertexAttribPointer(1, 3, GL_FLOAT, False, 0, ctypes.c_void_p(0)) if self._buffer_size_changed: glBufferData(GL_ARRAY_BUFFER, self._buffer_size, normals, draw) else: glBufferSubData(GL_ARRAY_BUFFER, 0, normals.nbytes, normals) # Bind TexCoords if len(self._texcoords) == len(self._vertices): glBindBuffer(GL_ARRAY_BUFFER, self._vbos[2]) glEnableVertexAttribArray(2) # shader layout location glVertexAttribPointer(2, 2, GL_FLOAT, False, 0, ctypes.c_void_p(0)) if self._t_buffer_size_changed: glBufferData( GL_ARRAY_BUFFER, self._t_buffer_size, texcoords, draw ) else: glBufferSubData( GL_ARRAY_BUFFER, 0, texcoords.nbytes, texcoords ) # Bind Vertex Colors if len(self._vertex_colors) == len(self._vertices): glBindBuffer(GL_ARRAY_BUFFER, self._vbos[4]) glEnableVertexAttribArray(3) # shader layout location glVertexAttribPointer(3, 3, GL_FLOAT, False, 0, ctypes.c_void_p(0)) self._has_vertex_colors = True if self._buffer_size_changed: glBufferData(GL_ARRAY_BUFFER, self._buffer_size, colors, draw) else: glBufferSubData(GL_ARRAY_BUFFER, 0, colors.nbytes, colors) self._buffer_size_changed = False self._t_buffer_size_changed = False # Bind Indices glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self._vbos[3]) glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, draw) self._vertex_count = len(indices) glBindVertexArray(0) glBindBuffer(GL_ARRAY_BUFFER, 0) if self.static: # we can clear this data to free some more memory glDeleteBuffers(4, self._vbos) self._vbos = [] self._needs_update = False return True
def create_vaos(self) -> None: """Bind VAOs to define vertex data.""" self._vao, self._vao_picking, self._vao_outline = glGenVertexArrays(3) vbo = glGenBuffers(6) # --- standard viewcube --- vertices = glm.array.from_numbers( ctypes.c_float, 1.0, 1.0, 1.0, 0.7, 0.7, 0.7, 1.0, -1.0, 1.0, 0.7, 0.7, 0.7, 1.0, -1.0, -1.0, 0.4, 0.4, 0.4, 1.0, 1.0, -1.0, 0.4, 0.4, 0.4, -1.0, 1.0, -1.0, 0.4, 0.4, 0.4, -1.0, 1.0, 1.0, 0.7, 0.7, 0.7, -1.0, -1.0, 1.0, 0.7, 0.7, 0.7, -1.0, -1.0, -1.0, 0.4, 0.4, 0.4, ) indices = glm.array.from_numbers( ctypes.c_uint, 0, 1, 2, 2, 3, 0, 0, 3, 4, 4, 5, 0, 0, 5, 6, 6, 1, 0, 1, 6, 7, 7, 2, 1, 7, 4, 3, 3, 2, 7, 4, 7, 6, 6, 5, 4, ) glBindVertexArray(self._vao) glBindBuffer(GL_ARRAY_BUFFER, vbo[0]) glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices.ptr, GL_STATIC_DRAW) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glBindBuffer(GL_ARRAY_BUFFER, vbo[1]) glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices.ptr, GL_STATIC_DRAW) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 24, ctypes.c_void_p(12)) glEnableVertexAttribArray(1) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]) glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices.ptr, GL_STATIC_DRAW) # --- viewcube for picking --- vertices = glm.array.from_numbers( ctypes.c_float, 1.0, -1.0, 1.0, # 1 front (id = 0) -1.0, -1.0, 1.0, # 6 -1.0, -1.0, -1.0, # 7 1.0, -1.0, -1.0, # 2 1.0, 1.0, 1.0, # 0 top (id = 1) -1.0, 1.0, 1.0, # 5 -1.0, -1.0, 1.0, # 6 1.0, -1.0, 1.0, # 1 1.0, 1.0, 1.0, # 0 right (id = 2) 1.0, -1.0, 1.0, # 1 1.0, -1.0, -1.0, # 2 1.0, 1.0, -1.0, # 3 -1.0, -1.0, -1.0, # 7 bottom (id = 3) -1.0, 1.0, -1.0, # 4 1.0, 1.0, -1.0, # 3 1.0, -1.0, -1.0, # 2 -1.0, -1.0, -1.0, # 7 left (id = 4) -1.0, -1.0, 1.0, # 6 -1.0, 1.0, 1.0, # 5 -1.0, 1.0, -1.0, # 4 1.0, 1.0, 1.0, # 0 back (id = 5) 1.0, 1.0, -1.0, # 3 -1.0, 1.0, -1.0, # 4 -1.0, 1.0, 1.0, # 5 ) colors = np.zeros(72, dtype=np.float32) colors[::3] = np.arange(6).repeat(4) / 255.0 glBindVertexArray(self._vao_picking) glBindBuffer(GL_ARRAY_BUFFER, vbo[3]) glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices.ptr, GL_STATIC_DRAW) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glBindBuffer(GL_ARRAY_BUFFER, vbo[4]) glBufferData(GL_ARRAY_BUFFER, colors.nbytes, colors, GL_STATIC_DRAW) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0)) glEnableVertexAttribArray(1) # --- outlined face of viewcube --- border_colors = glm.array.from_numbers(ctypes.c_float, 0.0000, 0.4088, 0.9486).repeat(24) glBindVertexArray(self._vao_outline) glBindBuffer(GL_ARRAY_BUFFER, vbo[3]) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0)) glEnableVertexAttribArray(0) glBindBuffer(GL_ARRAY_BUFFER, vbo[5]) glBufferData(GL_ARRAY_BUFFER, border_colors.nbytes, border_colors.ptr, GL_STATIC_DRAW) glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0)) glEnableVertexAttribArray(1) # --- glBindVertexArray(0) glDeleteBuffers(6, vbo)
def run(): #Start OpenGL and ask it for an OpenGL context pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode( SCREEN_SIZE, pygame.HWSURFACE | pygame.OPENGL | pygame.DOUBLEBUF) #The first thing we do is print some OpenGL details and check that we have a good enough version print("OpenGL Implementation Details:") if glGetString(GL_VENDOR): print("\tGL_VENDOR: {}".format(glGetString(GL_VENDOR).decode())) if glGetString(GL_RENDERER): print("\tGL_RENDERER: {}".format(glGetString(GL_RENDERER).decode())) if glGetString(GL_VERSION): print("\tGL_VERSION: {}".format(glGetString(GL_VERSION).decode())) if glGetString(GL_SHADING_LANGUAGE_VERSION): print("\tGL_SHADING_LANGUAGE_VERSION: {}".format( glGetString(GL_SHADING_LANGUAGE_VERSION).decode())) major_version = int( glGetString(GL_VERSION).decode().split()[0].split('.')[0]) minor_version = int( glGetString(GL_VERSION).decode().split()[0].split('.')[1]) if major_version < 3 or (major_version < 3 and minor_version < 0): print("OpenGL version must be at least 3.0 (found {0})".format( glGetString(GL_VERSION).decode().split()[0])) #Now onto the OpenGL initialisation #Set up depth culling glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) glDepthFunc(GL_LEQUAL) glDepthRange(0.0, 1.0) #We create out shaders which do little more than set a flat colour for each face VERTEX_SHADER = shaders.compileShader( b""" #version 130 in vec4 position; in vec4 normal; uniform mat4 projectionMatrix; uniform mat4 viewMatrix; uniform mat4 modelMatrix; flat out float theColor; void main() { vec4 temp = modelMatrix * position; temp = viewMatrix * temp; gl_Position = projectionMatrix * temp; theColor = clamp(abs(dot(normalize(normal.xyz), normalize(vec3(0.9,0.1,0.5)))), 0, 1); } """, GL_VERTEX_SHADER) FRAGMENT_SHADER = shaders.compileShader( b""" #version 130 flat in float theColor; out vec4 outputColor; void main() { outputColor = vec4(1.0, 0.5, theColor, 1.0); } """, GL_FRAGMENT_SHADER) shader = shaders.compileProgram(VERTEX_SHADER, FRAGMENT_SHADER) #And then grab our attribute locations from it glBindAttribLocation(shader, 0, b"position") glBindAttribLocation(shader, 1, b"normal") #Create the Vertex Array Object to hold our volume mesh vertexArrayObject = GLuint(0) glGenVertexArrays(1, vertexArrayObject) glBindVertexArray(vertexArrayObject) #Create the index buffer object indexPositions = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER, usage=GL_STATIC_DRAW) #Create the VBO vertexPositions = vbo.VBO(vertices, usage=GL_STATIC_DRAW) #Bind our VBOs and set up our data layout specifications with indexPositions, vertexPositions: glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, False, 6 * vertices.dtype.itemsize, vertexPositions + (0 * vertices.dtype.itemsize)) glEnableVertexAttribArray(1) glVertexAttribPointer(1, 3, GL_FLOAT, False, 6 * vertices.dtype.itemsize, vertexPositions + (3 * vertices.dtype.itemsize)) glBindVertexArray(0) glDisableVertexAttribArray(0) #Now grab out transformation martix locations modelMatrixUnif = glGetUniformLocation(shader, b"modelMatrix") viewMatrixUnif = glGetUniformLocation(shader, b"viewMatrix") projectionMatrixUnif = glGetUniformLocation(shader, b"projectionMatrix") modelMatrix = np.array([[1.0, 0.0, 0.0, -32.0], [0.0, 1.0, 0.0, -32.0], [0.0, 0.0, 1.0, -32.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') viewMatrix = np.array([[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, -50.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') projectionMatrix = np.array([[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], dtype='f') #These next few lines just set up our camera frustum fovDeg = 45.0 frustumScale = 1.0 / tan(radians(fovDeg) / 2.0) zNear = 1.0 zFar = 1000.0 projectionMatrix[0][0] = frustumScale projectionMatrix[1][1] = frustumScale projectionMatrix[2][2] = (zFar + zNear) / (zNear - zFar) projectionMatrix[2][3] = -1.0 projectionMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar) #viewMatrix and projectionMatrix don't change ever so just set them once here with shader: glUniformMatrix4fv(projectionMatrixUnif, 1, GL_TRUE, projectionMatrix) glUniformMatrix4fv(viewMatrixUnif, 1, GL_TRUE, viewMatrix) #These are used to track the rotation of the volume LastFrameMousePos = (0, 0) CurrentMousePos = (0, 0) xRotation = 0 yRotation = 0 while True: clock.tick() for event in pygame.event.get(): if event.type == pygame.QUIT: return if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: return if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: CurrentMousePos = event.pos LastFrameMousePos = CurrentMousePos if event.type == pygame.MOUSEMOTION and 1 in event.buttons: CurrentMousePos = event.pos diff = (CurrentMousePos[0] - LastFrameMousePos[0], CurrentMousePos[1] - LastFrameMousePos[1]) xRotation += event.rel[0] yRotation += event.rel[1] LastFrameMousePos = CurrentMousePos glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #Perform the rotation of the mesh moveToOrigin = np.array( [[1.0, 0.0, 0.0, -32.0], [0.0, 1.0, 0.0, -32.0], [0.0, 0.0, 1.0, -32.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') rotateAroundX = np.array( [[1.0, 0.0, 0.0, 0.0], [0.0, cos(radians(yRotation)), -sin(radians(yRotation)), 0.0], [0.0, sin(radians(yRotation)), cos(radians(yRotation)), 0.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') rotateAroundY = np.array( [[cos(radians(xRotation)), 0.0, sin(radians(xRotation)), 0.0], [0.0, 1.0, 0.0, 0.0], [-sin(radians(xRotation)), 0.0, cos(radians(xRotation)), 0.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') modelMatrix = rotateAroundY.dot(rotateAroundX.dot(moveToOrigin)) with shader: glUniformMatrix4fv(modelMatrixUnif, 1, GL_TRUE, modelMatrix) glBindVertexArray(vertexArrayObject) glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None) glBindVertexArray(0) # Show the screen pygame.display.flip()
def create_surface(rows, cols, size, fun, gen_textures, gen_relief=False): normals_vec = np.zeros((rows * cols, 3), dtype=np.float32) vertices_list = [] texcoords_list = [] faces_list = [] indices_list = [] if not gen_relief: for z in range(0, rows): for x in range(0, cols): xx = -size / 2 + x * size / cols zz = -size / 2 + z * size / rows try: yy = fun(xx, zz) if yy < -size / 2: yy = -size / 2 if yy > size / 2: yy = size / 2 except (ArithmeticError, ValueError): yy = 0.0 vertices_list.append([xx, yy, zz]) if gen_textures: texcoords_list.append( [x / float(cols - 1), z / float(rows - 1)]) else: buff1 = [] vertices_list_twodimensional = [] for z in range(0, rows): buff1.clear() for x in range(0, cols): xx = -size / 2 + x * size / cols zz = -size / 2 + z * size / rows yy = 0.0 buff1.append([xx, yy, zz]) vertices_list_twodimensional.append(buff1.copy()) for i in range(0, 150): radius = randint(1, 15) z = randint(0, rows - 1) x = randint(0, cols - 1) for iz in range(z - radius, z + radius): if iz < 0 or iz > rows - 1: continue else: for ix in range(x - radius, x + radius): if ix < 0 or ix > cols - 1: continue else: if 2 * radius**2 - ( (z - iz)**2 + (x - ix)**2 ) > vertices_list_twodimensional[iz][ix][1]**(2): vertices_list_twodimensional[iz][ix][1] = ( 2 * radius**2 - ((z - iz)**2 + (x - ix)**2))**(1 / 2) else: continue v = vertices_list_twodimensional.copy() vec_lines = [] for ii in range(0, 10): i = 2 * ii for z in range(0, rows - 1): for x in range(0, cols - 1): xx = -size / 2 + x * size / cols zz = -size / 2 + z * size / rows if v[z][x][1] < i and v[z][x + 1][1] < i and v[z + 1][x][1] < i and v[z + 1][x + 1][1] < i or \ v[z][x][1] >= i and v[z][x + 1][1] >= i and v[z + 1][x][1] >= i and v[z + 1][x + 1][1] >= i: continue elif v[z][x][1] >= i and v[z][x + 1][1] < i and v[ z + 1][x][1] < i and v[z + 1][x + 1][1] < i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] >= i and v[ z + 1][x][1] < i and v[z + 1][x + 1][1] < i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] < i and v[ z + 1][x][1] >= i and v[z + 1][x + 1][1] < i: vec_lines.append([xx + 0.25, i, zz + 0.5]) vec_lines.append([xx, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] < i and v[ z + 1][x][1] < i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz + 0.5]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] >= i and v[ z + 1][x][1] >= i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx, i, zz + 0.25]) elif v[z][x][1] >= i and v[z][x + 1][1] < i and v[ z + 1][x][1] >= i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] >= i and v[z][x + 1][1] >= i and v[ z + 1][x][1] < i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz + 0.5]) vec_lines.append([xx, i, zz + 0.25]) elif v[z][x][1] >= i and v[z][x + 1][1] >= i and v[ z + 1][x][1] >= i and v[z + 1][x + 1][1] < i: vec_lines.append([xx + 0.25, i, zz + 0.5]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] < i and v[z][x + 1][1] < i and v[z + 1][x][1] >= i and v[z + 1][x + 1][1] >= i or \ v[z][x][1] >= i and v[z][x + 1][1] >= i and v[z + 1][x][1] < i and v[z + 1][x + 1][1] < i: vec_lines.append([xx, i, zz + 0.25]) vec_lines.append([xx + 0.5, i, zz + 0.25]) elif v[z][x][1] >= i and v[z][x + 1][1] < i and v[z + 1][x][1] >= i and v[z + 1][x + 1][1] < i or \ v[z][x][1] < i and v[z][x + 1][1] >= i and v[z + 1][x][1] < i and v[z + 1][x + 1][1] >= i: vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx + 0.25, i, zz + 0.5]) elif v[z][x][1] >= i and v[z][x + 1][1] < i and v[z + 1][x][1] < i and v[z + 1][x + 1][1] >= i or \ v[z][x][1] < i and v[z][x + 1][1] >= i and v[z + 1][x][1] >= i and v[z + 1][x + 1][1] < i: vec_lines.append([xx, i, zz + 0.25]) vec_lines.append([xx + 0.25, i, zz]) vec_lines.append([xx + 0.5, i, zz + 0.25]) vec_lines.append([xx + 0.25, i, zz + 0.5]) index_lines = [it for it in range(0, len(vec_lines))] vector_lines = np.array(vec_lines, dtype=np.float32) vector_line_indexes = np.array(index_lines, dtype=np.uint32) for z in range(0, rows): for x in range(0, cols): vertices_list.append(vertices_list_twodimensional[z][x]) primRestart = rows * cols vertices_vec = np.array(vertices_list, dtype=np.float32) if gen_textures: texcoords_vec = np.array(texcoords_list, dtype=np.float32) for x in range(0, cols - 1): for z in range(0, rows - 1): offset = x * cols + z if z == 0: indices_list.append(offset) indices_list.append(offset + rows) indices_list.append(offset + 1) indices_list.append(offset + rows + 1) else: indices_list.append(offset + 1) indices_list.append(offset + rows + 1) if z == rows - 2: indices_list.append(primRestart) indices_vec = np.array(indices_list, dtype=np.uint32) currFace = 1 for i in range(0, indices_vec.size - 2): index0 = indices_vec[i] index1 = indices_vec[i + 1] index2 = indices_vec[i + 2] face = np.array([0, 0, 0], dtype=np.int32) if (index0 != primRestart) and (index1 != primRestart) and ( index2 != primRestart): if currFace % 2 != 0: face[0] = indices_vec[i] face[1] = indices_vec[i + 1] face[2] = indices_vec[i + 2] currFace += 1 else: face[0] = indices_vec[i] face[1] = indices_vec[i + 2] face[2] = indices_vec[i + 1] currFace += 1 faces_list.append(face) faces = np.reshape(faces_list, newshape=(len(faces_list), 3)) for i in range(0, faces.shape[0]): A = np.array([ vertices_vec[faces[i, 0], 0], vertices_vec[faces[i, 0], 1], vertices_vec[faces[i, 0], 2] ], dtype=np.float32) B = np.array([ vertices_vec[faces[i, 1], 0], vertices_vec[faces[i, 1], 1], vertices_vec[faces[i, 1], 2] ], dtype=np.float32) C = np.array([ vertices_vec[faces[i, 2], 0], vertices_vec[faces[i, 2], 1], vertices_vec[faces[i, 2], 2] ], dtype=np.float32) edge1A = normalize(B - A) edge2A = normalize(C - A) face_normal = np.cross(edge1A, edge2A) normals_vec[faces[i, 0]] += face_normal normals_vec[faces[i, 1]] += face_normal normals_vec[faces[i, 2]] += face_normal for i in range(0, normals_vec.shape[0]): normals_vec[i] = normalize(normals_vec[i]) vao = glGenVertexArrays(1) vbo_vertices = glGenBuffers(1) vbo_normals = glGenBuffers(1) if gen_textures: vbo_texcoords = glGenBuffers(1) vbo_indices = glGenBuffers(1) glBindVertexArray(vao) glBindBuffer(GL_ARRAY_BUFFER, vbo_vertices) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(vertices_vec), vertices_vec.flatten(), GL_STATIC_DRAW) # glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(0) glBindBuffer(GL_ARRAY_BUFFER, vbo_normals) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(normals_vec), normals_vec.flatten(), GL_STATIC_DRAW) # glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(1) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_indices) glBufferData(GL_ELEMENT_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(indices_vec), indices_vec.flatten(), GL_STATIC_DRAW) if gen_textures: glBindBuffer(GL_ARRAY_BUFFER, vbo_texcoords) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(texcoords_vec), texcoords_vec.flatten(), GL_STATIC_DRAW) # glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(2) glEnable(GL_PRIMITIVE_RESTART) glPrimitiveRestartIndex(primRestart) # der_z_y = lambda x,y,z: z * math.cos(y) # der_y_z = lambda x,y,z: y * math.cos(z) # der_x_z = lambda x,y,z: x * math.cos(z) # der_z_x = lambda x,y,z: z * math.cos(x) # der_y_x = lambda x,y,z: y * math.cos(x) # der_x_y = lambda x,y,z: x * math.cos(y) # rot = lambda x,y,z: math.sqrt( (der_z_y(x,y,z) - der_y_z(x,y,z))**2 + (der_x_z(x,y,z) - der_z_x(x,y,z))**2 + (der_y_x(x,y,z) - der_x_y(x,y,z))**2 ) # # # max and min of rot lengths # max_rot = 0 # min_rot = 0 # rott_lst = [] # for i in vertices_list: # # rott = rot(i[0], i[1], i[2]) # rott_lst.append(rott) glBindVertexArray(0) if gen_relief: return (vao, indices_vec.size, vector_lines, vector_line_indexes) else: return (vao, indices_vec.size)
def main(visualize): if args.config: config_path = args.config else: config_path = "config.yaml" with open(config_path) as file: config = yaml.load(file, Loader=yaml.FullLoader) teams, boxes, agents = generate_spatial_entities(config) agents_x_sorted = initial_sort(agents) if config["sotilaskoti"]["allow"]: # create queue to the sotilaskoti q = [] # table of meetings between agents, from the previous simulation step meets_prev = dict() if visualize: # verticies for area borders and inferred width and height of the map. # I.e. canvas contains map width and height in meters for computations fences_verts, canvas = generate_map(boxes, config) # verticies for traingles that represent agents agents_verts = generate_agents_verticies(config) if not glfw.init(): return window = glfw.create_window(config["window"][ "width"], config["window"]["height"], config["window"][ "title"], None, None) if not window: glfw.terminate() return glfw.make_context_current(window) # compile shader for on-the-fly configurable trianges shader = compile_shader() # create Buffer object in gpu VBO = glGenBuffers(2) # bind buffers glBindBuffer(GL_ARRAY_BUFFER, VBO[0]) glBufferData(GL_ARRAY_BUFFER, fences_verts.nbytes, fences_verts, GL_STATIC_DRAW) glBindBuffer(GL_ARRAY_BUFFER, VBO[1]) glBufferData(GL_ARRAY_BUFFER, agents_verts.nbytes, agents_verts, GL_STATIC_DRAW) fences_stride = fences_verts.strides[0] agents_stride = agents_verts.strides[0] # get the position from vertex shader # stride offset offset = ctypes.c_void_p(0) init_pos = glGetAttribLocation(shader, 'init_pos') glVertexAttribPointer(init_pos, 2, GL_FLOAT, GL_FALSE, agents_stride, offset) glEnableVertexAttribArray(init_pos) glUseProgram(shader) glClearColor(1.0, 1.0, 1.0, 1.0) """ Prepare directories to store: - source configuration files, - intermediate results in the form of meeting tables - output statistical reports """ if not os.path.exists("output"): os.makedirs("output") paths = { "configs" : os.path.join("output", "configs"), "meet_tables" : os.path.join("output", "meetings_tables"), "agents" : os.path.join("output", "agents"), "out_stats" : os.path.join("output", "stat_results"), } for path in paths.values(): if not os.path.exists(path): os.makedirs(path) if args.config: # in this usage scenario all identifiers are set manually # (unique tags are generated in meta-loop that launches these scripts) tag = args.name else: # in this usage scenario timestamp is autimatically appended to # distinguish between consequtive manual program launches timestamp = datetime.now().strftime("%H:%M:%S") tag = args.name +'_'+ timestamp # store the config file for the reference dump_config_path = os.path.join( paths["configs"], "config_"+ tag +".yaml") shutil.copy(config_path, dump_config_path) # store agents for the further move speed / infection spread correlating agents_souls_path = os.path.join( paths["agents"], "spatial_agents_"+ tag +".bin") with open(agents_souls_path, 'wb') as file: pickle.dump(agents, file) # create the file with agent meetings # originally a .bin file, is later compressed to the .bin.tar.bz2 format meets_table_path = os.path.join( paths["meet_tables"], "meet_table_"+ tag +".bin") with open(meets_table_path, 'wb') as file: # run until the end of the set simulation period T = config["simulationDuration"] * 24*60*60 dt = config[ "minSimulationStep"] eval_times = np.arange(0, T, dt) for eval_time in tqdm(eval_times): """ Transition agents between service and leave """ entities = (teams, boxes, agents) # some agents prefer to stay on the base during holidays stay_chance = config.get('dontGoOffDuty', 0.0) rotate_teams(entities, stay_chance, eval_time, dt) """ Transition agents to "Sotilaskoti" cafeteria and back """ if config["sotilaskoti"]["allow"]: queue_sotilaskoti(entities, q, eval_time, dt, config) """ Update agent positions (along one time step) """ increment_agent_positions(agents) """ Refresh the sorting of agents after the positions update """ x_sort(agents_x_sorted) """ Register new meetings between agents and export them to file """ meets_curr = detect_meetings(agents_x_sorted, eval_time, config, visualize) # each key is a meeting link between two agents # in the form {agent1_idx, agent2_idx} links_curr = set( meets_curr.keys() ) links_prev = set( meets_prev.keys() ) meets_new = dict() for link in links_curr: if link not in links_prev: meets_new[link] = meets_curr[link] if meets_new: timeline = {"timestamp" : eval_time, "meetings" : meets_new} pickle.dump(timeline, file) meets_prev = meets_curr """ Plot canvas if not specified otherwise (--no-visual option) """ if visualize: if glfw.window_should_close(window): break time_zero = time.time() glClear(GL_COLOR_BUFFER_BIT) """ Indicate current day in window title """ day_n = eval_time // (24*60*60) + 1 dayly_title = config["window"]["title"] +", day: "+ str(day_n) glfw.set_window_title(window, dayly_title) """ Draw borders (i.e. boxes, i.e. fences) - 1 px black outlines """ glBindBuffer(GL_ARRAY_BUFFER, VBO[0]) glVertexAttribPointer(init_pos, 2, GL_FLOAT, GL_FALSE, fences_stride, offset) glEnableVertexAttribArray(init_pos) transformLoc = glGetUniformLocation(shader, "dyn_pos") glUniform2f(transformLoc, 0.0, 0.0) transformLoc = glGetUniformLocation(shader, "dyn_color") glUniform4f(transformLoc, 0.0, 0.0, 0.0, 0.0) glDrawArrays(GL_TRIANGLES, 0, len(fences_verts)) """ Draw agents (i.e. conscripts and civilians) """ glBindBuffer(GL_ARRAY_BUFFER, VBO[1]) glVertexAttribPointer(init_pos, 2, GL_FLOAT, GL_FALSE, agents_stride, offset) glEnableVertexAttribArray(init_pos) for i, agent in enumerate(agents): poly_prop = np.zeros(1, [( "pos" , np.float32, 2), ("color", np.float32, 4)]) # absolute to relative coordinates, meters -> fractions x = (agent.x/canvas[ "width"]*2 - 1)*0.99 y = (agent.y/canvas["height"]*2 - 1)*0.99 poly_prop["pos"] = (x, y) transformLoc = glGetUniformLocation(shader, "dyn_pos") glUniform2f(transformLoc, *poly_prop["pos"].T) """ Agent triangle marker filling """ poly_prop["color"] = agent.color transformLoc = glGetUniformLocation(shader, "dyn_color") glUniform4f(transformLoc, *poly_prop["color"].T) if agent.conscripted: glDrawArrays(GL_TRIANGLES, 3, 6) else: glDrawArrays(GL_TRIANGLES, 0, 3) """ Marker outline """ transformLoc = glGetUniformLocation(shader, "dyn_color") glUniform4f(transformLoc, 0.0, 0.0, 0.0, 1.0) # black if agent.conscripted: glDrawArrays(GL_LINE_LOOP, 3, 6) else: glDrawArrays(GL_LINE_LOOP, 0, 3) glfw.swap_buffers(window) # FPS limited to 60 while(time.time() - time_zero < 1/60): time.sleep(0.001) glfw.poll_events() if visualize: glfw.terminate() """ Compress output file to save space """ compressed_path = os.path.join( paths["meet_tables"], "meet_table_"+ tag +".bin.tar.bz2") with tarfile.open(compressed_path, "w:bz2") as tar: tar.add(meets_table_path) # in case compressing went successful, remove the source file if os.path.exists(compressed_path): os.remove(meets_table_path)