osg demo14 漫游

本文介绍了一个基于OSG的漫游控制实现方法,通过键盘输入实现前后左右移动及上下视角调整,支持加速减速功能,并引入了碰撞检测机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

main.cpp
//DEMO14
//功能:正常的漫游,WASD键前进后退左右,UP DOWN LEFT RIGHT键前进后退左进右退
//	   HOME向上移,END向下移。+加速,-减速

#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osg/Node>
#include  "South.h"

void main()
{
	osgViewer::Viewer viewer;
	viewer.setSceneData(osgDB::readNodeFile("ceep.ive"));
	viewer.setCameraManipulator(new CSouth());
	viewer.realize();
	viewer.run();
}
South.h
#pragma once


#include <osgViewer/Viewer>
#include <osgGA/CameraManipulator>
#include <osgUtil/IntersectVisitor>
#include <osg/LineSegment>


class CSouth:public osgGA::CameraManipulator
{
public :
	CSouth(void);
	~CSouth(void);


private :
	//结点值,用来测试碰撞检测的:
	osg::ref_ptr<osg::Node> m_node;
	//相机操作器
	unsigned 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(void )const;


	//得到逆矩阵
	virtual osg::Matrixd getInverseMatrix(void )const;


	//主要事件控制器
	virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us);


	//屏幕角度
	float m_fAngle;


	//位置变换函数
	void ChangePosition(osg::Vec3& delta);


	//得到当前速度
	float getSpeed();


	//设置当前速度
	void setSpeed(float);


	//设置视点位置
	void SetPosition(osg::Vec3 &position);
	void SetPosition(double *);


	//得到当前视点位置
	osg::Vec3 GetPosition();


	//计算家的位置
	void computeHomePosition();
};
South.cpp
#include "South.h"


//设置一些初始值
CSouth::CSouth(void):m_fMoveSpeed(1.5f)
//左键没有按下
,m_bLeftButtonDown(false)
//左键点下时初始坐标为0
,m_fpushX(0)
//初始角度是2.5
,m_fAngle(2.5)  


// 开始时碰撞检测关闭  


, m_bPeng(false)  


//右键点下时初始坐标也为0  


, m_fpushY(0)  


{  


        // 出生点为000  


        m_vPosition = osg::Vec3(0.0f, 0.0f,5.0f);  


        //初始角度  


        m_vRotation = osg::Vec3(osg::PI_2, 0.0f, 0.0f);                             


}  




// 析构函数  


CSouth::~CSouth(void)  


{  


}  


void CSouth::setByMatrix(const osg::Matrixd & matrix)    


{  


}  


void CSouth::setByInverseMatrix(const osg::Matrixd& matrix)    


{  
}
//得到矩阵,这是标准接口,用于控制场景  


osg::Matrixd CSouth::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 CSouth::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));  


}  


//------------------------------//------------------------------  


//handle  


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)//home  
						  {  


                                  ChangePosition(osg::Vec3 (0, 0, m_fMoveSpeed)) ;  


                                  return true;  


                         }  


        // 如果是end键,同视点向下移动  


                         if (ea.getKey() == 0xFF57) //end  


                         {  


                                  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 -= 1.0f;  


                                  if (m_fMoveSpeed < 1.0f)  


                                  {  


                                          m_fMoveSpeed = 1.0f;  


                                  }  


                                  return true;  


                         }  


        // 向前走,W键,或者UP键  


                         if (ea.getKey() == 0xFF52 || ea.getKey () == 0x57 || ea.getKey () == 0x77)//up  


                         {  


                                  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;  


                         }  


        // 向后退,S键,或者DOWN键  


                         if (ea.getKey() == 0xFF54 || ea.getKey () == 0x53 || ea.getKey () == 0x73 )//down  


                         {  


                                  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;  


                         }  


        //A  


                         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;  


                          }  


        //D  


                          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)//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-m_fpushY)) ;    


                       // 防止背过去  


                       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::ChangePosition(osg::Vec3 &delta)  


{  


        if (m_bPeng)  


        {  


               //看新值与旧值之间的连线是否与模型有交点!如果要到达的位置与现在的位置有交点的话,如果碰撞检测也开启 了,就不移动。  


               osg::Vec3 newPos = m_vPosition + 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.0f, 0.0f, m_fMoveSpeed),    


                       newPos - osg::Vec3(0.0f, 0.0f, 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::getSpeed()  


{  


        return m_fMoveSpeed ;  


}  


//------------------------------//------------------------------  


// 设置移动速度  


void CSouth::setSpeed(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::setNode(osg::Node* node)  


{  


        m_node = node ;  


}  


//------------------------------//------------------------------  


//计算家的位置,其实是包围球的球心处  
void CSouth::computeHomePosition()  


{  


// 如果有模型,则计算包围球的球心  


        if(m_node.get())  


        {  


               const osg::BoundingSphere& boundingSphere=m_node ->getBound();  


               osg::Vec3 bp = boundingSphere._center;  


               SetPosition(bp) ;               


        }  


}  


//------------------------------//------------------------------  


// 设置碰撞检测为开启或者关闭  


void CSouth::setPeng(bool peng)  


{  


        m_bPeng = peng ;  


}  


//------------------------------//------------------------------  


//得到碰撞检测的状态  


bool CSouth::getPeng()  


{  


        return m_bPeng ;  


}  


//------------------------------//------------------------------  


// 如果碰撞测试在开启,则关闭它,如果在关闭,则开启它  


void CSouth::setFpeng()  


{  


        m_bPeng = !m_bPeng ;  


}  


//------------------------------//------------------------------  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值