def set_and_draw(self): """Setup the camera and draw""" # reset everything glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.pick_reset() self.shader_set() # skybox self.shader_set(self.shader_skybox) self.set_modelview_matrix( Mat4.rotate(math.radians(self.phi), 1, 0, 0) @ Mat4.rotate(math.radians(self.theta), 0, 0, 1) ) glDisable(GL_DEPTH_TEST) self.skybox.draw() glEnable(GL_DEPTH_TEST) self.shader_set() # set up camera self.set_modelview_matrix( Mat4.translate(0, 0, -1/self.zoom) @ Mat4.rotate(math.radians(self.phi), 1, 0, 0) @ Mat4.rotate(math.radians(self.theta), 0, 0, 1) ) self.draw() self.clear_pick_object()
def draw(self): """Draw the scene""" self.set_color(1, 1, 1, 1) self.add_pick_object("the sphere") glutSolidSphere(1, 16, 16) transform = self.modelview_matrix transform @= Mat4.translate(-4, -4, 0) self.set_modelview_matrix(transform) self.set_color(1, 0, 0, 1) self.add_pick_object("the cube") glutSolidCube(2) transform @= Mat4.translate(0, 8, 0) self.set_modelview_matrix(transform) self.set_color(1, 1, 0, 1) self.add_pick_object("the torus") glutSolidTorus(1, 2, 16, 16) transform @= Mat4.translate(8, 0, 0) self.set_modelview_matrix(transform) self.set_color(0, 0, 1, 1) self.add_pick_object("the cone") glutSolidCone(1, 2, 16, 16) transform @= Mat4.translate(0, -8, 0) @ Mat4.scale(.5, .5, .5) self.set_modelview_matrix(transform) self.set_color(0, 1, 1, 1) self.add_pick_object("the dodecahedron") glutSolidDodecahedron()
def set_and_draw(self): """Setup the camera and draw""" # reset everything glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.pick_reset() self.shader_set() # skybox self.shader_set(self.shader_skybox) self.set_modelview_matrix( Mat4.rotate(math.radians(self.phi), 1, 0, 0) @ Mat4.rotate( math.radians(self.theta), 0, 0, 1)) glDisable(GL_DEPTH_TEST) self.skybox.draw() glEnable(GL_DEPTH_TEST) self.shader_set() # set up camera self.set_modelview_matrix( Mat4.translate(0, 0, -1 / self.zoom) @ Mat4.rotate( math.radians(self.phi), 1, 0, 0) @ Mat4.rotate( math.radians(self.theta), 0, 0, 1)) self.draw() self.clear_pick_object()
def __init__(self, title=b'Scene'): # default settings self.zoom = .25 self.drag_active = False self.mouse_x = 0 self.mouse_y = 0 self.theta = 0 self.phi = -90 self.is_running = True # set to False for soft exit # GLUT init glutInit(sys.argv) glutInitContextVersion(3, 0) # 2.0 enough, 3.0 = forward compatiblity glutInitContextFlags(GLUT_FORWARD_COMPATIBLE | GLUT_DEBUG) glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE) glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS) glutInitWindowSize(1024, 768) glutCreateWindow(title) self.fullscreen = False # callbacks glutDisplayFunc(self.displayFunc) glutKeyboardFunc(self.keyboardFunc) glutSpecialFunc(self.specialFunc) glutReshapeFunc(self.reshapeFunc) glutMotionFunc(self.motionFunc) glutPassiveMotionFunc(self.passiveMotionFunc) glutMouseFunc(self.mouseFunc) glutCloseFunc(self.closeFunc) # OpenGL init glEnable(GL_CULL_FACE) # one-way faces glEnable(GL_DEPTH_TEST) glEnable(GL_BLEND) glEnable(GL_MULTISAMPLE) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glClearColor(0.0, 0.0, 0.0, 1.0) # use of VAO is required by OpenGL 3.2 core, so we use one if available if bool(glGenVertexArrays): # OpenGL 3.0 vao = glGenVertexArrays(1) glEnableVertexAttribArray(vao) glBindVertexArray(vao) # initialize textures gspyce.textures.init() # shader management program = main_program() self.default_shader = program self.current_shader = program glUseProgram(program) self.modelview_matrix = Mat4() self.projection_matrix = Mat4() self.set_color(1., 1., 1., 1.)
def __init__(self, orbit): self.orbit = orbit self.transform = ( Mat4.rotate(orbit.longitude_of_ascending_node, 0, 0, 1) @ Mat4.rotate(orbit.inclination, 1, 0, 0) @ Mat4.rotate(orbit.argument_of_periapsis, 0, 0, 1) @ Mat4.translate(-orbit.focus, 0, 0) @ Mat4.scale(orbit.semi_major_axis, orbit.semi_minor_axis, 1.0) ) super().__init__(GL_POINTS)
def draw(self): """Draw the scene""" self.set_modelview_matrix( self.modelview_matrix @ Mat4.rotate(radians(90), 1, 0, 0) @ # fixed-pipeline transforms in glutWireTeapot() (freeglut_teapot.c) Mat4.rotate(radians(270.0), 1, 0, 0) @ Mat4.scale(.5, .5, .5) @ Mat4.translate(0, 0, -1.5) ) glutWireTeapot(1)
def vertices(self): orbit = self.orbit # now, we fix the three issues mentioned above # draw the orbit from the body rather than from the orbit focus (1.) if orbit.eccentricity >= 1.: # open orbits # choose interpolation points def _(): true_anomaly = orbit.true_anomaly_at_time(self.time) # decide when to stop drawing max_true_anomaly = orbit.true_anomaly_at_escape() if max_true_anomaly is None: max_true_anomaly = orbit.ejection_angle() - 1e-2 # normal hyperbola n = 128 for i in range(n+1): t = 2.*i/n - 1 yield max_true_anomaly * t # ensure the body will be on the line (2.) # more points close to the camera (3.) n = 64 for i in range(n+1): t = 2.*i/n - 1 theta = true_anomaly + t * abs(t) if abs(theta) < max_true_anomaly: yield theta angles = sorted(_()) focus_offset = orbit.position_at_time(self.time) for angle in angles: yield orbit.position_at_true_anomaly(angle) - focus_offset else: # closed orbits # nice hack with circle symetry to draw the orbit from the body # while still using VBOs # unsure it can be adapted for parabolic and hyperbolic orbits # make tilted ellipse from a circle; and rotate at current anomaly anomaly = orbit.eccentric_anomaly_at_time(self.time) transform = ( Mat4.rotate(orbit.longitude_of_ascending_node, 0, 0, 1) @ Mat4.rotate(orbit.inclination, 1, 0, 0) @ Mat4.rotate(orbit.argument_of_periapsis, 0, 0, 1) @ Mat4.scale(orbit.semi_major_axis, orbit.semi_minor_axis, 1.0) @ Mat4.rotate(anomaly - math.pi, 0, 0, 1) ) # the first point of circle_through_origin is (0,0) (2.) # more points are located near the origin (3.) base_mesh = CircleThroughOrigin(1, 256) for vertice in base_mesh.vertices(): yield transform @ Vec4(*vertice)
def set_and_draw_hud(self): """Set up the camera and draw the HUD""" # save matrix state original_projection_matrix = self.projection_matrix original_modelview_matrix = self.modelview_matrix # set up matrices for HUD transform = Mat4.ortho(0.0, self.width, self.height, 0.0, -1.0, 10.0) self.set_projection_matrix(transform) self.set_modelview_matrix(Mat4()) # reset HUD self.texcoords = [] self.vertcoords = [] self.hud_grid(0, 1) # fill vertex lists self.draw_hud() program = self.current_shader # vertices var = glGetAttribLocation(program, "vertex") glEnableVertexAttribArray(var) self.text_vbo.fill(self.vertcoords) self.text_vbo.bind() glVertexAttribPointer(var, 2, GL_FLOAT, False, 0, None) self.text_vbo.unbind() # textures coordinates var = glGetAttribLocation(program, "texcoord") glEnableVertexAttribArray(var) self.text_tbo.fill(self.texcoords) self.text_tbo.bind() glVertexAttribPointer(var, 2, GL_FLOAT, False, 0, None) self.text_tbo.unbind() # actually draw self.set_color(1, 1, 1, 1) glBindTexture(GL_TEXTURE_2D, self.font) glDrawArrays(GL_TRIANGLES, 0, self.text_vbo.size // 2) glBindTexture(GL_TEXTURE_2D, 0) # restore state var = glGetAttribLocation(program, "texcoord") glDisableVertexAttribArray(var) var = glGetAttribLocation(program, "vertex") glDisableVertexAttribArray(var) self.set_modelview_matrix(original_modelview_matrix) self.set_projection_matrix(original_projection_matrix)
def set_and_draw(self): """Setup the camera and draw""" # reset everything glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.shader_set() # set camera self.set_modelview_matrix( Mat4.translate(0, 0, -1 / self.zoom) @ Mat4.rotate( radians(self.phi), 1, 0, 0) @ Mat4.rotate( radians(self.theta), 0, 0, 1)) # draw! self.draw()
def vertices(self): orbit = self.orbit transform = ( Mat4.rotate(orbit.longitude_of_ascending_node, 0, 0, 1) @ Mat4.rotate(orbit.inclination, 1, 0, 0) @ Mat4.rotate(orbit.argument_of_periapsis, 0, 0, 1) @ Mat4.translate(-orbit.focus, 0, 0) @ Mat4.scale(orbit.semi_major_axis, orbit.semi_minor_axis, 1.0) ) if orbit.eccentricity < 1.: base_mesh = Circle(1, 512) else: base_mesh = Parabola(256) for vertice in base_mesh.vertices(): yield transform @ Vec4(*vertice)
def set_and_draw(self): """Setup the camera and draw""" # reset everything glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) self.shader_set() # set camera self.set_modelview_matrix( Mat4.translate(0, 0, -1/self.zoom) @ Mat4.rotate(radians(self.phi), 1, 0, 0) @ Mat4.rotate(radians(self.theta), 0, 0, 1) ) # draw! self.draw()
def draw_body(self, body): """Draw a CelestialBody""" transform = ( self.modelview_matrix @ Mat4.translate(*body._relative_position) ) self.add_pick_object(body) # axial tilt if body.north_pole is not None: z_angle = body.north_pole.ecliptic_longitude - math.pi/2 transform @= Mat4.rotate(z_angle, 0, 0, 1) x_angle = body.north_pole.ecliptic_latitude - math.pi/2 transform @= Mat4.rotate(x_angle, 1, 0, 0) # OpenGL use single precision while Python has double precision # reducing modulo 2 PI in Python reduces loss of significance turn_fraction, _ = math.modf(self.time / body.rotational_period) transform @= Mat4.rotate(2 * math.pi * turn_fraction, 0, 0, 1) # radius transform @= Mat4.scale(body.radius, body.radius, body.radius) # textured quadric (representation from close by) # sphere with radius proportional to that of the body if body.texture: glBindTexture(GL_TEXTURE_2D, body.texture) else: original_color = self.color self.set_color(.5, .5, 1., 1.) original_modelview_matrix = self.modelview_matrix self.set_modelview_matrix(transform) self.sphere.draw() self.set_modelview_matrix(original_modelview_matrix) if body.texture: glBindTexture(GL_TEXTURE_2D, 0) else: self.set_color(*original_color) glDepthMask(True)
def draw_body(self, body): """Draw a CelestialBody""" transform = ( self.modelview_matrix @ Mat4.translate(*body._relative_position)) self.add_pick_object(body) # axial tilt if body.north_pole is not None: z_angle = body.north_pole.ecliptic_longitude - math.pi / 2 transform @= Mat4.rotate(z_angle, 0, 0, 1) x_angle = body.north_pole.ecliptic_latitude - math.pi / 2 transform @= Mat4.rotate(x_angle, 1, 0, 0) # OpenGL use single precision while Python has double precision # reducing modulo 2 PI in Python reduces loss of significance turn_fraction, _ = math.modf(self.time / body.rotational_period) transform @= Mat4.rotate(2 * math.pi * turn_fraction, 0, 0, 1) # radius transform @= Mat4.scale(body.radius, body.radius, body.radius) # textured quadric (representation from close by) # sphere with radius proportional to that of the body if body.texture: glBindTexture(GL_TEXTURE_2D, body.texture) else: original_color = self.color self.set_color(.5, .5, 1., 1.) original_modelview_matrix = self.modelview_matrix self.set_modelview_matrix(transform) self.sphere.draw() self.set_modelview_matrix(original_modelview_matrix) if body.texture: glBindTexture(GL_TEXTURE_2D, 0) else: self.set_color(*original_color) glDepthMask(True)
def reshapeFunc(self, width, height): """Handle window reshapings (GLUT callback)""" glViewport(0, 0, width, height) self.width = width self.height = height aspect = height / width near = .1 # see https://stackoverflow.com/a/16459424/4457767 self.set_projection_matrix( Mat4.frustrum(-near, near, -near * aspect, near * aspect, 2 * near, 1e7))
def reshapeFunc(self, width, height): """Handle window reshapings (GLUT callback)""" glViewport(0, 0, width, height) self.width = width self.height = height aspect = height / width near = .1 # see https://stackoverflow.com/a/16459424/4457767 self.set_projection_matrix( Mat4.frustrum(-near, near, -near*aspect, near*aspect, 2*near, 1e7) )
def draw_rocket(self): """Draw the rocket""" self.add_pick_object(self.rocket) # rocket orientation row1, row2, row3 = self.rocket.orientation orientation = Mat4([ [*row1, 0], [*row2, 0], [*row3, 0], [0, 0, 0, 1], ]) original_modelview_matrix = self.modelview_matrix transform = self.modelview_matrix @ \ Mat4.translate(*self.rocket._relative_position) @ \ Mat4.scale(1e4, 1e4, 1e4) @ \ orientation self.set_modelview_matrix(transform) # pick correct texture if self.rocket.throttle == 0: glBindTexture(GL_TEXTURE_2D, self.texture_rocket_off) else: glBindTexture(GL_TEXTURE_2D, self.texture_rocket_on) # draw texture glDisable(GL_CULL_FACE) self.set_color(1, 1, 1, 1) self.rocket_mesh.draw() glEnable(GL_CULL_FACE) # all done glBindTexture(GL_TEXTURE_2D, 0) self.set_modelview_matrix(original_modelview_matrix)
def draw(self): """Draw the scene""" # ancestors_descendants() can just be assumed to return all celestial # bodies, except that ancestors are in a separate list ancestors, descendants = ancestors_descendants(self.focus) bodies = ancestors + descendants # cache position of celestial bodies relative to the scene origin scene_origin = self.focus.global_position_at_time(self.time) for body in bodies: body_position = body.global_position_at_time(self.time) body._relative_position = body_position - scene_origin # draw celestial bodies # draw system star individually (without lighting) self.draw_body(self.system) # enable lighting and place light source self.shader_set(self.shader_lighting) x, y, z, _ = self.modelview_matrix @ self.system._relative_position glUniform3f(self.lighting_source, x, y, z) # draw planets and moons (with lighting) self.sphere.bind() for body in bodies: if body is self.system: continue self.draw_body(body) self.sphere.unbind() # clean self.shader_set() # draw circles around celestial bodies when from far away glPointSize(20) glDepthMask(False) self.shader_set(self.shader_position_marker) self.set_color(1, 0, 0, 0.5) self.clear_pick_object() points = (body._relative_position for body in bodies) gspyce.mesh.Generic(GL_POINTS, points).draw() self.shader_set() glDepthMask(True) # draw orbits glPointSize(5) self.set_color(1.0, 1.0, 0.0, 0.2) original_modelview_matrix = self.modelview_matrix for body in descendants: # skip ancestors (see below) self.set_modelview_matrix( original_modelview_matrix @ Mat4.translate(*body.orbit.primary._relative_position) ) self.add_pick_object(body) if not hasattr(body.orbit, "mesh"): body.orbit.mesh = gspyce.mesh.OrbitMesh(body.orbit) body.orbit.apses_mesh = gspyce.mesh.ApsesMesh(body.orbit) body.orbit.mesh.draw() body.orbit.apses_mesh.draw() self.set_modelview_matrix(original_modelview_matrix) # separately draw orbits of ancestors # since the focused celestial body and its ancestors are relatively # close to the camera, it is best to draw them with the origin the # orbit, rather than at the primary self.set_color(1.0, 1.0, 0.0, 1.0) for body in ancestors: if body.orbit is None: continue original_modelview_matrix = self.modelview_matrix self.set_modelview_matrix( self.modelview_matrix @ Mat4.translate(*body._relative_position) ) self.add_pick_object(body) gspyce.mesh.FocusedOrbitMesh(body.orbit, self.time).draw() gspyce.mesh.FocusedApsesMesh(body.orbit, self.time).draw() self.set_modelview_matrix(original_modelview_matrix)
def draw(self): """Draw the scene""" # ancestors_descendants() can just be assumed to return all celestial # bodies, except that ancestors are in a separate list ancestors, descendants = ancestors_descendants(self.focus) bodies = ancestors + descendants # cache position of celestial bodies relative to the scene origin scene_origin = self.focus.global_position_at_time(self.time) for body in bodies: body_position = body.global_position_at_time(self.time) body._relative_position = body_position - scene_origin # draw celestial bodies # draw system star individually (without lighting) self.draw_body(self.system) # enable lighting and place light source self.shader_set(self.shader_lighting) x, y, z, _ = self.modelview_matrix @ self.system._relative_position glUniform3f(self.lighting_source, x, y, z) # draw planets and moons (with lighting) self.sphere.bind() for body in bodies: if body is self.system: continue self.draw_body(body) self.sphere.unbind() # clean self.shader_set() # draw circles around celestial bodies when from far away glPointSize(20) glDepthMask(False) self.shader_set(self.shader_position_marker) self.set_color(1, 0, 0, 0.5) self.clear_pick_object() points = (body._relative_position for body in bodies) gspyce.mesh.Generic(GL_POINTS, points).draw() self.shader_set() glDepthMask(True) # draw orbits glPointSize(5) self.set_color(1.0, 1.0, 0.0, 0.2) original_modelview_matrix = self.modelview_matrix for body in descendants: # skip ancestors (see below) self.set_modelview_matrix( original_modelview_matrix @ Mat4.translate(*body.orbit.primary._relative_position)) self.add_pick_object(body) if not hasattr(body.orbit, "mesh"): body.orbit.mesh = gspyce.mesh.OrbitMesh(body.orbit) body.orbit.apses_mesh = gspyce.mesh.ApsesMesh(body.orbit) body.orbit.mesh.draw() body.orbit.apses_mesh.draw() self.set_modelview_matrix(original_modelview_matrix) # separately draw orbits of ancestors # since the focused celestial body and its ancestors are relatively # close to the camera, it is best to draw them with the origin the # orbit, rather than at the primary self.set_color(1.0, 1.0, 0.0, 1.0) for body in ancestors: if body.orbit is None: continue original_modelview_matrix = self.modelview_matrix self.set_modelview_matrix( self.modelview_matrix @ Mat4.translate(*body._relative_position)) self.add_pick_object(body) gspyce.mesh.FocusedOrbitMesh(body.orbit, self.time).draw() gspyce.mesh.FocusedApsesMesh(body.orbit, self.time).draw() self.set_modelview_matrix(original_modelview_matrix)