1. 前言
这段时间有一个大概类似数字孪生的任务,大概就是一个同事负责采集数据,我负责3d模型的显示,当然刚入职的我自然是什么都不会的。随后,问了下前辈,结果他推荐的方式是qt+opengl,那我岂不是更不会了。考虑到交付时间比较紧,就打算用qt3d来实现,结果相关方面度娘的资料也很少。最后写的不算完善吧,但是功能大概能用了。就打算记录一下,给后来的人留点东西。
2.基础概念
首先需要知道的一点小知识,
1.坐标轴
qt3d的坐标轴,z轴从屏幕穿出指向用户,x轴平行与屏幕指向右手边方向,y轴平行于屏幕指向头顶方向。
2. 模型运动
模型运动可拆解为:“缩放,平移,旋转”这三种。在代码中缩放与平移这两个一般比较好搞,主要是模型旋转这块。
旋转这边推荐去看四元数,或许有感觉对实际编写有点用?
演示视频
3.代码
//1.模型头文件
#pragma once
#include <QObject>
#include <qwidget.h>
#include <QtWidgets>
#include <QtGui>
#include <QGuiApplication>
#include <Qt3DCore>
#include <Qt3DExtras>
#include <Qt3DInput>
#include <Qt3DRender>
class MyWidget : public QWidget
{
Q_OBJECT
public slots:
void GetXDataAndYData(float x, float y);
public:
MyWidget(QWidget *parent = nullptr);
~MyWidget();
private:
Qt3DExtras::Qt3DWindow* p_window_view_;
QWidget* p_widget_container_;
QSize screen_size_;
Qt3DCore::QEntity* p_entity_root_;
Qt3DRender::QCamera* p_camera_;
Qt3DCore::QEntity* p_entity_light_;
Qt3DRender::QPointLight* p_point_light_;
Qt3DCore::QTransform* p_transform_light_;
Qt3DCore::QEntity* p_entity_airplane_;
Qt3DCore::QEntity* p_entity_lampstand_;
Qt3DRender::QMesh* p_mesh_;
Qt3DRender::QMesh* p_mesh_one_;
Qt3DExtras::QPhongMaterial* p_material_;
Qt3DExtras::QFirstPersonCameraController* p_camera_controller_;
Qt3DCore::QTransform* p_transform_mesh_;
Qt3DCore::QTransform* p_transform_airplane_;
QPropertyAnimation* p_animation_;
QVector3D now_loaction_,next_loaction_;
QVBoxLayout* p_layout_;
};
//模型实现
#include "mywidget.h"
MyWidget::MyWidget(QWidget *parent): QWidget(parent)
{
p_window_view_ = new Qt3DExtras::Qt3DWindow();
p_window_view_->defaultFrameGraph()->setClearColor(Qt::white);
p_widget_container_ = QWidget::createWindowContainer(p_window_view_);
screen_size_ = p_window_view_->screen()->size();
p_widget_container_->setMaximumSize(screen_size_);
p_widget_container_->setMinimumSize(QSize(200, 100));
p_entity_root_ = new Qt3DCore::QEntity();
p_camera_ = p_window_view_->camera();
p_camera_->lens()->setPerspectiveProjection(45.0, 16.0 / 9.0, 0.1, 1000.0);
p_camera_->setPosition(QVector3D(0, 0, 10));
p_camera_->setUpVector(QVector3D(0, 1, 0));
p_camera_->setViewCenter(QVector3D(0, 0, 0));
p_entity_light_ = new Qt3DCore::QEntity(p_entity_root_);
p_point_light_ = new Qt3DRender::QPointLight(p_entity_light_);
p_point_light_->setColor(Qt::white);
p_point_light_->setIntensity(0.8);
p_entity_light_->addComponent(p_point_light_);
p_transform_light_ = new Qt3DCore::QTransform(p_entity_root_);
p_transform_light_->setTranslation(p_camera_->position());
p_entity_light_->addComponent(p_transform_light_);
p_entity_airplane_ = new Qt3DCore::QEntity(p_entity_root_);
p_mesh_ = new Qt3DRender::QMesh();
p_mesh_->setSource(QUrl::fromLocalFile("./res/1.obj"));
p_entity_airplane_->addComponent(p_mesh_);
this->p_entity_lampstand_ = new Qt3DCore::QEntity(p_entity_root_);
p_mesh_one_ = new Qt3DRender::QMesh();
p_mesh_one_->setSource(QUrl::fromLocalFile("./res/2.obj"));
p_entity_lampstand_->addComponent(p_mesh_one_);
p_material_ = new Qt3DExtras::QPhongMaterial(p_entity_root_);
p_material_->setDiffuse(Qt::yellow);
p_material_->setShininess(0.0);
p_entity_airplane_->addComponent(p_material_);
p_entity_lampstand_->addComponent(p_material_);
p_transform_airplane_ = new Qt3DCore::QTransform(p_entity_root_);
p_transform_mesh_ = new Qt3DCore::QTransform(p_entity_root_);
now_loaction_.setX(0);
now_loaction_.setY(1);
now_loaction_.setZ(0);
QQuaternion pal = QQuaternion::rotationTo(QVector3D(1, 0, 0), now_loaction_);
p_transform_airplane_->setScale(0.1);
p_transform_mesh_->setScale(0.1);
p_entity_airplane_->addComponent(p_transform_airplane_);
p_entity_lampstand_->addComponent(p_transform_mesh_);
p_window_view_->setRootEntity(p_entity_root_);
p_layout_ = new QVBoxLayout;
QLineEdit* p_x_pos_, * p_z_pos_;
p_x_pos_ = new QLineEdit;
p_z_pos_ = new QLineEdit;
QPushButton* p_button_ = new QPushButton;
p_layout_->addWidget(p_widget_container_);
p_layout_->addWidget(p_x_pos_);
p_layout_->addWidget(p_z_pos_);
p_layout_->addWidget(p_button_);
connect(p_button_, &QPushButton::clicked, this, \
[=]()\
{\
float x = p_x_pos_->text().toFloat(); \
float z = p_z_pos_->text().toFloat(); \
if (x * x + z * z <= 1)\
{\
float y = sqrt(1 - x * x - z * z); \
next_loaction_.setX(x); \
next_loaction_.setY(y); \
next_loaction_.setZ(z); \
QQuaternion pal = QQuaternion::rotationTo(QVector3D(0, 1, 0), next_loaction_); \
now_loaction_ = next_loaction_; \
p_transform_airplane_->setRotation(pal); \
p_transform_airplane_->setTranslation(QVector3D(-0.405*x,0.405*(1-y), -0.4*z)); \
}\
}\
);
this->setLayout(p_layout_);
this->resize(1200, 800);
}
void MyWidget::GetXDataAndYData(float x, float y)
{
float x_pos = x;
float z_pos = y;
if (x_pos * x_pos + z_pos * z_pos <= 1)
{
float y_pos = sqrt(1 - x_pos * x_pos - z_pos * z_pos);
next_loaction_.setX(x_pos);
next_loaction_.setY(y_pos);
next_loaction_.setZ(z_pos);
QQuaternion pal = QQuaternion::rotationTo(QVector3D(0, 1, 0), next_loaction_);
now_loaction_ = next_loaction_;
p_transform_airplane_->setRotation(pal);
}
}
//记得自己实现析构函数,这里我偷个懒
MyWidget::~MyWidget()
{}
写的很菜,如果有什么不对的地方希望大家斧正。当然如果真要写3d部分还是推荐去看opengl,这个只能算是救急加参考。