实现功能
自定义相机的位置位于世界坐标系下的Y轴正方向斜向下45度观察水平面。
通过按键实现向前(按W)向后(按S)向左(按A)向右(按D)
向上(按PageUp)向下(按PageDown)
相机左右旋转(J/L)、相机上下旋转(I/K)
观察效果如图:
基础知识
实现相机我们所要用到的知识点有
1.向量,矩阵,四元素等概念
2.OSG坐标系统的知识。
3.视图与相机, 键盘事件消息处理的相关知识。
最重要的需要自己的空间思维能力,如果对以上的知识点不熟悉的话,可以去相关的网站看看。
实现原理
一.新建一个类共有继承 osgGA::CameraManipulator,并且重写四个虚函数,具体的代码需要根据要求来进行编写。
1.virtual void setByMatrix(const osg::Matrixd& matrix);
2.virtual void setByInverseMatrix(const osg::Matrixd& matrix) ;
3.virtual osg::Matrixd getMatrix() const ;
4.virtual osg::Matrixd getInverseMatrix() const ;
二.进行键盘事件处理我们需要重写handle函数
1.virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us) ;
代码实现
.h文件
class TraveManipulator :public osgGA::CameraManipulator
{
public:
//构造函数
TraveManipulator(osg::ref_ptr<osg::Node> node1);
//析构函数
~TraveManipulator();
//设置矩阵
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) ;
private:
//视点位置
osg::Vec3d m_Eye;
//参照物中心
osg::Vec3d m_Center;
//方向向量
osg::Vec3d m_Up;
//距离
double m_Distense;
//移动步长
float m_Step;
//旋转矩阵
osg::Matrix m_RotationMatrix;
//相机上下旋转的绕轴
osg::Vec3 m_CameraRotation;
};
.cpp文件
TraveManipulator::TraveManipulator(osg::ref_ptr<osg::Node> node1) :m_Distense(4000.0), m_Step(30)
{
//保存物体的中心点
osg::Vec3d node_Center = node1->getBound().center();
osg::Matrix rotation_Anngle;
//绕x轴旋转45°
rotation_Anngle = osg::Matrix::rotate(osg::Quat(-osg::PI_4,osg::Vec3f(1.0f, 0.0f, 0.0f)));
//设置视点的位置,
m_Eye = osg::Vec3d(0.0, 0.0, m_Distense);
//设置中心点的位置
m_Center = node_Center;
//up向量
m_Up = osg::Vec3d(0.0,- 1.0, 0.0);
//视点位于Y轴的正方向斜向上45°
m_Eye = m_Eye * rotation_Anngle;
m_Up = m_Up * rotation_Anngle;
m_CameraRotation = osg::Vec3(1.0f,0.0f,0.0f);
}
TraveManipulator::~TraveManipulator()
{
//
}
//设置矩阵
void TraveManipulator::setByMatrix(const osg::Matrixd& matrix)
{
//
}
//设置逆矩阵
void TraveManipulator::setByInverseMatrix(const osg::Matrixd& matrix)
{
//
}
//得到矩阵,用于控制场景
osg::Matrixd TraveManipulator::getMatrix() const
{
return osg::Matrixd();
}
//得到逆矩阵
osg::Matrixd TraveManipulator::getInverseMatrix() const
{
return osg::Matrixd::lookAt(m_Eye,m_Center,m_Up);
}
//键盘事件处理函数
bool TraveManipulator::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& us)
{
//获取事件
switch (ea.getEventType())
{
//如果是一个键盘事件
case osgGA::GUIEventAdapter::KEYDOWN:
{
//向前移动(按W)
if(ea.getKey() == 'w' || ea.getKey() == 'W')
{
m_Eye = m_Eye * osg::Matrix::translate(osg::Vec3(0.0,m_Step,0.0) * m_RotationMatrix);
m_Center = m_Center * osg::Matrix::translate(osg::Vec3(0.0,m_Step,0.0) * m_RotationMatrix);
}
//向后移动(按s)
else if (ea.getKey() == 's' || ea.getKey() == 'S')
{
m_Eye = m_Eye * osg::Matrix::translate(osg::Vec3(0.0,-m_Step,0.0) * m_RotationMatrix);
m_Center = m_Center * osg::Matrix::translate(osg::Vec3(0.0,-m_Step,0.0) * m_RotationMatrix);
}
//向左移动(按a)
else if (ea.getKey() == 'a' || ea.getKey() == 'A')
{
m_Eye = m_Eye * osg::Matrix::translate(osg::Vec3(-m_Step,0.0,0.0) * m_RotationMatrix);
m_Center = m_Center * osg::Matrix::translate(osg::Vec3(-m_Step,0.0,0.0) * m_RotationMatrix);
}
//向右移动(按d)
else if (ea.getKey() == 'd' || ea.getKey() == 'D')
{
m_Eye = m_Eye * osg::Matrix::translate(osg::Vec3(m_Step,0.0,0.0) * m_RotationMatrix);
m_Center = m_Center * osg::Matrix::translate(osg::Vec3(m_Step,0.0,0.0) * m_RotationMatrix);
}
//向上移动(按Page UP)
else if (ea.getKey() == 0XFF55)
{
m_Eye = m_Eye * osg::Matrix::translate(osg::Vec3(m_Step,0.0,0.0) * m_RotationMatrix)*
osg::Matrix::translate(osg::Vec3(0.0,m_Step,0.0) * m_RotationMatrix)*
osg::Matrix::translate(osg::Vec3(0.0,0.0, m_Step) * m_RotationMatrix)*
osg::Matrix::translate(osg::Vec3(-m_Step,0.0,0.0)* m_RotationMatrix);
}
//向下移动(按Page Down)
else if (ea.getKey() == 0xFF56)
{
m_Eye = m_Eye * osg::Matrix::translate(osg::Vec3(m_Step,0.0,0.0) * m_RotationMatrix)*
osg::Matrix::translate(osg::Vec3(0.0,-m_Step,0.0) * m_RotationMatrix)*
osg::Matrix::translate(osg::Vec3(0.0,0.0,-m_Step) * m_RotationMatrix)*
osg::Matrix::translate(osg::Vec3(-m_Step,0.0,0.0) * m_RotationMatrix);
}
//相机向左旋转
else if (ea.getKey() == 'j' || ea.getKey() == 'J')
{
osg::Matrix mt;
//设置旋转轴
mt = osg::Matrixd::rotate(-osg::DegreesToRadians(15.0),osg::Vec3(0.0f,0.0f,1.0f));
m_CameraRotation = m_CameraRotation * mt;
m_RotationMatrix = m_RotationMatrix * mt ;
m_Eye = m_Eye * mt;
m_Up = m_Up * mt;
m_Center = m_Center * mt;
}
//相机向右旋转
else if (ea.getKey() == 'l' || ea.getKey() == 'L')
{
osg::Matrix mt;
//设置旋转轴
mt = osg::Matrixd::rotate(osg::DegreesToRadians(15.0),osg::Vec3(0.0f,0.0f,1.0f));
m_CameraRotation = m_CameraRotation * mt;
m_RotationMatrix = m_RotationMatrix * mt;
m_Eye = m_Eye * mt;
m_Up = m_Up * mt;
m_Center = m_Center * mt;
}
//相机向上旋转
else if (ea.getKey() == 'i' || ea.getKey() == 'I')
{
osg::Matrix mt;
//设置旋转轴
mt = osg::Matrix::rotate(osg::DegreesToRadians(15.0),m_CameraRotation);
m_RotationMatrix = m_RotationMatrix* mt;
m_Eye = m_Eye * osg::Matrix::rotate(osg::DegreesToRadians(15.0),m_CameraRotation);
m_Up = m_Up * osg::Matrix::rotate(osg::DegreesToRadians(15.0),m_CameraRotation);
m_Center = m_Center * osg::Matrix::rotate(osg::DegreesToRadians(15.0),m_CameraRotation);
}
//相机向下旋转
else if (ea.getKey() == 'k' || ea.getKey() == 'K')
{
osg::Matrix mt;
//设置旋转矩阵
mt = osg::Matrix::rotate(-osg::DegreesToRadians(15.0),m_CameraRotation);
m_RotationMatrix = m_RotationMatrix * mt;
m_Eye = m_Eye * osg::Matrix::rotate(-osg::DegreesToRadians(15.0),m_CameraRotation);
m_Up = m_Up * osg::Matrix::rotate(-osg::DegreesToRadians(15.0),m_CameraRotation);
m_Center = m_Center * osg::Matrix::rotate(-osg::DegreesToRadians(15.0),m_CameraRotation);
}
}
default:
break;
return false;
}
return false;
}
main.cpp文件
#include "Trave.h"
#include "Setup.h"
int main()
{
osg::ref_ptr<osgViewer::Viewer>viewer = new osgViewer::Viewer();
osg::ref_ptr<osg::Group> root = new osg::Group();
Changeport a(viewer);
a.changeport();
osg::ref_ptr<osg::Node> node = a.createNode();
root->addChild(a.createTexture2DState(node));
//添加漫游器
viewer->setCameraManipulator(new TraveManipulator(node));
osgUtil::Optimizer optimizer;
optimizer.optimize(root.get());
//设置场景数据
viewer->setSceneData(root.get());
viewer->realize();
viewer->run();
return 0;
}
这是我对相机的理解和看法,代码仅供参考。如果大家有什么不同的意见,欢迎评论区留言