#!/usr/bin/env python import sys import math import random from PyOSG import Producer from PyOSG import osg from PyOSG import osgGA from PyOSG import osgDB from PyOSG import osgUtil from PyOSG import osgProducer from PyOSG import osgParticle from OpenGL.GL import * # for the grid data.. from terrain_coords import vertex wind = osg.Vec3(1.0,0.0,0.0) 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 = osg.Vec3(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 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.getOrCreateStateSet().setMode(GL_NORMALIZE, osg.StateAttribute.ON) xform.setUpdateCallback(osg.AnimationPathCallback(animationPath,0.0,0.5)) 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.getOrCreateStateSet().setMode(GL_NORMALIZE, osg.StateAttribute.ON) 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) positioned.addChild(cessna) xform = osg.MatrixTransform() xform.setUpdateCallback(osg.AnimationPathCallback(animationPath,0.0,1.0)) xform.addChild(positioned) model.addChild(xform) return model def computeTerrainIntersection(subgraph, x, y): iv = osgUtil.IntersectVisitor() segDown = osg.LineSegment() bs = subgraph.getBound() zMax = bs.center().z()+bs.radius() zMin = bs.center().z()-bs.radius() segDown.set(osg.Vec3(x,y,zMin),osg.Vec3(x,y,zMax)) iv.addLineSegment(segDown) subgraph.accept(iv) if iv.hits(): hitList = iv.getHitList(segDown) if not hitList.empty(): ip = hitList.front().getWorldIntersectPoint() return ip return osg.Vec3(x,y,0.0) #//////////////////////////////////////////////////////////////////////////// # MAIN SCENE GRAPH BUILDING FUNCTION #//////////////////////////////////////////////////////////////////////////// def build_world(root): terrainGeode = osg.Geode() # create terrain if True: stateset = osg.StateSet() image = osgDB.readImageFile("Images/lz.rgb") if image: texture = osg.Texture2D() texture.setImage(image) stateset.setTextureAttributeAndModes(0,texture,osg.StateAttribute.ON) terrainGeode.setStateSet( stateset ) size = 1000; # 10km scale = size/39.0; # 10km z_scale = scale*3.0 grid = osg.HeightField() grid.allocate(38,39) grid.setXInterval(scale) grid.setYInterval(scale) for r in range(39): for c in range(38): grid.setHeight(c,r,z_scale*vertex[r+c*39][2]) terrainGeode.addDrawable(osg.ShapeDrawable(grid)) root.addChild(terrainGeode) # create particle effects if True: position = computeTerrainIntersection(terrainGeode,100.0,100.0) explosion = osgParticle.ExplosionEffect(position, 10.0) explosionDebri = osgParticle.ExplosionDebrisEffect(position, 10.0) smoke = osgParticle.SmokeEffect(position, 10.0) fire = osgParticle.FireEffect(position, 10.0) explosion.setWind(wind) explosionDebri.setWind(wind) smoke.setWind(wind) fire.setWind(wind) root.addChild(explosion) root.addChild(explosionDebri) root.addChild(smoke) root.addChild(fire) # create particle effects if True: position = computeTerrainIntersection(terrainGeode,200.0,100.0) explosion = osgParticle.ExplosionEffect(position, 1.0) explosionDebri = osgParticle.ExplosionDebrisEffect(position, 1.0) smoke = osgParticle.SmokeEffect(position, 1.0) fire = osgParticle.FireEffect(position, 1.0) explosion.setWind(wind) explosionDebri.setWind(wind) smoke.setWind(wind) fire.setWind(wind) root.addChild(explosion) root.addChild(explosionDebri) root.addChild(smoke) root.addChild(fire) # create the moving models. if True: root.addChild(createMovingModel(osg.Vec3(500.0,500.0,500.0),100.0)) # class to handle events with a pick class PickHandler(osgGA.GUIEventHandler): def __init__(self): osgGA.GUIEventHandler.__init__(self) self._self = self def handle(self, ea, aa): eType = ea.getEventType() if eType == osgGA.GUIEventAdapter.PUSH: # viewer = dynamic_cast(&aa) viewer = aa self.pick(viewer,ea) return False else: return False def pick(self, viewer, ea): root = viewer.getSceneData().asGroup() if not root: return hlist = osgUtil.IntersectVisitor.HitList() if viewer.computeIntersections(ea.getX(),ea.getY(),hlist): hit = hlist.front() handleMovingModels = False nodePath = hit.getNodePath() for nitr in nodePath: transform = nitr.asTransform() if transform: if transform.getDataVariance()==osg.Object.DYNAMIC: handleMovingModels=True if handleMovingModels: position = hit.getLocalIntersectPoint() intensity = 5.0 else: position = hit.getWorldIntersectPoint() intensity = 1.0 scale = 20.0 * random.random() explosion = osgParticle.ExplosionEffect(position, scale, intensity) explosionDebri = osgParticle.ExplosionDebrisEffect(position, scale, intensity) smoke = osgParticle.SmokeEffect(position, scale, intensity) fire = osgParticle.FireEffect(position, scale, intensity) explosion.setWind(wind) explosionDebri.setWind(wind) smoke.setWind(wind) fire.setWind(wind) effectsGroup = osg.Group() effectsGroup.addChild(explosion) effectsGroup.addChild(explosionDebri) effectsGroup.addChild(smoke) effectsGroup.addChild(fire) if handleMovingModels: # insert particle effects alongside the hit node, therefore able to track that nodes movement, # however, this does require us to insert the ParticleSystem itself into the root of the scene graph # seperately from the the main particle effects group which contains the emitters and programs. # the follow code block implements this, note the path for handling particle effects which arn't attached to # moving models is easy - just a single line of code! # tell the effects not to attach to the particle system locally for rendering, as we'll handle add it into the # scene graph ourselves. explosion.setUseLocalParticleSystem(False) explosionDebri.setUseLocalParticleSystem(False) smoke.setUseLocalParticleSystem(False) fire.setUseLocalParticleSystem(False) # find a place to insert the particle effects group alongside the hit node. # there are two possible ways that this can be done, either insert it into # a pre-existing group along side the hit node, or if no pre existing group # is found then this needs to be inserted above the hit node, and then the # particle effect can be inserted into this. hitGeode = hit.getGeode() parents = hitGeode.getParents() insertGroup = None numGroupsFound = 0 for itr in parents: if type(itr) == type(osg.Group): numGroupsFound += 1 insertGroup = itr if numGroupsFound==parents.size() and numGroupsFound==1 and insertGroup: # osg.notify(osg.INFO)<<"PickHandler.pick(,) hit node's parent is a single osg.Group so we can simple the insert the particle effects group here."<