Ejemplo n.º 1
0
def main(argv):

    
    # use an ArgumentParser object to manage the program arguments.
    arguments = osg.ArgumentParser(argv)
    arguments.getApplicationUsage().addKeyboardMouseBinding("m", "Increase the number of depth peeling layers")
    arguments.getApplicationUsage().addKeyboardMouseBinding("n", "Decrease the number of depth peeling layers")
    arguments.getApplicationUsage().addKeyboardMouseBinding("l", "Toggle display of the individual or composed layer textures")
    arguments.getApplicationUsage().addKeyboardMouseBinding("p", "Increase the layer offset")
    arguments.getApplicationUsage().addKeyboardMouseBinding("o", "Decrease the layer offset")

    # Have the usual viewer
    viewer = osgViewer.Viewer(arguments)

    displaySettings = osg.DisplaySettings()
    viewer.setDisplaySettings(displaySettings)
   
    # Add the stats handler
    viewer.addEventHandler(osgViewer.StatsHandler)()
   
    # add the help handler
    viewer.addEventHandler(osgViewer.HelpHandler(arguments.getApplicationUsage()))

    # any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized()
   
    # read the dump truck, we will need it twice
    dt = osgDB.readNodeFile("dumptruck.osg")

    # display a solid version of the dump truck
    solidModel = osg.PositionAttitudeTransform()
    solidModel.setPosition(osg.Vec3f(7.0, -2.0, 7.0))
    solidModel.addChild(dt)

    # generate the 3D heatmap surface to display
    hm = Heatmap(30, 30, 10, 30, 30, 1.0, 0.25)
    float data[30][30]
    for (int x=0 x < 30 ++x)
        for (int y=0 y < 30 ++y)
            data[y][x] = (double)rand() / RAND_MAX
Ejemplo n.º 2
0
def main(argv):
    # use an ArgumentParser object to manage the program arguments.
    viewer = osgViewer.Viewer()
#    viewer.setThreadingModel(osgViewer.Viewer.SingleThreaded)

    # read the scene from the list of file specified commandline args.
    loadedModel = osgDB.readNodeFile("cessna.osg")
    if loadedModel == None:
        raise Exception('Could not load model file (is OSG_FILE_PATH set and correct?)')

    # create a transform to spin the model.
    loadedModelTransform = osg.MatrixTransform()
    loadedModelTransform.addChild(loadedModel)

    print loadedModelTransform.getBound()._center
#todo:    nc = osg.AnimationPathCallback(loadedModelTransform.getBound()._center,osg.Vec3(0.0,0.0,1.0),osg.inDegrees(45.0));
#    loadedModelTransform.setUpdateCallback(nc)

    rootNode = osg.Group()
    rootNode.stateSet.dataVariance = osg.Object.DYNAMIC
    rootNode.addChild(createMirroredScene(loadedModelTransform))

    viewer.addEventHandler(osgViewer.HelpHandler())
    viewer.addEventHandler(osgViewer.StatsHandler())
    viewer.addEventHandler(osgGA.StateSetManipulator(rootNode.stateSet))
    viewer.setSceneData(rootNode)
    print "set scene data"

    #hint to tell viewer to request stencil buffer when setting up windows
    # osg.DisplaySettings().setMinimumNumStencilBits(8)
    osg.DisplaySettings.instance().setMinimumNumStencilBits(8);

    osgDB.writeNodeFile(rootNode, "test_reflect.osg");

    viewer.run() #we need run, because that sets up a trackballmanipulator and so we have the correct "look" into the scene.
    return 0
Ejemplo n.º 3
0
# Create a 1x1 quad in XZ plane
g = osg.createTexturedQuadGeometry(osg.Vec3f(0, 0, 0), osg.Vec3f(1, 0, 0),
                                   osg.Vec3f(0, 0, 1), 0, 0, 1, 1)
g.getColorArray()[0] = osg.Vec4f(1, 1, 1,
                                 0.5)  # change color to semitransparent

# Add it to a geode
geode = osg.Geode()
geode.addDrawable(g)

# Add texture
i = osgDB.readImageFile("Images/osg256.png")
t = osg.Texture2D(i)
s = geode.stateSet
s.setTextureAttributeAndModes(0, t, osg.StateAttribute.Values.ON)

# Make sure blending is active and the geode is in the transparent (depth sorted) bin
s.setRenderingHint(osg.StateSet.TRANSPARENT_BIN)
s.setMode(osg.GL_BLEND, osg.StateAttribute.ON)

# Create viewer, add some standard handlers to it and run it
viewer = osgViewer.Viewer()
viewer.setUpViewInWindow(50, 50, 1024, 768)
viewer.addEventHandler(osgGA.StateSetManipulator(geode.stateSet))
viewer.addEventHandler(osgViewer.HelpHandler())
viewer.addEventHandler(osgViewer.StatsHandler())
viewer.setSceneData(geode)
viewer.run()
del viewer  # To cause the dtor to be called, hence the window to be destroyed.
Ejemplo n.º 4
0
def main(argv):


    
    # use an ArgumentParser object to manage the program arguments.
    arguments = osg.ArgumentParser(argv)

    arguments.getApplicationUsage().setApplicationName(arguments.getApplicationName())
    arguments.getApplicationUsage().setDescription(arguments.getApplicationName()+" demonstrates OpenGL occlusion query in OSG using the OcclusionQueryNode.")
    arguments.getApplicationUsage().setCommandLineUsage(arguments.getApplicationName()+" [options] [filename(s)]")
    arguments.getApplicationUsage().addCommandLineOption("-h or --help","Display command line parameters")

    # if user request help write it out to cout.
    if arguments.read("-h")  or  arguments.read("--help") :
        arguments.getApplicationUsage().write(std.cout, osg.ApplicationUsage.COMMAND_LINE_OPTION)
        return 1

    # report any errors if they have occurred when parsing the program arguments.
    if arguments.errors() :
        arguments.writeErrorMessages(std.cout)
        return 1

    viewer = osgViewer.Viewer( arguments )

    # add the state manipulator
    viewer.addEventHandler( osgGA.StateSetManipulator(viewer.getCamera().getOrCreateStateSet()) )

    # add the stats handler
    viewer.addEventHandler(osgViewer.StatsHandler)()

    # add the help handler
    viewer.addEventHandler(osgViewer.HelpHandler(arguments.getApplicationUsage()))

    optimize = arguments.read( "--opt" )

    # load the specified model
    root = 0

    if arguments.argc()>1 :
        root = osgDB.readNodeFiles( arguments )
        if root.valid() :
            # Run a NodeVisitor to insert OcclusionQueryNodes in the scene graph.
            oqv = OcclusionQueryVisitor()
            root.accept( oqv )
        else:
            print arguments.getApplicationName(), ": unable to load specified data."
            return 1
    else:
        root = createStockScene()
        if  not root :
            print arguments.getApplicationName(), ": Failed to create stock scene."
            return 1

    # any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized()

    # report any errors if they have occurred when parsing the program arguments.
    if arguments.errors() :
        arguments.writeErrorMessages(std.cout)
        return 1


    # optimize the scene graph, remove redundant nodes and state etc.
    if optimize :
        optimizer = osgUtil.Optimizer()
        optimizer.optimize( root )

    viewer.setSceneData( root )

    kh = KeyHandler( *root )
    viewer.addEventHandler( kh )

    return viewer.run()
Ejemplo n.º 5
0
def main(argv):

    
    # use an ArgumentParser object to manage the program arguments.
    arguments = osg.ArgumentParser(argv)
    arguments.getApplicationUsage().addCommandLineOption("-v","Set the terrain vertical scale.")
    arguments.getApplicationUsage().addCommandLineOption("-r","Set the terrain sample ratio.")
    arguments.getApplicationUsage().addCommandLineOption("--login <url> <username> <password>","Provide authentication information for http file access.")
   
    # construct the viewer.
    viewer = osgViewer.Viewer(arguments)


    # set the tile loaded callback to load the optional imagery
    whiteList = osgTerrain.WhiteListTileLoadedCallback()
    setname = str()
    while arguments.read("--allow",setname) :
        whiteList.allow(setname)
    while arguments.read("--allow-all") :
        whiteList.setAllowAll(True)
    osgTerrain.TerrainTile.setTileLoadedCallback(whiteList)


    # obtain the vertical scale
    verticalScale = 1.0
    while arguments.read("-v",verticalScale) : 
    
    # obtain the sample ratio
    sampleRatio = 1.0
    while arguments.read("-r",sampleRatio) : 


    # set up any authentication.
    str url, username, password
    while arguments.read("--login",url, username, password) :
        if  not osgDB.Registry.instance().getAuthenticationMap() :
            osgDB.Registry.instance().setAuthenticationMap(osgDB.AuthenticationMap)()
            osgDB.Registry.instance().getAuthenticationMap().addAuthenticationDetails(
                url,
                osgDB.AuthenticationDetails(username, password)
            )

    # add all the event handlers to the viewer
        # add the state manipulator
        viewer.addEventHandler( osgGA.StateSetManipulator(viewer.getCamera().getOrCreateStateSet()) )

        # add the thread model handler
        viewer.addEventHandler(osgViewer.ThreadingHandler)()

        # add the window size toggle handler
        viewer.addEventHandler(osgViewer.WindowSizeHandler)()

        # add the stats handler
        viewer.addEventHandler(osgViewer.StatsHandler)()

        # add the help handler
        viewer.addEventHandler(osgViewer.HelpHandler(arguments.getApplicationUsage()))

        # add the record camera path handler
        viewer.addEventHandler(osgViewer.RecordCameraPathHandler)()

        # add the LOD Scale handler
        viewer.addEventHandler(osgViewer.LODScaleHandler)()

    # add all the camera manipulators
        keyswitchManipulator = osgGA.KeySwitchMatrixManipulator()

        keyswitchManipulator.addMatrixManipulator( ord("1"), "Trackball", osgGA.TrackballManipulator() )
        keyswitchManipulator.addMatrixManipulator( ord("2"), "Flight", osgGA.FlightManipulator() )
        keyswitchManipulator.addMatrixManipulator( ord("3"), "Drive", osgGA.DriveManipulator() )

        num = keyswitchManipulator.getNumMatrixManipulators()
        keyswitchManipulator.addMatrixManipulator( ord("4"), "Terrain", osgGA.TerrainManipulator() )

        pathfile = str()
        keyForAnimationPath = ord("5")
        while arguments.read("-p",pathfile) :
            apm = osgGA.AnimationPathManipulator(pathfile)
            if apm  or   not apm.valid() : 
                num = keyswitchManipulator.getNumMatrixManipulators()
                keyswitchManipulator.addMatrixManipulator( keyForAnimationPath, "Path", apm )
                ++keyForAnimationPath

        keyswitchManipulator.selectMatrixManipulator(num)

        viewer.setCameraManipulator( keyswitchManipulator )

    # set up the scene graph
        # load the nodes from the commandline arguments.
        rootnode = osgDB.readNodeFiles(arguments)

        if  not rootnode :
            osg.notify(osg.NOTICE), "Warning: no valid data loaded, please specify a database on the command line."
            return 1

        terrain = findTopMostNodeOfType<osgTerrain.Terrain>(rootnode)
        if  not terrain :
            terrain = osgTerrain.Terrain()

            csn = findTopMostNodeOfType<osg.CoordinateSystemNode>(rootnode)
            if csn :
                terrain.set(*csn)

            terrain.addChild(rootnode)

            rootnode = terrain
            csn = terrain

        terrain.setSampleRatio(sampleRatio)
        terrain.setVerticalScale(verticalScale)

        # register our custom handler for adjust Terrain settings
        viewer.addEventHandler(TerrainHandler(terrain))


        numLayers = 1
        mtc = findTopMostNodeOfType<osgFX.MultiTextureControl>(rootnode)
        if mtc :

            numLayers = mtc.getNumTextureWeights()

            # switch on just the first texture layer.
            mtc.setTextureWeight(0,1.0)
            for(unsigned int i=1 i<numLayers ++i)
                mtc.setTextureWeight(i,0.0)

        if numLayers<2 :
            osg.notify(osg.NOTICE), "Warning: scene must have MultiTextureControl node with at least 2 texture units defined."
            return 1

        maxElevationTransition = 1e6
        elevations = ElevationLayerBlendingCallback.Elevations()
        for(unsigned int i=0 i<numLayers ++i)
            elevations.push_back(maxElevationTransition)
            maxElevationTransition /= 2.0


        # we must assign callback as both an update and cull callback, as update callback to do the update of
        # the the osgFX.MultiTextureControl node a thread safe way, and as a cull callback to gather the camera
        # position information.
        elbc = ElevationLayerBlendingCallback(mtc, elevations)
        terrain.setUpdateCallback(elbc)
        terrain.setCullCallback(elbc)

        # add a viewport to the viewer and attach the scene graph.
        viewer.setSceneData( rootnode )
    


    # create the windows and run the threads.
    viewer.realize()

    return viewer.run()
Ejemplo n.º 6
0
def main(argv):


    
    # use an ArgumentParser object to manage the program arguments.
    arguments = osg.ArgumentParser(argv)
    
    # set up the usage document, in case we need to print out how to use this program.
    arguments.getApplicationUsage().setDescription(arguments.getApplicationName()+" is the example which demonstrates use of node tracker.")
    arguments.getApplicationUsage().setCommandLineUsage(arguments.getApplicationName())
    arguments.getApplicationUsage().addCommandLineOption("-h or --help","Display this information")
    

    # construct the viewer.
    viewer = osgViewer.Viewer(arguments)

    # add the state manipulator
    viewer.addEventHandler( osgGA.StateSetManipulator(viewer.getCamera().getOrCreateStateSet()) )
    
    # add the thread model handler
    viewer.addEventHandler(osgViewer.ThreadingHandler)()

    # add the window size toggle handler
    viewer.addEventHandler(osgViewer.WindowSizeHandler)()
        
    # add the stats handler
    viewer.addEventHandler(osgViewer.StatsHandler)()
        
    # add the record camera path  handler
    viewer.addEventHandler(osgViewer.RecordCameraPathHandler)()

    # add the help handler
    viewer.addEventHandler(osgViewer.HelpHandler(arguments.getApplicationUsage()))

    # set the near far ration computation up.
    viewer.getCamera().setComputeNearFarMode(osg.CullSettings.COMPUTE_NEAR_FAR_USING_PRIMITIVES)
    viewer.getCamera().setNearFarRatio(0.000003)


    speed = 1.0
    while arguments.read("-f")  or  arguments.read("--fixed") : speed = 0.0


    rotation = osg.Quat()
    vec4 = osg.Vec4()
    while arguments.read("--rotate-model",vec4[0],vec4[1],vec4[2],vec4[3]) :
        local_rotate = osg.Quat()
        local_rotate.makeRotate(osg.DegreesToRadians(vec4[0]),vec4[1],vec4[2],vec4[3])
        
        rotation = rotation * local_rotate

    nc = 0
    flightpath_filename = str()
    while arguments.read("--flight-path",flightpath_filename) :
        fin = osgDB.ifstream(flightpath_filename.c_str())
        if fin :
            path = osg.AnimationPath()
            path.read(fin)
            nc = osg.AnimationPathCallback(path)
    
    trackerMode = osgGA.NodeTrackerManipulator.NODE_CENTER_AND_ROTATION
    mode = str()
    while arguments.read("--tracker-mode",mode) :
        if mode=="NODE_CENTER_AND_ROTATION" : trackerMode = osgGA.NodeTrackerManipulator.NODE_CENTER_AND_ROTATION
        elif mode=="NODE_CENTER_AND_AZIM" : trackerMode = osgGA.NodeTrackerManipulator.NODE_CENTER_AND_AZIM
        elif mode=="NODE_CENTER" : trackerMode = osgGA.NodeTrackerManipulator.NODE_CENTER
        else:
            print "Unrecognized --tracker-mode option ", mode, ", valid options are:"
            print "    NODE_CENTER_AND_ROTATION"
            print "    NODE_CENTER_AND_AZIM"
            print "    NODE_CENTER"
            return 1
    
    
    rotationMode = osgGA.NodeTrackerManipulator.TRACKBALL
    while arguments.read("--rotation-mode",mode) :
        if mode=="TRACKBALL" : rotationMode = osgGA.NodeTrackerManipulator.TRACKBALL
        elif mode=="ELEVATION_AZIM" : rotationMode = osgGA.NodeTrackerManipulator.ELEVATION_AZIM
        else:
            print "Unrecognized --rotation-mode option ", mode, ", valid options are:"
            print "    TRACKBALL"
            print "    ELEVATION_AZIM"
            return 1

    useOverlay = True
    while arguments.read("--no-overlay")  or  arguments.read("-n") : useOverlay = False
    
    technique = osgSim.OverlayNode.OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY
    while arguments.read("--object") : technique = osgSim.OverlayNode.OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY
    while arguments.read("--ortho")  or  arguments.read("--orthographic") : technique = osgSim.OverlayNode.VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY
    while arguments.read("--persp")  or  arguments.read("--perspective") : technique = osgSim.OverlayNode.VIEW_DEPENDENT_WITH_PERSPECTIVE_OVERLAY

    overlayTextureUnit = 1
    while arguments.read("--unit", overlayTextureUnit) : 
    
    pathfile = str()
    while arguments.read("-p",pathfile) : 

    addFireEffect = arguments.read("--fire")

    # if user request help write it out to cout.
    if arguments.read("-h")  or  arguments.read("--help") :
        arguments.getApplicationUsage().write(std.cout)
        return 1
    
    
    tm = osgGA.NodeTrackerManipulator()
    
    overlayFilename = str()
    while arguments.read("--overlay", overlayFilename) : 

    # read the scene from the list of file specified commandline args.
    root = osgDB.readNodeFiles(arguments)

    if  not root : root = createEarth()

    if  not root : return 0


    if  not overlayFilename.empty() :
        #osg.Object *pObj = osgDB.readObjectFile("alaska_clean.shp")
        #osg.Geode shapefile = dynamic_cast<osg.Geode*> (pObj)
        #
        #ConvertLatLon2EllipsoidCoordinates latlon2em
        #shapefile.accept(latlon2em)

        shapefile = osgDB.readNodeFile(overlayFilename)
        
        if  not shapefile :
            osg.notify(osg.NOTICE), "File `", overlayFilename, "` not found"
            return 1

        csn = dynamic_cast<osg.CoordinateSystemNode*>(root)
        if csn :

            overlayNode = osgSim.OverlayNode(technique)
            overlayNode.getOrCreateStateSet().setTextureAttribute(1, osg.TexEnv(osg.TexEnv.DECAL))
            overlayNode.setOverlaySubgraph(shapefile)
            overlayNode.setOverlayTextureSizeHint(1024)
            overlayNode.setOverlayTextureUnit(overlayTextureUnit)

            # insert the OverlayNode between the coordinate system node and its children.
            for(unsigned int i=0 i<csn.getNumChildren() ++i)
                overlayNode.addChild( csn.getChild(i) )

            csn.removeChildren(0, csn.getNumChildren())
            csn.addChild(overlayNode)

            viewer.setSceneData(csn)
        else:
            overlayNode = osgSim.OverlayNode(technique)
            overlayNode.getOrCreateStateSet().setTextureAttribute(1, osg.TexEnv(osg.TexEnv.DECAL))
            overlayNode.setOverlaySubgraph(shapefile)
            overlayNode.setOverlayTextureSizeHint(1024)
            overlayNode.addChild(root)

            viewer.setSceneData(overlayNode)
    else:
    

        # add a viewport to the viewer and attach the scene graph.
        viewer.setSceneData(root)

        csn = dynamic_cast<osg.CoordinateSystemNode*>(root)
        if csn :

            overlayNode = osgSim.OverlayNode()
            if useOverlay :
                overlayNode = osgSim.OverlayNode(technique)

                # insert the OverlayNode between the coordinate system node and its children.
                for(unsigned int i=0 i<csn.getNumChildren() ++i)
                    overlayNode.addChild( csn.getChild(i) )

                csn.removeChildren(0, csn.getNumChildren())
                csn.addChild(overlayNode)

                # tell the overlay node to continously update its overlay texture
                # as we know we'll be tracking a moving target.
                overlayNode.setContinuousUpdate(True)


            cessna = osgDB.readNodeFile("cessna.osgt")
            if cessna :
                s = 200000.0 / cessna.getBound().radius()

                scaler = osg.MatrixTransform()
                scaler.addChild(cessna)
                scaler.setMatrix(osg.Matrixd.scale(s,s,s)*osg.Matrixd.rotate(rotation))
                scaler.getOrCreateStateSet().setMode(GL_RESCALE_NORMAL,osg.StateAttribute.ON)
                
                if addFireEffect :
                    center = cessna.getBound().center()
                    
                    fire = osgParticle.FireEffect(center, 10.0)
                    scaler.addChild(fire)
                

                if False :
                    ss = osgSim.SphereSegment(
                                        osg.Vec3(0.0,0.0,0.0), # center
                                        19.9, # radius
                                        osg.DegreesToRadians(135.0),
                                        osg.DegreesToRadians(240.0),
                                        osg.DegreesToRadians(-10.0),
                                        osg.DegreesToRadians(30.0),
                                        60)

                    scaler.addChild(ss)

                mt = osg.MatrixTransform()
                mt.addChild(scaler)


                if  not nc : nc = ModelPositionCallback(speed)

                mt.setUpdateCallback(nc)

                csn.addChild(mt)

                # if we are using an overaly node, use the cessna subgraph as the overlay subgraph
                if overlayNode.valid() :
                    overlayNode.setOverlaySubgraph(mt)

                tm = osgGA.NodeTrackerManipulator()
                tm.setTrackerMode(trackerMode)
                tm.setRotationMode(rotationMode)
                tm.setTrackNode(scaler)
            else:
                 print "Failed to read cessna.osgt"


    # set up camera manipulators.
        keyswitchManipulator = osgGA.KeySwitchMatrixManipulator()

        if tm.valid() : keyswitchManipulator.addMatrixManipulator( ord("0"), "NodeTracker", tm )

        keyswitchManipulator.addMatrixManipulator( ord("1"), "Trackball", osgGA.TrackballManipulator() )
        keyswitchManipulator.addMatrixManipulator( ord("2"), "Flight", osgGA.FlightManipulator() )
        keyswitchManipulator.addMatrixManipulator( ord("3"), "Drive", osgGA.DriveManipulator() )
        keyswitchManipulator.addMatrixManipulator( ord("4"), "Terrain", osgGA.TerrainManipulator() )

        if  not pathfile.empty() :
            apm = osgGA.AnimationPathManipulator(pathfile)
            if apm  or   not apm.valid() : 
                num = keyswitchManipulator.getNumMatrixManipulators()
                keyswitchManipulator.addMatrixManipulator( ord("5"), "Path", apm )
                keyswitchManipulator.selectMatrixManipulator(num)

        viewer.setCameraManipulator( keyswitchManipulator )

    # viewer.setThreadingModel(osgViewer.Viewer.SingleThreaded)

    return viewer.run()


if __name__ == "__main__":
    main(sys.argv)
Ejemplo n.º 7
0
    viewer.addEventHandler( osgGA.StateSetManipulator(viewer.getCamera().getOrCreateStateSet()) )

    # add the thread model handler
    viewer.addEventHandler(osgViewer.ThreadingHandler)()

    # add the window size toggle handler
    viewer.addEventHandler(osgViewer.WindowSizeHandler)()

    # add the stats handler
    statsHandler = osgViewer.StatsHandler()
    viewer.addEventHandler(statsHandler)

    initUserStats(statsHandler)

    # add the help handler
    viewer.addEventHandler(osgViewer.HelpHandler(arguments.getApplicationUsage()))

    # load the data
    loadedModel = osgDB.readNodeFiles(arguments)
    if  not loadedModel :
        print arguments.getApplicationName(), ": No data loaded"
        return 1

    # any option left unread are converted into errors to write out later.
    arguments.reportRemainingOptionsAsUnrecognized()

    # report any errors if they have occurred when parsing the program arguments.
    if arguments.errors() :
        arguments.writeErrorMessages(std.cout)
        return 1
Ejemplo n.º 8
0

    # add the state manipulator
    viewer.addEventHandler( osgGA.StateSetManipulator(viewer.getCamera().getOrCreateStateSet()) )
    
    # add the thread model handler
    viewer.addEventHandler(osgViewer.ThreadingHandler)()

    # add the window size toggle handler
    viewer.addEventHandler(osgViewer.WindowSizeHandler)()
        
    # add the stats handler
    viewer.addEventHandler(osgViewer.StatsHandler)()

    # add the help handler
    viewer.addEventHandler(osgViewer.HelpHandler(psr.getApplicationUsage()))

    # add the LOD Scale handler
    viewer.addEventHandler(osgViewer.LODScaleHandler)()

    # add the screen capture handler
    viewer.addEventHandler(osgViewer.ScreenCaptureHandler)()

    viewer.setSceneData(root)

    return viewer.run()




if __name__ == "__main__":