OpenSceneGraph实现的NeHe OpenGL教程 - 第三十课
2016-08-17 14:06
435 查看
简介
这节课NeHe课程实现了在场景中进行碰撞检测以及简单的物理作用(碰撞之后的反弹),碰撞检测三维图形学中一个比较高级的主题,本课只涉及了简单的规则几何体之间的碰撞检测,更复杂的实例需要读者去更深入的学习。实现
本课中碰撞检测的算法包括线与平面的求交检测、线与圆柱体的求交、以及球体之间的碰撞检测,这些碰撞检测的原理可以参考NeHe中的介绍。具体实现在如下几个函数中:
[cpp] view
plain copy
///////////////////////////线面相交////////////////////////////////
//////////////////////////////////////////////////////////////////////////
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)
之后再每帧中计算了各球体与不同几何体之间的碰撞,具体代码在idle函数中
接下来创建本课中的几何体(包括墙面、地面、圆柱体等)
[cpp] view
plain copy
osg::Geode* createWalls()
osg::Geode* createFloor()
osg::Geode* createCylinder()
osg::Geode* createCylinder2()
osg::Geode* createBalls(int i)
在ManipulatorSceneHandler中的Frame时间中不断地进行计算和判断每个球体的位置(调用idle)
[cpp] view
plain copy
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课程中下载]
[cpp] view
plain copy
#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();
}
相关文章推荐
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第四课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第三课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十八课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十四课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第五课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十六课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十一课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十八课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十六课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十二课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十一课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第九课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十二课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十四课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第六课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第八课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十九课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十三课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第十九课_附录1