IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> osg使用osgQT和QT结合 -> 正文阅读

[开发工具]osg使用osgQT和QT结合

一、环境配置

新建QT空项目

添加QT Model

记得加入osgQT.lib到附加依赖项里面

二、代码

代码来源:OSG的b站小讲堂

main.cpp

#include <QApplication>
#include "mainWindow.h"
#include "ListWidget.h"

int main(int argc, char** argv)
{
	QApplication app(argc, argv);
	//CMainWindow为qt和osg结合类
	CMainWindow mainWindow;
	//CListWidget为列表展示
	CListWidget listWidget(&mainWindow);
	mainWindow.setGeometry(100, 100, 800, 600);
	mainWindow.show();
	return app.exec();
}

?mainWindow.cpp

#include <osgGA/TrackballManipulator>
#include <osgQt/GraphicsWindowQt>
#include <osgGA/StateSetManipulator>
#include <osgViewer/ViewerEventHandlers>
#include <QApplication>
#include<osgDB/ReadFile>
#include "mainWindow.h"

CMainWindow::CMainWindow(QWidget* parent, Qt::WindowFlags f)
	: QWidget(parent, f)
{
	//根据qt版本决定使用单线程或多线程,以及qt应用程序属性
	osgViewer::ViewerBase::ThreadingModel threadingModel;
#if QT_VERSION >= 0x050000
	threadingModel = osgViewer::ViewerBase::SingleThreaded;
#else
	threadingModel = osgViewer::ViewerBase::CullDrawThreadPerContext;
#endif

#if QT_VERSION >= 0x040800
	if (threadingModel != osgViewer::ViewerBase::SingleThreaded)
		QApplication::setAttribute(Qt::AA_X11InitThreads);
#endif
	m_rpViewer = new osgViewer::Viewer;
	m_rpViewer->setThreadingModel(threadingModel);//设置线程
	m_rpViewer->setCameraManipulator(new osgGA::TrackballManipulator);//设置相机操作器
	m_rpViewer->setKeyEventSetsDone(0);// disable the default setting of viewer.done() by pressing Escape.//设置不接受esc退出事件
	m_rpViewer->addEventHandler(new osgViewer::StatsHandler);//添加s键事件
	m_rpViewer->addEventHandler(new osgGA::StateSetManipulator(m_rpViewer->getCamera()->getOrCreateStateSet()));//添加w键事件
	m_rpRoot = new osg::Group;
	//m_rpRoot->addChild(osgDB::readNodeFile("clear.earth"));
	m_rpViewer->setSceneData(m_rpRoot.get());
	//初始化qt主窗口布局
	m_pVLayout = new QVBoxLayout;
	//表示控件与窗体的左右边距
	m_pVLayout->setMargin(1);
	//表示各个控件之间的上下间距
	m_pVLayout->setSpacing(0);
	m_pHLayout = new QHBoxLayout;
	m_pHLayout->setMargin(0);
	m_pHLayout->setSpacing(0);
	//创建场景widget指针
	QWidget* pSceneWidget = createGraphicsWindow(0, 0, 800, 600, "main window", true);
	//最小尺寸
	pSceneWidget->setMinimumSize(500, 500);
	m_pHLayout->addWidget(pSceneWidget);
	m_pVLayout->addLayout(m_pHLayout);
	setLayout(m_pVLayout);

	//设置每10ms更新场景
	//connect(Sender,SIGNAL(signal),Receiver,SLOT(slot));
	connect(&m_timer, SIGNAL(timeout()), this, SLOT(update())); //this指CMainWindow这个类
	//10ms执行一次定时器
	m_timer.start(10);
}

void CMainWindow::home()
{
	if (m_rpViewer.valid() && m_rpViewer->getCameraManipulator())
	{
		m_rpViewer->getCameraManipulator()->home(0);
	}
}

QWidget* CMainWindow::createGraphicsWindow(int nX, int nY, int nW, int nH, const std::string& strName, bool bWindowDecoration)
{
	//显示设置
	osg::DisplaySettings* pDS = osg::DisplaySettings::instance().get();
	osg::ref_ptr<osg::GraphicsContext::Traits> pTraits = new osg::GraphicsContext::Traits(pDS);
	//场景内容显示特征
	pTraits->windowName = strName;//窗口名称
	pTraits->windowDecoration = false;//窗口装饰
	pTraits->overrideRedirect = true;//重定向
	pTraits->x = nX;//x位置
	pTraits->y = nY;//y位置
	pTraits->width = nW;//宽
	pTraits->height = nH;//高
	pTraits->doubleBuffer = true;//双缓存
	pTraits->alpha = pDS->getMinimumNumAlphaBits();
	pTraits->stencil = pDS->getMinimumNumStencilBits();//模具
	pTraits->sampleBuffers = pDS->getMultiSamples();//采样缓存
	pTraits->samples = pDS->getNumMultiSamples();
	osgQt::GraphicsWindowQt* pGW = new osgQt::GraphicsWindowQt(pTraits.get());//新建窗口
	if (!pGW)
	{
		return nullptr;
	}
	if (!m_rpViewer)
	{
		return nullptr;
	}
	osg::Camera* pCamera = m_rpViewer->getCamera();
	if (!pCamera)
	{
		return nullptr;
	}
	pCamera->setGraphicsContext(pGW);
	pCamera->setClearColor(osg::Vec4(0.2, 0.2, 0.6, 1.0));
	pCamera->setViewport(new osg::Viewport(0, 0, pTraits->width, pTraits->height));
	//设置远近裁截面
	pCamera->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(pTraits->width) / static_cast<double>(pTraits->height), 1.0f, 10000.0f);
	return pGW->getGLWidget();
}

void CMainWindow::paintEvent(QPaintEvent* event)
{
	m_rpViewer->frame();
}

?mainWindow.h

/**************************************************************************************************
* @file name 文件名:MainWindow.h
* @note 描述:主界面
* @author 作者:z00105
* @data 创建时间:2021 -2 -23
**************************************************************************************************/
#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H
#include <QBoxLayout>
#include <QTimer>
#include <QWidget>
#include <osgViewer/Viewer>
//#include <CommonLib/MainWindow/Export.h>
/**
* @class 类名:CMainWindow
* @brief 简要说明:主窗口显示
* @note详细说明:
* @author 作者:z00105
*/
class CMainWindow : public QWidget
{
public:
	/**
	  * @brief 简要说明:主窗口的初始化
	  * @note 详细说明:
	  * @param parent [in]:父窗口
	  * @param f [in]:窗口属性
	*/
	CMainWindow(QWidget* parent = 0, Qt::WindowFlags f = 0);

	/**
	  * @brief 简要说明:获取视景器
	  * @note 详细说明:
	  * @return m_rpViewer:场景视景器
	*/
	osgViewer::Viewer* getViewer() { return m_rpViewer.get(); }

	/**
	  * @brief 简要说明:获取根节点
	  * @note 详细说明:
	  * @return m_rpRoot:场景根节点
	*/
	osg::Group* getRoot() { return m_rpRoot.get(); }

	/**
	  * @brief 简要说明:获取主窗口垂直布局
	  * @note 详细说明:
	  * @return m_pVLayout:主窗口垂直布局
	*/
	QVBoxLayout* getVLayout() { return m_pVLayout; }

	/**
	  * @brief 简要说明:获取主窗口水平布局
	  * @note 详细说明:
	  * @return m_pVLayout:主窗口水平布局
	*/
	QHBoxLayout* getHLayout() { return m_pHLayout; }

	/**
	  * @brief 简要说明:视口复位
	  * @note 详细说明:三维窗口的视口回到初始设置的位置
	  * @return :
	*/
	void home();

protected:
	/**
	  * @brief 简要说明:三维窗口与qt窗口的结合
	  * @note 详细说明:
	  * @param nX [in]:x位置
	  * @param nY [in]:y位置
	  * @param nW [in]:宽度
	  * @param nH [in]:高度
	  * @param strName [in]:窗口名
	  * @param bWindowDecoration [in]:是否装饰
	  * @return QWidget:三维与qt结合的窗口
	*/
	QWidget* createGraphicsWindow(int nX, int nY, int nW, int nH, const std::string& strName = "", bool bWindowDecoration = false);

	/**
	  * @brief 简要说明:绘制事件
	  * @note 详细说明:qt的窗口绘制事件,用于三维场景的刷新
	  * @param event [in]:绘制事件
	  * @return 返回值以及说明:
	*/
	virtual void paintEvent(QPaintEvent* event);

protected:
	osg::ref_ptr<osgViewer::Viewer>      m_rpViewer;	//视景器
	osg::ref_ptr<osg::Group>             m_rpRoot;		//根节点
	QVBoxLayout*                         m_pVLayout;	//垂直布局
	QHBoxLayout*                         m_pHLayout;	//水平布局
	QTimer                               m_timer;		//定时器
};
#endif MAIN_WINDOW_H

ListWidget.cpp?

#include <QFileDialog>
#include <osg/MatrixTransform>
#include "mainWindow.h"
#include "ModelObject.h"
#include "PropertyWidget.h"
#include "ListWidget.h"

//通过Q_DECLARE_METATYPE声明后,就可以让自定义的类型设置到QVariant
Q_DECLARE_METATYPE(CModelObject*)

CListWidget::CListWidget(CMainWindow* pMainWindow)
	:m_pMainWindow(pMainWindow)
	, m_pListWidget(nullptr)
	, m_pAxesItem(nullptr)
	, m_pCurItem(nullptr)
	, m_pMenu(nullptr)
	, m_pAddAction(nullptr)
	, m_pDelAction(nullptr)
	, m_pClearAction(nullptr)
	, m_pPropertyAction(nullptr)
{
	//创建列表控件
	m_pListWidget = new QListWidget;
	m_pListWidget->setContextMenuPolicy(Qt::CustomContextMenu);//菜单格式
	m_pListWidget->setFixedWidth(120);//固定宽度
	m_pListWidget->setStyleSheet("QListWidget { background-color: rgba(255,255,255,100); font-size:12px; border: 1px solid rgba(249,133,0,255);}");//样式配置
	m_pMainWindow->getHLayout()->insertWidget(0, m_pListWidget);//插入列表到主窗口0位置

	//添加坐标轴到三维场景
	osg::ref_ptr<CModelObject> rpModelObject = new CModelObject("axes.osgt");
	rpModelObject->setMatrix(osg::Matrix::scale(1, 1, 1));
	m_pMainWindow->getRoot()->addChild(rpModelObject.get());

	//添加坐标轴到列表
	m_pAxesItem = new QListWidgetItem(QString::fromLocal8Bit("坐标轴"));//新建列表项
	m_pAxesItem->setCheckState(Qt::Checked);//设置为已选
	m_pAxesItem->setData(Qt::UserRole, QVariant::fromValue(rpModelObject.get()));//设置用户数据绑定到选项
	m_pListWidget->addItem(m_pAxesItem);//添加到列表

	m_pMainWindow->home();//视点重置

	//信号槽连接,属性窗口应用,模型显隐设置
	connect(m_pListWidget, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(slotShowMenu(const QPoint &)));//绑定鼠标点击事件信号槽
	connect(m_pListWidget, SIGNAL(itemClicked(QListWidgetItem *)), this, SLOT(slotVisible(QListWidgetItem *)));//绑定选项勾选状态信号槽

	m_pMenu = new QMenu(m_pListWidget);//新建菜单
	m_pMenu->setStyleSheet("QMenu { background-color: rgba(255,255,255,100); font-size:12px; border:1px solid rgba(249,133,0,255);}");//设置样式表

	m_pAddAction = new QAction(QString::fromLocal8Bit("添加"), m_pMenu);//添加按钮动作
	connect(m_pAddAction, SIGNAL(triggered()), this, SLOT(slotAdd()));//绑定信号槽

	m_pDelAction = new QAction(QString::fromLocal8Bit("删除"), m_pMenu);//添加删除动作
	connect(m_pDelAction, SIGNAL(triggered()), this, SLOT(slotDel()));

	m_pClearAction = new QAction(QString::fromLocal8Bit("清空"), m_pMenu);//添加清空动作
	connect(m_pClearAction, SIGNAL(triggered()), this, SLOT(slotClear()));

	m_pPropertyAction = new QAction(QString::fromLocal8Bit("属性"), m_pMenu);//添加属性动作
	connect(m_pPropertyAction, SIGNAL(triggered()), this, SLOT(slotProperty()));


	m_pMenu->addAction(m_pAddAction);//添加动作
	m_pMenu->addAction(m_pDelAction);
	m_pMenu->addAction(m_pClearAction);
	m_pMenu->addAction(m_pPropertyAction);
}

CListWidget::~CListWidget()
{

}

void CListWidget::slotShowMenu(const QPoint &pos)
{
	m_pCurItem = m_pListWidget->currentItem();
	if (m_pCurItem)//所选位置是列表项
	{
		if (m_pCurItem == m_pAxesItem)//如果是坐标轴,则不显示删除事件
		{
			m_pDelAction->setVisible(false);
		}
		else
		{
			m_pDelAction->setVisible(true);
		}
		m_pAddAction->setVisible(true);
		m_pClearAction->setVisible(true);
		m_pPropertyAction->setVisible(true);
	}
	else
	{
		//添加动作
		m_pAddAction->setVisible(true);
		//删除动作
		m_pDelAction->setVisible(false);
		//清除动作
		m_pClearAction->setVisible(true);
		//属性动作
		m_pPropertyAction->setVisible(false);
	}
	m_pMenu->exec(m_pListWidget->mapToGlobal(pos));//显示菜单到鼠标点击的位置
}

void CListWidget::slotAdd()
{
	QStringList strPathList = QFileDialog::getOpenFileNames(m_pMainWindow, QString::fromLocal8Bit("添加模型"), ".", "*.ive *.osg *.osgt *.3ds");//通过打开资源管理窗口添加模型
	foreach(auto strPath, strPathList)
	{
		addModel(strPath);
	}
}

void CListWidget::addModel(const QString& strPath)
{
	osg::ref_ptr<CModelObject> rpModelObject = new CModelObject(strPath);
	m_pMainWindow->getRoot()->addChild(rpModelObject.get());

	QStringList strList = strPath.split("/");
	if (strList.size() < 2)
	{
		strList = strPath.split("\\");
	}

	QListWidgetItem* m_pItem = new QListWidgetItem(strList.back());
	m_pItem->setCheckState(Qt::Checked);
	m_pItem->setData(Qt::UserRole, QVariant::fromValue(rpModelObject.get()));
	m_pListWidget->addItem(m_pItem);
}

void CListWidget::addModel(const QString& strName, osg::Node* pNode)
{
	if (pNode)
	{
		osg::ref_ptr<CModelObject> rpModelObject = new CModelObject(pNode);
		m_pMainWindow->getRoot()->addChild(rpModelObject.get());

		QListWidgetItem* m_pItem = new QListWidgetItem(strName);
		m_pItem->setCheckState(Qt::Checked);
		m_pItem->setData(Qt::UserRole, QVariant::fromValue(rpModelObject.get()));
		m_pListWidget->addItem(m_pItem);
	}
}

bool CListWidget::changeModelState(bool bState)
{
	int nRow = m_pListWidget->model()->rowCount();
	for (int i = 0; i < nRow; ++i)
	{
		auto pItem = m_pListWidget->item(i);
		if (pItem)
		{
			CModelObject* pModelObject = pItem->data(Qt::UserRole).value<CModelObject*>();
			if (pModelObject)
			{
				if (bState)
				{
					pItem->setCheckState(Qt::CheckState::Checked);
					pModelObject->setNodeMask(0xffffffff);
				}
				else
				{
					pItem->setCheckState(Qt::CheckState::Unchecked);
					pModelObject->setNodeMask(0x00000000);
				}
			}
		}
	}
	return false;
}

void CListWidget::slotDel()
{
	if (m_pCurItem)
	{
		del(m_pListWidget->row(m_pCurItem));
	}
}

void CListWidget::slotClear()
{
	int nRow = m_pListWidget->model()->rowCount();
	for (int i = 1; i < nRow; ++i)
	{
		del(1);
	}
}

void CListWidget::slotProperty()
{
	CModelObject* pModelObject = m_pCurItem->data(Qt::UserRole).value<CModelObject*>();
	if (pModelObject)
	{
		CPropertyWidget* pPropertyWidget = new CPropertyWidget(pModelObject, m_pMainWindow);
		pPropertyWidget->show();
	}
}

void CListWidget::slotVisible(QListWidgetItem * pItem)
{
	if (pItem)
	{
		CModelObject* pModelObject = pItem->data(Qt::UserRole).value<CModelObject*>();
		if (pModelObject)
		{
			if (pItem->checkState() == Qt::Checked)
			{
				pModelObject->setNodeMask(0xffffffff);
			}
			else if (pItem->checkState() == Qt::Unchecked)
			{
				pModelObject->setNodeMask(0x00000000);
			}
		}
	}
}

void CListWidget::del(int nRow)
{
	auto pItem = m_pListWidget->item(nRow);
	if (pItem)
	{
		CModelObject* pModelObject = pItem->data(Qt::UserRole).value<CModelObject*>();
		if (pModelObject)
		{
			m_pMainWindow->getRoot()->removeChild(pModelObject);
		}
		m_pListWidget->takeItem(nRow);
		pItem = nullptr;
	}
}

ListWidget.h?

#ifndef LIST_WIDGET_H
#define LIST_WIDGET_H
#include <osg/Node>
#include <QListWidget>
#include <QListWidgetItem>
#include <QMenu>
#include <QAction>
class CMainWindow;
class CListWidget : public QObject
{
	Q_OBJECT

public:
	/**
	* @class 结构体名:SModelInfo
	* @brief 简要说明:添加模型所需信息
	* @note详细说明:bUseLLH决定是否使用vec3LLH
	* @author 作者:z00105
	*/
	struct SModelInfo
	{
		//初始化数据
		SModelInfo()
		{
			bUseLLH = false;
			vec3Scale = osg::Vec3d(1.0,1.0,1.0);
		}
		bool bUseLLH;			//是否使用经纬高
		osg::Vec3d vec3LLH;		//经纬高
		osg::Vec3d vec3Scale;	//模型缩放比例
		osg::Vec3d vec3Rotate;	//模型姿态
	};

	CListWidget(CMainWindow* pMainWindow);

	~CListWidget();

	/**
	  * @brief 简要说明:添加模型
	  * @note 详细说明:通过路径添加模型
	  * @param strPath [in]:绝对路径或相对data目录的路径
	  * @return :
	*/
	void addModel(const QString& strPat);

	/**
	  * @brief 简要说明:添加模型
	  * @note 详细说明:模型名称和节点指针添加
	  * @param strName [in]:模型名称
	  * @param pNode [in]:模型节点
	  * @return :
	*/
	void addModel(const QString& strName,osg::Node* pNode);
	
	/**
	  * @brief 简要说明:改变模型状态
	  * @note 详细说明:显隐控制
	  * @param bState [in]:模型状态
	  * @return :
	*/
	bool changeModelState(bool bState);
	protected slots:
		/**
		  * @brief 简要说明:显示右键菜单
		  * @note 详细说明:根据位置和选择的对象进行菜单显示
		  * @param pos [in]:位置
		  * @return :
		*/
		void slotShowMenu(const QPoint &pos);
		
		/**
		  * @brief 简要说明:添加选项
		  * @note 详细说明:添加模型节点
		  * @return :
		*/
		void slotAdd();
		
		/**
		  * @brief 简要说明:删除选项
		  * @note 详细说明:删除当前选中的列表项和三维场景中的对应节点
		  * @return :
		*/
		void slotDel();
		
		/**
		  * @brief 简要说明:显示清除菜单
		  * @note 详细说明:
		  * @return :
		*/
		void slotClear();
		
		/**
		  * @brief 简要说明:显示属性菜单
		  * @note 详细说明:
		  * @return :
		*/
		void slotProperty();
		
		/**
		  * @brief 简要说明:设置选项对应控制节点的显隐
		  * @note 详细说明:通过选项控制三维场景节点显隐
		  * @param pItem [in]:列表项
		  * @return :
		*/
		void slotVisible(QListWidgetItem * pItem);
protected:
	void del(int nRow);

protected:
	CMainWindow* m_pMainWindow;//主窗口
	QListWidget* m_pListWidget;//列表控件
	QListWidgetItem* m_pAxesItem;//坐标轴项
	QListWidgetItem* m_pCurItem;//当前项
	QMenu* m_pMenu;//菜单
	QAction* m_pAddAction;//添加动作
	QAction* m_pDelAction;//删除动作
	QAction* m_pClearAction;//清除动作
	QAction* m_pPropertyAction;//属性动作
};
#endif LIST_WIDGET_H

ModelObject.cpp?

#include "ModelObject.h"
CModelObject::CModelObject(const QString& strPath)
{
	osg::ref_ptr<osg::Node> rpNode = readNode(strPath.toStdString());
	this->addChild(rpNode.get());
}

CModelObject::CModelObject( osg::Node* pNode )
{
	this->addChild(pNode);
}

CModelObject::~CModelObject()
{

}

osg::Node* CModelObject::readNode(const std::string& strPath)
{
	osg::ref_ptr<osg::Node> rpNode = osgDB::readNodeFile(strPath);//读取路径所在的模型
	if (rpNode.valid())
	{
		rpNode->getOrCreateStateSet()->setMode(GL_RESCALE_NORMAL, osg::StateAttribute::ON);//重新设置节点规模后,重置法向量
	}
	return rpNode.release();//release()释放超级指针并传出节点指针
}

ModelObject.h

#ifndef MODEL_OBJECT_H
#define MODEL_OBJECT_H
#include <QString>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>

class CModelObject : public osg::MatrixTransform
{
public:
	CModelObject(const QString& strPath);

	CModelObject(osg::Node* pNode);

	~CModelObject();
	/**
	* @brief 简要说明:读取模型
	* @note 详细说明:根据路径,读取模型
	* @param strPath [in]:路径信息,要求绝对路径
	* @return :模型指针
	*/
	osg::Node* readNode(const std::string& strPath);

};
#endif MODEL_OBJECT_H

?PropertyWidget.cpp

#include <QLabel>
#include <QDoubleSpinBox>
#include "ModelObject.h"
#include "PropertyWidget.h"
CPropertyWidget::CPropertyWidget(CModelObject* pModelObject,QWidget* pParent)
	:QWidget(pParent)
	,m_pModelObject(pModelObject)
{
	setWindowFlags(Qt::Dialog);
	setAttribute(Qt::WA_DeleteOnClose);
	QVBoxLayout* pVlayout = new QVBoxLayout;
	this->setLayout(pVlayout);
	osg::Matrix mat = m_pModelObject->getMatrix();

	{
		m_vecPosition = mat.getTrans();
		QHBoxLayout* pHLayout = new QHBoxLayout;
		pVlayout->addLayout(pHLayout);
		QLabel* pLabel = new QLabel(QString::fromLocal8Bit("位移"));
		pLabel->setFixedWidth(30);
		pHLayout->addWidget(pLabel);
		{
			QDoubleSpinBox* pDSBox = new QDoubleSpinBox;
			pDSBox->setRange(-10000,10000);
			pDSBox->setValue(m_vecPosition.x());
			connect(pDSBox,SIGNAL(valueChanged(double)),this,SLOT(slotTX(double)));
			pHLayout->addWidget(pDSBox);
		}
		{
			QDoubleSpinBox* pDSBox = new QDoubleSpinBox;
			pDSBox->setRange(-10000,10000);
			pDSBox->setValue(m_vecPosition.y());
			connect(pDSBox,SIGNAL(valueChanged(double)),this,SLOT(slotTY(double)));
			pHLayout->addWidget(pDSBox);
		}
		{
			QDoubleSpinBox* pDSBox = new QDoubleSpinBox;
			pDSBox->setRange(-10000,10000);
			pDSBox->setValue(m_vecPosition.z());
			connect(pDSBox,SIGNAL(valueChanged(double)),this,SLOT(slotTZ(double)));
			pHLayout->addWidget(pDSBox);
		}
	}
	{
		Quat2DegreesRotate(mat.getRotate(),m_vecRotation);
		QHBoxLayout* pHLayout = new QHBoxLayout;
		pVlayout->addLayout(pHLayout);
		QLabel* pLabel = new QLabel(QString::fromLocal8Bit("旋转"));
		pLabel->setFixedWidth(30);
		pHLayout->addWidget(pLabel);
		{
			QDoubleSpinBox* pDSBox = new QDoubleSpinBox;
			pDSBox->setRange(-360,360);
			pDSBox->setValue(m_vecRotation.x());
			connect(pDSBox,SIGNAL(valueChanged(double)),this,SLOT(slotRX(double)));
			pHLayout->addWidget(pDSBox);
		}
		{
			QDoubleSpinBox* pDSBox = new QDoubleSpinBox;
			pDSBox->setRange(-360,360);
			pDSBox->setValue(m_vecRotation.y());
			connect(pDSBox,SIGNAL(valueChanged(double)),this,SLOT(slotRY(double)));
			pHLayout->addWidget(pDSBox);
		}
		{
			QDoubleSpinBox* pDSBox = new QDoubleSpinBox;
			pDSBox->setRange(-360,360);
			pDSBox->setValue(m_vecRotation.z());
			connect(pDSBox,SIGNAL(valueChanged(double)),this,SLOT(slotRZ(double)));
			pHLayout->addWidget(pDSBox);
		}
	}
	{
		m_vecScale = mat.getScale();
		QHBoxLayout* pHLayout = new QHBoxLayout;
		pVlayout->addLayout(pHLayout);
		QLabel* pLabel = new QLabel(QString::fromLocal8Bit("缩放"));
		pLabel->setFixedWidth(30);
		pHLayout->addWidget(pLabel);
		{
			QDoubleSpinBox* pDSBox = new QDoubleSpinBox;
			pDSBox->setRange(0,10000);
			pDSBox->setValue(m_vecScale.x());
			connect(pDSBox,SIGNAL(valueChanged(double)),this,SLOT(slotSX(double)));
			pHLayout->addWidget(pDSBox);
		}
		{
			QDoubleSpinBox* pDSBox = new QDoubleSpinBox;
			pDSBox->setRange(0,10000);
			pDSBox->setValue(m_vecScale.y());
			connect(pDSBox,SIGNAL(valueChanged(double)),this,SLOT(slotSY(double)));
			pHLayout->addWidget(pDSBox);
		}
		{
			QDoubleSpinBox* pDSBox = new QDoubleSpinBox;
			pDSBox->setRange(0,10000);
			pDSBox->setValue(m_vecScale.z());
			connect(pDSBox,SIGNAL(valueChanged(double)),this,SLOT(slotSZ(double)));
			pHLayout->addWidget(pDSBox);
		}
	}
}

CPropertyWidget::~CPropertyWidget()
{

}

osg::Vec3d CPropertyWidget::DegreesToRadians(const osg::Vec3& vecRotate)
{
	osg::Vec3 vecRotateNew;
	vecRotateNew.x() = osg::DegreesToRadians(vecRotate.x());
	vecRotateNew.y() = osg::DegreesToRadians(vecRotate.y());
	vecRotateNew.z() = osg::DegreesToRadians(vecRotate.z());
	return vecRotateNew;
}

osg::Vec3d CPropertyWidget::RadiansToDegrees(const osg::Vec3& vecRotate)
{
	osg::Vec3 vecRotateNew;
	vecRotateNew.x() = osg::RadiansToDegrees(vecRotate.x());
	vecRotateNew.y() = osg::RadiansToDegrees(vecRotate.y());
	vecRotateNew.z() = osg::RadiansToDegrees(vecRotate.z());
	return vecRotateNew;
}

void CPropertyWidget::Quat2DegreesRotate(const osg::Quat& quat, osg::Vec3& vecRotate)
{
	Quat2RadiansRotate(quat, vecRotate);
	vecRotate = RadiansToDegrees(vecRotate);
}

void CPropertyWidget::Quat2RadiansRotate(const osg::Quat& quat, osg::Vec3& vecRotate)
{
	double q0 = quat.w();
	double q1 = quat.x();
	double q2 = quat.y();
	double q3 = quat.z();

	vecRotate.x() = float(atan2(2 * (q2*q3 + q0 * q1), (q0*q0 - q1 * q1 - q2 * q2 + q3 * q3)));
	vecRotate.y() = float(asin(-2 * (q1*q3 - q0 * q2)));
	vecRotate.z() = float(atan2(2 * (q1*q2 + q0 * q3), (q0*q0 + q1 * q1 - q2 * q2 - q3 * q3)));
}

osg::Matrix CPropertyWidget::DegreesRotate2Matrix(const osg::Vec3d& vecRotate)
{
	return RadiansRotate2Matrix(DegreesToRadians(vecRotate));
}

osg::Matrix CPropertyWidget::RadiansRotate2Matrix(const osg::Vec3d& vecRotate)
{
	return osg::Matrix::rotate(vecRotate.x(), osg::X_AXIS, vecRotate.y(), osg::Y_AXIS, vecRotate.z(), osg::Z_AXIS);
}

void CPropertyWidget::slotTX(double dValue)
{
	m_vecPosition.x() = dValue;
	updateMatrix();
}

void CPropertyWidget::slotTY(double dValue)
{
	m_vecPosition.y() = dValue;
	updateMatrix();
}

void CPropertyWidget::slotTZ(double dValue)
{
	m_vecPosition.z() = dValue;
	updateMatrix();
}

void CPropertyWidget::slotRX( double dValue )
{
	m_vecRotation.x() = dValue;
	updateMatrix();
}

void CPropertyWidget::slotRY( double dValue )
{
	m_vecRotation.y() = dValue;
	updateMatrix();
}

void CPropertyWidget::slotRZ( double dValue )
{
	m_vecRotation.z() = dValue;
	updateMatrix();
}

void CPropertyWidget::slotSX( double dValue )
{
	m_vecScale.x() = dValue;
	updateMatrix();
}

void CPropertyWidget::slotSY( double dValue )
{
	m_vecScale.y() = dValue;
	updateMatrix();
}

void CPropertyWidget::slotSZ( double dValue )
{
	m_vecScale.z() = dValue;
	updateMatrix();
}

void CPropertyWidget::updateMatrix()
{
	m_pModelObject->setMatrix(osg::Matrix::scale(m_vecScale)*DegreesRotate2Matrix(m_vecRotation)*osg::Matrix::translate(m_vecPosition));
}

PropertyWidget.h?

#ifndef PROPERTY_WIDGET_H
#define PROPERTY_WIDGET_H
#include <QWidget>
#include<osg/Node>
#include "MainWindow.h"

class CModelObject;
class CPropertyWidget : public QWidget
{
	Q_OBJECT
public:
	CPropertyWidget(CModelObject* pModelObject,QWidget* pParent);

	~CPropertyWidget();

	/**
	*@note: 度转弧度
	*/
	osg::Vec3d DegreesToRadians(const osg::Vec3& vecRotate);

	/**
	*@note: 弧度转度
	*/
	osg::Vec3d RadiansToDegrees(const osg::Vec3& vecRotate);

	/**
	*@note: 四元数转度欧拉角
	*/
	void Quat2DegreesRotate(const osg::Quat& quat, osg::Vec3& vecRotate);

	/**
	*@note: 四元数转弧度欧拉角
	*/
	void Quat2RadiansRotate(const osg::Quat& quat, osg::Vec3& vecRotate);

	/**
	*@note: 度欧拉角转旋转矩阵
	*/
	osg::Matrix DegreesRotate2Matrix(const osg::Vec3d& vecRotate);

	/**
	*@note: 弧度欧拉角转旋转矩阵
	*/
	osg::Matrix RadiansRotate2Matrix(const osg::Vec3d& vecRotate);

	protected slots:
		void slotTX(double dValue);

		void slotTY(double dValue);

		void slotTZ(double dValue);

		void slotRX(double dValue);

		void slotRY(double dValue);

		void slotRZ(double dValue);

		void slotSX(double dValue);

		void slotSY(double dValue);

		void slotSZ(double dValue);

protected:
	void updateMatrix();

protected:
	CModelObject* m_pModelObject;
	osg::Vec3 m_vecPosition;
	osg::Vec3 m_vecRotation;
	osg::Vec3 m_vecScale;
};
#endif PROPERTY_WIDGET_H

代码下载: 博客资源里面

三、展示

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-01-29 23:17:35  更:2022-01-29 23:18:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 10:08:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码