您的位置:首页 > 运维架构

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();

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: