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

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

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

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

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

OSG学习笔记10-简单的操作器设置(漫游小区基础)_第1张图片

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

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

方框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();
}



你可能感兴趣的:(OSG学习笔记10-简单的操作器设置(漫游小区基础))