终于看到《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
#include
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(&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
int main()
{
osg::ref_ptr viewer = new osgViewer::Viewer;
viewer->setSceneData(osgDB::readNodeFile("E:\\model_data\\house\\atest.ive"));
viewer->setCameraManipulator(new South());
return viewer->run();
}