osg指定路径点漫游器

本来打算用现成的路径点漫游器,发现很不好用,限制也多,干脆自己写一个得了。

一,派生于osgGA::CameraManipulator
class TravelManipulator : public osgGA::CameraManipulator
二,设置位置和朝向
//视点
osg::Vec3 m_vPosition;
//朝向
osg::Vec3 m_vRotation;
把初始位置可以放在原点,也可以任意一点。实际上,应该放在路径点的第0个位置。
m_vPosition = osg::Vec3(0, 0, 0);
值得注意的是,朝向要绕X轴转90度,才能和默认漫游器一样,look方向指向Y轴正向,即
m_vRotation = osg::Vec3(osg::PI_2, 0, 0);
这里用到了路径点,从X轴正向开始,所以再减去90度,使look方向的初始方向为X轴正向,便于计算。

m_vRotation = osg::Vec3(osg::PI_2, 0, -osg::PI_2);

三,设置漫游器的矩阵和逆矩阵,这个是固定的。没有它,就不能正确看到场景了。

/** set the position of the matrix manipulator using a 4x4 Matrix.*/
virtual void setByMatrix(const osg::Matrixd& matrix);

/** set the position of the matrix manipulator using a 4x4 Matrix.*/
virtual void setByInverseMatrix(const osg::Matrixd& matrix) ;

/** get the position of the manipulator as 4x4 Matrix.*/
virtual osg::Matrixd getMatrix() const;

/** get the position of the manipulator as a inverse matrix of the manipulator, typically used as a model view matrix.*/
virtual osg::Matrixd getInverseMatrix() const;

void TravelManipulator::setByMatrix(const osg::Matrixd& matrix)
{
}

void TravelManipulator::setByInverseMatrix(const osg::Matrixd& matrix)
{
}

osg::Matrixd TravelManipulator::getMatrix() const
{
osg::Matrixd mat1;
mat1.makeTranslate(m_vPosition);
osg::Matrixd mat2;
mat2.makeRotate(m_vRotation[0], osg::X_AXIS, m_vRotation[1], osg::Y_AXIS, m_vRotation[2], osg::Z_AXIS);

return mat2 * mat1;

}

osg::Matrixd TravelManipulator::getInverseMatrix() const
{
osg::Matrixd mat1;
mat1.makeTranslate(m_vPosition);
osg::Matrixd mat2;
mat2.makeRotate(m_vRotation[0], osg::X_AXIS, m_vRotation[1], osg::Y_AXIS, m_vRotation[2], osg::Z_AXIS);

return osg::Matrixd::inverse(mat2 * mat1);

}

四,在handle()中,使用frame,这样就可以自由漫游了
即在virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);

五,漫游器的朝向,不是坐标系的XYZ轴,而是PItch,roll,yaw,所以,要涉及到一个球面坐标转向XYZ坐标系的过程,由于在初始化时, m_vRotation = osg::Vec3(osg::PI_2, 0, -osg::PI_2);所以,要在移动时,在相应坐标减去这个值。

六,每个点的朝向是根据和下一个点的向量决定,可以适当插值。

代码如下:
travel.h
#pragma once
#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgGA/GUIEventAdapter>
#include <osgViewer/ViewerEventHandlers>
#include <osg/AnimationPath>
#include
#include <osg/PositionAttitudeTransform>
#include <osg/MatrixTransform>
#include <osgGA/CameraManipulator>
#include <osg/matrixd>

struct Vertex
{
double x;
double y;
double z;
double pitch;
double roll;
double yaw;
};
class TravelManipulator : public osgGA::CameraManipulator
{
public:
TravelManipulator(osg::ref_ptrosg::Vec3Array posArray);

public:
//设置当前视口
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);
void ChangePosition(osg::Vec3d& delta);

private:
//视点
osg::Vec3 m_vPosition;
//朝向
osg::Vec3 m_vRotation;
//移动步长
float m_vStep;
//旋转步长
float m_vRotateSpeed;

//暂停
bool _bPause;

private:
//位置点集合
osg::ref_ptrosg::Vec3Array _posArray;
std::vector _vertexVector;
//目标点
osg::Vec3 _destPosition;
//推动运行
void FrameMove();
//初始化数组.成功返回true,不成功返回false
bool InitPosArray();
bool _bInitPosArray;
//当前目的点所在的数组ID
int _currentDestPositionID;
//是否结束
bool _bFinished;
//转弯插值数目
int _segNumber;
//根据传递过来的数组计算弧度数组
osg::ref_ptrosg::Vec3Array getRotationArrayByVertexArray(osg::ref_ptrosg::Vec3Array vertexArray);
//角度数组
osg::ref_ptrosg::Vec3Array _rotationArray;
//插值位置数组
void InterpolatePositionArray(osg::ref_ptrosg::Vec3Array vertexArray,int segNumber);
//插值朝向数组
void InterpolateRotationArray(osg::ref_ptrosg::Vec3Array rotationArray, int segNumber);

};

travel.cpp
#include “Travel.h”

TravelManipulator::TravelManipulator(osg::ref_ptrosg::Vec3Array posArray)
{
m_vPosition = osg::Vec3(0, 0, 0);
m_vRotation = osg::Vec3(osg::PI_2,0, -osg::PI_2);
m_vStep = 0.05;
_segNumber = 0;
_currentDestPositionID = -1;
_bFinished = false;
_bPause = false;
this->InterpolatePositionArray(posArray,_segNumber);
osg::ref_ptrosg::Vec3Array rotationArray = this->getRotationArrayByVertexArray(posArray);
this->InterpolateRotationArray(rotationArray,_segNumber);
_bInitPosArray = this->InitPosArray();
}

void TravelManipulator::setByMatrix(const osg::Matrixd & matrix)
{
}

void TravelManipulator::setByInverseMatrix(const osg::Matrixd & matrix)
{
}

osg::Matrixd TravelManipulator::getMatrix() const
{
osg::Matrixd matTrans;
matTrans.makeTranslate(m_vPosition);
osg::Matrixd matRotate;
matRotate.makeRotate(m_vRotation[0], osg::X_AXIS, m_vRotation[1], osg::Y_AXIS, m_vRotation[2], osg::Z_AXIS);
return matRotate * matTrans;
}

osg::Matrixd TravelManipulator::getInverseMatrix() const
{
osg::Matrixd mat = getMatrix();
return osg::Matrixd::inverse(mat);
}

bool TravelManipulator::handle(const osgGA::GUIEventAdapter & ea, osgGA::GUIActionAdapter & us)
{
switch (ea.getEventType())
{
case osgGA::GUIEventAdapter::FRAME:
{
if (!_bInitPosArray)
{
return false;
}
if (_bFinished)
{
return false;
}
FrameMove();
}
break;
default:
break;
}
return false;
}

void TravelManipulator::ChangePosition(osg::Vec3d & delta)
{
m_vPosition += delta;
}

void TravelManipulator::FrameMove()
{
osg::Vec3 posStart = m_vPosition;
osg::Vec3 posEnd = _destPosition;
osg::Vec3 deltaVec = posEnd - posStart;
//如果向量长度小于或者等于speed,则直接赋值。并查看下一个目的点。如果不是,则按照速度向前推进
double length = deltaVec.length();

if (length > m_vStep)
{
	//ChangePosition(osg::Vec3d(m_vStep * cosf(m_vRotation._v[2] + osg::PI_2), m_vStep * sinf(m_vRotation._v[2] + osg::PI_2), 0));
	ChangePosition(osg::Vec3d(m_vStep * cosf(m_vRotation._v[2] + osg::PI_2)*cosf(m_vRotation._v[0] - osg::PI_2),
		m_vStep * sinf(m_vRotation._v[2] + osg::PI_2)*cosf(m_vRotation._v[0] - osg::PI_2),
		m_vStep * sinf(m_vRotation._v[0] - osg::PI_2)));
}
else
{
	m_vPosition = posEnd;
	int posCount = _posArray->size();
	if (_currentDestPositionID + 1 < posCount)
	{	
			//设置下一个目的点的位置和朝向
		m_vRotation = _rotationArray->at(_currentDestPositionID);
		_destPosition = _posArray->at(_currentDestPositionID + 1);
		//下一个目的点的ID也要+1
		_currentDestPositionID++;

	}
	else
	{
		_bFinished = true;
	}
}
_sleep(20);

}

bool TravelManipulator::InitPosArray()
{
bool bSuccess = true;
if (_posArray->size() < 2)
{
bSuccess = false;
_bFinished = true;
return bSuccess;
}

m_vPosition = _posArray->at(0);
_destPosition = _posArray->at(1);
m_vRotation = _rotationArray->at(0);
_currentDestPositionID = 1;

return bSuccess;

}

osg::ref_ptrosg::Vec3Array TravelManipulator::getRotationArrayByVertexArray(osg::ref_ptrosg::Vec3Array vertexArray)
{
osg::ref_ptrosg::Vec3Array rotationArray = new osg::Vec3Array;
int vertexNumber = vertexArray->size();
if (vertexNumber < 2)
{
rotationArray->clear();
return rotationArray;
}
//根据向量计算角度值,最后一个角度值不需要加,因为停止了.
for (int i = 0; i < vertexNumber -1; i++)
{
osg::Vec3 posStart = vertexArray->at(i);
osg::Vec3 posEnd = vertexArray->at(i+1);
osg::Vec3 deltaVec = posEnd - posStart;
//float degreeZ = atan2f(deltaVec.y(), deltaVec.x());
//osg::Vec3 rotation = osg::Vec3(osg::PI_2, 0, -osg::PI_2) + osg::Vec3(0, 0, degreeZ);
float yaw = atan2f(deltaVec.y(), deltaVec.x());
float pitch = atan2f(deltaVec.z(), osg::Vec3(deltaVec.x(), deltaVec.y(), 0).length());
osg::Vec3 rotation = osg::Vec3(osg::PI_2, 0, -osg::PI_2) + osg::Vec3(pitch, 0, yaw);
rotationArray->push_back(rotation);

}

//计算完z轴旋转角度后,再减去一个90度,从Z轴转过来.
return rotationArray;

}

void TravelManipulator::InterpolatePositionArray(osg::ref_ptrosg::Vec3Array vertexArray, int segNumber)
{
_posArray = new osg::Vec3Array;
_posArray->clear();
int vertexNumber = vertexArray->size();
if (vertexNumber < 2)
{
_posArray->clear();
return;
}
//第0个和最后一个不变,其余的都插值segNumber个值
_posArray->push_back(vertexArray->at(0));
for (int i = 1; i < vertexNumber - 1; i++)
{
for (int segID = 0; segID <= segNumber; segID++)
{
_posArray->push_back(vertexArray->at(i));
}
}

_posArray->push_back(vertexArray->at(vertexNumber - 1));

}

void TravelManipulator::InterpolateRotationArray(osg::ref_ptrosg::Vec3Array rotationArray, int segNumber)
{
_rotationArray = new osg::Vec3Array;
_rotationArray->clear();
int vertexNumber = rotationArray->size();
if (vertexNumber < 1)
{
_rotationArray->clear();
return;
}
_rotationArray->push_back(rotationArray->at(0));

for (int i = 1; i < vertexNumber ; i++)
{
	osg::Vec3 lastRotation = rotationArray->at(i-1);
	osg::Vec3 CurrentRotation = rotationArray->at(i);
	osg::Vec3 deltaRotation = CurrentRotation - lastRotation;
	
	//插值角度
	osg::Vec3 deltaRotationPerSeg = deltaRotation / (segNumber + 1);
	for (int segID = 0; segID < segNumber; segID++)
	{
		float deltaRotationX = (segID + 1) * deltaRotationPerSeg.x();
		float deltaRotationY = (segID + 1) * deltaRotationPerSeg.y();
		float deltaRotationZ = (segID + 1) * deltaRotationPerSeg.z();
		osg::Vec3 theRotation = lastRotation + osg::Vec3(deltaRotationX, deltaRotationY, deltaRotationZ);
		_rotationArray->push_back(theRotation);
	}
	
	_rotationArray->push_back(CurrentRotation);

}

}

只要传递位置坐标数组即可。

猜你喜欢

转载自blog.csdn.net/directx3d_beginner/article/details/131239154