Files
HPPA/HPPA/View3D.cpp
tangchao0503 30306e9396 初步完成美化:
1、左下角3d模型预览看板;
2、右下角控制看板
2026-01-16 22:03:30 +08:00

375 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "View3D.h"
#include <QHBoxLayout>
#include <QShowEvent>
#include <QMouseEvent>
#include <QWheelEvent>
#include <Qt3DExtras/QForwardRenderer>
#include <QtMath>
#include <Qt3DRender/QAttribute>
#include <QGeometryRenderer>
View3DBase::View3DBase(const QString& baseModelPath,
const QString& armModelPath,
QWidget* parent)
: QWidget(parent),
m_container(nullptr),
m_baseModelPath(baseModelPath),
m_armModelPath(armModelPath)
{
m_view = new Qt3DExtras::Qt3DWindow();
// 部分 Qt5.9 构建可能需要强转 frame graph但 defaultFrameGraph() 通常可用
QColor c1("#0D1233");
m_view->defaultFrameGraph()->setClearColor(c1);
m_rootEntity = new Qt3DCore::QEntity();
initScene();
initCamera();
// 自动旋转臂(如果不需要可注释掉 timer/connect
//connect(&m_timer, &QTimer::timeout, this, [=]() {
// m_angle += 1.0f;
// m_t += 1.0f;
// if (m_angle >= 360.0f) m_angle = 0.0f;
// if (m_armTransform)
// {
// //m_armTransform->setRotationX(m_angle);
// //m_armTransform->setTranslation(QVector3D(m_t, 0, 0));
//
// Qt3DCore::QTransform transform;
// transform.setTranslation(QVector3D(2, 0, 0));
// QMatrix4x4 M = m_armTransform->matrix();
// M = transform.matrix() * M; // 左乘:在世界坐标系叠加
// m_armTransform->setMatrix(M);
// qDebug() << m_armTransform->matrix();
// }
// });
}
void View3DBase::setViewCenter(float x, float y, float z)
{
m_viewCenter.setX(x);
m_viewCenter.setY(y);
m_viewCenter.setZ(z);
}
void View3DBase::setDistance(float distance)
{
m_distance = distance;
}
void View3DBase::initScene()
{
/*auto* lightEntity = new Qt3DCore::QEntity(m_rootEntity);
auto* light = new Qt3DRender::QPointLight(lightEntity);
light->setColor(Qt::white);
light->setIntensity(1.2f);
auto* lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(QVector3D(500, 500, 500));
lightEntity->addComponent(light);
lightEntity->addComponent(lightTransform);*/
// ===== 创建 base 根节点 =====
auto* baseModel = new Qt3DCore::QEntity(m_rootEntity);
auto* baseLoader = new Qt3DRender::QSceneLoader(baseModel);
baseLoader->setSource(QUrl::fromLocalFile(m_baseModelPath));
//connect(baseLoader, &Qt3DRender::QSceneLoader::statusChanged,
// this, &View3DBase::onSceneLoaderStatusChanged);
m_baseTransform = new Qt3DCore::QTransform();
m_baseTransform->setTranslation(QVector3D(0, 0, 0));
baseModel->addComponent(baseLoader);
baseModel->addComponent(m_baseTransform);
connect(baseLoader, &Qt3DRender::QSceneLoader::statusChanged,
this, [=](Qt3DRender::QSceneLoader::Status status) {
if (status == Qt3DRender::QSceneLoader::Ready) {
applyWhiteMaterialRecursive(baseModel);
}
});
// ===== 创建 arm 根节点 =====
auto* armModel = new Qt3DCore::QEntity(m_rootEntity);
auto* armLoader = new Qt3DRender::QSceneLoader(armModel);
armLoader->setSource(QUrl::fromLocalFile(m_armModelPath));
m_armTransform = new Qt3DCore::QTransform();
m_armTransform->setTranslation(QVector3D(0, 0, 0));
armModel->addComponent(armLoader);
armModel->addComponent(m_armTransform);
connect(armLoader, &Qt3DRender::QSceneLoader::statusChanged,
this, [=](Qt3DRender::QSceneLoader::Status status) {
if (status == Qt3DRender::QSceneLoader::Ready) {
applyWhiteMaterialRecursive(armModel);
}
});
// 坐标轴依然挂在 root不会被移动
//createAxes();
m_view->setRootEntity(m_rootEntity);
qDebug() << m_baseTransform->matrix();
qDebug() << m_armTransform->matrix();
//m_armTransform->setTranslation(QVector3D(2000, 0, 0));
//m_baseTransform->setTranslation(QVector3D(-1000, -1000, -1000));
qDebug() << m_baseTransform->matrix();
qDebug() << m_armTransform->matrix();
}
void View3DBase::applyWhiteMaterialRecursive(Qt3DCore::QEntity* entity)
{
// 如果这个 entity 有 mesh就给它加白色材质
auto meshes = entity->componentsOfType<Qt3DRender::QGeometryRenderer>();
if (!meshes.isEmpty()) {
auto* mat = new Qt3DExtras::QPhongMaterial(entity);
QColor c1("#cccccc");
mat->setDiffuse(c1);
mat->setAmbient(c1);
mat->setSpecular(c1);
mat->setShininess(50.0f);
entity->addComponent(mat);
}
// 递归处理子节点
const auto children = entity->children();
for (QObject* obj : children) {
auto* childEntity = qobject_cast<Qt3DCore::QEntity*>(obj);
if (childEntity)
applyWhiteMaterialRecursive(childEntity);
}
}
void View3DBase::createAxes()
{
// 参数
float axisLength = 500.0f;
float axisRadius = 50.0f;
// ----- X axis (red) -----
Qt3DCore::QEntity* xAxis = new Qt3DCore::QEntity(m_rootEntity);
auto* xMesh = new Qt3DExtras::QCylinderMesh();
xMesh->setRadius(axisRadius);
xMesh->setLength(axisLength);
xMesh->setRings(16);
xMesh->setSlices(16);
auto* xTrans = new Qt3DCore::QTransform();
// cylinder 默认沿 Y 轴,绕 Z 轴 90 度让其沿 X
xTrans->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), 90.0f));
xTrans->setTranslation(QVector3D(axisLength / 2.0f, 0.0f, 0.0f));
auto* xMat = new Qt3DExtras::QPhongMaterial();
xMat->setDiffuse(QColor(Qt::red));
xAxis->addComponent(xMesh);
xAxis->addComponent(xTrans);
xAxis->addComponent(xMat);
// ----- Y axis (green) -----
Qt3DCore::QEntity* yAxis = new Qt3DCore::QEntity(m_rootEntity);
auto* yMesh = new Qt3DExtras::QCylinderMesh();
yMesh->setRadius(axisRadius);
yMesh->setLength(axisLength*2);
yMesh->setRings(16);
yMesh->setSlices(16);
auto* yTrans = new Qt3DCore::QTransform();
// Y 轴无需旋转cylinder 默认沿 Y
yTrans->setTranslation(QVector3D(0.0f, axisLength / 2.0f, 0.0f));
auto* yMat = new Qt3DExtras::QPhongMaterial();
yMat->setDiffuse(QColor(Qt::green));
yAxis->addComponent(yMesh);
yAxis->addComponent(yTrans);
yAxis->addComponent(yMat);
// ----- Z axis (blue) -----
Qt3DCore::QEntity* zAxis = new Qt3DCore::QEntity(m_rootEntity);
auto* zMesh = new Qt3DExtras::QCylinderMesh();
zMesh->setRadius(axisRadius);
zMesh->setLength(axisLength*3);
zMesh->setRings(16);
zMesh->setSlices(16);
auto* zTrans = new Qt3DCore::QTransform();
// 让 cylinder 沿 Z绕 X 轴 90 度
zTrans->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1, 0, 0), 90.0f));
zTrans->setTranslation(QVector3D(0.0f, 0.0f, axisLength / 2.0f));
auto* zMat = new Qt3DExtras::QPhongMaterial();
zMat->setDiffuse(QColor(Qt::blue));
zAxis->addComponent(zMesh);
zAxis->addComponent(zTrans);
zAxis->addComponent(zMat);
}
void View3DBase::initCamera()
{
m_camera = m_view->camera();
// 16:10 假设窗口比例,后续 resize 时相机透视会保持
m_camera->lens()->setPerspectiveProjection(50.0f, 16.0f / 10.0f, 0.1f, 10000.0f);
updateCameraPosition();
}
void View3DBase::updateCameraPosition()
{
float yaw = qDegreesToRadians(m_yawDeg);
float pitch = qDegreesToRadians(m_pitchDeg);
float x = m_distance * qCos(pitch) * qSin(yaw);
float y = m_distance * qSin(pitch);
float z = m_distance * qCos(pitch) * qCos(yaw);
QVector3D camPos = m_viewCenter + QVector3D(x, y, z);
m_camera->setPosition(camPos);
m_camera->setViewCenter(m_viewCenter);
}
void View3DBase::showEvent(QShowEvent* event)
{
QWidget::showEvent(event);
if (!m_container) {
m_container = QWidget::createWindowContainer(m_view, this);
m_view->installEventFilter(this);
auto* layout = new QHBoxLayout(this);
layout->addWidget(m_container);
layout->setMargin(0);
setLayout(layout);
// 启动自动旋转 timer如果你不需要可以注释
m_timer.start(100);
}
}
bool View3DBase::eventFilter(QObject* obj, QEvent* event)
{
if (obj == m_view)
{
// 鼠标按下
if (event->type() == QEvent::MouseButtonPress) {
auto* e = static_cast<QMouseEvent*>(event);
if (e->button() == Qt::LeftButton) {
m_mouseDragging = true;
m_lastMousePos = e->pos();
}
else if (e->button() == Qt::MiddleButton) {
m_middleDragging = true;
m_lastMousePos = e->pos();
}
}
// 鼠标释放
else if (event->type() == QEvent::MouseButtonRelease) {
auto* e = static_cast<QMouseEvent*>(event);
if (e->button() == Qt::LeftButton) {
m_mouseDragging = false;
}
else if (e->button() == Qt::MiddleButton) {
m_middleDragging = false;
}
}
// 鼠标移动
else if (event->type() == QEvent::MouseMove) {
auto* e = static_cast<QMouseEvent*>(event);
QPoint pos = e->pos();
QPoint delta = pos - m_lastMousePos;
// 左键orbit旋转
if (m_mouseDragging) {
float sensitivity = 0.3f;
m_yawDeg -= delta.x() * sensitivity;
m_pitchDeg += delta.y() * sensitivity;
if (m_pitchDeg > 89.0f) m_pitchDeg = 89.0f;
if (m_pitchDeg < -89.0f) m_pitchDeg = -89.0f;
updateCameraPosition();
}
// 中键pan平移 viewCenter
if (m_middleDragging) {
float speed = 2.0f;
// 根据摄像机方向计算平移方向
QVector3D camPos = m_camera->position();
QVector3D forward = (m_viewCenter - camPos).normalized();
QVector3D up(0, 1, 0);
QVector3D right = QVector3D::crossProduct(forward, up).normalized();
// 世界坐标变化量
QVector3D deltaMove =
-right * (delta.x() * speed) +
up * (delta.y() * speed);
// 将平移应用到两个模型根 Transform
if (m_baseRootTransform)
m_baseRootTransform->setTranslation(
m_baseRootTransform->translation() + deltaMove*-1);
if (m_armRootTransform)
m_armRootTransform->setTranslation(
m_armRootTransform->translation() + deltaMove*-1);
}
m_lastMousePos = pos;
}
// 滚轮缩放
else if (event->type() == QEvent::Wheel) {
auto* e = static_cast<QWheelEvent*>(event);
// Qt5: angleDelta 返回像素值(通常为 120 per notch
int delta = e->angleDelta().y();
if (delta == 0) delta = e->delta(); // 备选
m_distance -= delta * 2.0f; // 缩放速度
if (m_distance < 2.0f) m_distance = 2.0f;
if (m_distance > 10000.0f) m_distance = 10000.0f;
updateCameraPosition();
}
}
// 让 Qt 继续处理(保持原行为)
return QWidget::eventFilter(obj, event);
}
View3DPlantPhenotype::View3DPlantPhenotype(const QString& baseModelPath, const QString& armModelPath, QWidget* parent)
:View3DBase(baseModelPath, armModelPath, parent)
{
}
void View3DPlantPhenotype::setLoc(std::vector<double> loc)
{
double x = round(loc[0] * 100) / 100;
double y = round(loc[1] * 100) / 100;
m_armTransform->setTranslation(QVector3D(x, y, 0));
}
View3DLinearStage::View3DLinearStage(const QString& baseModelPath, const QString& armModelPath, QWidget* parent)
:View3DBase(baseModelPath, armModelPath, parent)
{
}
void View3DLinearStage::setLoc(std::vector<double> loc)
{
double x = round(loc[0] * 100) / 100;
m_armTransform->setTranslation(QVector3D(x, 0, 0));
}