终于看到《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(); }