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

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法