程序运行效果图:

以上效果图使用Qt原生控件,没有对控件进行QSS设置,下面有源码,你可以在mainwindow.cpp中对控件进行样式设置。
该工程用的是Qt6进行开发 使用C++语言 用CMake进行构建工程。
代码讲解可能不太详细或者有兴趣再加,首先了解Qt3D进行开发时,相关类的作用。该工程为你提供参考示例。
箭头讲解:
箭头源码:
arrowentity.h
cpp
#ifndef ARROWENTITY_H
#define ARROWENTITY_H
#include <QObject>
#include <QWidget>
#include <QDebug>
#include <QTimer>
#include <QColor>
#include <QColorDialog>
#include <Qt3DCore/QEntity>
#include <Qt3DCore/QTransform>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DRender/QCamera>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DExtras/QPlaneMesh>
#include <Qt3DRender/QCamera>
#include <Qt3DRender/QPointLight>
#include <Qt3DRender/QDirectionalLight>
#include <Qt3DExtras/QForwardRenderer>
#include <Qt3DExtras/QCylinderMesh>
#include <Qt3DExtras/QConeMesh>
#include <QVector3D>
struct ArrowSize{
double cyLen_ = 1;
double conLen_ = 1;
double cyR_ = 1;
double conR_ = 1;
public:
ArrowSize()
{
}
ArrowSize(double cyLen,double cyR,double conLen,double conR)
:cyLen_(cyLen),cyR_(cyR),conLen_(conLen),conR_(conR)
{
}
};
class ArrowEntity : public Qt3DCore::QEntity
{
Q_OBJECT
public:
explicit ArrowEntity(Qt3DCore::QEntity* parent = nullptr);
~ArrowEntity(){}
//获取跟实体
Qt3DCore::QEntity* getRootEntity();
//重置视图按钮
void ResetView();
//设置箭头位置函数 ,输入位置QVector3D
void setArrowPosition(QVector3D& pos);
//设置柱体 圆锥 的长度与最大半径 ,输入参数是大于0的double数值
void setArrowLenAndRot(ArrowSize& sz);
//设置圆柱体颜色 位置
void setCylinderColorSelected(QColor& col);
//设置圆锥体颜色 位置
void setConeColorSelected(QColor& col);
//获取圆柱颜色
QColor getCyColor();
//获取圆锥颜色
QColor getConColor();
private:
//禁用拷贝构造 和 赋值重载
ArrowEntity(ArrowEntity& arrow)=delete;
ArrowEntity& operator=(ArrowEntity& arrow)=delete;
//创建 圆柱体 圆锥体实体
void createCylinderAndConeEntity();
//物体自动旋转
void updateRotation();
public slots:
//自动旋转 -- 用定时器控制
void onAutoRotateTimer(const QVector3D &eulerAngles);
//通过滑杆控件 -- 控制物体旋转 x y z 速度
void onXRotationChanged(int angle);
void onYRotationChanged(int angle);
void onZRotationChanged(int angle);
void onRotationSpeedChanged(int speed);
void onXDirect(const QString& x);
void onYDirect(const QString& y);
void onZDirect(const QString& z);
private:
//颜色
QColor cylinderColor; //圆柱体颜色
QColor coneColor; //圆锥体颜色
//长度 半径
ArrowSize entitySz;//该对象可以设置 圆柱圆锥的长度半径
//圆柱体 圆锥体实体 根实体
// Qt3DCore::QEntity *rootEntity; // 根实体
Qt3DCore::QEntity *rootNextEntity; //部分跟实体
Qt3DCore::QEntity *cylinderEntity; // 圆柱体实体
Qt3DCore::QEntity *coneEntity; // 圆锥体实体
//物体旋转 x y z 速度
QVector3D xyzRotation;
int rotationSpeed = 2;
//物体坐标
QVector3D xyzPos = {0,0,0};
//网格
Qt3DExtras::QCylinderMesh* cylinder;
Qt3DExtras::QConeMesh* cone;
//材质 变换
Qt3DCore::QTransform *partTransform; // 模型局部变换--不包含上一层的任何实体
Qt3DCore::QTransform *modelTransform; // 模型整体变换
Qt3DCore::QTransform *cylinderTransform; // 圆柱体变换
Qt3DCore::QTransform *coneTransform; // 圆锥体变换
Qt3DExtras::QPhongMaterial *cylinderMaterial; // 圆柱体材质
Qt3DExtras::QPhongMaterial *coneMaterial; // 圆锥体材质
//自动旋转定时器
QTimer* autoRotateTimer;
};
#endif // ARROWENTITY_H
arrowentity.cpp
cpp
#include "arrowentity.h"
#include <QSize>
#include <QScreen>
ArrowEntity::ArrowEntity(Qt3DCore::QEntity* parent)
:Qt3DCore::QEntity(parent)
,cylinderEntity(nullptr)
,coneEntity(nullptr)
,modelTransform(nullptr)
,cylinderTransform(nullptr)
,coneTransform(nullptr)
,cylinderMaterial(nullptr)
,coneMaterial(nullptr)
{
qDebug()<<"arrowentity";
ArrowSize sz(2.0,0.5,3,1);
entitySz = sz;
createCylinderAndConeEntity();
}
Qt3DCore::QEntity *ArrowEntity::getRootEntity()
{
return this;
}
void ArrowEntity::createCylinderAndConeEntity()
{
//创建模型整体变换
modelTransform = new Qt3DCore::QTransform();
this->addComponent(modelTransform);
//创建光源
// Qt3DRender::QPointLight* light = new Qt3DRender::QPointLight();
Qt3DRender::QDirectionalLight* light = new Qt3DRender::QDirectionalLight();
// light->setIntensity(1.0f);
// light->setColor("white");
light->setColor(QColor(Qt::white));
light->setIntensity(1.0f);
light->setWorldDirection(QVector3D(-1, -1, -1));
Qt3DCore::QTransform* lightTrans = new Qt3DCore::QTransform();
lightTrans->setTranslation(QVector3D(10,10,20));//光源位置
//光实体
Qt3DCore::QEntity* lightEntity = new Qt3DCore::QEntity(this);
lightEntity->addComponent(light);
lightEntity->addComponent(lightTrans);
rootNextEntity = new Qt3DCore::QEntity(this);
partTransform = new Qt3DCore::QTransform();
rootNextEntity->addComponent(partTransform);
//创建圆柱实体
cylinderEntity = new Qt3DCore::QEntity(rootNextEntity);
//创建网格
cylinder = new Qt3DExtras::QCylinderMesh();
// cylinder->setLength(5.0f); //长度
// cylinder->setRadius(0.8f); //半径
cylinder->setLength(entitySz.cyLen_); //长度
cylinder->setRadius(entitySz.cyR_); //半径
cylinder->setRings(100); //环数
cylinder->setSlices(20); //切片数
//创建位置
cylinderTransform = new Qt3DCore::QTransform();
cylinderTransform->setTranslation(QVector3D(0, entitySz.cyLen_/2.0, 0));
//创建材质
cylinderMaterial = new Qt3DExtras::QPhongMaterial();
cylinderMaterial->setDiffuse(QColor(QRgb(0x0055ff)));
cylinderEntity->addComponent(cylinder);
cylinderEntity->addComponent(cylinderTransform);
cylinderEntity->addComponent(cylinderMaterial);
//创建圆锥实体
coneEntity = new Qt3DCore::QEntity(rootNextEntity);
cone = new Qt3DExtras::QConeMesh();
// cone->setRings(8); //半径
// cone->setLength(3.0f); //长度
cone->setBottomRadius(entitySz.conR_); //半径
cone->setLength(entitySz.conLen_); //长度
cone->setSlices(20); //切片
cone->setRings(200); //环数
//位置
coneTransform = new Qt3DCore::QTransform();
coneTransform->setTranslation(QVector3D(0, entitySz.cyLen_ + entitySz.conLen_/2.0, 0));
//创建材质
coneMaterial = new Qt3DExtras::QPhongMaterial();
coneMaterial->setDiffuse(QColor(QRgb(0xff5500)));
coneEntity->addComponent(cone);
coneEntity->addComponent(coneTransform);
coneEntity->addComponent(coneMaterial);
}
void ArrowEntity::updateRotation()
{
// 设置模型的旋转,使用四元数避免万向锁问题
modelTransform->setRotation(QQuaternion::fromEulerAngles(xyzRotation));
}
void ArrowEntity::setCylinderColorSelected(QColor &col)
{
cylinderMaterial->setDiffuse(col);
}
void ArrowEntity::setConeColorSelected(QColor &col)
{
coneMaterial->setDiffuse(col);
}
// void ArrowEntity::onCylinderColorSelected()
// {
// // QWidget* parentWidget = new QWidget(); // 创建临时QWidget
// // QColor color = QColorDialog::getColor(cylinderMaterial->diffuse(), parentWidget, "选择圆柱体颜色");
// // if (color.isValid()) {
// // cylinderMaterial->setDiffuse(color);
// // }
// // delete parentWidget;
// cylinderMaterial->setDiffuse(color);
// }
// void ArrowEntity::onConeColorSelected()
// {
// // QWidget* parentWidget = new QWidget(); // 创建临时QWidget
// // QColor color = QColorDialog::getColor(coneMaterial->diffuse(), parentWidget, "选择圆锥体颜色");
// // if (color.isValid()) {
// // coneMaterial->setDiffuse(color);
// // }
// // delete parentWidget;
// coneMaterial->setDiffuse(color);
// }
void ArrowEntity::onAutoRotateTimer(const QVector3D &eulerAngles)
{
// // 初始化自动旋转定时器
// autoRotateTimer = new QTimer(this);
// connect(autoRotateTimer, &QTimer::timeout, [this]() {
// // 自动旋转逻辑 - 同时绕三个轴旋转,速度由rotationSpeed控制
// xRotation += 0.5f * rotationSpeed;
// yRotation += 0.3f * rotationSpeed;
// zRotation += 0.2f * rotationSpeed;
// // 确保角度在0-360之间
// if (xRotation >= 360) xRotation -= 360;
// if (yRotation >= 360) yRotation -= 360;
// if (zRotation >= 360) zRotation -= 360;
// QVector3D xyzRotation(xRotation,yRotation,zRotation);
// // updateRotation();
// // 更新滑块位置
// QSlider* xSlider = findChild<QSlider*>();
// if (xSlider) xSlider->setValue(static_cast<int>(xRotation));
// });
}
void ArrowEntity::onXRotationChanged(int angle)
{
xyzRotation.setX(angle);
updateRotation();
}
void ArrowEntity::onYRotationChanged(int angle)
{
xyzRotation.setY(angle);
updateRotation();
}
void ArrowEntity::onZRotationChanged(int angle)
{
xyzRotation.setZ(angle);
updateRotation();
}
void ArrowEntity::onRotationSpeedChanged(int speed)
{
rotationSpeed = speed;
}
void ArrowEntity::onXDirect(const QString &x)
{
qDebug()<<"ArrowEntity::onXDirect";
// cylinderTransform->setRotation(QQuaternion::fromEulerAngles(QVector3D(x.toDouble(),1,1)));
// coneTransform->setRotation(QQuaternion::fromEulerAngles(QVector3D(x.toDouble(),1,1)));
partTransform->setRotation(QQuaternion::fromEulerAngles(QVector3D(x.toDouble(),1,1)));
}
void ArrowEntity::onYDirect(const QString &y)
{
partTransform->setRotation(QQuaternion::fromEulerAngles(QVector3D(1,y.toDouble(),1)));
}
void ArrowEntity::onZDirect(const QString &z)
{
partTransform->setRotation(QQuaternion::fromEulerAngles(QVector3D(1,1,z.toDouble())));
}
void ArrowEntity::ResetView()
{
xyzRotation.setX(0);
xyzRotation.setY(0);
xyzRotation.setZ(0);
updateRotation();
}
void ArrowEntity::setArrowPosition(QVector3D &pos)
{
xyzPos = pos;
modelTransform->setTranslation(xyzPos);
}
void ArrowEntity::setArrowLenAndRot(ArrowSize& sz)
{
if(sz.cyLen_>0)
{
entitySz.cyLen_ = sz.cyLen_;
}
if(sz.conLen_>0)
{
entitySz.conLen_ = sz.conLen_;
}
if(sz.cyR_>0)
{
entitySz.cyR_ = sz.cyR_;
}
if(sz.conR_>0)
{
entitySz.conR_ = sz.conR_;
}
if(sz.cyLen_>0||sz.conLen_>0||sz.cyR_>0||sz.conR_>0)
{
// entitySz = sz;
cylinder->setLength(entitySz.cyLen_); //长度
cylinder->setRadius(entitySz.cyR_); //半径
cylinder->setRings(100); // 保持网格精度一致
cylinder->setSlices(20);
// cylinder->setEnabled(false);
// cylinderTransform->setTranslation(QVector3D(0,0,0)+xyzPos);
cylinderTransform->setTranslation(QVector3D(0,entitySz.cyLen_/2.0,0));
cone->setBottomRadius(entitySz.conR_); //半径
cone->setLength(entitySz.conLen_); //长度
cone->setRings(200); // 保持网格精度
cone->setSlices(20);
// qDebug()<<entitySz.cyLen_/2.0 + entitySz.conLen_/2.0;
coneTransform->setTranslation(QVector3D(0,entitySz.cyLen_/*/2.0*/ + entitySz.conLen_/2.0,0));
}
}
QColor ArrowEntity::getCyColor()
{
return cylinderMaterial->diffuse();
}
QColor ArrowEntity::getConColor()
{
return coneMaterial->diffuse();
}
坐标轴讲解:
坐标轴源码:
coordinateaxis.h
cpp
#ifndef COORDINATEAXIS_H
#define COORDINATEAXIS_H
#include <QWidget>
#include <QObject>
#include <Qt3DCore/QEntity>
#include <Qt3DExtras/QCylinderMesh>
#include <Qt3DExtras/QConeMesh>
#include <QColor>
#include <QColorDialog>
#include <QSize>
#include <QVector3D>
#include <QDebug>
struct AxisSize{
double cyLen_ = 1;
double conLen_ = 1;
double cyR_ = 1;
double conR_ = 1;
public:
AxisSize()
{
}
AxisSize(double cyLen,double cyR,double conLen,double conR)
:cyLen_(cyLen),cyR_(cyR),conLen_(conLen),conR_(conR)
{
}
// AxisSize& operator=(AxisSize& axSz)
// {
// if(*this != axSz)
// {
// conLen_ = axSz.conLen_;
// conR_ = axSz.conR_;
// cyLen_ = axSz.cyLen_;
// cyR_ = axSz.cyR_;
// }
// return *this;
// }
// bool operator!=(AxisSize& axSz)
// {
// return *this == axSz;
// }
// bool operator==(AxisSize& axSz)
// {
// if(conLen_ == axSz.conLen_&&conR_ == axSz.conR_&&
// cyLen_ == axSz.cyLen_&&cyR_ == axSz.cyR_)
// return true;
// else
// return false;
// }
};
class CoordinateAxis : public Qt3DCore::QEntity
{
Q_OBJECT
public:
CoordinateAxis(Qt3DCore::QEntity* parent = nullptr)
:Qt3DCore::QEntity(parent)
,m_rootEntity(new Qt3DCore::QEntity(parent))
{
AxisSize ax(7.0,0.05,0.5,0.1);
axSz = ax;
createAxis(7.0f);
}
void createAxis(double length);
Qt3DCore::QEntity* getAxisEntity() const;
private:
Qt3DCore::QEntity* createSingleAxis(double length, const QVector3D& direction,const QColor& color);
private:
Qt3DCore::QEntity* m_rootEntity = nullptr;
double m_axisLength;
AxisSize axSz;
};
#endif // COORDINATEAXIS_H
coordinateaxis.cpp
cpp
#include "coordinateaxis.h"
#include <Qt3DExtras/QCylinderMesh>
#include <Qt3DExtras/QConeMesh>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DCore/QTransform>
void CoordinateAxis::createAxis(double length)
{
m_axisLength = length;
// 创建X轴(红色)
createSingleAxis(length, QVector3D(1, 0, 0), QColor(255, 0, 0));
// 创建Y轴(绿色)
createSingleAxis(length, QVector3D(0, 1, 0), QColor(0, 255, 0));
// 创建Z轴(蓝色)
createSingleAxis(length, QVector3D(0, 0, 1), QColor(0, 0, 255));
}
Qt3DCore::QEntity* CoordinateAxis::getAxisEntity() const
{
return m_rootEntity;
}
Qt3DCore::QEntity* CoordinateAxis::createSingleAxis(double length, const QVector3D& direction, const QColor& color)
{
// 创建轴实体
Qt3DCore::QEntity* axis = new Qt3DCore::QEntity(m_rootEntity);
Qt3DCore::QEntity* axis1 = new Qt3DCore::QEntity(m_rootEntity);
// 创建圆柱(轴主体)
Qt3DExtras::QCylinderMesh* cylinderMesh = new Qt3DExtras::QCylinderMesh(axis);
cylinderMesh->setRadius(axSz.cyR_);
cylinderMesh->setLength(axSz.cyLen_);
cylinderMesh->setSlices(20); // 切片数
cylinderMesh->setRings(200); // 环数
// 计算圆柱变换(位置和旋转)
Qt3DCore::QTransform* cylinderTrans = new Qt3DCore::QTransform(axis);
if (direction == QVector3D(1, 0, 0)) {
// X轴:绕Z轴旋转90°,使圆柱体沿X轴正方向延伸
cylinderTrans->setRotation(QQuaternion::fromEulerAngles(0, 0, -90));
} else if (direction == QVector3D(0, 0, 1)) {
// Z轴:绕X轴旋转90°,使圆柱体沿Z轴延伸
cylinderTrans->setRotation(QQuaternion::fromEulerAngles(90, 0, 0));
}
// Y轴无需旋转(默认沿Y轴延伸)
// 设置平移,使轴从原点开始到length长度
cylinderTrans->setTranslation(direction * (float)(length / 2.0));
// 创建材质
Qt3DExtras::QPhongMaterial* material = new Qt3DExtras::QPhongMaterial(axis1);
material->setDiffuse(color);
// 创建圆锥(轴端点)
Qt3DExtras::QConeMesh* coneMesh = new Qt3DExtras::QConeMesh(axis1);
coneMesh->setBottomRadius(axSz.conR_);
coneMesh->setLength(axSz.conLen_); // 锥体长
coneMesh->setSlices(20);
coneMesh->setRings(200);
// 计算圆锥变换
Qt3DCore::QTransform* coneTrans = new Qt3DCore::QTransform(axis1);
coneTrans->setRotation(cylinderTrans->rotation()); // 与圆柱同方向
// 圆锥位置:轴末端 + 圆锥长度的一半(使圆锥尖端朝外)
// 关键修复:确保方向向量正确指向正方向
coneTrans->setTranslation(direction * (float)length + direction * axSz.conLen_/2.0);
// 添加组件到轴实体(关键修复:使用axis->addComponent)
axis->addComponent(material);
axis->addComponent(cylinderMesh);
axis->addComponent(cylinderTrans);
axis1->addComponent(coneMesh);
axis1->addComponent(material);
axis1->addComponent(coneTrans);
return axis;
}
// Qt3DCore::QEntity* CoordinateAxis::createSingleAxis(double length,const QVector3D& direction,const QColor& color)
// {
// // 创建轴实体
// Qt3DCore::QEntity* axis = new Qt3DCore::QEntity(m_rootEntity);
// // 创建圆柱(轴主体)
// Qt3DExtras::QCylinderMesh* cylinderMesh = new Qt3DExtras::QCylinderMesh(axis);
// cylinderMesh->setRadius(0.05f);
// cylinderMesh->setLength(length);
// cylinderMesh->setSlices(20); //切片
// cylinderMesh->setRings(200); //环数
// // 计算圆柱变换(位置和旋转)
// Qt3DCore::QTransform* cylinderTrans = new Qt3DCore::QTransform(m_rootEntity);
// if (direction == QVector3D(1, 0, 0)) {
// // 修改前(错误):QQuaternion::fromEulerAngles(0, 180, 90)
// // 修改后(正确):仅绕Z轴旋转90°,使圆柱体沿X轴延伸
// cylinderTrans->setRotation(QQuaternion::fromEulerAngles(0, 0, 90));
// } else if (direction == QVector3D(0, 0, 1)) {
// // 保持正确:绕X轴旋转90°,使圆柱体沿Z轴延伸
// cylinderTrans->setRotation(QQuaternion::fromEulerAngles(90, 0, 0));
// }
// // Y轴无需旋转(默认沿Y轴延伸),保持原逻辑
// // 设置平移,使轴从原点开始
// cylinderTrans->setTranslation(direction * (float)(length / 2.0));
// // 创建材质
// Qt3DExtras::QPhongMaterial* material = new Qt3DExtras::QPhongMaterial(m_rootEntity);
// material->setDiffuse(color);
// // 创建圆锥(轴端点)
// Qt3DExtras::QConeMesh* coneMesh = new Qt3DExtras::QConeMesh();
// coneMesh->setBottomRadius(0.3f);
// coneMesh->setLength(1.0f); // 锥体长
// coneMesh->setSlices(20); //切片
// coneMesh->setRings(200); //环数
// // 计算圆锥变换
// Qt3DCore::QTransform* coneTrans = new Qt3DCore::QTransform();
// coneTrans->setRotation(cylinderTrans->rotation()); // 与圆柱同方向
// // 圆锥位置:轴末端 + 圆锥长度的一半(使圆锥尖端朝外)
// coneTrans->setTranslation(direction * (float)(length) + direction * 0.5f);
// // 添加组件到轴实体
// addComponent(material);
// addComponent(cylinderMesh);
// addComponent(cylinderTrans);
// // axis->addComponent(coneMesh);
// // axis->addComponent(material);
// // axis->addComponent(coneTrans);
// return axis;
// }
实体管理类讲解:
实体管理类源码:
totalentity.h
cpp
#ifndef TOTALENTITY_H
#define TOTALENTITY_H
#include <QWidget>
#include <QObject>
#include <QVector>
#include <QSize>
#include <Qt3DCore/QEntity>
#include <Qt3DRender/QCamera>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DExtras/Qt3DWindow>
#include <QScreen>
#include <Qt3DExtras/QForwardRenderer>
class TotalEntity
{
public:
TotalEntity();
//创建场景
void create3DScene();
//创建摄像机
void createCamera();
//获取3D场景控件
QWidget* get3DViewWidget();
//获取对象实体类型
template<class T>
T* getEntityObject()
{
for (auto& entity : allEntity) {
// 直接转换 "基类指针 entity(QEntity*)" 为 "派生类指针 T*(如 ArrowEntity*)"
T* derivedEntity = dynamic_cast<T*>(entity);
if (derivedEntity != nullptr) {
return derivedEntity;
}
}
return nullptr;
}
private:
//存储所有需要展示的对象实体
QVector<Qt3DCore::QEntity*> allEntity;
Qt3DCore::QEntity* m_rootEntity = nullptr;//祖宗跟实体
Qt3DCore::QEntity* m_currentEntity = nullptr;//当前跟实体
//窗口
Qt3DExtras::Qt3DWindow *view = nullptr; // 主3D视图
Qt3DExtras::Qt3DWindow *previewView = nullptr; // 预览3D视图
//相机
Qt3DRender::QCamera* camera = nullptr;
Qt3DExtras::QOrbitCameraController *cameraController = nullptr; // 相机控制器
//3D视图显示控件
QWidget* Widget3D = nullptr;
};
#endif // TOTALENTITY_H
totalentity.cpp
cpp
#include "totalentity.h"
#include "arrowentity.h"
#include "coordinateaxis.h"
TotalEntity::TotalEntity()
:m_rootEntity(new Qt3DCore::QEntity())
{
create3DScene();
createCamera();
ArrowEntity* arrow = new ArrowEntity(m_rootEntity);
// ArrowSize sz = {1,1,3,3};
// arrow->setArrowLenAndRot(sz);
CoordinateAxis* axis = new CoordinateAxis();
axis->getAxisEntity()->setParent(arrow->getRootEntity());
CoordinateAxis* axis1 = new CoordinateAxis();
axis1->getAxisEntity()->setParent(m_rootEntity);
// axis->setEnabled(false);
// QVector3D pos(-2,-2,3);
// arrow->setArrowPosition(pos);
allEntity.append(arrow);
allEntity.append(axis);
}
void TotalEntity::create3DScene()
{
if(view==nullptr)
{
//创建3D视图
view = new Qt3DExtras::Qt3DWindow();
view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f)));
//创建容纳3D视图的widget
Widget3D = QWidget::createWindowContainer(view);
QSize screen = view->screen()->size();
view->setMinimumSize(QSize(400,300));
view->setMaximumSize(screen);
//将跟实体设置到场景
view->setRootEntity(m_rootEntity);
}
}
void TotalEntity::createCamera()
{
if(view!=nullptr)
{
//设置相机
camera = view->camera();
camera->lens()->setPerspectiveProjection(45.0f,16.0f/9.0f,1.0f,1000.0f);
camera->setPosition(QVector3D(0,0,20));
camera->setViewCenter(QVector3D(3,3,3));
// 相机控制器 - 支持鼠标拖拽旋转、滚轮缩放
cameraController = new Qt3DExtras::QOrbitCameraController(m_rootEntity);
cameraController->setCamera(camera);
cameraController->setLinearSpeed(50.0f); // 平移速度
cameraController->setLookSpeed(180.0f); // 旋转速度
//创建光源
// Qt3DRender::QPointLight* light = new Qt3DRender::QPointLight();
Qt3DRender::QDirectionalLight* light = new Qt3DRender::QDirectionalLight();
// light->setIntensity(1.0f);
// light->setColor("white");
light->setColor(QColor(Qt::white));
light->setIntensity(1.0f);
light->setWorldDirection(QVector3D(-5, 1, 1));
Qt3DCore::QTransform* lightTrans = new Qt3DCore::QTransform();
lightTrans->setTranslation(QVector3D(10,10,20));//光源位置
//光实体
Qt3DCore::QEntity* lightEntity = new Qt3DCore::QEntity();
lightEntity->addComponent(light);
lightEntity->addComponent(lightTrans);
lightEntity->setParent(camera);
}
else
{
qDebug()<<"view is nullptr,cannot create camera.";
}
}
QWidget* TotalEntity::get3DViewWidget()
{
return Widget3D?Widget3D:nullptr; //感觉多次一举 在调用的地方判断不就可以了
}
界面控件设置类:
界面控件设置类源码:
mainwindow.h
cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QString>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QLayout>
#include <QPushButton>
#include <QCheckBox>
#include <QSlider>
#include <QLabel>
#include <QTimer>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QLineEdit>
#include "totalentity.h"
#include "arrowentity.h"
class ArrowEntity;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
//创建控制面板
void createControlWidget();
//对所有控件进行信号和槽的绑定
void allSignalBindSlot();
public slots:
//重置视图
void onResetView();
//是否自动旋转
void onToggleAutoRotation(bool checked);
//输入框
void on_XSpinBox(int x);
void on_YSpinBox(int y);
void on_ZSpinBox(int z);
void on_speedSpinBox(int speed);
void on_XLineEdit(const QString& x);
void on_YLineEdit(const QString& y);
void on_ZLineEdit(const QString& z);
void on_SpeedLineEdit(const QString& speed);
//实体信息槽函数
void on_xEdit(const QString& x);
void on_yEdit(const QString& y);
void on_zEdit(const QString& z);
void on_cyEdit(const QString& cyLen);
void on_cyREdit(const QString& cyR);
void on_conEdit(const QString& conLen);
void on_conREdit(const QString& conR);
void onCylinderColorSelected();
void onConeColorSelected();
void onSetEntityVisible(int flag);
private:
//需要嵌入到 view的QWidget控件
QWidget* widget3DView = nullptr;
TotalEntity* rootEntity = nullptr;
//滑杆控件
QSlider *xRotSlider = nullptr;
QSlider *yRotSlider = nullptr;
QSlider *zRotSlider = nullptr;
QSlider *speedSlider = nullptr;
//输入框
QLineEdit* xSpinBox = nullptr;
QLineEdit* ySpinBox = nullptr;
QLineEdit* zSpinBox = nullptr;
QLineEdit* speedSpinBox = nullptr;
//属性半径 信息
QLineEdit* xEdit = nullptr;
QLineEdit* yEdit = nullptr;
QLineEdit* zEdit = nullptr;
QLineEdit* cyEdit = nullptr;
QLineEdit* cyREdit = nullptr;
QLineEdit* conEdit = nullptr;
QLineEdit* conREdit = nullptr;
QLineEdit* xArrDirEdit = nullptr;
QLineEdit* yArrDirEdit = nullptr;
QLineEdit* zArrDirEdit = nullptr;
QVector3D entityPos;
ArrowSize att;
//单选框
// QCheckBox *autoRotateCheckBox = nullptr;//有点多余
QCheckBox *coordModeCheckBox = nullptr;
//颜色选择按钮
QPushButton *cylinderColorBtn = nullptr;
QPushButton *coneColorBtn = nullptr;
QPushButton *resetBtn = nullptr;
//定时器
QTimer* autoRotateTimer = nullptr;
};
#endif // MAINWINDOW_H
mainwindow..cpp
cpp
#include "mainwindow.h"
#include "arrowentity.h"
#include "coordinateaxis.h"
class ArrowEntity;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
,rootEntity(new TotalEntity())
{
widget3DView = rootEntity->get3DViewWidget();
createControlWidget();
allSignalBindSlot();
}
MainWindow::~MainWindow() {}
void MainWindow::createControlWidget()
{
// 创建控制面板
QWidget *controlPanel = new QWidget();
QVBoxLayout *controlLayout = new QVBoxLayout(controlPanel);
// 添加标题
QLabel *titleLabel = new QLabel("<h3>模型控制器</h3>");
controlLayout->addWidget(titleLabel);
// 旋转控制 - X轴
QHBoxLayout *xRotLayout = new QHBoxLayout();
xRotLayout->addWidget(new QLabel("X轴旋转:"));
xRotSlider = new QSlider(Qt::Horizontal);
xRotSlider->setRange(0, 360);
xRotSlider->setValue(0);
xRotLayout->addWidget(xRotSlider);
// xSpinBox = new QDoubleSpinBox();
// xSpinBox->setMaximum(360);
// xSpinBox->setMinimum(0);
xSpinBox = new QLineEdit();
// 创建整数验证器,设置范围0-360
QIntValidator *xvalidator = new QIntValidator(0, 360, xSpinBox);
// 设置验证器到QLineEdit
xSpinBox->setValidator(xvalidator);
// 可选:设置输入提示
xSpinBox->setPlaceholderText("0-360整数");
xRotLayout->addWidget(xSpinBox);
controlLayout->addLayout(xRotLayout);
// 旋转控制 - Y轴
QHBoxLayout *yRotLayout = new QHBoxLayout();
yRotLayout->addWidget(new QLabel("Y轴旋转:"));
yRotSlider = new QSlider(Qt::Horizontal);
yRotSlider->setRange(0, 360);
yRotSlider->setValue(0);
yRotLayout->addWidget(yRotSlider);
ySpinBox = new QLineEdit();
// 创建整数验证器,设置范围0-360
QIntValidator *yvalidator = new QIntValidator(0, 360, ySpinBox);
// 设置验证器到QLineEdit
ySpinBox->setValidator(yvalidator);
// 可选:设置输入提示
ySpinBox->setPlaceholderText("0-360整数");
yRotLayout->addWidget(ySpinBox);
controlLayout->addLayout(yRotLayout);
// 旋转控制 - Z轴
QHBoxLayout *zRotLayout = new QHBoxLayout();
zRotLayout->addWidget(new QLabel("Z轴旋转:"));
zRotSlider = new QSlider(Qt::Horizontal);
zRotSlider->setRange(0, 360);
zRotSlider->setValue(0);
zRotLayout->addWidget(zRotSlider);
zSpinBox = new QLineEdit();
// 创建整数验证器,设置范围0-360
QIntValidator *zvalidator = new QIntValidator(0, 360, zSpinBox);
// 设置验证器到QLineEdit
zSpinBox->setValidator(zvalidator);
// 可选:设置输入提示
zSpinBox->setPlaceholderText("0-360整数");
zRotLayout->addWidget(zSpinBox);
controlLayout->addLayout(zRotLayout);
// // 旋转速度控制
// QHBoxLayout *speedLayout = new QHBoxLayout();
// speedLayout->addWidget(new QLabel("旋转速度:"));
// speedSlider = new QSlider(Qt::Horizontal);
// speedSlider->setRange(1, 10);
// speedSlider->setValue(2);
// speedLayout->addWidget(speedSlider);
// speedSpinBox = new QLineEdit();
// 创建整数验证器,设置范围0-360
// QIntValidator *speedvalidator = new QIntValidator(0, 360, speedSpinBox);
// // 设置验证器到QLineEdit
// speedSpinBox->setValidator(speedvalidator);
// // 可选:设置输入提示
// speedSpinBox->setPlaceholderText("1-10整数");
// speedLayout->addWidget(speedSpinBox);
// controlLayout->addLayout(speedLayout);
//设置实体的空间坐标系
QWidget* posWidget = new QWidget(this);
QGridLayout* posLayout = new QGridLayout(posWidget);
QLabel* xlabel = new QLabel("X坐标:",this);
xEdit = new QLineEdit(this);
xEdit->setPlaceholderText("请输入数值");
QLabel* ylabel = new QLabel("Y坐标:",this);
yEdit = new QLineEdit(this);
yEdit->setPlaceholderText("请输入数值");
QLabel* zlabel = new QLabel("Z坐标:",this);
zEdit = new QLineEdit(this);
zEdit->setPlaceholderText("请输入数值");
posLayout->addWidget(xlabel,0,0);
posLayout->addWidget(xEdit,0,1);
posLayout->addWidget(ylabel,1,0);
posLayout->addWidget(yEdit,1,1);
posLayout->addWidget(zlabel,2,0);
posLayout->addWidget(zEdit,2,1);
controlLayout->addWidget(posWidget);
//设置圆柱 圆锥 长 半径
QWidget* entityAttribute = new QWidget(this);
QGridLayout* attLayout = new QGridLayout(entityAttribute);
QLabel* cylabel = new QLabel("圆柱长度:",this);
cyEdit = new QLineEdit(this);
cyEdit->setPlaceholderText("请输入长度");
QLabel* cyRlabel = new QLabel("圆柱半径:",this);
cyREdit = new QLineEdit(this);
cyREdit->setPlaceholderText("请输入半径");
QLabel* conlabel = new QLabel("圆锥长度:",this);
conEdit = new QLineEdit(this);
conEdit->setPlaceholderText("请输入长度");
QLabel* conRlabel = new QLabel("圆锥半径:",this);
conREdit = new QLineEdit(this);
conREdit->setPlaceholderText("请输入半径");
attLayout->addWidget(cylabel,0,0);
attLayout->addWidget(cyEdit,0,1);
attLayout->addWidget(cyRlabel,0,2);
attLayout->addWidget(cyREdit,0,3);
attLayout->addWidget(conlabel,1,0);
attLayout->addWidget(conEdit,1,1);
attLayout->addWidget(conRlabel,1,2);
attLayout->addWidget(conREdit,1,3);
controlLayout->addWidget(entityAttribute);
//设置箭头的朝向
QWidget* arrowDirect = new QWidget(this);
QGridLayout* arrowDirectLayout = new QGridLayout(arrowDirect);
QLabel* xArrDirlabel = new QLabel("箭头X轴方向:",this);
xArrDirEdit = new QLineEdit(this);
xArrDirEdit->setPlaceholderText("请输入X长度");
QLabel* yArrDirlabel = new QLabel("箭头Y轴方向:",this);
yArrDirEdit = new QLineEdit(this);
yArrDirEdit->setPlaceholderText("请输入Y长度");
QLabel* zArrDirlabel = new QLabel("箭头Z轴方向:",this);
zArrDirEdit = new QLineEdit(this);
zArrDirEdit->setPlaceholderText("请输入Z长度");
arrowDirectLayout->addWidget(xArrDirlabel,0,0);
arrowDirectLayout->addWidget(xArrDirEdit,0,1);
arrowDirectLayout->addWidget(yArrDirlabel,1,0);
arrowDirectLayout->addWidget(yArrDirEdit,1,1);
arrowDirectLayout->addWidget(zArrDirlabel,2,0);
arrowDirectLayout->addWidget(zArrDirEdit,2,1);
controlLayout->addWidget(arrowDirect);
// // 自动旋转复选框
// autoRotateCheckBox = new QCheckBox("自动旋转");
// controlLayout->addWidget(autoRotateCheckBox);
// 坐标系模式切换
coordModeCheckBox = new QCheckBox("只显示坐标系");
controlLayout->addWidget(coordModeCheckBox);
// 颜色选择按钮 - 圆柱体
cylinderColorBtn = new QPushButton("选择圆柱体颜色");
controlLayout->addWidget(cylinderColorBtn);
// 颜色选择按钮 - 圆锥体
coneColorBtn = new QPushButton("选择圆锥体颜色");
controlLayout->addWidget(coneColorBtn);
// 重置按钮
resetBtn = new QPushButton("重置视图");
controlLayout->addWidget(resetBtn);
// 添加伸缩项,使控件靠上显示
controlLayout->addStretch();
// 主布局 - 包含预览窗口
QWidget *mainContainer = new QWidget();
QVBoxLayout *mainContainerLayout = new QVBoxLayout(mainContainer);
// // 预览窗口容器
// QWidget *previewContainer = QWidget::createWindowContainer(previewView);
// previewContainer->setFixedSize(200, 200); // 预览窗口大小
//顶部布局 - 主视图和预览窗口
QHBoxLayout *topLayout = new QHBoxLayout();
topLayout->addWidget(widget3DView, 1);
// // 预览窗口放在右上角
// QVBoxLayout *previewLayout = new QVBoxLayout();
// previewLayout->addStretch();
// previewLayout->addWidget(previewContainer, 0, Qt::AlignRight);
// topLayout->addLayout(previewLayout);
mainContainerLayout->addLayout(topLayout);
// 主布局
QHBoxLayout *mainLayout = new QHBoxLayout();
mainLayout->addWidget(controlPanel, 3); // 控制面板占30%宽度
mainLayout->addWidget(mainContainer, 7); // 3D视图占70%宽度
// 主窗口设置
QWidget *mainWidget = new QWidget();
mainWidget->setLayout(mainLayout);
setCentralWidget(mainWidget);
setWindowTitle("Qt3D 坐标系演示");
resize(1200, 800);
}
void MainWindow::allSignalBindSlot()
{
//创建定时器
autoRotateTimer = new QTimer();
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow!=nullptr)
{
// 连接信号槽
connect(xRotSlider, &QSlider::valueChanged, arrow, &ArrowEntity::onXRotationChanged);
connect(yRotSlider, &QSlider::valueChanged, arrow, &ArrowEntity::onYRotationChanged);
connect(zRotSlider, &QSlider::valueChanged, arrow, &ArrowEntity::onZRotationChanged);
// connect(speedSlider, &QSlider::valueChanged, arrow, &ArrowEntity::onRotationSpeedChanged);
connect(cylinderColorBtn, &QPushButton::clicked, this, &MainWindow::onCylinderColorSelected);
connect(coneColorBtn, &QPushButton::clicked, this, &MainWindow::onConeColorSelected);
connect(xArrDirEdit, &QLineEdit::textEdited, arrow, &ArrowEntity::onXDirect);
connect(yArrDirEdit, &QLineEdit::textEdited, arrow, &ArrowEntity::onYDirect);
connect(zArrDirEdit, &QLineEdit::textEdited, arrow, &ArrowEntity::onZDirect);
connect(coordModeCheckBox, &QCheckBox::stateChanged, this, &MainWindow::onSetEntityVisible);
}
// connect(autoRotateCheckBox, &QCheckBox::toggled, this, &MainWindow::onToggleAutoRotation);
connect(resetBtn, &QPushButton::clicked, this, &MainWindow::onResetView);
//实体坐标 圆柱 圆锥半径 长度
connect(xEdit,&QLineEdit::textEdited,this,&MainWindow::on_xEdit);
connect(zEdit,&QLineEdit::textEdited,this,&MainWindow::on_yEdit);
connect(yEdit,&QLineEdit::textEdited,this,&MainWindow::on_zEdit);
connect(cyEdit,&QLineEdit::textEdited,this,&MainWindow::on_cyEdit);
connect(cyREdit,&QLineEdit::textEdited,this,&MainWindow::on_cyREdit);
connect(conEdit,&QLineEdit::textEdited,this,&MainWindow::on_conEdit);
connect(conREdit,&QLineEdit::textEdited,this,&MainWindow::on_conREdit);
//输入框
connect(xSpinBox,&QLineEdit::textEdited,this,&MainWindow::on_XLineEdit);
connect(ySpinBox,&QLineEdit::textEdited,this,&MainWindow::on_YLineEdit);
connect(zSpinBox,&QLineEdit::textEdited,this,&MainWindow::on_ZLineEdit);
// connect(speedSpinBox,&QLineEdit::textEdited,this,&MainWindow::on_SpeedLineEdit);
connect(xRotSlider, &QSlider::valueChanged, this,&MainWindow::on_XSpinBox);
connect(yRotSlider, &QSlider::valueChanged, this,&MainWindow::on_YSpinBox);
connect(zRotSlider, &QSlider::valueChanged, this,&MainWindow::on_ZSpinBox);
// connect(speedSlider, &QSlider::valueChanged, this,&MainWindow::on_speedSpinBox);
}
void MainWindow::onResetView()
{
// 重置滑块
QList<QSlider*> sliders = findChildren<QSlider*>();
for (int i = 0; i < sliders.size() && i < 3; ++i) {
sliders[i]->setValue(0);
}
// 停止自动旋转
autoRotateTimer->stop();
QCheckBox* autoRotateCheckBox = findChild<QCheckBox*>();
if (autoRotateCheckBox) {
autoRotateCheckBox->setChecked(false);
}
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow==nullptr)
{
qDebug()<<"MainWindow::allSignalBindSlot:get class Failed.";
return ;
}
arrow->ResetView();
}
void MainWindow::onToggleAutoRotation(bool checked)
{
if (checked) {
autoRotateTimer->start(50); // 每50毫秒更新一次
} else {
autoRotateTimer->stop();
}
}
void MainWindow::on_XSpinBox(int x)
{
if(sender()==xRotSlider)
xSpinBox->setText(QString::number(x, 10));
else if(sender()==xSpinBox)
xRotSlider->setValue(x);
}
void MainWindow::on_YSpinBox(int y)
{
if(sender()==yRotSlider)
ySpinBox->setText(QString::number(y, 10));
else if(sender()==ySpinBox)
yRotSlider->setValue(y);
}
void MainWindow::on_ZSpinBox(int z)
{
if(sender()==zRotSlider)
zSpinBox->setText(QString::number(z, 10));
else if(sender()==zSpinBox)
zRotSlider->setValue(z);
}
void MainWindow::on_speedSpinBox(int speed)
{
if(sender()==speedSlider)
speedSpinBox->setText(QString::number(speed, 10));
else if(sender()==speedSpinBox)
speedSlider->setValue(speed);
}
void MainWindow::on_XLineEdit(const QString &x)
{
xRotSlider->setValue(x.toInt());
}
void MainWindow::on_YLineEdit(const QString &y)
{
yRotSlider->setValue(y.toInt());
}
void MainWindow::on_ZLineEdit(const QString &z)
{
zRotSlider->setValue(z.toInt());
}
void MainWindow::on_SpeedLineEdit(const QString &speed)
{
speedSlider->setValue(speed.toInt());
}
void MainWindow::on_xEdit(const QString &x)
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow==nullptr)
{
qDebug()<<"MainWindow::allSignalBindSlot:get class Failed.";
return ;
}
entityPos.setX(x.toDouble());
arrow->setArrowPosition(entityPos);
}
void MainWindow::on_yEdit(const QString &y)
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow==nullptr)
{
qDebug()<<"MainWindow::allSignalBindSlot:get class Failed.";
return ;
}
entityPos.setY(y.toDouble());
arrow->setArrowPosition(entityPos);
}
void MainWindow::on_zEdit(const QString &z)
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow==nullptr)
{
qDebug()<<"MainWindow::allSignalBindSlot:get class Failed.";
return ;
}
entityPos.setZ(z.toDouble());
arrow->setArrowPosition(entityPos);
}
void MainWindow::on_cyEdit(const QString &cyLen)
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow==nullptr)
{
qDebug()<<"MainWindow::allSignalBindSlot:get class Failed.";
// return ;
}
att.cyLen_ = cyLen.toDouble();
arrow->setArrowLenAndRot(att);
}
void MainWindow::on_cyREdit(const QString &cyR)
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow==nullptr)
{
qDebug()<<"MainWindow::allSignalBindSlot:get class Failed.";
return ;
}
att.cyR_ = cyR.toDouble();
arrow->setArrowLenAndRot(att);
}
void MainWindow::on_conEdit(const QString &conLen)
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow==nullptr)
{
qDebug()<<"MainWindow::allSignalBindSlot:get class Failed.";
return ;
}
att.conLen_ = conLen.toDouble();
arrow->setArrowLenAndRot(att);
}
void MainWindow::on_conREdit(const QString &conR)
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow==nullptr)
{
qDebug()<<"MainWindow::allSignalBindSlot:get class Failed.";
return ;
}
att.conR_ = conR.toDouble();
arrow->setArrowLenAndRot(att);
}
void MainWindow::onCylinderColorSelected()
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow!=nullptr)
{
QColor color = QColorDialog::getColor(arrow->getCyColor(), this, "选择圆柱体颜色");
if (color.isValid()) {
arrow->setCylinderColorSelected(color);
}
}
}
void MainWindow::onConeColorSelected()
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow!=nullptr)
{
QColor color = QColorDialog::getColor(arrow->getCyColor(), this, "选择圆锥体颜色");
if (color.isValid()) {
arrow->setConeColorSelected(color);
}
}
}
void MainWindow::onSetEntityVisible(int flag)
{
if(Qt::Unchecked == flag)
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow!=nullptr)
{
arrow->setEnabled(true);
}
}
else if(Qt::Checked == flag)
{
ArrowEntity* arrow = rootEntity->getEntityObject<ArrowEntity>();
if(arrow!=nullptr)
{
arrow->setEnabled(false);
}
}
}
工程MakeList.txt
cpp
cmake_minimum_required(VERSION 3.19)
project(3DModelArrow LANGUAGES CXX)
find_package(Qt6 6.5 REQUIRED COMPONENTS Core Widgets
3DCore
3DRender
3DExtras
3DInput)
qt_standard_project_setup()
qt_add_executable(3DModelArrow
WIN32 MACOSX_BUNDLE
main.cpp
mainwindow.cpp
mainwindow.h
arrowentity.h arrowentity.cpp
coordinateaxis.h coordinateaxis.cpp
totalentity.h totalentity.cpp
)
target_link_libraries(3DModelArrow
PRIVATE
Qt::Core
Qt::Widgets
Qt6::3DCore
Qt6::3DRender
Qt6::3DExtras
Qt6::3DInput
)
include(GNUInstallDirs)
install(TARGETS 3DModelArrow
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
qt_generate_deploy_app_script(
TARGET 3DModelArrow
OUTPUT_SCRIPT deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})