-
简介
本文实现从外部文件中加载场景,并进行简单的场景漫游操作。
一般来说,场景都是通过外部建模工具生成的,然后再通过osg进行读取加载,一方面直接通过顶点生成场景对程序员来说十分困难,另一方面通过外部建模的方式加载场景使得程序变得十分灵活。像我们玩的CS游戏就是通过加载一些地图文件实现在不同的场景之中战斗。
在NeHe教程中实现的过程介绍的非常清楚,不熟悉的读者可以参考NeHe教程第十课。在这里我们同样使用NeHe中读取文件的方式以及行进的方式,代码如下
- typedef struct tagVERTEX
- {
- float x,y,z;
- float u,v;
- }VERTEX;
- typedef struct tagTRIANGLE
- {
- VERTEX vertex[3];
- }TRIANGLE;
- typedef struct tagSECTOR
- {
- int iNumTriangle;
- TRIANGLE *pTriangle;
- }SECTOR;
- SECTOR Sector;
- void readstr(FILE *f,char *string)
- {
- do
- {
- fgets(string, 255, f);
- } while ((string[0] == '/') || (string[0] == '\n'));
- }
- void SetupWorld()
- {
- float x, y, z, u, v;
- int numtriangles;
- FILE *filein;
- char oneline[255];
- filein = fopen("Data/world.txt", "rt"); // File To Load World Data From
- readstr(filein,oneline);
- sscanf(oneline, "NUMPOLLIES %d\n", &numtriangles);
- Sector.iNumTriangle = numtriangles;
- Sector.pTriangle = new TRIANGLE[numtriangles];
- for(int i = 0; i < numtriangles; i++)
- {
- for(int j = 0; j < 3; j++)
- {
- readstr(filein,oneline);
- sscanf(oneline, "%f %f %f %f %f", &x, &y, &z, &u, &v);
- Sector.pTriangle[i].vertex[j].x = x;
- Sector.pTriangle[i].vertex[j].y = y;
- Sector.pTriangle[i].vertex[j].z = z;
- Sector.pTriangle[i].vertex[j].u = u;
- Sector.pTriangle[i].vertex[j].v = v;
- }
- }
- fclose(filein);
- }
读取文件的方式有很多种,(在我们的Qt框架中可以通过QFile和QTextStream等方式读取)为了节省时间此处借用了NeHe源码中的读取方式
- const float piover180 = 0.0174532925f;
- float heading;
- float xpos;
- float zpos;
- GLfloat yrot;
- GLfloat walkbias = 0;
- GLfloat walkbiasangle = 0;
- GLfloat lookupdown = 0.0f;
(绕X轴旋转)
- class TransUpdateCallback : public osg::NodeCallback
- {
- public:
- TransUpdateCallback()
- {
- GLfloat xtrans = -xpos;
- GLfloat ztrans = -zpos;
- GLfloat ytrans = -walkbias-0.25f;
- _trans = osg::Vec3d(xtrans, ytrans, ztrans);
- }
- virtual void operator()(Node* node, NodeVisitor* nv)
- {
- if (dynamic_cast<osg::MatrixTransform*>(node))
- {
- osg::MatrixTransform *moveMT = dynamic_cast<osg::MatrixTransform*>(node);
- moveMT->setMatrix(osg::Matrix::translate(_trans));
- }
- traverse(node, nv);
- }
- void setTrans(osg::Vec3d trans)
- {
- _trans = trans;
- }
- osg::Vec3d _trans;
- };
- class RotateXUpdateCallback : public osg::NodeCallback
- {
- public:
- RotateXUpdateCallback()
- {
- _pitch = lookupdown;
- }
- virtual void operator()(Node* node, NodeVisitor* nv)
- {
- if (dynamic_cast<osg::MatrixTransform*>(node))
- {
- osg::MatrixTransform *rotateX = dynamic_cast<osg::MatrixTransform*>(node);
- rotateX->setMatrix(osg::Matrix::rotate(_pitch, osg::X_AXIS));
- }
- traverse(node, nv);
- }
- void setPitch(double pitch)
- {
- _pitch = pitch;
- }
- double _pitch;
- };
- class RotateYUpdateCallback : public osg::NodeCallback
- {
- public:
- RotateYUpdateCallback()
- {
- _heading = osg::DegreesToRadians(360.0f) - yrot;
- }
- virtual void operator()(Node* node, NodeVisitor* nv)
- {
- if (dynamic_cast<osg::MatrixTransform*>(node))
- {
- osg::MatrixTransform *rotateY = dynamic_cast<osg::MatrixTransform*>(node);
- rotateY->setMatrix(osg::Matrix::rotate(_heading, osg::Y_AXIS));
- }
- traverse(node, nv);
- }
- void setHeading(double heading)
- {
- _heading = heading;
- }
- double _heading;
- };
- TransUpdateCallback *g_moveMTCB;
- RotateXUpdateCallback *g_xRotMTCB;
- RotateYUpdateCallback *g_yRotMTCB;
- osg::Group *root = new osg::Group;
- osg::Vec3Array *vertexArray = new osg::Vec3Array;
- osg::Vec2Array *textureArray = new osg::Vec2Array;
- unsigned int num = Sector.iNumTriangle;
- for (unsigned i = 0; i < num; ++i)
- {
- vertexArray->push_back(osg::Vec3(Sector.pTriangle[i].vertex[0].x, Sector.pTriangle[i].vertex[0].y, Sector.pTriangle[i].vertex[0].z));
- vertexArray->push_back(osg::Vec3(Sector.pTriangle[i].vertex[1].x, Sector.pTriangle[i].vertex[1].y, Sector.pTriangle[i].vertex[1].z));
- vertexArray->push_back(osg::Vec3(Sector.pTriangle[i].vertex[2].x, Sector.pTriangle[i].vertex[2].y, Sector.pTriangle[i].vertex[2].z));
- textureArray->push_back(osg::Vec2(Sector.pTriangle[i].vertex[0].u, Sector.pTriangle[i].vertex[0].v));
- textureArray->push_back(osg::Vec2(Sector.pTriangle[i].vertex[1].u, Sector.pTriangle[i].vertex[1].v));
- textureArray->push_back(osg::Vec2(Sector.pTriangle[i].vertex[2].u, Sector.pTriangle[i].vertex[2].v));
- }
- osg::MatrixTransform *moveMT = new osg::MatrixTransform;
- TransUpdateCallback *tucb = new TransUpdateCallback;
- moveMT->setUpdateCallback(tucb);
- g_moveMTCB = tucb;
- osg::MatrixTransform *headingMT = new osg::MatrixTransform;
- RotateYUpdateCallback *ryuc = new RotateYUpdateCallback;
- headingMT->setUpdateCallback(ryuc);
- g_yRotMTCB = ryuc;
- osg::MatrixTransform *pitchMT = new osg::MatrixTransform;
- RotateXUpdateCallback *rxuc = new RotateXUpdateCallback;
- pitchMT->setUpdateCallback(rxuc);
- g_xRotMTCB = rxuc;
- headingMT->addChild(pitchMT);
- pitchMT->addChild(moveMT);
- osg::Geometry *triangleGeometry = new osg::Geometry;
- triangleGeometry->setVertexArray(vertexArray);
- triangleGeometry->setTexCoordArray(0, textureArray);
- triangleGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, createTexture(0));
- triangleGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 108));
- osg::Geode *triangleGeode = new osg::Geode;
- triangleGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- triangleGeode->addDrawable(triangleGeometry);
- moveMT->addChild(triangleGeode);
- root->addChild(headingMT);
- switch(ea.getEventType())
- {
- case(osgGA::GUIEventAdapter::KEYDOWN):
- {
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)
- {
- xpos -= (float)sin(heading*piover180) * 0.05f;
- zpos -= (float)cos(heading*piover180) * 0.05f;
- if (walkbiasangle >= 359.0f)
- {
- walkbiasangle = 0.0f;
- }
- else
- {
- walkbiasangle+= 10;
- }
- walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
- GLfloat ytrans = -walkbias-0.25f;
- g_moveMTCB->setTrans(osg::Vec3d(-xpos, ytrans, -zpos));
- }
- if (ea.getKey()== osgGA::GUIEventAdapter::KEY_Down)
- {
- xpos += (float)sin(heading*piover180) * 0.05f;
- zpos += (float)cos(heading*piover180) * 0.05f;
- if (walkbiasangle <= 1.0f)
- {
- walkbiasangle = 359.0f;
- }
- else
- {
- walkbiasangle-= 10;
- }
- walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
- GLfloat ytrans = -walkbias-0.25f;
- g_moveMTCB->setTrans(osg::Vec3d(-xpos, ytrans, -zpos));
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)
- {
- heading -= 1.0f;
- yrot = heading;
- double direction = osg::DegreesToRadians(360.0f) - osg::DegreesToRadians(yrot);
- g_yRotMTCB->setHeading(direction);
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)
- {
- heading += 1.0f;
- yrot = heading;
- double direction = osg::DegreesToRadians(360.0f) - osg::DegreesToRadians(yrot);
- g_yRotMTCB->setHeading(direction);
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Up)
- {
- lookupdown += 1.0f;
- double direction = osg::DegreesToRadians(lookupdown);
- g_xRotMTCB->setPitch(direction);
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Down)
- {
- lookupdown -= 1.0f;
- double direction = osg::DegreesToRadians(lookupdown);
- g_xRotMTCB->setPitch(direction);
- }
- }
- default: break;
- }
编译运行程序
附:本课源码(源码中可能存在错误和不足,仅供参考)
- #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/Texture2D>
- #include <osgGA/TrackballManipulator>
- using namespace osg;
- //
- //Copied From NeHe Tutorial
- typedef struct tagVERTEX
- {
- float x,y,z;
- float u,v;
- }VERTEX;
- typedef struct tagTRIANGLE
- {
- VERTEX vertex[3];
- }TRIANGLE;
- typedef struct tagSECTOR
- {
- int iNumTriangle;
- TRIANGLE *pTriangle;
- }SECTOR;
- SECTOR Sector;
- void readstr(FILE *f,char *string)
- {
- do
- {
- fgets(string, 255, f);
- } while ((string[0] == '/') || (string[0] == '\n'));
- }
- void SetupWorld()
- {
- float x, y, z, u, v;
- int numtriangles;
- FILE *filein;
- char oneline[255];
- filein = fopen("Data/world.txt", "rt"); // File To Load World Data From
- readstr(filein,oneline);
- sscanf(oneline, "NUMPOLLIES %d\n", &numtriangles);
- Sector.iNumTriangle = numtriangles;
- Sector.pTriangle = new TRIANGLE[numtriangles];
- for(int i = 0; i < numtriangles; i++)
- {
- for(int j = 0; j < 3; j++)
- {
- readstr(filein,oneline);
- sscanf(oneline, "%f %f %f %f %f", &x, &y, &z, &u, &v);
- Sector.pTriangle[i].vertex[j].x = x;
- Sector.pTriangle[i].vertex[j].y = y;
- Sector.pTriangle[i].vertex[j].z = z;
- Sector.pTriangle[i].vertex[j].u = u;
- Sector.pTriangle[i].vertex[j].v = v;
- }
- }
- fclose(filein);
- }
- //End
- //
- const float piover180 = 0.0174532925f;
- float heading;
- float xpos;
- float zpos;
- GLfloat yrot;
- GLfloat walkbias = 0;
- GLfloat walkbiasangle = 0;
- GLfloat lookupdown = 0.0f;
- //
- //TransUpdateCallback
- class TransUpdateCallback : public osg::NodeCallback
- {
- public:
- TransUpdateCallback()
- {
- GLfloat xtrans = -xpos;
- GLfloat ztrans = -zpos;
- GLfloat ytrans = -walkbias-0.25f;
- _trans = osg::Vec3d(xtrans, ytrans, ztrans);
- }
- virtual void operator()(Node* node, NodeVisitor* nv)
- {
- if (dynamic_cast<osg::MatrixTransform*>(node))
- {
- osg::MatrixTransform *moveMT = dynamic_cast<osg::MatrixTransform*>(node);
- moveMT->setMatrix(osg::Matrix::translate(_trans));
- }
- traverse(node, nv);
- }
- void setTrans(osg::Vec3d trans)
- {
- _trans = trans;
- }
- osg::Vec3d _trans;
- };
- //End
- //
- //
- //RotateUpdateCallback
- class RotateXUpdateCallback : public osg::NodeCallback
- {
- public:
- RotateXUpdateCallback()
- {
- _pitch = lookupdown;
- }
- virtual void operator()(Node* node, NodeVisitor* nv)
- {
- if (dynamic_cast<osg::MatrixTransform*>(node))
- {
- osg::MatrixTransform *rotateX = dynamic_cast<osg::MatrixTransform*>(node);
- rotateX->setMatrix(osg::Matrix::rotate(_pitch, osg::X_AXIS));
- }
- traverse(node, nv);
- }
- void setPitch(double pitch)
- {
- _pitch = pitch;
- }
- double _pitch;
- };
- class RotateYUpdateCallback : public osg::NodeCallback
- {
- public:
- RotateYUpdateCallback()
- {
- _heading = osg::DegreesToRadians(360.0f) - yrot;
- }
- virtual void operator()(Node* node, NodeVisitor* nv)
- {
- if (dynamic_cast<osg::MatrixTransform*>(node))
- {
- osg::MatrixTransform *rotateY = dynamic_cast<osg::MatrixTransform*>(node);
- rotateY->setMatrix(osg::Matrix::rotate(_heading, osg::Y_AXIS));
- }
- traverse(node, nv);
- }
- void setHeading(double heading)
- {
- _heading = heading;
- }
- double _heading;
- };
- //End
- //
- TransUpdateCallback *g_moveMTCB;
- RotateXUpdateCallback *g_xRotMTCB;
- RotateYUpdateCallback *g_yRotMTCB;
- osg::Texture2D* createTexture(int mode)
- {
- osg::Image *textureImage = osgDB::readImageFile("Data/Mud.bmp");
- osg::Texture2D *texture2D = new osg::Texture2D;
- texture2D->setImage(textureImage);
- if (mode == 0)
- {
- texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
- texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
- }
- else if (mode == 1)
- {
- texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
- texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- }
- else if (mode == 2)
- {
- texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_NEAREST);
- texture2D->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- }
- texture2D->setWrap(osg::Texture::WRAP_R, osg::Texture::REPEAT);
- texture2D->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
- texture2D->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
- return texture2D;
- }
- //
- class ManipulatorSceneHandler : public osgGA::GUIEventHandler
- {
- public:
- ManipulatorSceneHandler()
- {
- }
- 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::KEYDOWN):
- {
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Up)
- {
- xpos -= (float)sin(heading*piover180) * 0.05f;
- zpos -= (float)cos(heading*piover180) * 0.05f;
- if (walkbiasangle >= 359.0f)
- {
- walkbiasangle = 0.0f;
- }
- else
- {
- walkbiasangle+= 10;
- }
- walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
- GLfloat ytrans = -walkbias-0.25f;
- g_moveMTCB->setTrans(osg::Vec3d(-xpos, ytrans, -zpos));
- }
- if (ea.getKey()== osgGA::GUIEventAdapter::KEY_Down)
- {
- xpos += (float)sin(heading*piover180) * 0.05f;
- zpos += (float)cos(heading*piover180) * 0.05f;
- if (walkbiasangle <= 1.0f)
- {
- walkbiasangle = 359.0f;
- }
- else
- {
- walkbiasangle-= 10;
- }
- walkbias = (float)sin(walkbiasangle * piover180)/20.0f;
- GLfloat ytrans = -walkbias-0.25f;
- g_moveMTCB->setTrans(osg::Vec3d(-xpos, ytrans, -zpos));
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)
- {
- heading -= 1.0f;
- yrot = heading;
- double direction = osg::DegreesToRadians(360.0f) - osg::DegreesToRadians(yrot);
- g_yRotMTCB->setHeading(direction);
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)
- {
- heading += 1.0f;
- yrot = heading;
- double direction = osg::DegreesToRadians(360.0f) - osg::DegreesToRadians(yrot);
- g_yRotMTCB->setHeading(direction);
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Up)
- {
- lookupdown += 1.0f;
- double direction = osg::DegreesToRadians(lookupdown);
- g_xRotMTCB->setPitch(direction);
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Page_Down)
- {
- lookupdown -= 1.0f;
- double direction = osg::DegreesToRadians(lookupdown);
- g_xRotMTCB->setPitch(direction);
- }
- }
- default: break;
- }
- return false;
- }
- };
- //
- 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, 1.0) );
- camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
- camera->setProjectionMatrixAsPerspective(45.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 0.1f, 100.0f );
- camera->setViewMatrixAsLookAt(osg::Vec3d(0, 0, 1), osg::Vec3d(0, 0, 0), osg::Vec3d(0, 1, 0));
- this->setSceneData( scene );
- this->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()
- {
- SetupWorld();
- osg::Group *root = new osg::Group;
- osg::Vec3Array *vertexArray = new osg::Vec3Array;
- osg::Vec2Array *textureArray = new osg::Vec2Array;
- unsigned int num = Sector.iNumTriangle;
- for (unsigned i = 0; i < num; ++i)
- {
- vertexArray->push_back(osg::Vec3(Sector.pTriangle[i].vertex[0].x, Sector.pTriangle[i].vertex[0].y, Sector.pTriangle[i].vertex[0].z));
- vertexArray->push_back(osg::Vec3(Sector.pTriangle[i].vertex[1].x, Sector.pTriangle[i].vertex[1].y, Sector.pTriangle[i].vertex[1].z));
- vertexArray->push_back(osg::Vec3(Sector.pTriangle[i].vertex[2].x, Sector.pTriangle[i].vertex[2].y, Sector.pTriangle[i].vertex[2].z));
- textureArray->push_back(osg::Vec2(Sector.pTriangle[i].vertex[0].u, Sector.pTriangle[i].vertex[0].v));
- textureArray->push_back(osg::Vec2(Sector.pTriangle[i].vertex[1].u, Sector.pTriangle[i].vertex[1].v));
- textureArray->push_back(osg::Vec2(Sector.pTriangle[i].vertex[2].u, Sector.pTriangle[i].vertex[2].v));
- }
- osg::MatrixTransform *moveMT = new osg::MatrixTransform;
- TransUpdateCallback *tucb = new TransUpdateCallback;
- moveMT->setUpdateCallback(tucb);
- g_moveMTCB = tucb;
- osg::MatrixTransform *headingMT = new osg::MatrixTransform;
- RotateYUpdateCallback *ryuc = new RotateYUpdateCallback;
- headingMT->setUpdateCallback(ryuc);
- g_yRotMTCB = ryuc;
- osg::MatrixTransform *pitchMT = new osg::MatrixTransform;
- RotateXUpdateCallback *rxuc = new RotateXUpdateCallback;
- pitchMT->setUpdateCallback(rxuc);
- g_xRotMTCB = rxuc;
- headingMT->addChild(pitchMT);
- pitchMT->addChild(moveMT);
- osg::Geometry *triangleGeometry = new osg::Geometry;
- triangleGeometry->setVertexArray(vertexArray);
- triangleGeometry->setTexCoordArray(0, textureArray);
- triangleGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, createTexture(0));
- triangleGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 108));
- osg::Geode *triangleGeode = new osg::Geode;
- triangleGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- triangleGeode->addDrawable(triangleGeometry);
- moveMT->addChild(triangleGeode);
- root->addChild(headingMT);
- 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();
- }