def __init__(self, filename: str, scale: vec3 = vec3(1.0)): super().__init__() self._filename = filename self._wavefront_vertices: glm.array self.scale = vec3(scale) self.vertices: glm.array self.normals: glm.array self.indices: glm.array self._store = Store() self.obj = pywavefront.Wavefront(self._store.find_path(filename)) for _, material in self.obj.materials.items(): v = material.vertices v = [v[i:i + 8] for i in range(0, len(v), 8)] self.vertices = glm.array([vec3(chunk[5:8]) * scale for chunk in v]) self.normals = glm.array([vec3(chunk[2:5]) for chunk in v]) self.indices = glm.array([u32vec3(i*3, i*3+1, i*3+2) for i in range(len(self.vertices) // 3)]) # only use first mesh break # create bbox self._bbox = BoundingBox(vec3(inf), vec3(-inf)) for v in self.vertices: self._bbox.vec3_extend(v)
def update_device_vaos(self) -> None: """Update VAO when device list changes.""" self._num_devices = len(self.core.devices) if self._num_devices > 0: scale = glm.scale(mat4(), vec3(3, 3, 3)) mats = glm.array([mat * scale for mat in self._devices]) cols = glm.array([ self.colors[i % len(self.colors)] for i in range(self._num_devices) ]) ids = glm.array(ctypes.c_int, *list(range(self._num_devices))) self._bind_vao_mat_col_id(self._vaos['camera'], mats, cols, ids)
def __init__(self, data_type, array_type=GL_ARRAY_BUFFER, max_size=10000): self._data_type = data_type self._array_type = array_type self._arr = glm.array(data_type()) * max_size self._index = 0 self._vbo = glGenBuffers(1) self._changed = True
def main(): # initializing glfw library if not glfw.init(): raise Exception("glfw can not be initialized!") # Configure the OpenGL context. # If we are planning to use anything above 2.1 we must at least # request a 3.3 core context to make this work across platforms. if "Windows" in pltf.platform(): glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 6) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True) else: glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 1) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True) # 4 MSAA is a good default with wide support glfw.window_hint(glfw.SAMPLES, 4) # creating the window window = glfw.create_window(1280, 720, "My OpenGL window", None, None) # check if window was created if not window: glfw.terminate() raise Exception("glfw window can not be created!") # Query the actual framebuffer size so we can set the right viewport later # -> glViewport(0, 0, framebuffer_size[0], framebuffer_size[1]) framebuffer_size = glfw.get_framebuffer_size(window) # set window's position glfw.set_window_pos(window, 100, 100) # make the context current glfw.make_context_current(window) # glClearColor(0.5, 0.5, 0.5, 1.0) print("GL_RENDERER = ", glGetString(GL_RENDERER).decode("utf8")) print("GL_VERSION = ", glGetString(GL_VERSION).decode("utf8")) # the main application loop while not glfw.window_should_close(window): glfw.poll_events() # glClear(GL_COLOR_BUFFER_BIT) COLOR = glm.array( glm.vec4([ glm.sin(glfw.get_time()) * 0.5 + 0.5, glm.cos(glfw.get_time()) * 0.5 + 0.5, 0.0, 1.0 ])) glClearBufferfv(GL_COLOR, 0, COLOR.ptr) glfw.swap_buffers(window) # terminate glfw, free up allocated resources glfw.terminate()
def get_cylinder_vertices( cylinder: CylinderObject3D, sides: int) -> Tuple[glm.array, glm.array, glm.array]: """Get vertices, normals, and indices for a cylinder object. Args: cylinder: A CylinderObject3D. sides: An int representing the number of sides per circle. """ # faster way to calculate points along a circle theta = 2.0 * math.pi / sides tan_factor = tan(theta) rad_factor = cos(theta) x = vec3(cylinder.radius, 0.0, 0.0) vertices = [] for i in range(sides): vertices.append(vec3(0.0, 0.0, 0.0) + x) vertices.append(vec3(0.0, 0.0, cylinder.height) + x) delta = vec3(x[1] * tan_factor, -x[0] * tan_factor, 0.0) x = (x + delta) * rad_factor vertices.append(vec3(0.0, 0.0, 0.0)) vertices.append(vec3(0.0, 0.0, cylinder.height)) normals = [] for i in range(len(vertices)): n = vec3(vertices[i].x, vertices[i].y, 0.0) * mat3( cylinder.trans_matrix) normals.append(glm.normalize(n)) vertices[i] = vec3(vec4(vertices[i], 1.0) * cylinder.trans_matrix) normals[-2] = vec3(0.0, 0.0, -1.0) * mat3(cylinder.trans_matrix) normals[-1] = vec3(0.0, 0.0, 1.0) * mat3(cylinder.trans_matrix) indices = [] for i in range(0, sides * 2, 2): i2 = (i + 2) % (2 * sides) i3 = (i + 3) % (2 * sides) indices.extend((u32vec3(i, i + 1, i2), u32vec3(i + 1, i3, i2), u32vec3(2 * sides, i, i2), u32vec3(2 * sides + 1, i3, i + 1))) return glm.array(vertices), glm.array(normals), glm.array(indices)
def create_vaos(self) -> None: """Bind VAOs to define vertex data.""" vbo = glGenBuffers(1) # initialize camera box # TODO: update to obj file vertices = glm.array( vec3(-1.0, -0.5, -1.0), # bottom vec3(-1.0, -0.5, 1.0), vec3(-1.0, 0.5, 1.0), vec3(-1.0, 0.5, -1.0), vec3(1.0, -0.5, -1.0), # right vec3(-1.0, -0.5, -1.0), vec3(-1.0, 0.5, -1.0), vec3(1.0, 0.5, -1.0), vec3(1.0, -0.5, 1.0), # top vec3(1.0, -0.5, -1.0), vec3(1.0, 0.5, -1.0), vec3(1.0, 0.5, 1.0), vec3(-1.0, -0.5, 1.0), # left vec3(1.0, -0.5, 1.0), vec3(1.0, 0.5, 1.0), vec3(-1.0, 0.5, 1.0), vec3(1.0, 0.5, -1.0), # back vec3(-1.0, 0.5, -1.0), vec3(-1.0, 0.5, 1.0), vec3(1.0, 0.5, 1.0), vec3(-1.0, -0.5, -1.0), # front vec3(1.0, -0.5, -1.0), vec3(1.0, -0.5, 1.0), vec3(-1.0, -0.5, 1.0), ) glBindBuffer(GL_ARRAY_BUFFER, vbo) glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices.ptr, GL_STATIC_DRAW) self._vaos['box'] = glGenVertexArrays(1) glBindVertexArray(self._vaos['box']) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0)) glEnableVertexAttribArray(0) self._vaos['camera'] = glGenVertexArrays(1) glBindVertexArray(self._vaos['camera']) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0)) glEnableVertexAttribArray(0)
def __init__(self, start: vec3, end: vec3, radius: float): super().__init__() self.start: vec3 = vec3(start) self.end: vec3 = vec3(end) self.radius: float = radius self.height: float = glm.distance(self.start, self.end) self.normal: vec3 = glm.normalize(self.end - self.start) self.b1: vec3 self.b2: vec3 self.b1, self.b2 = orthonormal_basis_of(self.normal) # calculate rotation matrix for cylinder self.trans_matrix: mat4 = glm.orientation(vec3(0.0, 0.0, 1.0), self.normal) # add translation to matrix self.trans_matrix[0][3] = start.x self.trans_matrix[1][3] = start.y self.trans_matrix[2][3] = start.z # get corners of OBB points = glm.array( vec3(self.radius, self.radius, 0.0), vec3(-self.radius, self.radius, 0.0), vec3(self.radius, -self.radius, 0.0), vec3(-self.radius, -self.radius, 0.0), vec3(self.radius, self.radius, self.height), vec3(-self.radius, self.radius, self.height), vec3(self.radius, -self.radius, self.height), vec3(-self.radius, -self.radius, self.height)) # inflate OBB into AABB # TODO: # BoundingBox _should_ have default values - we shouldn't have to # initialize with inf and -inf manually. but if we do that, # it seems to initialize with other BoundingBox's values. # Something weird is going on with (I presume) glm pointers? self._bbox = BoundingBox(vec3(inf), vec3(-inf)) for v in points: self._bbox.vec3_extend(vec3(vec4(v, 1.0) * self.trans_matrix))
def update_action_vaos(self) -> None: """Update VAOs when action list changes.""" self._vaos['line'].clear() self._vaos['point'].clear() # --- bind data for lines --- for key, value in self._items['line'].items(): # ignore if 1 or fewer points if len(value) <= 1: continue points = glm.array([vec3(mat[1][3]) for mat in value]) vbo = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, vbo) glBufferData(GL_ARRAY_BUFFER, points.nbytes, points.ptr, GL_STATIC_DRAW) vao = glGenVertexArrays(1) glBindVertexArray(vao) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, ctypes.c_void_p(0)) glEnableVertexAttribArray(0) self._vaos['line'][key] = vao glBindVertexArray(0) # --- bind data for points --- point_mats: glm.array = None point_cols: glm.array = None point_ids: glm.array = None scale = glm.scale(mat4(), vec3(3, 3, 3)) for key, value in self._items['point'].items(): new_mats = glm.array([p[1] * scale for p in value]) color = shade_color(vec4(self.colors[key % len(self.colors)]), -0.3) new_cols = glm.array([color] * len(value)) # if point is selected, darken its color for i, v in enumerate(value): # un-offset ids if (v[0] - self._num_devices) in self.core.selected_points: new_cols[i] = shade_color(vec4(new_cols[i]), 0.6) new_ids = glm.array.from_numbers(ctypes.c_int, *(p[0] for p in value)) point_mats = new_mats if point_mats is None else point_mats.concat( new_mats) point_cols = new_cols if point_cols is None else point_cols.concat( new_cols) point_ids = new_ids if point_ids is None else point_ids.concat( new_ids) # we're done if no points to set if not self._items['point']: return self._num_points = sum(len(i) for i in self._items['point'].values()) self._bind_vao_mat_col_id(self._vaos['box'], point_mats, point_cols, point_ids)
def get_aabb_vertices( aabb: AABBObject3D) -> Tuple[glm.array, glm.array, glm.array]: """Get vertices, normals, and indices for an axis-aligned box object. Args: cylinder: An AABBObject3D. """ vertices = glm.array( vec3(aabb.upper.x, aabb.lower.y, aabb.upper.z), # front vec3(aabb.lower.x, aabb.lower.y, aabb.upper.z), vec3(aabb.lower.x, aabb.lower.y, aabb.lower.z), vec3(aabb.upper.x, aabb.lower.y, aabb.lower.z), vec3(aabb.upper.x, aabb.upper.y, aabb.upper.z), # top vec3(aabb.lower.x, aabb.upper.y, aabb.upper.z), vec3(aabb.lower.x, aabb.lower.y, aabb.upper.z), vec3(aabb.upper.x, aabb.lower.y, aabb.upper.z), vec3(aabb.upper.x, aabb.upper.y, aabb.upper.z), # right vec3(aabb.upper.x, aabb.lower.y, aabb.upper.z), vec3(aabb.upper.x, aabb.lower.y, aabb.lower.z), vec3(aabb.upper.x, aabb.upper.y, aabb.lower.z), vec3(aabb.lower.x, aabb.lower.y, aabb.lower.z), # bottom vec3(aabb.lower.x, aabb.upper.y, aabb.lower.z), vec3(aabb.upper.x, aabb.upper.y, aabb.lower.z), vec3(aabb.upper.x, aabb.lower.y, aabb.lower.z), vec3(aabb.lower.x, aabb.lower.y, aabb.lower.z), # left vec3(aabb.lower.x, aabb.lower.y, aabb.upper.z), vec3(aabb.lower.x, aabb.upper.y, aabb.upper.z), vec3(aabb.lower.x, aabb.upper.y, aabb.lower.z), vec3(aabb.upper.x, aabb.upper.y, aabb.upper.z), # back vec3(aabb.upper.x, aabb.upper.y, aabb.lower.z), vec3(aabb.lower.x, aabb.upper.y, aabb.lower.z), vec3(aabb.lower.x, aabb.upper.y, aabb.upper.z), ) normals = glm.array( vec3(0.0, -1.0, 0.0), # front vec3(0.0, -1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), # top vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), # right vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(0.0, 0.0, -1.0), # bottom vec3(0.0, 0.0, -1.0), vec3(0.0, 0.0, -1.0), vec3(0.0, 0.0, -1.0), vec3(-1.0, 0.0, 0.0), # left vec3(-1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), # back vec3(0.0, 1.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 1.0, 0.0), ) indices = glm.array( u32vec3(0, 1, 2), # front u32vec3(2, 3, 0), u32vec3(4, 5, 6), # top u32vec3(6, 7, 4), u32vec3(8, 9, 10), # right u32vec3(10, 11, 8), u32vec3(12, 13, 14), # bottom u32vec3(14, 15, 12), u32vec3(16, 17, 18), # left u32vec3(18, 19, 16), u32vec3(20, 21, 22), # back u32vec3(22, 23, 20), ) return vertices, normals, indices
for args in gen_args("#uM{C}{R}".format(C=C, R=R) + "V{R}".format(R=R)*C + "_" + "_".join(["M{C}{R}M{c}{r}".format(C=C, R=R, c=c, r=r) for c in range(2, 5) for r in range(2,5)]) + "__fFiI"): fassert(type(args[0]), args[1:]) ## quat for args in gen_args("#u-_V3_M33_M44_NV3_V3V3_NNNN_Q__f"): # need support for conversion constructors fassert(glm.quat, args) ## dquat for args in gen_args("#u-_V3_M33_M44_NV3_V3V3_NNNN_Q__F"): # need support for conversion constructors fassert(glm.dquat, args) ## array for args in gen_args("V_M_Q_VV_MM_QQ_VVV_MMM_QQQ"): fassert(glm.array, args) assert glm.array([glm.vec4() for x in range(10)]) assert glm.array(tuple([glm.vec4() for x in range(10)])) assert glm.array({x : glm.vec4() for x in range(10)}.values()) assert glm.array(memoryview(glm.array([glm.vec4() for x in range(10)]))) assert glm.array([glm.quat() for x in range(10)]) assert glm.array(tuple([glm.quat() for x in range(10)])) assert glm.array({x : glm.quat() for x in range(10)}.values()) assert glm.array(memoryview(glm.array([glm.quat() for x in range(10)]))) assert glm.array([glm.mat4() for x in range(10)]) assert glm.array(tuple([glm.mat4() for x in range(10)])) assert glm.array({x : glm.mat4() for x in range(10)}.values()) assert glm.array(memoryview(glm.array([glm.mat4() for x in range(10)]))) arr = glm.array(glm.mat4(), glm.mat4(2))
def __init__(self, a = 1.0, b = 1.0, c = 1.0): # 编译着色器 self.shaderProgram = compileProgram( compileShader(vertexShaderSource, GL_VERTEX_SHADER), compileShader(fragmentShaderSource, GL_FRAGMENT_SHADER) ) self.transformIndex = glGetUniformLocation(self.shaderProgram, "transform") # self.textureIndex = glGetUniformLocation(self.shaderProgram, "myTexture") # 链接顶点属性 a2, b2, c2 = a / 2.0, b / 2.0, c / 2.0 vertices = [ -a2, -c2, -b2, 0.0, 0.0, a2, -c2, -b2, 1.0, 0.0, a2, c2, -b2, 1.0, 1.0, a2, c2, -b2, 1.0, 1.0, -a2, c2, -b2, 0.0, 1.0, -a2, -c2, -b2, 0.0, 0.0, -a2, -c2, b2, 0.0, 0.0, a2, -c2, b2, 1.0, 0.0, a2, c2, b2, 1.0, 1.0, a2, c2, b2, 1.0, 1.0, -a2, c2, b2, 0.0, 1.0, -a2, -c2, b2, 0.0, 0.0, -a2, c2, b2, 1.0, 0.0, -a2, c2, -b2, 1.0, 1.0, -a2, -c2, -b2, 0.0, 1.0, -a2, -c2, -b2, 0.0, 1.0, -a2, -c2, b2, 0.0, 0.0, -a2, c2, b2, 1.0, 0.0, a2, c2, b2, 1.0, 0.0, a2, c2, -b2, 1.0, 1.0, a2, -c2, -b2, 0.0, 1.0, a2, -c2, -b2, 0.0, 1.0, a2, -c2, b2, 0.0, 0.0, a2, c2, b2, 1.0, 0.0, -a2, -c2, -b2, 0.0, 1.0, a2, -c2, -b2, 1.0, 1.0, a2, -c2, b2, 1.0, 0.0, a2, -c2, b2, 1.0, 0.0, -a2, -c2, b2, 0.0, 0.0, -a2, -c2, -b2, 0.0, 1.0, -a2, c2, -b2, 0.0, 1.0, a2, c2,-b2, 1.0, 1.0, a2, c2, b2, 1.0, 0.0, a2, c2, b2, 1.0, 0.0, -a2, c2, b2, 0.0, 0.0, -a2, c2,-b2, 0.0, 1.0 ] # vertexData = glm.array([glm.float32(vertex) for vertex in vertices]) vertexData = glm.array(glm.float32, *vertices) vertexBuffer = glGenBuffers(1) # VBO 顶点缓冲数据 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer) glBufferData(GL_ARRAY_BUFFER, vertexData.nbytes, vertexData.ptr, GL_STATIC_DRAW) # 只有array有这个nbytes和ptr self.vertexArray = glGenVertexArrays(1) # VAO 顶点数组对象 glBindVertexArray(self.vertexArray) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), ctypes.c_void_p(0)) # 最后一个参数必须强制转换为void* # https://github.com/mcfletch/pyopengl/issues/3 glEnableVertexAttribArray(0) glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), ctypes.c_void_p(3 * sizeof(GLfloat))) glEnableVertexAttribArray(1) glBindVertexArray(0) # 用完别忘解绑 # 设置纹理贴图 image = Image.open("box.png") width, height = image.size raw_image = image.tobytes("raw", "RGBA") self.texture = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, self.texture) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) # 重复边缘 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) # 临近插值 # glPixelStorei(GL_UNPACK_ALIGNMENT, 1) # 默认4字节对齐, 可以改成1或者用RGBA glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, raw_image) # glPixelStorei(GL_UNPACK_ALIGNMENT, 4) glBindTexture(GL_TEXTURE_2D, 0) # 初始化一下变换矩阵 self.rorate(0, 0, 0)