效果图如下:
以下是South.h文件的源码
//操作器管理类,用来管理操作器
#include <osgViewer/Viewer>
#include <osgGA/CameraManipulator>
#include <osgUtil/IntersectVisitor>
#include <osg/LineSegment>
class CSouth:public osgGA::CameraManipulator
{
public:
CSouth();
public:
~CSouth();
private:
//节点值,用来测试碰撞检测的
osg::ref_ptr<osg::Node> m_node;
//相机操作器
unsigned int m_nID;
//移动速度
float m_fMoveSpeed;
//位置
osg::Vec3 m_vPosition;
//旋转角度
osg::Vec3 m_vRotation;
//左键是否按下
bool m_bLeftButtonDown;
//左键点下时屏幕坐标
float m_fpushX;
//碰撞检测开启状态查询。
bool m_bPeng;
//右键点下时屏幕坐标
float m_fpushY;
public:
//碰撞检测是否开启
void setPeng(bool peng);
//得到碰撞检测开启状态
bool getPeng();
//如果碰撞检测开启则关闭,如果关闭则开启
void setFpeng();
//设置要进行碰撞检测的数据
virtual void setNode(osg::Node *);
virtual void setByMatrix(const osg::Matrixd& matrix);
virtual void setByInverseMatrix(const osg::Matrixd& 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 changePostition(osg::Vec3 &delta);
//得到当前速度
float getSpend();
//设置当前速度
void setSpend(float);
//设置视点位置
void setPosition(osg::Vec3 &position);
void setPosition(double *);
//得到当前视点位置
osg::Vec3 getPosition();
//计算家的位置
void computeHomePosition();
};
以下是South.cpp文件的源码:
#include "stdafx.h"
#include "South.h"
//设置一些初始值 左键没有按下,左键点下时初始坐标为0,初始角速度是2.5,开始时碰撞检测关闭,右键点下时初始坐标也为0
CSouth::CSouth():m_fMoveSpeed(1.5),m_bLeftButtonDown(false),m_fpushX(0),m_fAngle(2.5),m_bPeng(false),m_fpushY(0)
{
//出生点为000
m_vPosition=osg::Vec3(0.0,0.0,5.0);
//初始角度
m_vRotation=osg::Vec3(osg::PI_2,0.0,0.0);
}
CSouth::~CSouth()
{
}
//碰撞检测是否开启
void CSouth::setPeng(bool peng)
{
m_bPeng=peng;
}
//得到碰撞检测开启状态
bool CSouth::getPeng()
{
return m_bPeng;
}
//如果碰撞检测开启则关闭,如果关闭则开启
void CSouth::setFpeng()
{
m_bPeng=!m_bPeng;
}
//设置要进行碰撞检测的数据
void CSouth::setNode(osg::Node *node)
{
m_node=node;
}
void CSouth::setByMatrix(const osg::Matrixd &matrix)
{
}
void CSouth::setByInverseMatrix(const osg::Matrixd &matrix)
{
}
//得到矩阵,这是标准接口,用于控制场景
osg::Matrixd CSouth::getMatrix() const
{
//得到旋转后的矩阵,其实也就是视口矩阵,用此控制场景
osg::Matrixd mat;
mat.makeRotate(m_vRotation._v[0],osg::Vec3(1.0,0.0,0.0),m_vRotation._v[1],osg::Vec3(0.0,1.0,0.0),m_vRotation._v[2],osg::Vec3(0.0,0.0,1.0));
return mat*osg::Matrixd::translate(m_vRotation);
}
//得到逆矩阵,标准接口,控制场景
osg::Matrixd CSouth::getInverseMatrix() const
{
osg::Matrixd mat;
mat.makeRotate(m_vRotation._v[0],osg::Vec3(1.0,0.0,0.0),m_vRotation._v[1],osg::Vec3(0.0,1.0,0.0),m_vRotation._v[2],osg::Vec3(0.0,0.0,1.0));
return osg::Matrixd::inverse(mat*osg::Matrixd::translate(m_vPosition));
}
//主要事件控制器
bool CSouth::handle(const osgGA::GUIEventAdapter &ea,osgGA::GUIActionAdapter &us)
{
//得到x的初始屏幕坐标
float mouseX=ea.getX();
//得到y的初始屏幕坐标
float mouseY=ea.getY();
//判断事件类型
switch(ea.getEventType())
{
case osgGA::GUIEventAdapter::KEYDOWN:
{
//如果是空格,重绘
if (ea.getKey()==0x20)
{
us.requestRedraw();
us.requestContinuousUpdate(false);
return true;
}
//如果是home键,则视点向上移动
if (ea.getKey()==0xFF50)
{
changePostition(osg::Vec3(0,0,m_fMoveSpeed));
return true;
}
//如果是end键,同视点向下移动
if (ea.getKey()==0xFF57)
{
changePostition(osg::Vec3(0,0,-m_fMoveSpeed));
return true;
}
//如果是加号键则加速
if (ea.getKey()==0x2B)
{
m_fMoveSpeed+=1.0;
return true;
}
//如果是减号键则减速
if (ea.getKey()==0x2D)
{
m_fMoveSpeed-=1.0;
if (m_fMoveSpeed<1.0)
{
m_fMoveSpeed=1.0;
}
return true;
}
//向前走,W键,或者UP键
if (ea.getKey()==0xFF52||ea.getKey()==0x57||ea.getKey()==0x77)
{
changePostition(osg::Vec3(0,m_fMoveSpeed*sinf(osg::PI_2+m_vRotation._v[2]),0));
changePostition(osg::Vec3(m_fMoveSpeed*cosf(osg::PI_2+m_vRotation._v[2]),0,0));
return true;
}
//向后退,S键,或者DOWN键
if (ea.getKey()==0xFF54||ea.getKey()==0x53||ea.getKey()==0x73)
{
changePostition(osg::Vec3(0,-m_fMoveSpeed*sinf(osg::PI_2+m_vRotation._v[2]),0));
changePostition(osg::Vec3(-m_fMoveSpeed*cosf(osg::PI_2+m_vRotation._v[2]),0,0));
return true;
}
//A
if (ea.getKey()==0x41||ea.getKey()==0x61)
{
changePostition(osg::Vec3(0,m_fMoveSpeed*cosf(osg::PI_2+m_vRotation._v[2]),0));
changePostition(osg::Vec3(m_fMoveSpeed*sinf(osg::PI_2+m_vRotation._v[2]),0,0));
return true;
}
//D
if (ea.getKey () == 0x44||ea.getKey () == 0x64)
{
changePostition(osg::Vec3 (0,-m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0)) ;
changePostition(osg::Vec3 (m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]), 0, 0)) ;
return true;
}
if (ea.getKey() == 0xFF53)//Right
{
m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle);
}
if (ea.getKey()== 0xFF51)//Left
{
m_vRotation._v[2] += osg::DegreesToRadians(m_fAngle);
}
if (ea.getKey() == 0x46 || ea.getKey() == 0x66)//F
{
computeHomePosition();
m_fAngle -= 0.2 ;
return true ;
}
if (ea.getKey() == 0x47 || ea.getKey() == 0x67)//G
{
m_fAngle += 0.2 ;
return true ;
}
return false;
}
case osgGA::GUIEventAdapter::PUSH:
if (ea.getButton()==1)
{
//如果是左键,记录下来,因为左键拖动时场景也要转的
m_fpushX=mouseX;
m_fpushY=mouseY;
m_bLeftButtonDown=true;
}
return false;
case osgGA::GUIEventAdapter::DRAG:
//拖动
if (m_bLeftButtonDown)
{
m_vRotation._v[2]-=osg::DegreesToRadians(m_fAngle*(mouseX-m_fpushX));
m_vRotation._v[0]+=osg::DegreesToRadians(1.1*(mouseY-mouseY));
//防止背过去
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 CSouth::changePostition(osg::Vec3 &delta)
{
if (m_bPeng)
{
//看新值与旧值之间的连线是否与模型有交点!如果要到达的位置与现在的位置有交点的话,如果碰撞检测也开启了,就不移动。
osg::Vec3 newPos=m_vRotation+delta;
osgUtil::IntersectVisitor iv;
//前后的线段
osg::ref_ptr<osg::LineSegment> line=new osg::LineSegment(newPos,m_vPosition);
//上下移动的线段,加入两条线段来检测碰撞
osg::ref_ptr<osg::LineSegment> lineZ=new osg::LineSegment(newPos+osg::Vec3(0.0,0.0,m_fMoveSpeed),newPos-osg::Vec3(0.0,0.0,m_fMoveSpeed));
iv.addLineSegment(lineZ.get());
iv.addLineSegment(line.get());
//接受碰撞的检测node
m_node->accept(iv);
if(!iv.hits())
{
//如果没有碰撞,则移动旧位置到新的位置上
m_vPosition+=delta;
}
}
else
{
//如果碰撞检测根本没开,则直接移过去
m_vPosition+=delta;
}
}
//得到当前速度
float CSouth::getSpend()
{
return m_fMoveSpeed;
}
//设置当前速度
void CSouth::setSpend(float sp)
{
m_fMoveSpeed=sp;
}
//设置视点位置
void CSouth::setPosition(osg::Vec3 &position)
{
m_vPosition=position;
}
void CSouth::setPosition(double *position)
{
m_vPosition._v[0]=position[0];
m_vPosition._v[1]=position[1];
m_vPosition._v[2]=position[2];
}
//得到当前视点位置
osg::Vec3 CSouth::getPosition()
{
return m_vPosition;
}
//计算家的位置,其实是包围球的球心处
void CSouth::computeHomePosition()
{
//如果有模型,则计算包围球的球心
if (m_node.get())
{
const osg::BoundingSphere &boundingSphere=m_node->getBound();
osg::Vec3 bp=boundingSphere._center;
setPosition(bp);
}
}
以下是main函数文件的源码:
// HideModel.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/Node>
#include "South.h"
int _tmain(int argc, _TCHAR* argv[])
{
osgViewer::Viewer viewer;
osg::ref_ptr<osg::Group> root=new osg::Group();
root->addChild(osgDB::readNodeFile("ceep.ive"));
viewer.setSceneData(root.get());
viewer.setCameraManipulator(new CSouth());
viewer.realize();
return viewer.run();
}
以下是ceep.ive文件的下载链接: http://pan.baidu.com/s/1kUgdUmV 密码:umnc
注意:在此的ceep.ive我是放在了data目录下的,因此不用加路径