#!/bin/env python import sys import math from PyOSG import Producer from PyOSG import osg from PyOSG import osgGA from PyOSG import osgUtil from PyOSG import osgProducer from PyOSG import osgDB def createAnimationPath(center, radius, looptime): # set up the animation path animationPath = osg.AnimationPath() animationPath.setLoopMode(osg.AnimationPath.LOOP) numSamples = 40 yaw = 0.0 yaw_delta = 2.0*osg.PI/(numSamples-1.0) roll = osg.inDegrees(30.0) time=0.0 time_delta = looptime/float(numSamples) for i in range(numSamples): position = center + osg.Vec3(math.sin(yaw)*radius,math.cos(yaw)*radius,0.0) rotation = osg.Quat(roll,osg.Vec3(0.0,1.0,0.0)) * osg.Quat(-(yaw+osg.inDegrees(90.0)),osg.Vec3(0.0,0.0,1.0)) animationPath.insert(time,osg.AnimationPath.ControlPoint(position,rotation)) yaw += yaw_delta time += time_delta return animationPath def createBase(center, radius): numTilesX = 10 numTilesY = 10 width = 2*radius height = 2*radius v000 = center - osg.Vec3(width*0.5,height*0.5,0.0) dx = osg.Vec3(width/float(numTilesX),0.0,0.0) dy = osg.Vec3(0.0,height/float(numTilesY),0.0) # fill in vertices for grid, note numTilesX+1 * numTilesY+1... coords = osg.Vec3Array() for iy in range(numTilesY + 1): for ix in range(numTilesX + 1): coords.push_back(v000 + dx*ix + dy*iy) #Just two colours - black and white. colors = osg.Vec4Array() colors.push_back(osg.Vec4(1.0,1.0,1.0,1.0)); # white colors.push_back(osg.Vec4(0.0,0.0,0.0,1.0)); # black numColors=colors.size() numIndicesPerRow=numTilesX+1 coordIndices = osg.UByteArray() # assumes we are using less than 256 points... colorIndices = osg.UByteArray() for iy in range(numTilesY): for ix in range(numTilesX): # four vertices per quad. coordIndices.push_back(ix +(iy+1)*numIndicesPerRow) coordIndices.push_back(ix +iy*numIndicesPerRow) coordIndices.push_back((ix+1)+iy*numIndicesPerRow) coordIndices.push_back((ix+1)+(iy+1)*numIndicesPerRow) # one color per quad colorIndices.push_back((ix+iy)%numColors) # set up a single normal normals = osg.Vec3Array() normals.push_back(osg.Vec3(0.0,0.0,1.0)) geom = osg.Geometry() geom.setVertexArray(coords) geom.setVertexIndices(coordIndices) geom.setColorArray(colors) geom.setColorIndices(colorIndices) geom.setColorBinding(osg.Geometry.BIND_PER_PRIMITIVE) geom.setNormalArray(normals) geom.setNormalBinding(osg.Geometry.BIND_OVERALL) geom.addPrimitiveSet(osg.DrawArrays(osg.PrimitiveSet.QUADS,0,coordIndices.size())) geode = osg.Geode() geode.addDrawable(geom) return geode def createMovingModel(center, radius): animationLength = 10.0 animationPath = createAnimationPath(center,radius,animationLength) model = osg.Group() glider = osgDB.readNodeFile("glider.osg") if glider: bs = glider.getBound() size = radius/bs.radius()*0.3 positioned = osg.MatrixTransform() positioned.setDataVariance(osg.Object.STATIC) positioned.setMatrix(osg.Matrix.translate(-bs.center())* osg.Matrix.scale(size,size,size)* osg.Matrix.rotate(osg.inDegrees(-90.0),0.0,0.0,1.0)) positioned.addChild(glider) xform = osg.PositionAttitudeTransform() xform.setUpdateCallback(osg.AnimationPathCallback(animationPath,0.0,1.0)) xform.addChild(positioned) model.addChild(xform) cessna = osgDB.readNodeFile("cessna.osg") if cessna: bs = cessna.getBound() size = radius/bs.radius()*0.3 positioned = osg.MatrixTransform() positioned.setDataVariance(osg.Object.STATIC) positioned.setMatrix(osg.Matrix.translate(-bs.center())* osg.Matrix.scale(size,size,size)* osg.Matrix.rotate(osg.inDegrees(180.0),0.0,0.0,1.0)) positioned.addChild(cessna) xform = osg.MatrixTransform() xform.setUpdateCallback(osg.AnimationPathCallback(animationPath,0.0,2.0)) xform.addChild(positioned) model.addChild(xform) return model def createModel(): center = osg.Vec3(0.0, 0.0, 0.0) radius = 100.0 root = osg.Group() root.addChild(createMovingModel(center, radius * 0.8)) root.addChild(createBase(center-osg.Vec3(0.0,0.0,radius*0.5),radius)) return root 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 standard OpenSceneGraph example which loads and visualises 3d models.") arguments.getApplicationUsage().setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...") arguments.getApplicationUsage().addCommandLineOption("-h or --help","Display this information") # initialize the viewer. viewer = osgProducer.Viewer(arguments) # set up the value with sensible default event handlers. viewer.setUpViewer(osgProducer.Viewer.STANDARD_SETTINGS) # get details on keyboard and mouse bindings used by the viewer. viewer.getUsage(arguments.getApplicationUsage()) # if user request help write it out to cout. if arguments.read("-h") or arguments.read("--help"): arguments.getApplicationUsage().write() return 1 # any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized() # report any errors if they have occured when parsing the program aguments. if arguments.errors(): arguments.writeErrorMessages() return 1 # load the nodes from the commandline arguments. model = createModel() if not model: return 1 # tilt the scene so the default eye position is looking down on the model. rootnode = osg.MatrixTransform() rootnode.setMatrix(osg.Matrix.rotate(osg.inDegrees(30.0),1.0,0.0,0.0)) rootnode.addChild(model) # run optimization over the scene graph optimzer = osgUtil.Optimizer() optimzer.optimize(rootnode) # add model to viewer viewer.setSceneData(rootnode) # create the windows and run the threads. viewer.realize() while not viewer.done(): # wait for all cull and draw threads to complete. viewer.sync() # update the scene by traversing it with the the update visitor which will # call all node update callbacks and animations. viewer.update() # fire off the cull and draw traversals of the scene. viewer.frame() # wait for all cull and draw threads to complete before exit. viewer.sync() return 0 if __name__ == "__main__": main(sys.argv)