osg指定路径点漫游器_osg 漫游-程序员宅基地

技术标签: osg  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);

}

}

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/directx3d_beginner/article/details/131239154

智能推荐

c# 调用c++ lib静态库_c#调用lib-程序员宅基地

文章浏览阅读2w次,点赞7次,收藏51次。四个步骤1.创建C++ Win32项目动态库dll 2.在Win32项目动态库中添加 外部依赖项 lib头文件和lib库3.导出C接口4.c#调用c++动态库开始你的表演...①创建一个空白的解决方案,在解决方案中添加 Visual C++ , Win32 项目空白解决方案的创建:添加Visual C++ , Win32 项目这......_c#调用lib

deepin/ubuntu安装苹方字体-程序员宅基地

文章浏览阅读4.6k次。苹方字体是苹果系统上的黑体,挺好看的。注重颜值的网站都会使用,例如知乎:font-family: -apple-system, BlinkMacSystemFont, Helvetica Neue, PingFang SC, Microsoft YaHei, Source Han Sans SC, Noto Sans CJK SC, W..._ubuntu pingfang

html表单常见操作汇总_html表单的处理程序有那些-程序员宅基地

文章浏览阅读159次。表单表单概述表单标签表单域按钮控件demo表单标签表单标签基本语法结构<form action="处理数据程序的url地址“ method=”get|post“ name="表单名称”></form><!--action,当提交表单时,向何处发送表单中的数据,地址可以是相对地址也可以是绝对地址--><!--method将表单中的数据传送给服务器处理,get方式直接显示在url地址中,数据可以被缓存,且长度有限制;而post方式数据隐藏传输,_html表单的处理程序有那些

PHP设置谷歌验证器(Google Authenticator)实现操作二步验证_php otp 验证器-程序员宅基地

文章浏览阅读1.2k次。使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码。实现Google Authenticator功能需要服务器端和客户端的支持。服务器端负责密钥的生成、验证一次性密码是否正确。客户端记录密钥后生成一次性密码。下载谷歌验证类库文件放到项目合适位置(我这边放在项目Vender下面)https://github.com/PHPGangsta/GoogleAuthenticatorPHP代码示例://引入谷_php otp 验证器

【Python】matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距-程序员宅基地

文章浏览阅读4.3k次,点赞5次,收藏11次。matplotlib.plot画图横坐标混乱及间隔处理_matplotlib更改横轴间距

docker — 容器存储_docker 保存容器-程序员宅基地

文章浏览阅读2.2k次。①Storage driver 处理各镜像层及容器层的处理细节,实现了多层数据的堆叠,为用户 提供了多层数据合并后的统一视图②所有 Storage driver 都使用可堆叠图像层和写时复制(CoW)策略③docker info 命令可查看当系统上的 storage driver主要用于测试目的,不建议用于生成环境。_docker 保存容器

随便推点

网络拓扑结构_网络拓扑csdn-程序员宅基地

文章浏览阅读834次,点赞27次,收藏13次。网络拓扑结构是指计算机网络中各组件(如计算机、服务器、打印机、路由器、交换机等设备)及其连接线路在物理布局或逻辑构型上的排列形式。这种布局不仅描述了设备间的实际物理连接方式,也决定了数据在网络中流动的路径和方式。不同的网络拓扑结构影响着网络的性能、可靠性、可扩展性及管理维护的难易程度。_网络拓扑csdn

JS重写Date函数,兼容IOS系统_date.prototype 将所有 ios-程序员宅基地

文章浏览阅读1.8k次,点赞5次,收藏8次。IOS系统Date的坑要创建一个指定时间的new Date对象时,通常的做法是:new Date("2020-09-21 11:11:00")这行代码在 PC 端和安卓端都是正常的,而在 iOS 端则会提示 Invalid Date 无效日期。在IOS年月日中间的横岗许换成斜杠,也就是new Date("2020/09/21 11:11:00")通常为了兼容IOS的这个坑,需要做一些额外的特殊处理,笔者在开发的时候经常会忘了兼容IOS系统。所以就想试着重写Date函数,一劳永逸,避免每次ne_date.prototype 将所有 ios

如何将EXCEL表导入plsql数据库中-程序员宅基地

文章浏览阅读5.3k次。方法一:用PLSQL Developer工具。 1 在PLSQL Developer的sql window里输入select * from test for update; 2 按F8执行 3 打开锁, 再按一下加号. 鼠标点到第一列的列头,使全列成选中状态,然后粘贴,最后commit提交即可。(前提..._excel导入pl/sql

Git常用命令速查手册-程序员宅基地

文章浏览阅读83次。Git常用命令速查手册1、初始化仓库git init2、将文件添加到仓库git add 文件名 # 将工作区的某个文件添加到暂存区 git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件...

分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120-程序员宅基地

文章浏览阅读202次。分享119个ASP.NET源码总有一个是你想要的_千博二手车源码v2023 build 1120

【C++缺省函数】 空类默认产生的6个类成员函数_空类默认产生哪些类成员函数-程序员宅基地

文章浏览阅读1.8k次。版权声明:转载请注明出处 http://blog.csdn.net/irean_lau。目录(?)[+]1、缺省构造函数。2、缺省拷贝构造函数。3、 缺省析构函数。4、缺省赋值运算符。5、缺省取址运算符。6、 缺省取址运算符 const。[cpp] view plain copy_空类默认产生哪些类成员函数

推荐文章

热门文章

相关标签