您的位置:首页 > 其它

OSG学习笔记10-简单的操作器设置(漫游小区基础)

2016-05-07 19:18 549 查看
终于看到《OpenSceneGraph三维渲染引擎设计与实践》第八章啦,结合另一本书《OpenSceneGraph3.0三维视景仿真技术开发详解》上的例子,还有有的一个小区的.ive二进制模型。做了一个简单的漫游器。

三维场景中的漫游器改变的是观察者(也就是相机)的位置和观察方向,以实时修正场景相机(Camera类)的观察矩阵的方式实现平滑的导航浏览。

相机在世界中的位置姿态矩阵,等于相机观察矩阵的逆矩阵。

设计场景漫游器实际就是要设置合适的相机位置姿态矩阵。《OpenSceneGraph3.0三维视景仿真技术开发详解》书中的一幅OSG操作器更新场景流程图一下就让我理解到了漫游器是如何实现的。



(我真的不知道如何把这个图变小一点!)

和上一个键盘事件响应笔记中我自己画的理解图相类似.

方框1:在主函数中使用Viewer场景核心管理器,setSceneData设置场景要显示的内容,setCameraManipulator设置一个自定义的漫游器(操作器)CSouth

方框2:Viewer在帧绘制时读取操作器控制的矩阵,然后更新相机,这里其实就是在获取要改变的相机的位置姿态矩阵。

方框3:当有事件发生时,这个例子中是键盘事件,就会调用South中的handle方法,在其中改变矩阵,矩阵改变后,方框2中获取的矩阵将会改变,因此达到更新场景的作用。

整个程序由三块组成

South.h写类的声明,包括类里的成员和方法的声明,函数原型,一般不写具体实现。

#pragma once//编译宏,代表只对South编译一次。
#include<osgGA/CameraManipulator>
#include<osgViewer/Viewer>

class South :public osgGA::CameraManipulator//South类派生自CameraManipulator
{
public:
South();
virtual void setByMatrix(const osg::Matrixd& matrix){};//直接通过矩阵设置视口
//渲染过程中外部将会调用这个两个接口来获取矩阵
virtual osg::Matrixd getMatrix() const;//返回当前矩阵
virtual void setByInverseMatrix(const osg::Matrixd& matrix){};
virtual osg::Matrixd getInverseMatrix() const;//返回逆矩阵

virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);//事件处理

bool changePosition(osg::Vec3 delta);//改变位置,delta为要改变的值
private:
osg::Vec3 m_vPosition;//视点当前位置
osg::Vec3 m_vRotation;//视点当前朝向
int m_vStep;//行进步长
float m_vRotateStep;//旋转角度
~South();
};


South.cpp主要写实现头文件中声明的函数,其实这里还有点没有弄懂,就是获取视口矩阵的方法,书上写的是运用视点和朝向得到的视口矩阵,首先按朝向旋转,然后再与使用translate方法平移到视点的矩阵相乘。

#include "stdafx.h"
#include "South.h"

South::South()
{
m_vPosition = osg::Vec3(0, 0, 5.0);
m_vRotation = osg::Vec3(osg::PI_2, 0, 0);
m_vStep = 1000.0;
m_vRotateStep = 0.0;
}//初始化,当前初始点位于0,0,5的位置,即在z轴上,距xy平面5m,把xy看成地面,视线方向要水平地面,所以要沿x轴旋转90°

osg::Matrixd South::getMatrix() const
{
osg::Matrixd mat;
mat.makeTranslate(m_vPosition);//把当前矩阵设为平移矩阵
return osg::Matrixd::rotate(m_vRotation[0], osg::X_AXIS, m_vRotation[1], osg::Y_AXIS, m_vRotation[2], osg::Z_AXIS)*mat;
}//获取视口矩阵

osg::Matrixd South::getInverseMatrix() const
{
osg::Matrixd mat;
mat.makeTranslate(m_vPosition);
return osg::Matrixd::inverse(osg::Matrixd::rotate(m_vRotation[0], osg::X_AXIS, m_vRotation[1], osg::Y_AXIS, m_vRotation[2], osg::Z_AXIS)*mat);
}//对视口矩阵求逆,获得位置姿态矩阵

bool South::handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &us)//响应事件函数
{
osgViewer::Viewer* view = dynamic_cast<osgViewer::Viewer*>(&us);
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::KEYDOWN:
{
if (ea.getKey() == 'w' || ea.getKey() == 'W')
{
changePosition(osg::Vec3(0.0, m_vStep, 0.0));//向y轴正方向移m_vStep的距离
}
else if (ea.getKey() == 's' || ea.getKey() == 'S')
{
changePosition(osg::Vec3(0.0, -m_vStep, 0.0));
}
else if (ea.getKey() == 'a' || ea.getKey() == 'A')
{
changePosition(osg::Vec3(-m_vStep, 0.0, 0.0));
}
else if (ea.getKey() == 'd' || ea.getKey() == 'D')
{
changePosition(osg::Vec3(m_vStep, 0.0, 0.0));
}
else if (ea.getKey() == 'q' || ea.getKey() == 'Q')
{
changePosition(osg::Vec3(0.0, 0.0, m_vStep));
}
else if (ea.getKey() == 'e' || ea.getKey() == 'E')
{
changePosition(osg::Vec3(0.0, 0.0, -m_vStep));
}
}
break;
return false;
}
}

bool South::changePosition(osg::Vec3 delta)
{
m_vPosition += delta;
return true;
}
South::~South()
{
}


main.cpp

// osg5_7.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "South.h"
#include<osgDB/ReadFile>

int main()
{
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
viewer->setSceneData(osgDB::readNodeFile("E:\\model_data\\house\\atest.ive"));
viewer->setCameraManipulator(new South());
return viewer->run();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: