OSG-Planet

由于未提供博客具体内容,无法生成包含关键信息的摘要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#ifndef PLANET_H
#define	PLANET_H

#include <QObject>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/MatrixTransform>
#include <osg/PrimitiveSet>
#include <osgParticle/Particle>
#include <osgParticle/PointPlacer>
#include "CSphereCallBack.h"
#include <QObject>

struct STPlanetData
{
	STPlanetData(){}
	STPlanetData(const double R, const double autoRS, const double revolR, const double doublerevolRS, const QString &texName)
		: radius(R)
		, autoRotSpeed(autoRS)
		, revolRadius(revolR)
		, revolRotSpeed(doublerevolRS)
		, strTexName(texName) {}
	QString name;			//行星名字
	QString orbitName;		//轨迹名字

	double radius;			//半径
	double autoRotSpeed;	//自转速度
	double revolRadius;		//公转半径
	double revolRotSpeed;	//公转速度
	QString strTexName;		//纹理名称
};

class Planet : public QObject, public osg::Geode
{
	Q_OBJECT
public:
	Planet();
	~Planet();

	//设置行星数据
	void setData(const STPlanetData &data, const osg::Matrix &translateMat = osg::Matrix());

	//设置行星暂停转动
	void setRotable(const bool rot) 
	{
		if (m_rpCallBack) 
			m_rpCallBack->setRotatable(rot); 
		if(m_rpTailCallBack)
			m_rpTailCallBack->setRotatable(rot);
	}

	//设置、获取行星半径
	void setRadius(const double radius) { m_data.radius = radius; }
	double radius()const { return m_data.radius; }
	//设置、获取行星自传速度
	void setAutoRotSpeed(const double speed) {m_data.autoRotSpeed = speed; updateCallBack();}
	double autoRotSpeed()const { return m_data.autoRotSpeed; }
	//设置、获取行星公转半径
	void setRevolRadius(const double revolRadius) {m_data.revolRadius = revolRadius;  updateCallBack();}
	double revolRadius()const { return m_data.revolRadius; }
	//设置、获取行星公转速度
	void setRevolRotSpeed(const double revolSpeed) { m_data.revolRotSpeed = revolSpeed; updateCallBack(); }
	double revolRotSpeed()const {return m_data.revolRotSpeed;}
	//设置行星加速、减速
	void setRevolrotPlusSpeed() { m_data.revolRotSpeed += 0.01; updateCallBack(); }
	void setRevolrotSubSpeed() { m_data.revolRotSpeed -= 0.01; updateCallBack(); }
	//设置、获取行星纹理名称
	void setTextureName(const QString &texName) { m_data.strTexName = texName; }
	QString textureName()const { return m_data.strTexName; }

	//获取行星变换节点
	osg::ref_ptr<osg::MatrixTransform> matrixTrans();
	//获取轨迹节点
	osg::ref_ptr<osg::Geode> orbitLine();
	//设置轨迹是否可见
	void setOrbitLineVisible(const bool vis);
	//设置轨迹name
	void setOrbitName(const QString &name);
	//设置轨迹线宽
	void setOrbitLineWidth(const bool plus);
	//设置轨迹颜色
	void setOrbitLineColor(const osg::Vec4 &color);
	//改变轨迹样式
	void setOrbitLineStyle(const osg::PrimitiveSet::Mode &lineStyle);

	osg::ref_ptr<osg::MatrixTransform> createTail();
	osg::ref_ptr<osg::Geode> createTailNode(int vertexNum);

private:
	void createSphere();
	void createOrbit();

	void updateCallBack();

	osg::ref_ptr<osg::MatrixTransform> m_matrixTrans;
	osg::Matrix m_translateMat;

	osg::ref_ptr<osg::Geode> m_orbitGeode;
	osg::ref_ptr<osg::Geometry> m_orbitGeometry;

	QString m_sphereName;
	QString m_orbitName;
	float m_orbitLineWidth;
	osg::Vec4 m_orbitLineColor;
	osg::PrimitiveSet::Mode m_lineStyle;

	osg::ref_ptr<CSphereCallBack> m_rpCallBack;
	osg::ref_ptr<TailCallback> m_rpTailCallBack;//粒子
	osg::ref_ptr<CTrailerCallback> m_rpCTailCallBack;

	STPlanetData m_data;		//行星数据
};

#endif
#include "Planet.h"
#include <osgDB/ReadFile>
#include <osg/AnimationPath>
#include <osg/Texture2D> 
#include <osg/Image> 
#include <osg/Material>
#include <osg/LineWidth>
#include <osg/Program>
#include <osg/BlendColor>
#include <osgParticle/Particle>
#include <osgParticle/ParticleSystem>
#include <osgParticle/ModularEmitter>
#include <osgParticle/RandomRateCounter>
#include <osgParticle/RadialShooter>
#include <osgParticle/ModularProgram>
#include <osgParticle/AccelOperator>
#include <osgParticle/FluidFrictionOperator>
#include <osgParticle/ParticleSystemUpdater>
#include <QDebug>
#include <QTimer>
#include <QCoreApplication>

const int NUM = 50;

Planet::Planet()
	: m_translateMat(osg::Matrix())
	, m_orbitLineWidth(1.0)
	, m_orbitLineColor(0.0, 0.0, 1.0, 1)
	, m_lineStyle(osg::PrimitiveSet::LINE_LOOP)
	, m_rpCallBack(new CSphereCallBack())
	, m_rpCTailCallBack(nullptr)
{
	
}

Planet::~Planet()
{
}

void Planet::setData(const STPlanetData &data, const osg::Matrix &translateMat)
{
	m_data = data;
	m_translateMat = translateMat;

	setName(data.name.toStdString());
	setOrbitName(data.orbitName);

	createSphere();
	updateCallBack();
}

osg::ref_ptr<osg::MatrixTransform> Planet::matrixTrans()
{
	return m_matrixTrans.get();
}

void Planet::createSphere()
{
	osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
	osg::ref_ptr<osg::Vec3Array> vertexes = new osg::Vec3Array;		// 顶点
	osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array;		// 法线
	osg::ref_ptr<osg::Vec2Array> texCoord = new osg::Vec2Array;		// 纹理
	osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;		// 颜色-为了不被轨迹节点的颜色影响

	for (int i = 0; i <= NUM; ++i)//NUM:纬线数
	{
		for (int j = 0; j <= NUM * 2; ++j)//NUM * 2:经线数
		{
			osg::Vec3 vec3(
				sin(osg::PI * i / NUM) * cos(osg::PI * j / NUM),
				sin(osg::PI * i / NUM) * sin(osg::PI * j / NUM),
				cos(osg::PI * i / NUM));
			vertexes->push_back(vec3 * m_data.radius);
			normal->push_back(-vec3);
			texCoord->push_back(osg::Vec2(double(j) / (2.0 * NUM), 1.0 - double(i) / NUM));//y从上到下
			colors->push_back(osg::Vec4(1.0, 1.0, 1.0, 0.0));
		}
	}

	geometry->setVertexArray(vertexes);
	geometry->setNormalArray(normal, osg::Array::BIND_PER_VERTEX);
	geometry->setTexCoordArray(0, texCoord);
	geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
	
	QString path = QCoreApplication::applicationDirPath();
	path.append("/../../data/Star/");
	path.append(m_data.strTexName);

	osg::StateSet* state = geometry->getOrCreateStateSet();
	osg::ref_ptr<osg::Image> image = osgDB::readImageFile(path.toStdString());
	osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
	tex->setImage(image.get());
	tex->setWrap(osg::Texture::WRAP_S ,osg::Texture::REPEAT);
	tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
	state->setTextureAttributeAndModes(0, tex.get());
	

	osg::ref_ptr<osg::DrawElementsUInt> elements = new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLE_STRIP);
	for (int i = 0; i < NUM; ++i)
	{
		for (int j = 0; j <= NUM * 2; ++j)
		{
			elements->push_back(i * (NUM * 2 + 1) + j);
			elements->push_back((i + 1) * (NUM * 2 + 1) + j);
		}
	}
	geometry->addPrimitiveSet(elements);
	this->addDrawable(geometry);

	//矩阵变换
	m_matrixTrans = new osg::MatrixTransform;
	m_matrixTrans->addChild(this);
	m_matrixTrans->setUpdateCallback(m_rpCallBack);
	if (!m_translateMat.isIdentity())//小行星带使用
		m_rpCallBack->setTranslateMat(m_translateMat);
}

osg::ref_ptr<osg::MatrixTransform> Planet::createTail()
{
	osgParticle::Particle parTemplate;
	parTemplate.setLifeTime(1);
	parTemplate.setSizeRange(osgParticle::rangef(1.0f, 0.2f));
	parTemplate.setAlphaRange(osgParticle::rangef(0.0f, 1.0f));
	parTemplate.setColorRange(osgParticle::rangev4(osg::Vec4f(1.0, 0.5, 0.3, 1.0), osg::Vec4f(0.0, 0.7, 1.0, 0.0)));
	parTemplate.setRadius(0.02);
	parTemplate.setMass(0.001);//重量

	osg::ref_ptr<osgParticle::ParticleSystem> parSystem = new osgParticle::ParticleSystem();
	parSystem->setDefaultAttributes("", false, false);
	parSystem->setDefaultParticleTemplate(parTemplate);

	//粒子放射器(计数器、放置器、发射器)
	osg::ref_ptr<osgParticle::ModularEmitter> parEmitter = new osgParticle::ModularEmitter();
	parEmitter->setParticleSystem(parSystem);

	osg::ref_ptr<osgParticle::RandomRateCounter> parCounter = new osgParticle::RandomRateCounter();
	parCounter->setRateRange(50, 50);//粒子数量
	parEmitter->setCounter(parCounter);

	osg::ref_ptr<osgParticle::PointPlacer> placer = new osgParticle::PointPlacer();//粒子生成位置
	placer->setCenter(getBound().center());
	parEmitter->setPlacer(placer);

	//弧度发射器
	osg::ref_ptr<osgParticle::RadialShooter> parShooter = new osgParticle::RadialShooter();
	parShooter->setInitialSpeedRange(1.0,1.0);
	//与z轴的夹角
	parShooter->setThetaRange(osg::PI_2, osg::PI_2);
	//与x y面夹角
	parShooter->setPhiRange(osg::PI_2, osg::PI_2);;

	parEmitter->setShooter(parShooter);

	//重力、空气阻力模拟
	osg::ref_ptr<osgParticle::ModularProgram> parProgram = new osgParticle::ModularProgram();
	parProgram->setParticleSystem(parSystem);

	osg::ref_ptr<osgParticle::AccelOperator> parAccOperator = new osgParticle::AccelOperator();
	parAccOperator->setToGravity(2);
	parProgram->addOperator(parAccOperator);
	osg::ref_ptr<osgParticle::FluidFrictionOperator> parFluOperator = new osgParticle::FluidFrictionOperator();
	parFluOperator->setFluidToAir();
	parProgram->addOperator(parFluOperator);

	osg::ref_ptr<osgParticle::ParticleSystemUpdater> parUpdater = new osgParticle::ParticleSystemUpdater();
	parUpdater->addParticleSystem(parSystem);
	osg::ref_ptr<osg::Geode> parGeode = new osg::Geode;
	parGeode->addDrawable(parSystem);

	osg::ref_ptr<osg::MatrixTransform> particleMat = new osg::MatrixTransform();//尾迹结点
	m_rpTailCallBack = new TailCallback(m_data.revolRadius, m_data.revolRotSpeed);
	particleMat->setUpdateCallback(m_rpTailCallBack);
	particleMat->addChild(parEmitter);
	particleMat->addChild(parProgram);
	particleMat->addChild(parGeode);
	particleMat->addChild(parUpdater);

	return particleMat.release();
}

void Planet::createOrbit()
{
	m_orbitGeode = new osg::Geode;
	osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;

	geometry->setName(m_orbitName.toStdString());
	osg::ref_ptr<osg::Vec3Array> vertexes = new osg::Vec3Array;
	osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
	osg::ref_ptr<osg::Vec3Array> normal = new osg::Vec3Array;

	for (int j = 0; j <= NUM * 2; ++j)
	{
		osg::Vec3 vec3(cos(osg::PI * j / NUM), sin(osg::PI * j / NUM), 0);
		vertexes->push_back(vec3 * m_data.revolRadius);
		colors->push_back(m_orbitLineColor);
		normal->push_back(osg::Vec3(0.0, 0.0, 1.0));
	}
	geometry->setVertexArray(vertexes);
	geometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
	geometry->setNormalArray(normal, osg::Array::BIND_PER_VERTEX);
	geometry->getOrCreateStateSet()->setAttribute(new osg::LineWidth(m_orbitLineWidth));

	/*osg::Program *program = new osg::Program;
	program->addShader(new osg::Shader(osg::Shader::VERTEX, vershader));
	program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragshader));
	geometry->getOrCreateStateSet()->setAttribute(program, osg::StateAttribute::ON);
	geometry->getOrCreateStateSet()->setAttributeAndModes(lineProgram,osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED);
	geometry->getOrCreateStateSet()->addUniform(new osg::Uniform("a_Color",osgEarth::Color(_style.lineColor())));*/// 线条颜色

	geometry->addPrimitiveSet(new osg::DrawArrays(m_lineStyle, 0, vertexes->size()));
	m_orbitGeode->addDrawable(geometry);
	m_orbitGeometry = geometry;
}

osg::ref_ptr<osg::Geode> Planet::createTailNode(int vertexNum)
{
	osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
	osg::ref_ptr<osg::Vec3Array> vec3Vertex = new osg::Vec3Array(vertexNum);
	osg::ref_ptr<osg::Vec4Array> vec4Color = new osg::Vec4Array(vertexNum);

	for (unsigned int i = 0; i < vertexNum; ++i)
	{
		(*vec3Vertex)[i] = osg::Vec3(0, 0, 0);

		float alpha = sinf(osg::PI * (float)i / (float)vertexNum);

		(*vec4Color)[i] = osg::Vec4(1.0, 1.0, 0.0, alpha);
	}

	geometry->setDataVariance(osg::Object::DYNAMIC);	//场景数据动态改变
	geometry->setUseDisplayList(false);					//禁用显示列表,动态更新不安全
	geometry->setUseVertexBufferObjects(true);			//使用VBO模式

	geometry->setVertexArray(vec3Vertex);
	geometry->setColorArray(vec4Color);
	geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
	geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, vertexNum));

	geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);	//关闭灯光
	geometry->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);		//打开混合
	geometry->getOrCreateStateSet()->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);	//透明度

	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	geode->addDrawable(geometry);

	geode->setNodeMask(0);
	QTimer::singleShot(6000, this, [=]() {geode->setNodeMask(1); });

    m_rpCTailCallBack = new CTrailerCallback(geometry, vertexNum);
	m_matrixTrans->addUpdateCallback(m_rpCTailCallBack);

	return geode.release();
}

void Planet::updateCallBack()
{
	if(m_rpCallBack)
		m_rpCallBack->setPlanetPama(m_data.autoRotSpeed, m_data.revolRadius, m_data.revolRotSpeed);
	if(m_rpTailCallBack)
		m_rpTailCallBack->updatePara(m_data.revolRadius, m_data.revolRotSpeed);
}

osg::ref_ptr<osg::Geode> Planet::orbitLine()
{
	if(m_orbitGeode)
		m_orbitGeode->setNodeMask(0);
	return m_orbitGeode.get();
}

void Planet::setOrbitLineVisible(const bool vis)
{
	if(m_orbitGeode)
		m_orbitGeode->setNodeMask(vis);
}

void Planet::setOrbitName(const QString &name)
{
	m_orbitName = name;
	createOrbit();
}

void Planet::setOrbitLineWidth(const bool plus)
{
	if (plus)
		m_orbitLineWidth++;
	else
		m_orbitLineWidth--;
	if(m_orbitGeometry)
		m_orbitGeometry->getOrCreateStateSet()->setAttribute(new osg::LineWidth(m_orbitLineWidth),osg::StateAttribute::ON);
}

void Planet::setOrbitLineColor(const osg::Vec4 &color)
{
	if (!m_orbitGeometry) return;
	osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
	m_orbitLineColor = color;
	for (int j = 0; j <= NUM * 2; ++j)
	{
		colors->push_back(m_orbitLineColor);
	}
	m_orbitGeometry->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
}

void Planet::setOrbitLineStyle(const osg::PrimitiveSet::Mode &lineStyle)
{
	if (!m_orbitGeometry) return;
	m_lineStyle = lineStyle;
	m_orbitGeometry->removePrimitiveSet(0);
	m_orbitGeometry->addPrimitiveSet(new osg::DrawArrays(m_lineStyle, 0, NUM * 2 + 1));
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值