9、osg3.2.1中漫游

效果图如下:



以下是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目录下的,因此不用加路径


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值