OSG实现场景漫游

下面的代码将可以实现场景模型的导入,然后在里面任意行走,于此同时还实现了碰撞检测。

源代码下载地址:

/* * File : Travel.cpp * Description : * Author : GuoShaoHao * E-mail : [email protected] * Date : 2011/01/08 * * CopyRight @ South China Institute of Software Engineering,.GZU * */ #include <iostream> #include <osgViewer/Viewer> #include <osg/Node> #include <osg/Geode> #include <osg/Group> #include <osgDB/ReadFile> #include <osgDB/WriteFile> #include <osgUtil/Optimizer> #include <osg/MatrixTransform> #include <osgViewer/ViewerEventHandlers> #include <osgGA/StateSetManipulator> #include "TravelManipulator.h" using namespace std; int main() { //创建Viewer对象 osg::ref_ptr<osgViewer::Viewer>viewer = new osgViewer::Viewer(); //添加状态事件 //viewer.get()->addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) ); //窗口大小变化事件 viewer.get()->addEventHandler(new osgViewer::WindowSizeHandler); //添加一些常用状态设置 viewer.get()->addEventHandler(new osgViewer::StatsHandler); // 把漫游器加入到场景中 TravelManipulator::TravelToScence(viewer.get()); osg::ref_ptr<osg::Group>root = new osg::Group(); // 读取地形 osg::ref_ptr<osg::Node>node = osgDB::readNodeFile("D://OSG//data//lz.osg"); // 读取飞机 //osg::ref_ptr<osg::Node>tank = osgDB::readNodeFile("F://Models//Amx30//Amx30.IVE"); osg::ref_ptr<osg::Node>B25 = osgDB::readNodeFile("Models//B25//B25.IVE"); osg::ref_ptr < osg::MatrixTransform> scale = new osg::MatrixTransform ; scale ->setMatrix(osg::Matrix::scale(0.1, 0.1, 0.1)*osg::Matrix::translate(-10.0f, -250.0f, 99.0f)) ; scale ->addChild(B25.get()) ; // 添加到场景 root->addChild(node.get()); root->addChild(scale.get()); //root->addChild(B25.get()); // 优化场景数据 osgUtil::Optimizer optimizer; optimizer.optimize(root.get()); viewer->setSceneData(root.get()); viewer->realize(); viewer->run(); return 0; }

#pragma once #include <osgViewer/Viewer> #include <osg/LineSegment> #include <osg/Point> #include <osg/Geometry> #include <osg/Node> #include <osg/Geode> #include <osg/Group> #include <osgGA/MatrixManipulator> #include <osgUtil/IntersectVisitor> #include <vector> class TravelManipulator:public osgGA::MatrixManipulator { public: TravelManipulator(void); ~TravelManipulator(void); // 把漫游器添加到场景中 static TravelManipulator * TravelToScence(osg::ref_ptr<osgViewer::Viewer>viewer); private: osg::ref_ptr<osgViewer::Viewer>m_pHostViewer; // 移动速度 float m_fMoveSpeed; // 当前位置 osg::Vec3 m_vPosition; // 旋转角度 osg::Vec3 m_vRotation; public: // 鼠标左键状态 bool m_bLeftButtonDown; // 鼠标位置 float m_fpushX; float m_fpushY; // 设置矩阵 virtual void setByMatrix(const osg::Matrix &matrix); // 设置逆矩阵 virtual void setByInverseMatrix(const osg::Matrix &matrix); // 获取矩阵 virtual osg::Matrixd getMatrix() const; // 获取逆矩阵 virtual osg::Matrixd getInverseMatrix() const; // 事件处理函数 virtual bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us); // 屏幕角度 float m_fAngle; // 位置变换 void ChangePosition(osg::Vec3 &delta); // 碰撞检测状态 bool m_bPeng; // 设置速度 float getSpeed(); void setSpeed(float &); // 设置初始位置 void SetPosition(osg::Vec3 &position); osg::Vec3 GetPosition(); };

#include "TravelManipulator.h" // 构造函数 TravelManipulator::TravelManipulator():m_fMoveSpeed(1.0f), m_bLeftButtonDown(false), m_fpushX(0), m_fAngle(2.5), m_bPeng(true), m_fpushY(0) { m_vPosition = osg::Vec3(-22.0f, -274.0f, 100.0f); m_vRotation = osg::Vec3(osg::PI_2, 0.0f, 0.0f); } TravelManipulator::~TravelManipulator(void) { } // 把漫游器添加到场景中 TravelManipulator *TravelManipulator::TravelToScence(osg::ref_ptr<osgViewer::Viewer> viewer) { TravelManipulator* camera = new TravelManipulator; viewer->setCameraManipulator(camera); camera->m_pHostViewer = viewer; return camera; } // 设置矩阵 void TravelManipulator::setByMatrix(const osg::Matrix &matrix) { } // 设置逆矩阵 void TravelManipulator::setByInverseMatrix(const osg::Matrix &matrix) { } // 得到矩阵 osg::Matrixd TravelManipulator::getMatrix(void)const { osg::Matrixd mat; mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f), m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f), m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f)); return mat * osg::Matrixd::translate(m_vPosition); } // 得到逆矩阵 osg::Matrixd TravelManipulator::getInverseMatrix(void) const { osg::Matrixd mat; mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f), m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f), m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f)); return osg::Matrixd::inverse(mat * osg::Matrixd::translate(m_vPosition)); } // 事件处理函数 bool TravelManipulator::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us) { // 获取鼠标位置 float mouseX = ea.getX(); float mouseY = ea.getY(); switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYDOWN): { // 空格键 if(ea.getKey() == 0x20) { us.requestRedraw(); us.requestContinuousUpdate(false); return true; } // 上移键 if (ea.getKey() == 0xFF50) { ChangePosition(osg::Vec3(0, 0, m_fMoveSpeed)); return true; } // 下移键 if (ea.getKey() == 0xFF57) { ChangePosition(osg::Vec3(0, 0, -m_fMoveSpeed)); return true; } // 加速 if (ea.getKey() == 0x2B) { m_fMoveSpeed += 1.0f; return true; } // 减少速度 if (ea.getKey() == 0x2D) { m_fMoveSpeed -= 0.1f; if(m_fMoveSpeed < 1.0f) { m_fMoveSpeed = 1.0f; } return true; } // 前进 if (ea.getKey() == 0xFF52 || ea.getKey() == 0x57 || ea.getKey() == 0x77) { ChangePosition(osg::Vec3(0, m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0)); ChangePosition(osg::Vec3(m_fMoveSpeed * cosf(osg::PI_2 + m_vRotation._v[2]),0,0)); return true; } // 后退 if (ea.getKey() == 0xFF54 || ea.getKey() == 0x53 || ea.getKey() == 0x73) { ChangePosition(osg::Vec3(0, -m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]), 0)); ChangePosition(osg::Vec3(-m_fMoveSpeed * cosf(osg::PI_2 + m_vRotation._v[2]),0,0)); return true; } // 向左 if (ea.getKey() == 0x41 || ea.getKey() == 0x61) { ChangePosition(osg::Vec3(0, m_fMoveSpeed * cosf(osg::PI_2 + m_vRotation._v[2]),0)); ChangePosition(osg::Vec3(-m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]),0,0)); return true; } // 向右 if (ea.getKey() == 0x44 || ea.getKey() == 0x64) { ChangePosition(osg::Vec3(0, -m_fMoveSpeed * cosf(osg::PI_2 + m_vRotation._v[2]),0)); ChangePosition(osg::Vec3(m_fMoveSpeed * sinf(osg::PI_2 + m_vRotation._v[2]),0,0)); return true; } // 向右转 if (ea.getKey() == 0xFF53) { m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle); } // 向左转 if (ea.getKey() == 0xFF51) { m_vRotation._v[2] += osg::DegreesToRadians(m_fAngle); } // 改变屏幕角度F键 if (ea.getKey() == 0x46 || ea.getKey() == 0x66) { m_fAngle -= 0.2; return true; } //G键 if (ea.getKey() == 0x47 || ea.getKey() == 0x66) { m_fAngle += 0.2; return true; } return true; } case(osgGA::GUIEventAdapter::PUSH): if (ea.getButton() == 1) { m_fpushX = mouseX; m_fpushY = mouseY; m_bLeftButtonDown = true; } return true; // 拖动 case(osgGA::GUIEventAdapter::DRAG): if (m_bLeftButtonDown) { m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle * (mouseX - m_fpushX)) / 200; m_vRotation._v[0] += osg::DegreesToRadians(1.1 * (mouseY - m_fpushY)) / 200; if (m_vRotation._v[0] >= 3.14) { m_vRotation._v[0] = 3.14; } if (m_vRotation._v[0] <= 0) { m_vRotation._v[0] = 0; } } return false; // 鼠标释放 case(osgGA::GUIEventAdapter::RELEASE): if (ea.getButton() == 1) { m_bLeftButtonDown = false; } return false; default: return false; } } // 位置变换函数 void TravelManipulator::ChangePosition(osg::Vec3 &delta) { // 碰撞检测 if (m_bPeng) { // 得到新的位置 osg::Vec3 newPos1 = m_vPosition + delta; osgUtil::IntersectVisitor ivXY; // 根据新的位置得到两条线段检测 osg::ref_ptr<osg::LineSegment>lineXY = new osg::LineSegment(newPos1, m_vPosition); osg::ref_ptr<osg::LineSegment>lineZ = new osg::LineSegment(newPos1 + osg::Vec3(0.0f, 0.0f, 10.0f), newPos1 - osg::Vec3(0.0f, 0.0f, -10.0f)); ivXY.addLineSegment(lineZ.get()); ivXY.addLineSegment(lineXY.get()); // 结构交集检测 m_pHostViewer->getSceneData()->accept(ivXY); // 如果没有碰撞 if (!ivXY.hits()) { m_vPosition += delta; } } else { m_vPosition += delta; } } // 设置速度 void TravelManipulator::setSpeed(float &sp) { m_fMoveSpeed = sp; } // 获得当前速度 float TravelManipulator::getSpeed() { return m_fMoveSpeed; } // 设置起始的位置 void TravelManipulator::SetPosition(osg::Vec3 &position) { m_vPosition = position; } // 得到当前所在位置 osg::Vec3 TravelManipulator::GetPosition() { return m_vPosition; }

<!--EndFragment-->