OsgEarth下实现雷达波束扫描飞机动画

OsgEarth下实现雷达波束扫描飞机动画

void GraphicsView::addRadar()
{	
	/****************制作轨迹点数据,测试用**********************/
	osg::Vec3d startPoint = osg::Vec3d(115, 18, 100000);//起始位置
	queue <PlanePoint> *PlanePP = new queue <PlanePoint>;//飞机用
	queue <PlanePoint> *PlanePR = new queue <PlanePoint>;//雷达用
	int n = 20;
	double Alltime = 10.0;
	double Alldis = 10;
	double _addtime = Alltime / (double)n;
	double _addDis = 5 / (double)n;
	double time = 0.0;
	osg::Vec3d _add = osg::Vec3d(0.0, 0.0, 0.0);
	for (int i = 0; i < n; i++)
	{
		osg::Vec3d newpoint = startPoint + _add;
		PlanePoint *pPP = new PlanePoint();
		pPP->point = newpoint;
		pPP->time = time;
		PlanePP->push(*pPP);
		PlanePR->push(*pPP);
		_add = _add + osg::Vec3d(_addDis, _addDis, 0.0);
		time = time + _addtime;
	}
	 
		radarGroup = new osg::Group;//初始化雷达节点组
		/*添加雷达半球*/
		osg::Vec3 radarposition = osg::Vec3(116.7176, 20.699, 10);	//0点对应的地球坐标
		double radarDistance = 500000;//雷达最大探测距离
		//创建精细度对象,精细度越高,细分就越多
		osg::Vec3d RWpoint;
		m_pMapSRS->transformToWorld(radarposition, RWpoint);
		osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints;
		hints->setDetailRatio(1.0f);
		osg::Geode *geodeR = new osg::Geode;
		osg::ShapeDrawable* RadarShp = new osg::ShapeDrawable(new osg::Sphere(RWpoint, radarDistance), hints);
		geodeR->addDrawable(RadarShp);
		RadarShp->setColor(osg::Vec4(0.0, 0.0, 0.3, 0.2));
		//设置雷达罩透明效果
		osg::ref_ptr<osg::StateSet> statesetR = geodeR->getOrCreateStateSet();
		statesetR->setMode(GL_BLEND, osg::StateAttribute::ON);//Alpha混合开启
		statesetR->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);//设置透明渲染元
		statesetR->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
		//statesetR->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); //取消深度测试
		radarGroup->addChild(geodeR);
	/********************加载雷达动画*************************/ {
		/****************绘制圆锥,并将顶点平移到0点**********************/ 		
		double radarRadius = 10000;//圆锥半径		
		osg::Cone *Cone = new osg::Cone(osg::Vec3(0, 0, 0), radarRadius, radarDistance);//初始化,cone不能做回调	
		osg::Matrixd rotMat = osg::Matrixd::rotate(osg::Z_AXIS, osg::Vec3(0, 0, -1));//转180
		Cone->setRotation(rotMat.getRotate());
		Cone->setCenter(osg::Vec3(0, 0, 3 * radarDistance / 4));//平移,使得0点位于顶点	
		/****************加载圆锥**********************/
		osg::Geode* geode = new osg::Geode;
		osg::ShapeDrawable* shpcone = new osg::ShapeDrawable(Cone);
		shpcone->setColor(osg::Vec4(0.5, 0.0, 0.0, 0.25));
		geode->addDrawable(shpcone);
		//设置圆锥透明效果
		osg::ref_ptr<osg::StateSet> stateset = geode->getOrCreateStateSet();
		stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
		stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
		stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); //取消深度测试
		//stateset->setRenderBinDetails(11, "RenderBin");
	    //试着加回调函数,解决圆锥长度的问题,先将conebufen放到飞机里面去,这样也可以试试雷达,试了好像不行
		shpcone->setDataVariance(osg::Object::DYNAMIC);
		//DrawableUpdateCallback p;// = new DrawableUpdateCallback();
		//shpcone->setUpdateCallback(new DrawableUpdateCallback());


		//设置圆锥网格模型
		osg::ref_ptr<osg::PolygonMode> polyMode = new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
		stateset->setAttribute(polyMode);
		/****************加载圆锥1暂时没有找到骨架线和填充同时存在的接口,画两次实现**********************/
		osg::Geode* geode1 = new osg::Geode;
		osg::ShapeDrawable* shpcone1 = new osg::ShapeDrawable(Cone);
		shpcone1->setColor(osg::Vec4(1.0, 0.0, 0.0, 0.25));//
		geode1->addDrawable(shpcone1);
		//设置圆锥透明效果
		osg::ref_ptr<osg::StateSet> stateset2 = geode1->getOrCreateStateSet();
		stateset2->setMode(GL_BLEND, osg::StateAttribute::ON);
		stateset2->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
		stateset2->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); //取消深度测试
		//stateset2->setRenderBinDetails(11, "RenderBin2");//优先级,暂时没用
		/****************加入平台**********************/
		osg::MatrixTransform* mtCone = new osg::MatrixTransform();
		//mtCone->addChild(geode);
		mtCone->addChild(geode1);
		osg::ref_ptr<GeoTransform> pGTRadar = new GeoTransform();//应该是模型移动平台的意思	
		radarGroup->addChild(pGTRadar);
		m_pRoot->addChild(radarGroup);
		pGTRadar->addChild(mtCone);
		pGTRadar->setPosition(GeoPoint(m_pMapSRS, radarposition, ALTMODE_ABSOLUTE));
		
		
		/****************生成雷达动画**********************/
		osg::AnimationPath* animationPathRadar = rotateCone1(mtCone, m_pMapSRS, radarposition, PlanePR, radarDistance);
		mtCone->setUpdateCallback(new osg::AnimationPathCallback(animationPathRadar, 0.0, 1.0));
		//mtCone->addUpdateCallback(new RotateCallback(osg::Z_AXIS, 0.01));//直接用,时间可以统一,但是回看怎么操作?自己写?还不如直接用path
	}
	/*****************添加飞机动画****************/	{
	osg::Node* glider = osgDB::readNodeFile("models\\f35c.osgb");
	glider->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);
	//glider->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); //取消深度测试
	  if (glider)
	  {
		const osg::BoundingSphere& bs = glider->getBound();
		float size = 2000;//
		osg::MatrixTransform* planeMT = new osg::MatrixTransform;
		planeMT->setDataVariance(osg::Object::STATIC);
		planeMT->addChild(glider);
		planeMT->setMatrix(planeMT->getMatrix()*osg::Matrix::scale(size, size, size));// *osg::Matrix::translate(-(bs.center()))* osg::Matrix::rotate(osg::DegreesToRadians(90.0 - earthCenter.y()), 0, 1, 0)*osg::Matrixd::translate(bs.center()));// /*osg::Matrix::rotate(osg::DegreesToRadians(90.0), 1, 0, 0) osg::Matrix::rotate(osg::DegreesToRadians(90.0), 0, 1, 0)*osg::Matrix::translate(bs.center()));///*osg::Matrix::rotate(osg::inDegrees(earthCenter.x()), 0.0f, 0.0f, 1.0f)*osg::Matrix::rotate(osg::inDegrees(90.0f - earthCenter.y()), 0.0f, 1.0f, 0.0f)* / );//
		osg::ref_ptr<GeoTransform> pGTPlane = new GeoTransform();//
		pGTPlane->addChild(planeMT);
		radarGroup->addChild(pGTPlane);
		osg::AnimationPath* animationPathPlane = createAnimationPath(PlanePP, planeMT);
		//动画的关键。依然使用了回调函数,执行完{},再执行它,后面两个参数是干啥用的?
		pGTPlane->setUpdateCallback(new osg::AnimationPathCallback(animationPathPlane, 0.0, 1.0));		
	  }
	}//飞机添加动画 结束
	
	/***********窗口定位*****************/
	osgEarth::Viewpoint vp("", radarposition.x(), radarposition.y(), radarposition.z(), -2.50, 0, 1.5e6);//窗口定位到
	(dynamic_cast<osgEarth::Util::EarthManipulator*>(m_pViewer->getCameraManipulator()))->setViewpoint(vp);
}
osg::AnimationPath* GraphicsView::createAnimationPath(queue <PlanePoint> *PlaneP, osg::MatrixTransform *planeMT)//需要改成地球坐标系
{
	osg::AnimationPath* animationPath = new osg::AnimationPath;//自动路径
	animationPath->setLoopMode(osg::AnimationPath::LOOP);//设置动画模式为循环(LOOP)
	/**********获取第一个点************/
	osg::Vec3d  FEpoint = PlaneP->front().point;	
	while (!PlaneP->empty())
	{
		double time = PlaneP->front().time;
		osg::Vec3d FWpoint;
		m_pMapSRS->transformToWorld(FEpoint, FWpoint);
		osg::Vec3d BEpoint = PlaneP->front().point;
		osg::Vec3d BWpoint;
		m_pMapSRS->transformToWorld(BEpoint, BWpoint);
		osg::Vec3  _vector = BWpoint - FWpoint;
		osg::Matrixd rotMat = osg::Matrixd::rotate((osg::Y_AXIS), _vector);
		//计算对应地面点的指天向量,方法1
		GeoPoint localPoint(m_pMapSRS, BEpoint.x(), FEpoint.y(), FEpoint.z());
		osg::Vec3d v3HorizonUp;//指天向量
		localPoint.createWorldUpVector(v3HorizonUp);
		osg::Matrixd rotMatsky = osg::Matrixd::rotate((osg::Z_AXIS), osg::Vec3(v3HorizonUp.x(), v3HorizonUp.y(), v3HorizonUp.z()));
		//计算移动向量对应的旋转角
		osg::Quat rotation = rotMat.getRotate();
		double heading = 0; double pitch = 0; double roll = 0;
		QuatToHPR(rotation, heading, pitch, roll);
		//计算翻滚向量对应的旋转角,瞎猫碰上死耗子,换地方不行,尤其是在高纬度地区
		osg::Quat rotation2 = (osg::Matrix::rotate(osg::DegreesToRadians(90-BEpoint.x()), 1, 0, 0)).getRotate()*(osg::Matrix::rotate(osg::DegreesToRadians(90.0 - BEpoint.y()), 0, 1, 0)).getRotate()*rotMatsky.getRotate();//
		double heading2 = 0; double pitch2 = 0; double roll2 = 0;
		QuatToHPR(rotation2, heading2, pitch2, roll2);
		//取移动向量的偏航角和俯仰角,翻滚向量的翻滚角,合成新的旋转角,并计算对应的矩阵
		osg::Quat rotation3 = HPRToQuat(heading, pitch, roll2);//合成旋转角
		//将新的坐标和角度压入动画
		const osg::BoundingSphere& bs = planeMT->getBound();
		//因为起始点用了两次,所以这里插入动画时用了后点,相当于飞机方向用了该点后面飞行路径产生的向量,如果改前点,需要考虑左后一个点的处理,因为后面没有点了
		animationPath->insert(time, osg::AnimationPath::ControlPoint(BWpoint, (osg::Matrixd::translate(-bs.center())).getRotate()*rotation3*(osg::Matrixd::translate(bs.center())).getRotate()));
		PlaneP->pop();	
		/*for (int i = 0; i < numSamples; ++i)//步长循环
	{
		osg::Vec3d oldposition;
		m_pMapSRS->transformToWorld(OldEarthPosition, oldposition);
		//osg::Vec3 NewEarthPosition(earthPosition + osg::Vec3(yaw, yaw, 0.0f));
		osg::Vec3d newposition;
		m_pMapSRS->transformToWorld(NewEarthPosition, newposition);//osgearth坐标转osg坐标
		//计算飞机移动的向量
		double a_x = (newposition.x())- (oldposition.x());
		double a_y = (newposition.y())- (oldposition.y());
		double a_z =(newposition.z())- (oldposition.z());
		//计算将飞机移动到向量osg::Vec3(a_x, a_y, a_z)的旋转矩阵
		osg::Matrixd rotMat = osg::Matrixd::rotate((osg::Y_AXIS), osg::Vec3(a_x, a_y, a_z));
		//计算对应地面点的指天向量,方法1
		GeoPoint localPoint(m_pMapSRS, NewEarthPosition.x(), NewEarthPosition.y(), NewEarthPosition.z());
		osg::Vec3d v3HorizonUp;//指天向量
		localPoint.createWorldUpVector(v3HorizonUp);
		//计算对应地面点的指天向量,方法2
		//osg::EllipsoidModel* em = new osg::EllipsoidModel();
		//osg::Vec3d v3HorizonUp2=(em->computeLocalUpVector(newposition.x(), newposition.y(), newposition.z()));
		//计算将飞机移动到向量v3HorizonUp的旋转矩阵
		osg::Matrixd rotMatsky = osg::Matrixd::rotate((osg::Z_AXIS), osg::Vec3(v3HorizonUp.x(), v3HorizonUp.y(), v3HorizonUp.z()));
		//计算移动向量对应的旋转角
		osg::Quat rotation = rotMat.getRotate();
		double heading = 0; double pitch = 0; double roll = 0;
		QuatToHPR(rotation, heading, pitch, roll);
		//计算翻滚向量对应的旋转角
		osg::Quat rotation2 = rotMatsky.getRotate();//
		double heading2 = 0; double pitch2 = 0; double roll2 = 0;
		QuatToHPR(rotation2, heading2, pitch2, roll2);
		//取移动向量的偏航角和俯仰角,翻滚向量的翻滚角,合成新的旋转角,并计算对应的矩阵
		osg::Quat rotation3=HPRToQuat(heading, pitch, roll2);//合成旋转角
		//将新的坐标和角度压入动画
		const osg::BoundingSphere& bs = modelmt->getBound();
		animationPath->insert(time, osg::AnimationPath::ControlPoint(newposition, (osg::Matrixd::translate(-bs.center())).getRotate()*rotation3*(osg::Matrixd::translate(bs.center())).getRotate()));


		yaw += yaw_delta;
		time += time_delta;
		//过程记录
		/*1得到的不是欧拉角而是四元素,pitch,yaw,roll来自航空界的叫法,翻译为俯仰角,偏航角,翻滚角
		 2但是对于有缩放和位移的矩阵,不能直接使用上述方法, osg中提供了分解的方法
		 3欧拉角转四元素 只需要清楚知道旋转的顺序,和旋转轴即可,一般是通过下面这种方式来旋转,即先y轴,再x轴,再z轴
		 4应该是沿着前进方向逆时针翻滚,就是顺时针旋转,
		 5翻滚量跟纬度有关,?
		 6翻滚方向与经度有关,经度递增翻滚逆时针,经度递减翻滚顺时针????
		 7得到合成的旋转角度,在跨维度90,经度180的时候好像有点问题,暂时用不到,待后续处理
		 8翻滚角依然有问题,暂时先放一放
	   */
		/*********绘制轨迹**********/
		std::vector<osg::Vec3d> m_vecPoint;
		m_vecPoint.push_back(FEpoint);
		m_vecPoint.push_back(BEpoint);
		createLine(m_vecPoint, radarGroup);
		FEpoint = BEpoint;
	}
	return animationPath;
}
void GraphicsView::removeRadar()
{
	if (radarGroup)
	{
		radarGroup->removeChildren(0, radarGroup->getNumChildren());
	}
	m_pRoot->removeChild(radarGroup);
}
void GraphicsView::rotateCone(osg::MatrixTransform* mt, const osgEarth::SpatialReference* sr, osg::Vec3d lonlat1, osg::Vec3d lonlat2)// osg与OSGearth坐标不一致,添加矩阵变换函数。lonlat1:雷达波圆锥顶点, lonlat2:目标点               
{
	// 雷达波模型所在位置
	osgEarth::GeoPoint geoPoint1(
		sr,
		lonlat1.x(),
		lonlat1.y(),
		lonlat1.z(),
		osgEarth::ALTMODE_ABSOLUTE);
	osg::Matrixd matrix1;
	// 获取雷达波模型从原点变换到lonlat1位置的变换矩阵
	geoPoint1.createLocalToWorld(matrix1);
	// 经纬度高程到xyz的变换
	osg::Vec3d world1, world2;
	// geoPoint1.toWorld(world1);//等同于    sr->transformToWorld(lonlat1,world1);
	sr->transformToWorld(lonlat2, world2);
	// 计算轨迹点在雷达波模型坐标系下的位置
	osg::Vec3 point2InRadarCoordinateSystem = world2 * osg::Matrix::inverse(matrix1);
	// 在雷达波模型坐标系下,对Z轴进行旋转,与连接原点指向轨迹点方向的矢量重合,计算出此旋转矩阵
	osg::Matrixd rotMat = osg::Matrixd::rotate(osg::Z_AXIS, point2InRadarCoordinateSystem - osg::Vec3(0, 0, 0));
	// 将计算出的旋转矩阵赋给雷达波模型所在的mt
	mt->setMatrix(rotMat);	
}
osg::AnimationPath* GraphicsView::rotateCone1(osg::MatrixTransform* mt, const osgEarth::SpatialReference* sr, osg::Vec3d lonlat1, queue <PlanePoint> *PlaneP/*飞机轨迹点*/, double radarDistance)// osg与OSGearth坐标不一致,添加矩阵变换函数。lonlat1:雷达波圆锥顶点, lonlat2:目标点               
{
	osg::AnimationPath* animationPath = new osg::AnimationPath;//自动路径
	animationPath->setLoopMode(osg::AnimationPath::LOOP);//设置动画模式为循环(LOOP)
	// 雷达波模型所在位置
	osgEarth::GeoPoint geoPoint1(
		sr,
		lonlat1.x(),
		lonlat1.y(),
		lonlat1.z(),
		osgEarth::ALTMODE_ABSOLUTE);
	osg::Matrixd matrix1;
	// 获取雷达波模型从原点变换到lonlat1位置的变换矩阵
	geoPoint1.createLocalToWorld(matrix1);

	while (!PlaneP->empty())	
	{
		
		osg::Vec3d  Epoint = PlaneP->front().point;
		double time = PlaneP->front().time;
		osg::Vec3d  Wpoint;
		sr->transformToWorld(Epoint, Wpoint);// 计算轨迹点在雷达波模型坐标系下的位置		
		osg::Vec3 point2InRadarCoordinateSystem = Wpoint * osg::Matrix::inverse(matrix1);// 在雷达波模型坐标系下,对Z轴进行旋转,与连接原点指向轨迹点方向的矢量重合,计算出此旋转矩阵
		osg::Matrixd rotMat = osg::Matrixd::rotate(osg::Z_AXIS, point2InRadarCoordinateSystem - osg::Vec3(0, 0, 0));// 将计算出的旋转矩阵赋给雷达波模型所在的mt
				
		//double newDistance = osgEarth::GeoMath::distance(lonlat1, Epoint, sr);//新的半径
		osg::Vec3d wop;
		sr->transformToWorld(lonlat1, wop);
		double newDistance= sqrt((Wpoint.x() - wop.x())*(Wpoint.x() - wop.x()) + (Wpoint.y() - wop.y())*(Wpoint.y() - wop.y())+ (Wpoint.z() - wop.z())*(Wpoint.z() - wop.z()));
		double scale1 = newDistance / radarDistance;
		osg::Vec3d scale2 = osg::Vec3d(1, 1, scale1);
		
		
		animationPath->insert(time, osg::AnimationPath::ControlPoint(lonlat1/*位置不变,没啥用*/, rotMat.getRotate(), scale2));
		PlaneP->pop();
		
		
		//调整雷达波束长度,不起作用,cone只是图形数据,似乎需要再绘制成图形,在这里回调不行
		/*double radarDistance = osgEarth::GeoMath::distance(lonlat1, Epoint, sr);
		Cone->setHeight(radarDistance);
		Cone->setCenter(osg::Vec3(0, 0, 3 * radarDistance / 4));//平移,使得0点位于顶点*/
		
	}	
	return animationPath;
}
#ifndef RADARMAP_H
#define RADARMAP_H

#include "framehandle.h"
#include "graphicsview.h"

class RadarMap : public QObject
{
	Q_OBJECT

public:
	RadarMap(GraphicsView* view, QObject *parent = nullptr);
	~RadarMap();

	void setGeomtry(int x = 20, int y = 20, int width = 320, int height = 180)
	{
		m_iX = x; m_iY = y; m_iWidth = width; m_iHeight = height;
	}

	void enableMap();
	void disableMap();

private slots:
	void slotFrameViewport(const osg::Vec3d& pos);

private:
	void createMap();
	// 根据世界坐标去经纬度坐标
	osg::Vec3d getLonLat(const osg::Vec3d& worldPos);

private:
	// 显示的区域
	int m_iX;
	int m_iY;
	int m_iWidth;
	int m_iHeight;

	// HUD相机
	osg::ref_ptr<osg::Camera> m_pHUDCamera;
	GraphicsView* m_pOSGViewer;
	osg::ref_ptr<osg::Group> m_pGroup;
	FrameHandle* m_pFrameHandle;

	// 十字架,显示当前视点位置
	osg::ref_ptr<osg::Geode> m_pGeodeCross;
	osg::ref_ptr<osg::Vec3dArray> m_pVertexCross;
};

#endif // RADARMAP_H
#include "radarmap.h"

RadarMap::RadarMap(GraphicsView* view, QObject* parent/* = nullptr*/)
	: m_pOSGViewer(view), QObject(parent)
{
	m_pHUDCamera = nullptr;
	m_pGroup = new osg::Group;
	m_pOSGViewer->getRoot()->addChild(m_pGroup);//添加到大的视图中
	m_pFrameHandle = new FrameHandle;
	m_pGeodeCross = nullptr;
	setGeomtry();
}

RadarMap::~RadarMap()
{

}

void RadarMap::enableMap()
{
	if (m_pHUDCamera == nullptr)
	{
		createMap();
	}
	m_pGroup->addChild(m_pHUDCamera);
	m_pOSGViewer->getOSGViewer()->addEventHandler(m_pFrameHandle);
	connect(m_pFrameHandle, SIGNAL(signalFrameViewport(const osg::Vec3d&)),
		this, SLOT(slotFrameViewport(const osg::Vec3d&)));
}

void RadarMap::disableMap()
{
	if (m_pHUDCamera)
	{
		m_pGroup->removeChild(m_pHUDCamera);
		m_pHUDCamera = nullptr;
		disconnect(m_pFrameHandle, SIGNAL(signalFrameViewport(const osg::Vec3d&)),
			this, SLOT(slotFrameViewport(const osg::Vec3d&)));
		m_pOSGViewer->getOSGViewer()->removeEventHandler(m_pFrameHandle);
	}
}

void RadarMap::slotFrameViewport(const osg::Vec3d& pos)
{
	if (m_pGeodeCross == nullptr)
	{
		m_pGeodeCross = new osg::Geode;
		osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;
		// 使用VBO,每帧实时的修改数据
		pGeometry->setUseVertexBufferObjects(true);
		m_pVertexCross = new osg::Vec3dArray;
		pGeometry->setVertexArray(m_pVertexCross);
		osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array;
		normal->push_back(osg::Vec3(0, 0, 1));
		pGeometry->setNormalArray(normal, osg::Array::BIND_OVERALL);
		osg::ref_ptr<osg::Vec4Array> color = new osg::Vec4Array;
		color->push_back(osg::Vec4(0.8, 0.8, 0.8, 1));
		pGeometry->setColorArray(color, osg::Array::BIND_OVERALL);
		pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, 4));

		m_pGeodeCross->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
		m_pGeodeCross->getOrCreateStateSet()->setAttribute(
			new osg::LineWidth(0.5), osg::StateAttribute::ON);
		m_pGeodeCross->addDrawable(pGeometry);
		m_pHUDCamera->addChild(m_pGeodeCross);
	}
	osg::Vec3d mapPos = getLonLat(pos);
	// 经纬度是-180~180,-90~90,保证算出的是0~360和0~180
	double x = (mapPos.x() + 180.0) * m_iWidth / 360.0;
	double y = (mapPos.y() + 90.0) * m_iHeight / 180.0;

	// 更新缓冲区数据
	m_pVertexCross->clear();
	m_pVertexCross->push_back(osg::Vec3d(x, y - 5, 0));
	m_pVertexCross->push_back(osg::Vec3d(x, y + 5, 0));
	m_pVertexCross->push_back(osg::Vec3d(x - 5, y, 0));
	m_pVertexCross->push_back(osg::Vec3d(x + 5, y, 0));
	m_pVertexCross->dirty();
}

void RadarMap::createMap()
{
	m_pHUDCamera = new osg::Camera;

	// 设置投影矩阵
	m_pHUDCamera->setProjectionMatrixAsOrtho2D(m_iX, m_iWidth, m_iY, m_iHeight);

	// 设置视口矩阵
	m_pHUDCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
	m_pHUDCamera->setViewMatrix(osg::Matrix::identity());

	// 只清除深度缓冲区
	m_pHUDCamera->setClearMask(GL_DEPTH_BUFFER_BIT);

	// 设置HUD相机在主相机之后渲染
	m_pHUDCamera->setRenderOrder(osg::Camera::POST_RENDER);

	// HUD相机不获取Event的焦点
	m_pHUDCamera->setAllowEventFocus(false);
	m_pHUDCamera->setViewport(m_iX, m_iY, m_iWidth, m_iHeight);

	// 增加HUD相机的渲染内容,即map
	osg::ref_ptr<osg::Geode> pGeode = new osg::Geode;

	// 创建纹理
	osg::ref_ptr<osg::Geometry> pGeometry = new osg::Geometry;
	{
		// 顶点
		osg::ref_ptr<osg::Vec3Array> verArray = new osg::Vec3Array;
		verArray->push_back(osg::Vec3(0, 0, -1));
		verArray->push_back(osg::Vec3(m_iWidth, 0, -1));
		verArray->push_back(osg::Vec3(m_iWidth, m_iHeight, -1));
		verArray->push_back(osg::Vec3(0, m_iHeight, -1));
		pGeometry->setVertexArray(verArray);
		// 纹理坐标
		osg::ref_ptr<osg::Vec2Array> textArray = new osg::Vec2Array;
		textArray->push_back(osg::Vec2(0, 0));
		textArray->push_back(osg::Vec2(1, 0));
		textArray->push_back(osg::Vec2(1, 1));
		textArray->push_back(osg::Vec2(0, 1));
		pGeometry->setTexCoordArray(0, textArray);
		// 法线,指向用户,即y轴
		osg::ref_ptr < osg::Vec3Array> normal = new osg::Vec3Array;
		normal->push_back(osg::Vec3(0, 1, 0));
		pGeometry->setNormalArray(normal);
		pGeometry->setNormalBinding(osg::Geometry::BIND_OVERALL);
		// 指定绘制方式
		pGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));
		// 纹理图片
		osg::ref_ptr<osg::Image> image = osgDB::readImageFile(
			"./Images/image_formats/png/world.png");// E:\osg\data\Images\image_formats\png
		if (image)
		{
			osg::ref_ptr<osg::Texture2D> text2D = new osg::Texture2D;
			text2D->setImage(image);
			text2D->setDataVariance(osg::Object::DYNAMIC);

			pGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(
				0, text2D, osg::StateAttribute::ON);
		}
	}

	// 创建HUD相机的边框
	osg::ref_ptr<osg::Geometry> pGeoBorder = new osg::Geometry;
	{
		// 顶点
		osg::ref_ptr<osg::Vec3Array> verBorder = new osg::Vec3Array;
		verBorder->push_back(osg::Vec3(1.0, 1.0, 0));
		verBorder->push_back(osg::Vec3(m_iWidth - 1.0, 1.0, 0));
		verBorder->push_back(osg::Vec3(m_iWidth - 1.0, m_iHeight - 1.0, 0));
		verBorder->push_back(osg::Vec3(1.0, m_iHeight - 1.0, 0));
		pGeoBorder->setVertexArray(verBorder);
		// 法线
		osg::ref_ptr<osg::Vec3Array> normalBorder = new osg::Vec3Array;
		normalBorder->push_back(osg::Vec3(0.0, 0.0, 1.0));
		pGeoBorder->setNormalArray(normalBorder, osg::Array::BIND_OVERALL);
		// 颜色
		osg::ref_ptr<osg::Vec4Array> color = new osg::Vec4Array;
		color->push_back(osg::Vec4(1, 0.8, 0, 1));
		pGeoBorder->setColorArray(color);
		pGeoBorder->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::LINE_LOOP, 0, 4));
		pGeoBorder->getOrCreateStateSet()->setAttribute(new osg::LineWidth(2), osg::StateAttribute::ON);
	}
	pGeode->addDrawable(pGeometry);
	pGeode->addDrawable(pGeoBorder);
	pGeode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

	m_pHUDCamera->addChild(pGeode);
}

osg::Vec3d RadarMap::getLonLat(const osg::Vec3d& worldPos)
{
	osg::Vec3d vecPos = osg::Vec3d();
	if (m_pOSGViewer)
	{
		m_pOSGViewer->getSRS()->getEllipsoid()->convertXYZToLatLongHeight(
			worldPos.x(), worldPos.y(), worldPos.z(), vecPos.y(), vecPos.x(), vecPos.z());
		vecPos.x() = osg::RadiansToDegrees(vecPos.x());
		vecPos.y() = osg::RadiansToDegrees(vecPos.y());
	}
	return vecPos;
}

时间久了,代码整理的不是很全,请见谅。

上一篇:osgearth加载mapbox在线高程数据


下一篇:调试最长的一帧(第29天)