import pyscene scene = pyscene.pyscene() import osg, osgDB import math, re, os scene.setScale(5e4, 0.5) scene.viewer.getCamera().setClearColor(osg.Vec4f(0, 0, 0, 0)) mars = scene.readNodeFile("mars.osg") # make the north pole face up instead of down mars_trans = osg.MatrixTransform() mars_trans.postMult( osg.Matrixd.rotate( math.radians(180), 1, 0, 0 ) ) # and position the planet with the meridian facing the camera mars_trans.postMult( osg.Matrixd.rotate( math.radians(180), 0, 0, 1 ) ) mars_trans.addChild(mars) # make it blend (http://www.palomino3d.org/pal/openscenegraph/) GL_BLEND=3042 GL_DEPTH_TEST=2929 GL_LIGHTING=2896 trans_state = osg.StateSet() trans_state.setMode(GL_BLEND, osg.StateAttribute.ON) trans_state.setRenderingHint(osg.StateSet.TRANSPARENT_BIN) trans_state.setMode(GL_DEPTH_TEST, osg.StateAttribute.OFF) trans_state.setMode(GL_LIGHTING, osg.StateAttribute.OFF) trans = 0.15 for radius in 6.4, 6.45, 6.5, 6.6, 6.7, 6.75 : trans /= 1.5 atmo = osg.Sphere( osg.Vec3f(0, 0, 0), radius * 1e6 ) atmo_drawable = osg.ShapeDrawable(atmo) atmo_drawable.setColor( osg.Vec4f(0.76, 0.54, 0.37, trans) ) atmo_geode = osg.Geode() atmo_geode.addDrawable(atmo_drawable) atmo_drawable.setStateSet(trans_state) mars_trans.addChild(atmo_geode) scene.addChild(mars_trans) def plot_coord(lat, lon, image=None, flag=None) : """ Plot a coordinate on the globe with a pin and a billboard that changes its opacity based on the viewer's location """ geode = osg.Geode() cone = osg.Cone( osg.Vec3f(0, 0, 6.7e6), 3e4, -0.3e6 ) cone_drawable = osg.ShapeDrawable(cone) cone_drawable.setColor( osg.Vec4f(1, 0, 0, 1) ) geode.addDrawable(cone_drawable) sphere = osg.Sphere( osg.Vec3f(0, 0, 6.775e6), 3e4 ) sphere_drawable = osg.ShapeDrawable(sphere) sphere_drawable.setColor( osg.Vec4f(1, 0, 0, 0.5) ) geode.addDrawable(sphere_drawable) # Use negative dimensions on the Box to trick out plane-like behaviour board = osg.Box( osg.Vec3f(0, 0, 7.2e6), -5e5 * 1.6, -1e3, 5e5 ) board_drawable = osg.ShapeDrawable(board) bb = osg.Billboard() bb.setNormal( osg.Vec3f(0, 1, 0) ) bb.addDrawable(board_drawable) texture = osg.Texture2D() if isinstance(image, str) : im = osgDB.readImageFile(image) texture.setImage(im) state = osg.StateSet(trans_state) bb.setStateSet(state) depth = osg.Depth() depth.setWriteMask(True) state.setAttributeAndModes(depth, osg.StateAttribute.ON) state.setTextureAttributeAndModes(0, texture, osg.StateAttribute.ON) pin_trans = osg.MatrixTransform() pin_trans.addChild(geode) pin_trans.addChild(bb) pin_trans.postMult( osg.Matrixd.rotate( math.radians(90.0 + lat), 1, 0, 0 ) ) pin_trans.postMult( osg.Matrixd.rotate( math.radians(lon - 90.0), 0, 0, 1 ) ) position = pin_trans.getMatrix() * osg.Vec3d(0, 0, 7.2e6) flag_drawable = None if isinstance(flag, str) : flag_im = osgDB.readImageFile(flag) flag_texture = osg.Texture2D() flag_texture.setImage(flag_im) flag_board = osg.Box( osg.Vec3f( -683.0 / 2 * 5e5 / 512, 1e3, 7.2e6 + (512.0 - 50.0 - 20.0) / 2 * 5.0e5 / 512, ), -100.0 * 5.0e5 / 512, -1e3, 50.0 * 5.0e5 / 512, ) flag_drawable = osg.ShapeDrawable(flag_board) flag_bb = osg.Billboard() flag_bb.setNormal( osg.Vec3f(0, 1, 0) ) flag_bb.addDrawable(flag_drawable) flag_state = osg.StateSet(trans_state) flag_bb.setStateSet(flag_state) flag_state.setAttributeAndModes(depth, osg.StateAttribute.ON) flag_state.setTextureAttributeAndModes( 0, flag_texture, osg.StateAttribute.ON ) pin_trans.addChild(flag_bb) return { "board_drawable" : board_drawable, "flag_drawable" : flag_drawable, "position" : position, "trans" : pin_trans, } labels = { "Olympus Mons" : plot_coord( 18.4, -134, "images/olympus_mons.png", ), "Arsia Mons" : plot_coord( -9.5, -120.5, "images/arsia_mons.png" ), "Ascraeus Mons" : plot_coord( 11.3, -104.5, "images/ascraeus_mons.png" ), "Pavonis Mons" : plot_coord( 0.8, -113.4, "images/pavonis_mons.png" ), "Cydonia Mensae" : plot_coord( 40.7, -170.2, "images/cydonia_mensae.png" ), "Phoenix Lander" : plot_coord( 68, 234, "images/phoenix_lander.png", "images/usa.png", ), "Spirit Rover" : plot_coord( -14.6, 175.5, "images/spirit_rover.png", "images/usa.png", ), "Opportunity Rover" : plot_coord( -1.9, 354.5, "images/opportunity_rover.png", "images/usa.png", ), "Sojourner Rover" : plot_coord( 19.1, -33.2, "images/sojourner_rover.png", "images/usa.png", ), "Viking 1 Lander" : plot_coord( 22.7, -48.2, "images/viking_1_lander.png", "images/usa.png", ), "Viking 2 Lander" : plot_coord( 48.3, -226.0, "images/viking_2_lander.png", "images/usa.png", ), "Mars 2 Lander" : plot_coord( 4, -47, "images/mars_2_lander.png", "images/ussr.png", ), "Mars 3 Lander" : plot_coord( -45, -158, "images/mars_3_lander.png", "images/ussr.png", ), } for value in labels.itervalues() : mars_trans.addChild(value["trans"]) scene.setLighting(False) def label_proximity(self, nv, node) : for (key, value) in labels.iteritems() : d = ( osg.Matrixd.inverse( mars_trans.getMatrix() ) * value["position"] - self.getPosition() ).length() if d > 2e7 : d = 0 else : d = (1 - d / 2e7) ** 2 * 3 color = osg.Vec4f(1, 1, 1, d) labels[key]["board_drawable"].setColor(color) if labels[key]["flag_drawable"] : labels[key]["flag_drawable"].setColor(color) scene.addCallback(label_proximity) scene.planet_velocity = osg.Matrixd() def spin_planet(self, nv, node) : mars_trans.postMult(scene.planet_velocity) scene.addCallback(spin_planet) def button_handler(self, event) : if event["mode"] != "button" : return r = osg.Matrixd.inverse( osg.Matrixd.rotate( self.getViewMatrix().getRotate() ) ) if event["data"][0] == 9 : scene.planet_velocity = osg.Matrixd() elif event["data"][1] == "released" and event["data"][0] in range(4) : scene.planet_velocity = osg.Matrixd() elif event["data"][0] in [ 0, 4 ] : scene.planet_velocity = osg.Matrixd.rotate( math.radians(0.1), r * osg.Vec3d(0, 1, 0) ) elif event["data"][0] == 1 : scene.planet_velocity = osg.Matrixd.rotate( math.radians(0.1), r * osg.Vec3d(1, 0, 0) ) elif event["data"][0] in [ 2, 5 ] : scene.planet_velocity = osg.Matrixd.rotate( math.radians(0.1), r * osg.Vec3d(0, -1, 0) ) elif event["data"][0] == 3 : scene.planet_velocity = osg.Matrixd.rotate( math.radians(0.1), r * osg.Vec3d(-1, 0, 0) ) scene.add_vrpn_handler("mars_buttons", button_handler) scene.postMult( osg.Matrixd.translate(0, 0, 3e7) ) scene.ds.setEyeSeparation(0.001) coordinates = [ (-6.209900, -99.394042, 0), (-6.642782, -92.307128, 0), (-7.079088, -84.440917, 0), (-8.537565, -77.255859, 0), (-10.639013, -70.620117, 0), (-13.304102, -60.644531, 0), (-14.753635, -56.381835, 0), (-15.199386, -50.009765, 0), (-13.432366, -41.352539, 0), (-5.244127, -36.079101, 0), (2.591888, -33.156738, 0), ] def build_links(n=0) : if not coordinates[n:] : return None lat, lon, elev = coordinates[n] point_trans = osg.MatrixTransform() point_trans.postMult( osg.Matrixd.translate(0, 0, 7e6 + elev) ) point_trans.postMult( osg.Matrixd.rotate( math.radians(90.0 + lat), 1, 0, 0 ) ) point_trans.postMult( osg.Matrixd.rotate( math.radians(lon - 90.0), 0, 0, 1 ) ) sphere = osg.Sphere(osg.Vec3f(), 5e4) drawable = osg.ShapeDrawable(sphere) drawable.setColor( osg.Vec4f(0.76, 0.54, 0.37, 0.5) ) geode = osg.Geode() geode.addDrawable(drawable) point_trans.addChild(geode) mars_trans.addChild(point_trans) m = point_trans.getMatrix().getTrans() point = osg.Vec3f(m[0], m[1], m[2]) return { "geode" : geode, "drawable" : drawable, "bound" : osg.BoundingSphere(point, 5e5), "next" : build_links(n+1), } scene.links = build_links() scene.link = scene.links def link_path(self, nv, node) : v = osg.Matrixd.inverse( mars_trans.getMatrix() ) * self.getPosition() v = osg.Vec3f(v[0], v[1], v[2]) if self.link["bound"].contains(v) : print "bound" self.link["drawable"].setColor( osg.Vec4f(0.8, 0.2, 0.2, 0.5) ) self.link = self.link["next"] if not self.link : print "none" self.link = self.links return c = self.link["bound"].center() p = self.getPosition() velocity = osg.Vec3f(p[0], p[1], p[2]) - c #velocity = v - c velocity = osg.Vec3d( velocity[0] / 5e2, velocity[1] / 5e2, velocity[2] / -5e2, ) self.velocity = osg.Matrixd.translate(velocity) #self.getPosition() - osg.Vec3d(c[0], c[1], c[2]) scene.addCallback(link_path) scene.run()