-
简介
这节课NeHe课程实现了在场景中进行碰撞检测以及简单的物理作用(碰撞之后的反弹),碰撞检测三维图形学中一个比较高级的主题,本课只涉及了简单的规则几何体之间的碰撞检测,更复杂的实例需要读者去更深入的学习。
本课中碰撞检测的算法包括线与平面的求交检测、线与圆柱体的求交、以及球体之间的碰撞检测,这些碰撞检测的原理可以参考NeHe中的介绍。
具体实现在如下几个函数中:
- ///线面相交
- //
- int TestIntersionPlane(const Plane& plane,const TVector& position,const TVector& direction, double& lamda, TVector& pNormal)
- /线与圆柱体相交///
- //
- int TestIntersionCylinder(const Cylinder& cylinder,const TVector& position,const TVector& direction, double& lamda, TVector& pNormal,TVector& newposition)
- //球体相交/
- //
- int FindBallCol(TVector& point, double& TimePoint, double Time2, int& BallNr1, int& BallNr2)
接下来创建本课中的几何体(包括墙面、地面、圆柱体等)
- osg::Geode* createWalls()
- osg::Geode* createFloor()
- osg::Geode* createCylinder()
- osg::Geode* createCylinder2()
- osg::Geode* createBalls(int i)
- switch(ea.getEventType())
- {
- case (osgGA::GUIEventAdapter::FRAME):
- {
- idle();
- viewer->getCamera()->setViewMatrixAsLookAt(osg::Vec3(Pos.X(),Pos.Y(),Pos.Z()), osg::Vec3(Pos.X()+dir.X(),Pos.Y()+dir.Y(),Pos.Z()+dir.Z()), osg::Y_AXIS);
- }
在BuildScene中查看相应的代码
编译运行程序:
附:本课源码(源码中可能存在错误和不足,仅供参考)[其他头文件可以在NeHe课程中下载]
- #include "../osgNeHe.h"
- #include <QtCore/QTimer>
- #include <QtGui/QApplication>
- #include <QtGui/QVBoxLayout>
- #include <osgViewer/Viewer>
- #include <osgDB/ReadFile>
- #include <osgQt/GraphicsWindowQt>
- #include <osg/MatrixTransform>
- #include <osg/Plane>
- #include <osg/Texture2D>
- #include <osg/Geode>
- #include <osg/Geometry>
- #include <osg/CullFace>
- #include <osgGA/TrackballManipulator>
- #include <osg/ShapeDrawable>
- #include <osgGA/GUIEventHandler>
- #include <osgGA/GUIEventAdapter>
- #include <osg/AnimationPath>
- #include <osg/BlendFunc>
- #include <osg/Switch>
- #include <osg/Material>
- #include "Tray.h"
- #include "Tvector.h"
- //
- GLfloat spec[]={1.0, 1.0 ,1.0 ,1.0}; //sets specular highlight of balls
- GLfloat posl[]={0,400,0,1}; //position of ligth source
- GLfloat amb[]={0.2f, 0.2f, 0.2f ,1.0f}; //global ambient
- GLfloat amb2[]={0.3f, 0.3f, 0.3f ,1.0f}; //ambient of lightsource
- TVector dir(0,0,-10); //initial direction of camera
- TVector Pos(0,-50,1000); //initial position of camera
- float camera_rotation=0; //holds rotation around the Y axis
- TVector veloc(0.5,-0.1,0.5); //initial velocity of balls
- TVector accel(0,-0.05,0); //acceleration ie. gravity of balls
- TVector ArrayVel[10]; //holds velocity of balls
- TVector ArrayPos[10]; //position of balls
- TVector OldPos[10]; //old position of balls
- int NrOfBalls; //sets the number of balls
- double Time=0.6; //timestep of simulation
- int hook_toball1=0, sounds=1; //hook camera on ball, and sound on/off
- //Plane structure
- struct Plane{
- TVector _Position;
- TVector _Normal;
- };
- //Cylinder structure
- struct Cylinder{
- TVector _Position;
- TVector _Axis;
- double _Radius;
- };
- //Explosion structure
- struct Explosion{
- TVector _Position;
- float _Alpha;
- float _Scale;
- };
- Plane pl1,pl2,pl3,pl4,pl5; //the 5 planes of the room
- Cylinder cyl1,cyl2,cyl3; //the 2 cylinders of the room
- GLuint texture[4], dlist; //stores texture objects and display list
- Explosion ExplosionArray[20]; //holds max 20 explosions at once
- //Perform Intersection tests with primitives
- osg::Switch *g_SwitchNode;
- //
- ///线面相交
- //
- int TestIntersionPlane(const Plane& plane,const TVector& position,const TVector& direction, double& lamda, TVector& pNormal)
- {
- double DotProduct=direction.dot(plane._Normal);
- double l2;
- //determine if ray paralle to plane
- if ((DotProduct<ZERO)&&(DotProduct>-ZERO))
- return 0;
- l2=(plane._Normal.dot(plane._Position-position))/DotProduct;
- if (l2<-ZERO)
- return 0;
- pNormal=plane._Normal;
- lamda=l2;
- return 1;
- }
- //
- /线与圆柱体相交///
- //
- int TestIntersionCylinder(const Cylinder& cylinder,const TVector& position,const TVector& direction, double& lamda, TVector& pNormal,TVector& newposition)
- {
- TVector RC;
- double d;
- double t,s;
- TVector n,D,O;
- double ln;
- double in,out;
- TVector::subtract(position,cylinder._Position,RC);
- TVector::cross(direction,cylinder._Axis,n);
- ln=n.mag();
- if ( (ln<ZERO)&&(ln>-ZERO) ) return 0;
- n.unit();
- d= fabs( RC.dot(n) );
- if (d<=cylinder._Radius)
- {
- TVector::cross(RC,cylinder._Axis,O);
- t= - O.dot(n)/ln;
- TVector::cross(n,cylinder._Axis,O);
- O.unit();
- s= fabs( sqrt(cylinder._Radius*cylinder._Radius - d*d) / direction.dot(O) );
- in=t-s;
- out=t+s;
- if (in<-ZERO){
- if (out<-ZERO) return 0;
- else lamda=out;
- }
- else
- if (out<-ZERO) {
- lamda=in;
- }
- else
- if (in<out) lamda=in;
- else lamda=out;
- newposition=position+direction*lamda;
- TVector HB=newposition-cylinder._Position;
- pNormal=HB - cylinder._Axis*(HB.dot(cylinder._Axis));
- pNormal.unit();
- return 1;
- }
- return 0;
- }
- //
- //球体相交/
- //
- int FindBallCol(TVector& point, double& TimePoint, double Time2, int& BallNr1, int& BallNr2)
- {
- TVector RelativeV;
- TRay rays;
- double MyTime=0.0, Add=Time2/150.0, Timedummy=10000, Timedummy2=-1;
- TVector posi;
- //Test all balls against eachother in 150 small steps
- for (int i=0;i<NrOfBalls-1;i++)
- {
- for (int j=i+1;j<NrOfBalls;j++)
- {
- RelativeV=ArrayVel[i]-ArrayVel[j];
- rays=TRay(OldPos[i],TVector::unit(RelativeV));
- MyTime=0.0;
- if ( (rays.dist(OldPos[j])) > 40) continue;
- while (MyTime<Time2)
- {
- MyTime+=Add;
- posi=OldPos[i]+RelativeV*MyTime;
- if (posi.dist(OldPos[j])<=40) {
- point=posi;
- if (Timedummy>(MyTime-Add))
- Timedummy=MyTime-Add;
- BallNr1=i;
- BallNr2=j;
- break;
- }
- }
- }
- }
- if (Timedummy!=10000) {
- TimePoint=Timedummy;
- return 1;
- }
- return 0;
- }
- void initVars()
- {
- //create palnes
- pl1._Position=TVector(0,-300,0);
- pl1._Normal=TVector(0,1,0);
- pl2._Position=TVector(300,0,0);
- pl2._Normal=TVector(-1,0,0);
- pl3._Position=TVector(-300,0,0);
- pl3._Normal=TVector(1,0,0);
- pl4._Position=TVector(0,0,300);
- pl4._Normal=TVector(0,0,-1);
- pl5._Position=TVector(0,0,-300);
- pl5._Normal=TVector(0,0,1);
- //create cylinders
- cyl1._Position=TVector(0,0,0);
- cyl1._Axis=TVector(0,1,0);
- cyl1._Radius=60+20;
- cyl2._Position=TVector(200,-300,0);
- cyl2._Axis=TVector(0,0,1);
- cyl2._Radius=60+20;
- cyl3._Position=TVector(-200,0,0);
- cyl3._Axis=TVector(0,1,1);
- cyl3._Axis.unit();
- cyl3._Radius=30+20;
- //Set initial positions and velocities of balls
- //also initialize array which holds explosions
- NrOfBalls=10;
- ArrayVel[0]=veloc;
- ArrayPos[0]=TVector(199,180,10);
- ExplosionArray[0]._Alpha=0;
- ExplosionArray[0]._Scale=1;
- ArrayVel[1]=veloc;
- ArrayPos[1]=TVector(0,150,100);
- ExplosionArray[1]._Alpha=0;
- ExplosionArray[1]._Scale=1;
- ArrayVel[2]=veloc;
- ArrayPos[2]=TVector(-100,180,-100);
- ExplosionArray[2]._Alpha=0;
- ExplosionArray[2]._Scale=1;
- for (int i=3; i<10; i++)
- {
- ArrayVel[i]=veloc;
- ArrayPos[i]=TVector(-500+i*75, 300, -500+i*50);
- ExplosionArray[i]._Alpha=0;
- ExplosionArray[i]._Scale=1;
- }
- for (int i=10; i<20; i++)
- {
- ExplosionArray[i]._Alpha=0;
- ExplosionArray[i]._Scale=1;
- }
- }
- void idle()
- {
- double rt,rt2,rt4,lamda=10000;
- TVector norm,uveloc;
- TVector normal,point,time;
- double RestTime,BallTime;
- TVector Pos2;
- int BallNr=0,dummy=0,BallColNr1,BallColNr2;
- TVector Nc;
- if (!hook_toball1)
- {
- camera_rotation+=0.1f;
- if (camera_rotation>360)
- camera_rotation=0;
- }
- RestTime=Time;
- lamda=1000;
- //Compute velocity for next timestep using Euler equations
- for (int j=0;j<NrOfBalls;j++)
- ArrayVel[j]+=accel*RestTime;
- //While timestep not over
- while (RestTime>ZERO)
- {
- lamda=10000; //initialize to very large value
- //For all the balls find closest intersection between balls and planes/cylinders
- for (int i=0;i<NrOfBalls;i++)
- {
- //compute new position and distance
- OldPos[i]=ArrayPos[i];
- TVector::unit(ArrayVel[i],uveloc);
- ArrayPos[i]=ArrayPos[i]+ArrayVel[i]*RestTime;
- rt2=OldPos[i].dist(ArrayPos[i]);
- //Test if collision occured between ball and all 5 planes
- if (TestIntersionPlane(pl1,OldPos[i],uveloc,rt,norm))
- {
- //Find intersection time
- rt4=rt*RestTime/rt2;
- //if smaller than the one already stored replace and in timestep
- if (rt4<=lamda)
- {
- if (rt4<=RestTime+ZERO)
- if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
- {
- normal=norm;
- point=OldPos[i]+uveloc*rt;
- lamda=rt4;
- BallNr=i;
- }
- }
- }
- if (TestIntersionPlane(pl2,OldPos[i],uveloc,rt,norm))
- {
- rt4=rt*RestTime/rt2;
- if (rt4<=lamda)
- {
- if (rt4<=RestTime+ZERO)
- if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
- {
- normal=norm;
- point=OldPos[i]+uveloc*rt;
- lamda=rt4;
- BallNr=i;
- dummy=1;
- }
- }
- }
- if (TestIntersionPlane(pl3,OldPos[i],uveloc,rt,norm))
- {
- rt4=rt*RestTime/rt2;
- if (rt4<=lamda)
- {
- if (rt4<=RestTime+ZERO)
- if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
- {
- normal=norm;
- point=OldPos[i]+uveloc*rt;
- lamda=rt4;
- BallNr=i;
- }
- }
- }
- if (TestIntersionPlane(pl4,OldPos[i],uveloc,rt,norm))
- {
- rt4=rt*RestTime/rt2;
- if (rt4<=lamda)
- {
- if (rt4<=RestTime+ZERO)
- if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
- {
- normal=norm;
- point=OldPos[i]+uveloc*rt;
- lamda=rt4;
- BallNr=i;
- }
- }
- }
- if (TestIntersionPlane(pl5,OldPos[i],uveloc,rt,norm))
- {
- rt4=rt*RestTime/rt2;
- if (rt4<=lamda)
- {
- if (rt4<=RestTime+ZERO)
- if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
- {
- normal=norm;
- point=OldPos[i]+uveloc*rt;
- lamda=rt4;
- BallNr=i;
- }
- }
- }
- //Now test intersection with the 3 cylinders
- if (TestIntersionCylinder(cyl1,OldPos[i],uveloc,rt,norm,Nc))
- {
- rt4=rt*RestTime/rt2;
- if (rt4<=lamda)
- {
- if (rt4<=RestTime+ZERO)
- if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
- {
- normal=norm;
- point=Nc;
- lamda=rt4;
- BallNr=i;
- }
- }
- }
- if (TestIntersionCylinder(cyl2,OldPos[i],uveloc,rt,norm,Nc))
- {
- rt4=rt*RestTime/rt2;
- if (rt4<=lamda)
- {
- if (rt4<=RestTime+ZERO)
- if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
- {
- normal=norm;
- point=Nc;
- lamda=rt4;
- BallNr=i;
- }
- }
- }
- if (TestIntersionCylinder(cyl3,OldPos[i],uveloc,rt,norm,Nc))
- {
- rt4=rt*RestTime/rt2;
- if (rt4<=lamda)
- {
- if (rt4<=RestTime+ZERO)
- if (! ((rt<=ZERO)&&(uveloc.dot(norm)>ZERO)) )
- {
- normal=norm;
- point=Nc;
- lamda=rt4;
- BallNr=i;
- }
- }
- }
- }
- //After all balls were teste with planes/cylinders test for collision
- //between them and replace if collision time smaller
- if (FindBallCol(Pos2,BallTime,RestTime,BallColNr1,BallColNr2))
- {
- //if (sounds)
- // PlaySound("Data/Explode.wav",NULL,SND_FILENAME|SND_ASYNC);
- if ( (lamda==10000) || (lamda>BallTime) )
- {
- RestTime=RestTime-BallTime;
- TVector pb1,pb2,xaxis,U1x,U1y,U2x,U2y,V1x,V1y,V2x,V2y;
- double a,b;
- pb1=OldPos[BallColNr1]+ArrayVel[BallColNr1]*BallTime;
- pb2=OldPos[BallColNr2]+ArrayVel[BallColNr2]*BallTime;
- xaxis=(pb2-pb1).unit();
- a=xaxis.dot(ArrayVel[BallColNr1]);
- U1x=xaxis*a;
- U1y=ArrayVel[BallColNr1]-U1x;
- xaxis=(pb1-pb2).unit();
- b=xaxis.dot(ArrayVel[BallColNr2]);
- U2x=xaxis*b;
- U2y=ArrayVel[BallColNr2]-U2x;
- V1x=(U1x+U2x-(U1x-U2x))*0.5;
- V2x=(U1x+U2x-(U2x-U1x))*0.5;
- V1y=U1y;
- V2y=U2y;
- for (int j=0;j<NrOfBalls;j++)
- ArrayPos[j]=OldPos[j]+ArrayVel[j]*BallTime;
- ArrayVel[BallColNr1]=V1x+V1y;
- ArrayVel[BallColNr2]=V2x+V2y;
- //Update explosion array
- for(int j=0;j<20;j++)
- {
- if (ExplosionArray[j]._Alpha<=0)
- {
- ExplosionArray[j]._Alpha=1;
- ExplosionArray[j]._Position=ArrayPos[BallColNr1];
- ExplosionArray[j]._Scale=1;
- break;
- }
- }
- continue;
- }
- }
- //End of tests
- //If test occured move simulation for the correct timestep
- //and compute response for the colliding ball
- if (lamda!=10000)
- {
- RestTime-=lamda;
- for (int j=0;j<NrOfBalls;j++)
- ArrayPos[j]=OldPos[j]+ArrayVel[j]*lamda;
- rt2=ArrayVel[BallNr].mag();
- ArrayVel[BallNr].unit();
- ArrayVel[BallNr]=TVector::unit( (normal*(2*normal.dot(-ArrayVel[BallNr]))) + ArrayVel[BallNr] );
- ArrayVel[BallNr]=ArrayVel[BallNr]*rt2;
- //Update explosion array
- for(int j=0;j<20;j++)
- {
- if (ExplosionArray[j]._Alpha<=0)
- {
- ExplosionArray[j]._Alpha=1;
- ExplosionArray[j]._Position=point;
- ExplosionArray[j]._Scale=1;
- break;
- }
- }
- }
- else RestTime=0;
- }
- }
- //
- //
- //
- osg::Geode* createWalls()
- {
- osg::Geode *geode = new osg::Geode;
- osg::Geometry *geometry = new osg::Geometry;
- osg::Vec3Array *vertexArray = new osg::Vec3Array;
- osg::Vec2Array *textureArray = new osg::Vec2Array;
- osg::Vec3Array *colorArray = new osg::Vec3Array;
- colorArray->push_back(osg::Vec3(1,1,1));
- vertexArray->push_back(osg::Vec3(320,320,320));
- vertexArray->push_back(osg::Vec3(320,-320,320));
- vertexArray->push_back(osg::Vec3(-320,-320,320));
- vertexArray->push_back(osg::Vec3(-320,320,320));
- textureArray->push_back(osg::Vec2(1.0f, 0.0f));
- textureArray->push_back(osg::Vec2(1.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 0.0f));
- vertexArray->push_back(osg::Vec3(-320,320,-320));
- vertexArray->push_back(osg::Vec3(-320,-320,-320));
- vertexArray->push_back(osg::Vec3(320,-320,-320));
- vertexArray->push_back(osg::Vec3(320,320,-320));
- textureArray->push_back(osg::Vec2(1.0f, 0.0f));
- textureArray->push_back(osg::Vec2(1.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 0.0f));
- vertexArray->push_back(osg::Vec3(320,320,-320));
- vertexArray->push_back(osg::Vec3(320,-320,-320));
- vertexArray->push_back(osg::Vec3(320,-320,320));
- vertexArray->push_back(osg::Vec3(320,320,320));
- textureArray->push_back(osg::Vec2(1.0f, 0.0f));
- textureArray->push_back(osg::Vec2(1.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 0.0f));
- vertexArray->push_back(osg::Vec3(-320,320,320));
- vertexArray->push_back(osg::Vec3(-320,-320,320));
- vertexArray->push_back(osg::Vec3(-320,-320,-320));
- vertexArray->push_back(osg::Vec3(-320,320,-320));
- textureArray->push_back(osg::Vec2(1.0f, 0.0f));
- textureArray->push_back(osg::Vec2(1.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 0.0f));
- geometry->setVertexArray(vertexArray);
- geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
- geometry->setTexCoordArray(0, textureArray, osg::Array::BIND_PER_VERTEX);
- osg::Texture2D *texture2D = new osg::Texture2D;
- texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- texture2D->setImage(osgDB::readImageFile("Data/wand.bmp"));
- geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture2D);
- geometry->getOrCreateStateSet()->setAttributeAndModes(new osg::CullFace());
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertexArray->size()));
- geode->addDrawable(geometry);
- return geode;
- }
- osg::Geode* createFloor()
- {
- osg::Geode *geode = new osg::Geode;
- osg::Geometry *geometry = new osg::Geometry;
- osg::Vec3Array *vertexArray = new osg::Vec3Array;
- osg::Vec2Array *textureArray = new osg::Vec2Array;
- osg::Vec3Array *colorArray = new osg::Vec3Array;
- colorArray->push_back(osg::Vec3(1,1,1));
- vertexArray->push_back(osg::Vec3(-320,-320,320));
- vertexArray->push_back(osg::Vec3(320,-320,320));
- vertexArray->push_back(osg::Vec3(320,-320,-320));
- vertexArray->push_back(osg::Vec3(-320,-320,-320));
- textureArray->push_back(osg::Vec2(1.0f, 0.0f));
- textureArray->push_back(osg::Vec2(1.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 1.0f));
- textureArray->push_back(osg::Vec2(0.0f, 0.0f));
- geometry->setVertexArray(vertexArray);
- geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
- geometry->setTexCoordArray(0, textureArray, osg::Array::BIND_PER_VERTEX);
- osg::Texture2D *texture2D = new osg::Texture2D;
- texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- texture2D->setImage(osgDB::readImageFile("Data/boden.bmp"));
- geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture2D);
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertexArray->size()));
- geode->addDrawable(geometry);
- return geode;
- }
- osg::Geode* createCylinder()
- {
- osg::Geode *cylinderGeode = new osg::Geode;
- osg::ShapeDrawable *shapeDrawable = new osg::ShapeDrawable;
- osg::Texture2D *texture2D = new osg::Texture2D;
- texture2D->setImage(osgDB::readImageFile("Data/Marble.bmp"));
- shapeDrawable->getOrCreateStateSet()->setTextureAttributeAndModes(0,texture2D);
- shapeDrawable->setColor(osg::Vec4(0.5,0.5,0.5, 1.0));
- shapeDrawable->setShape(new osg::Cylinder(osg::Vec3(), 60, 2000));
- cylinderGeode->addDrawable(shapeDrawable);
- return cylinderGeode;
- }
- osg::Geode* createCylinder2()
- {
- osg::Geode *cylinderGeode = new osg::Geode;
- osg::ShapeDrawable *shapeDrawable = new osg::ShapeDrawable;
- osg::Texture2D *texture2D = new osg::Texture2D;
- texture2D->setImage(osgDB::readImageFile("Data/Marble.bmp"));
- shapeDrawable->getOrCreateStateSet()->setTextureAttributeAndModes(0,texture2D);
- shapeDrawable->setColor(osg::Vec4(0.5,0.5,0.5, 1.0));
- shapeDrawable->setShape(new osg::Cylinder(osg::Vec3(), 30, 2000));
- cylinderGeode->addDrawable(shapeDrawable);
- return cylinderGeode;
- }
- osg::Geode* createBalls(int i)
- {
- osg::Geode *cylinderSphere = new osg::Geode;
- osg::ShapeDrawable *shapeDrawable = new osg::ShapeDrawable;
- switch(i){
- case 1: shapeDrawable->setColor(osg::Vec4(1.0f,1.0f,1.0f, 1.0f));
- break;
- case 2: shapeDrawable->setColor(osg::Vec4(1.0f,1.0f,0.0f, 1.0f));
- break;
- case 3: shapeDrawable->setColor(osg::Vec4(0.0f,1.0f,1.0f, 1.0f));
- break;
- case 4: shapeDrawable->setColor(osg::Vec4(0.0f,1.0f,0.0f, 1.0f));
- break;
- case 5: shapeDrawable->setColor(osg::Vec4(0.0f,0.0f,1.0f, 1.0f));
- break;
- case 6: shapeDrawable->setColor(osg::Vec4(0.65f,0.2f,0.3f, 1.0f));
- break;
- case 7: shapeDrawable->setColor(osg::Vec4(1.0f,0.0f,1.0f, 1.0f));
- break;
- case 8: shapeDrawable->setColor(osg::Vec4(0.0f,0.7f,0.4f,1.0f));
- break;
- default: shapeDrawable->setColor(osg::Vec4(1.0f, 0.0, 0.0, 1.0));
- }
- shapeDrawable->setShape(new osg::Sphere(osg::Vec3(), 20));
- cylinderSphere->addDrawable(shapeDrawable);
- return cylinderSphere;
- }
- //
- //
- //
- //
- //
- class ManipulatorSceneHandler : public osgGA::GUIEventHandler
- {
- public:
- ManipulatorSceneHandler()
- {
- }
- public:
- virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
- {
- osgViewer::Viewer *viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
- if (!viewer)
- return false;
- if (!viewer->getSceneData())
- return false;
- if (ea.getHandled())
- return false;
- osg::Group *root = viewer->getSceneData()->asGroup();
- switch(ea.getEventType())
- {
- case (osgGA::GUIEventAdapter::FRAME):
- {
- idle();
- viewer->getCamera()->setViewMatrixAsLookAt(osg::Vec3(Pos.X(),Pos.Y(),Pos.Z()), osg::Vec3(Pos.X()+dir.X(),Pos.Y()+dir.Y(),Pos.Z()+dir.Z()), osg::Y_AXIS);
- }
- case(osgGA::GUIEventAdapter::KEYDOWN):
- {
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)
- {
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)
- {
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Space)
- {
- }
- }
- default: break;
- }
- return false;
- }
- };
- //
- class PostionUpdateCallback : public osg::NodeCallback
- {
- public:
- PostionUpdateCallback(int index) : _index(index){ }
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform*>(node);
- if (!mt)
- return;
- mt->setMatrix(osg::Matrix::translate(ArrayPos[_index].X(),ArrayPos[_index].Y(),ArrayPos[_index].Z()));
- traverse(node, nv);
- }
- int _index;
- };
- class CollisionSwitchUpdateCallback : public osg::NodeCallback
- {
- public:
- CollisionSwitchUpdateCallback(int index) : _index(index){ }
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- osg::Switch *st = dynamic_cast<osg::Switch*>(node);
- if (!st)
- return;
- if (ExplosionArray[_index]._Alpha >= 0)
- {
- ExplosionArray[_index]._Alpha-=0.01f;
- ExplosionArray[_index]._Scale+=0.03f;
- st->setAllChildrenOn();
- }
- else
- {
- st->setAllChildrenOff();
- }
- traverse(node, nv);
- }
- int _index;
- };
- class CollisionScaleUpdateCallback : public osg::NodeCallback
- {
- public:
- CollisionScaleUpdateCallback(int index) : _index(index){ }
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform*>(node);
- if (!mt)
- return;
- if (ExplosionArray[_index]._Alpha >= 0)
- {
- mt->setMatrix(osg::Matrix::scale(ExplosionArray[_index]._Scale,ExplosionArray[_index]._Scale,ExplosionArray[_index]._Scale));
- }
- traverse(node, nv);
- }
- int _index;
- };
- class CollisionTransUpdateCallback : public osg::NodeCallback
- {
- public:
- CollisionTransUpdateCallback(int index) : _index(index){ }
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- osg::MatrixTransform *mt = dynamic_cast<osg::MatrixTransform*>(node);
- if (!mt)
- return;
- if (ExplosionArray[_index]._Alpha >= 0)
- {
- mt->setMatrix(osg::Matrix::translate(ArrayPos[_index].X(),ArrayPos[_index].Y(),ArrayPos[_index].Z()));
- }
- traverse(node, nv);
- }
- int _index;
- };
- class CollisionGeometryUpdateCallback : public osg::Drawable::UpdateCallback
- {
- public:
- CollisionGeometryUpdateCallback(int index) : _index(index){ }
- virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
- {
- osg::Geometry *geo = dynamic_cast<osg::Geometry*>(drawable);
- if (!geo)
- return;
- osg::Vec4Array *colorArray = dynamic_cast<osg::Vec4Array*>(geo->getColorArray());
- if(!colorArray)
- return;
- colorArray->clear();
- colorArray->push_back(osg::Vec4(1,1,0,ExplosionArray[_index]._Alpha));
- geo->setColorArray(colorArray, osg::Array::BIND_OVERALL);
- }
- int _index;
- };
- //
- osg::Node* createExplorsionNode(int i)
- {
- osg::MatrixTransform *rotMT = new osg::MatrixTransform;
- rotMT->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(-45.0), osg::Y_AXIS));
- osg::Geode *geode = new osg::Geode;
- osg::Geometry *geometry = new osg::Geometry;
- geometry->setUpdateCallback(new CollisionGeometryUpdateCallback(i));
- osg::Vec3Array *vertexArray = new osg::Vec3Array;
- osg::Vec3Array *normalArray = new osg::Vec3Array;
- osg::Vec2Array *textureArray = new osg::Vec2Array;
- osg::Vec4Array *colorArray = new osg::Vec4Array;
- colorArray->push_back(osg::Vec4(0,0,0,1));
- vertexArray->push_back(osg::Vec3(-50,-40,0));
- vertexArray->push_back(osg::Vec3(50,-40,0));
- vertexArray->push_back(osg::Vec3(50,40,0));
- vertexArray->push_back(osg::Vec3(-50,40,0));
- for (int j = 0; j < 4; ++j)
- {
- normalArray->push_back(osg::Vec3(0,0,1));
- }
- textureArray->push_back(osg::Vec2(0.0f, 0.0f));
- textureArray->push_back(osg::Vec2(0.0f, 1.0f));
- textureArray->push_back(osg::Vec2(1.0f, 1.0f));
- textureArray->push_back(osg::Vec2(1.0f, 0.0f));
- vertexArray->push_back(osg::Vec3(-50,40,0));
- vertexArray->push_back(osg::Vec3(50,40,0));
- vertexArray->push_back(osg::Vec3(50,-40,0));
- vertexArray->push_back(osg::Vec3(-50,-40,0));
- for (int j = 0; j < 4; ++j)
- {
- normalArray->push_back(osg::Vec3(0,0,-1));
- }
- textureArray->push_back(osg::Vec2(0.0f, 0.0f));
- textureArray->push_back(osg::Vec2(0.0f, 1.0f));
- textureArray->push_back(osg::Vec2(1.0f, 1.0f));
- textureArray->push_back(osg::Vec2(1.0f, 0.0f));
- vertexArray->push_back(osg::Vec3(0,-40,50));
- vertexArray->push_back(osg::Vec3(0,-40,-50));
- vertexArray->push_back(osg::Vec3(0,40,-50));
- vertexArray->push_back(osg::Vec3(0,40,50));
- for (int j = 0; j < 4; ++j)
- {
- normalArray->push_back(osg::Vec3(1,0,0));
- }
- textureArray->push_back(osg::Vec2(0.0f, 0.0f));
- textureArray->push_back(osg::Vec2(0.0f, 1.0f));
- textureArray->push_back(osg::Vec2(1.0f, 1.0f));
- textureArray->push_back(osg::Vec2(1.0f, 0.0f));
- vertexArray->push_back(osg::Vec3(0,40,50));
- vertexArray->push_back(osg::Vec3(0,40,-50));
- vertexArray->push_back(osg::Vec3(0,-40,-50));
- vertexArray->push_back(osg::Vec3(0,-40,50));
- for (int j = 0; j < 4; ++j)
- {
- normalArray->push_back(osg::Vec3(-1,0,0));
- }
- textureArray->push_back(osg::Vec2(0.0f, 0.0f));
- textureArray->push_back(osg::Vec2(0.0f, 1.0f));
- textureArray->push_back(osg::Vec2(1.0f, 1.0f));
- textureArray->push_back(osg::Vec2(1.0f, 0.0f));
- osg::Texture2D *texture2D = new osg::Texture2D;
- texture2D->setImage(osgDB::readImageFile("Data/spark.bmp"));
- osg::BlendFunc *blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE);
- osg::Material *material = new osg::Material();
- material->setShininess(osg::Material::FRONT,100.0);
- material->setSpecular(osg::Material::FRONT, osg::Vec4(1.0, 1.0 ,1.0 ,1.0));
- material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
- geometry->setVertexArray(vertexArray);
- geometry->setNormalArray(normalArray, osg::Array::BIND_PER_VERTEX);
- geometry->setTexCoordArray(0, textureArray, osg::Array::BIND_PER_VERTEX);
- geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
- geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture2D);
- geometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);
- geometry->getOrCreateStateSet()->setAttributeAndModes(material);
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertexArray->size()));
- geometry->setUseDisplayList(false);
- geode->addDrawable(geometry);
- rotMT->addChild(geode);
- return rotMT;
- }
- //
- /osgNeHe框架/
- //
- class ViewerWidget : public QWidget, public osgViewer::Viewer
- {
- public:
- ViewerWidget(osg::Node *scene = NULL)
- {
- QWidget* renderWidget = getRenderWidget( createGraphicsWindow(0,0,100,100), scene);
- QVBoxLayout* layout = new QVBoxLayout;
- layout->addWidget(renderWidget);
- layout->setContentsMargins(0, 0, 0, 1);
- setLayout( layout );
- connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
- _timer.start( 10 );
- }
- QWidget* getRenderWidget( osgQt::GraphicsWindowQt* gw, osg::Node* scene )
- {
- osg::Camera* camera = this->getCamera();
- camera->setGraphicsContext( gw );
- const osg::GraphicsContext::Traits* traits = gw->getTraits();
- camera->setClearColor( osg::Vec4(0.0, 0.0, 0.0, 0.0) );
- camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
- camera->setProjectionMatrixAsPerspective(50.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 10.0f, 1000.0f);
- this->setSceneData(scene);
- addEventHandler(new ManipulatorSceneHandler);
- return gw->getGLWidget();
- }
- osgQt::GraphicsWindowQt* createGraphicsWindow( int x, int y, int w, int h, const std::string& name="", bool windowDecoration=false )
- {
- osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
- osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
- traits->windowName = name;
- traits->windowDecoration = windowDecoration;
- traits->x = x;
- traits->y = y;
- traits->width = w;
- traits->height = h;
- traits->doubleBuffer = true;
- traits->alpha = ds->getMinimumNumAlphaBits();
- traits->stencil = ds->getMinimumNumStencilBits();
- traits->sampleBuffers = ds->getMultiSamples();
- traits->samples = ds->getNumMultiSamples();
- return new osgQt::GraphicsWindowQt(traits.get());
- }
- virtual void paintEvent( QPaintEvent* event )
- {
- frame();
- }
- protected:
- QTimer _timer;
- };
- osg::Node* buildScene()
- {
- initVars();
- osg::Group *root = new osg::Group;
- osg::Light *light = new osg::Light;
- light->setAmbient(osg::Vec4(amb2[0], amb2[1],amb2[2], amb2[3]));
- light->setLightNum(0);
- light->setPosition(osg::Vec4(posl[0],posl[1],posl[2],posl[3]) );
- osg::LightSource *lightSource = new osg::LightSource;
- lightSource->setLight(light);
- root->addChild(lightSource);
- osg::MatrixTransform *rotMT = new osg::MatrixTransform;
- rotMT->addUpdateCallback(new osg::AnimationPathCallback(osg::Vec3(), osg::Y_AXIS, 0.5));
- rotMT->addChild(createWalls());
- rotMT->addChild(createFloor());
- osg::MatrixTransform *cylinderRotMT1 = new osg::MatrixTransform;
- osg::MatrixTransform *cylinderTransMT1 = new osg::MatrixTransform;
- cylinderRotMT1->setMatrix(osg::Matrix::rotate(osg::PI_2, osg::X_AXIS));
- cylinderTransMT1->setMatrix(osg::Matrix::translate(0, 0, -500));
- cylinderTransMT1->addChild(createCylinder());
- cylinderRotMT1->addChild(cylinderTransMT1);
- osg::MatrixTransform *cylinderTransMT2 = new osg::MatrixTransform;
- cylinderTransMT2->setMatrix(osg::Matrix::translate(200,-300,-500));
- cylinderTransMT2->addChild(createCylinder());
- osg::MatrixTransform *cylinderTransMT31 = new osg::MatrixTransform;
- osg::MatrixTransform *cylinderRotMT3 = new osg::MatrixTransform;
- osg::MatrixTransform *cylinderTransMT32 = new osg::MatrixTransform;
- cylinderTransMT31->setMatrix(osg::Matrix::translate(-200, 0, 0));
- cylinderRotMT3->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(135.0), osg::X_AXIS));
- cylinderTransMT32->setMatrix(osg::Matrix::translate(0, 0, -500));
- cylinderTransMT32->addChild(createCylinder2());
- cylinderTransMT31->addChild(cylinderRotMT3);
- cylinderRotMT3->addChild(cylinderTransMT32);
- rotMT->addChild(cylinderRotMT1);
- rotMT->addChild(cylinderTransMT2);
- rotMT->addChild(cylinderTransMT31);
- for (int i = 0; i < NrOfBalls; ++i)
- {
- osg::MatrixTransform *mt = new osg::MatrixTransform;
- mt->addUpdateCallback(new PostionUpdateCallback(i));
- mt->addChild(createBalls(i));
- rotMT->addChild(mt);
- }
- //
- for (int i = 0; i < 20; ++i)
- {
- osg::Switch *switchNode = new osg::Switch;
- g_SwitchNode = switchNode;
- switchNode->addUpdateCallback(new CollisionSwitchUpdateCallback(i));
- osg::MatrixTransform *collisionScale = new osg::MatrixTransform;
- collisionScale->addUpdateCallback(new CollisionScaleUpdateCallback(i));
- osg::MatrixTransform *collisionMT = new osg::MatrixTransform;
- collisionMT->addUpdateCallback(new CollisionTransUpdateCallback(i));
- osg::Node *collisionNode = createExplorsionNode(i);
- collisionScale->addChild(collisionMT);
- collisionMT->addChild(collisionNode);
- switchNode->addChild(collisionScale);
- rotMT->addChild(switchNode);
- }
- root->addChild(rotMT);
- return root;
- }
- int main( int argc, char** argv )
- {
- QApplication app(argc, argv);
- ViewerWidget* viewWidget = new ViewerWidget(buildScene());
- viewWidget->setGeometry( 100, 100, 640, 480 );
- viewWidget->show();
- return app.exec();
- }