Skip to content

Instantly share code, notes, and snippets.

@ashumeow
Last active August 29, 2015 14:25
Show Gist options
  • Save ashumeow/ccd95e08a1ab1c407a01 to your computer and use it in GitHub Desktop.
Save ashumeow/ccd95e08a1ab1c407a01 to your computer and use it in GitHub Desktop.

Revisions

  1. James Halliday created this gist Apr 21, 2011.
    301 changes: 301 additions & 0 deletions mars.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,301 @@
    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()