Files
EJM_Display/PublicFunctions/ObjLoader.h

680 lines
23 KiB
C
Raw Normal View History

2025-09-28 17:14:34 +08:00
#ifndef OBJLOADER_H
#define OBJLOADER_H
#include <QObject>
#include <QVector>
#include <QVector2D>
#include <QVector3D>
#include <Qt3DCore>
#include <Qt3DRender>
#include <Qt3DExtras>
#include <QString>
#include <QMap>
#include <QColor>
#include <QWidget>
#include <QTimer>
2025-09-30 15:36:46 +08:00
#include <QtConcurrent/QtConcurrent>
#include <QFutureWatcher>
2025-09-28 17:14:34 +08:00
2025-09-30 15:36:46 +08:00
#include <QMutex>
#include <QTimer>
2025-09-28 17:14:34 +08:00
/**
* @brief
* OBJ文件中面的顶点索引
*/
struct VertexIndex {
/**
* @brief
* m_positions中的顶点位置数据索引
*/
int position;
/**
* @brief
* m_texCoords中的纹理坐标数据索引
*/
int texCoord;
/**
* @brief
* m_normals中的法向量数据索引
*/
int normal;
/**
* @brief
* -1使
*/
VertexIndex() : position(-1), texCoord(-1), normal(-1) {}
/**
* @brief
* @param p
* @param t
* @param n
*/
VertexIndex(int p, int t, int n) : position(p), texCoord(t), normal(n) {}
};
/**
* @brief
* MTL文件解析的材质属性
*/
struct Material {
/**
* @brief
*
*/
QString name;
/**
* @brief
* MTL文件中的Ka属性
*/
QColor ambient;
/**
* @brief
* MTL文件中的Kd属性
*/
QColor diffuse;
/**
* @brief
* MTL文件中的Ks属性
*/
QColor specular;
/**
* @brief
* MTL文件中的Ns属性
*/
float shininess;
/**
* @brief
* MTL文件中的map_Kd属性
*/
QString diffuseMap;
/**
* @brief
* MTL文件中的d参数0.0-1.01.0
*/
float opacity;
};
/**
* @brief
* OBJ文件中的一个面使
*/
struct Face {
/**
* @brief
*
*/
QVector<VertexIndex> vertices;
/**
* @brief 使
* m_materials中的名称
*/
QString materialName;
};
/**
* @brief
* 3D场景中一个器件
*/
struct Device {
/**
* @brief
*
*/
QString name;
/**
* @brief
*
*/
Qt3DCore::QEntity* entity;
/**
* @brief
*
*/
Qt3DCore::QEntity* modelEntity;
/**
* @brief
*
*/
Qt3DCore::QTransform* transform;
/**
* @brief
*
*/
Qt3DCore::QTransform* modelTransform;
/**
* @brief
*
*/
QVector3D worldPosition;
/**
* @brief
*
*/
QVector3D originalPosition;
/**
* @brief
* XYZ轴的旋转角度
*/
QVector3D currentRotation;
/**
* @brief
*
*/
QVector3D modelCenter;
/**
* @brief
* 1.0
*/
float scale;
/**
* @brief
* true表示初始化完成
*/
bool isInitialized;
// 父子模型关联字段
/**
* @brief
*
*/
QString parentDeviceName;
/**
* @brief
*
*/
QVector3D offsetToParent;
/**
* @brief
*
*/
QVector3D initialWorldPosition;
/**
* @brief
*
*/
QMatrix4x4 initialTransformMatrix;
/**
* @brief
*
*/
QMatrix4x4 initialModelTransformMatrix;
/**
* @brief
*
*/
QVector3D initialRotation;
/**
* @brief
* {0,0,0}
*/
QVector3D localPivot;
/**
* @brief
*
*/
QVector3D rotationCenter;
/**
* @brief
* 使false
*/
bool useCustomRotationCenter;
};
/**
* @brief OBJ模型加载器类
* 3D场景初始化OBJ/MTL文件加载//
*/
class ObjLoader : public QObject
{
Q_OBJECT
public:
/**
* @brief
* @param parent
*/
explicit ObjLoader(QObject *parent = nullptr);
/**
* @brief
* 3D资源和动态分配的对象
*/
~ObjLoader();
/**
* @brief ObjLoader::setEnDebug qDebug打印信息
* @param En True=,False=;
*/
void setEnDebug(bool En);
/**
* @brief 3D场景
* @param containerWidget 3D场景的窗口容器
*/
void init3DScene(QWidget *containerWidget);
/**
* @brief 3D场景
* 3D窗口
* @param containerWidget 3D场景的窗口容器QFrame
* @param enableTransparent true=false=
* @return truefalselastError()
*/
bool init3DScene(QWidget *containerWidget, bool enableTransparent);
2025-09-30 15:36:46 +08:00
void loadModelAsync(const QString &deviceName, const QString &filePath, const QVector3D &position);
2025-09-28 17:14:34 +08:00
/**
* @brief
* /MTL材质
*
* @param deviceName
* @param filePath OBJ文件路径
* @param position
* @return true
*/
bool loadModel(const QString &deviceName, const QString &filePath, const QVector3D &position = QVector3D(0,0,0));
/**
* @brief
* @param deviceName
* @param filePath OBJ文件路径
* @param position
* @return truefalse
*/
bool loadDevice(const QString &deviceName, const QString &filePath, const QVector3D &position = QVector3D(0,0,0));
/**
* @brief
*
* @param childDeviceName
* @param filePath OBJ文件路径
* @param parentDeviceName
* @param offsetDir
* @param diffuse
* @return true
*/
bool loadChildDevice(
const QString &childDeviceName,
const QString &filePath,
const QString &parentDeviceName,
const QVector3D &offsetDir = QVector3D(0, 0, 0),
const QColor &diffuse = QColor(255, 255, 255,30)
);
/**
* @brief OBJ文件计算模型的包围球半径
* OBJ文件中的顶点数据
*
* @param filePath OBJ模型文件的路径
* @return 1.0f
*/
float calculateModelRadiusFromFile(const QString &filePath);
/**
* @brief
* @param deviceName
* @return Device指针nullptr
*/
Device* getDevice(const QString &deviceName);
/**
* @brief
* @param deviceName
* @param xAngle X轴旋转角度
* @param yAngle Y轴旋转角度
* @param zAngle Z轴旋转角度
*/
void rotateDevice(const QString &deviceName, float xAngle, float yAngle, float zAngle);
/**
* @brief
* @param deviceName
* @param offset
*/
void moveDevice(const QString &deviceName, const QVector3D &offset);
/**
* @brief
* @param deviceName
* @param targetPos
*/
void setDevicePos(const QString &deviceName, const QVector3D &targetPos);
/**
* @brief
* @param deviceName
* @param scaleFactor >0
*/
void scaleDevice(const QString &deviceName, float scaleFactor);
/**
* @brief
* @param deviceName
*/
void resetDevice(const QString &deviceName);
/**
* @brief
* @param deviceData
*/
void updateDevicesFromData(const QMap<QString, QMap<QString, float>> &deviceData);
/**
* @brief
*/
void resetCamera();
/**
* @brief
* @param lookSpeed
* @param linearSpeed
*/
void setCameraSpeed(float lookSpeed, float linearSpeed);
/**
* @brief gizmo3D定位
* @param parent 使
* @param length
*/
void addAxisGizmo(Qt3DCore::QEntity *parent = nullptr, float length = 5.0f);
/**
* @brief
* @param childDeviceName
* @param newOffset
*/
void adjustChildDeviceOffset(const QString &childDeviceName, const QVector3D &newOffset);
/**
* @brief
* @param deviceName
* @param position
*/
void setParentDevicePosition(const QString &deviceName, const QVector3D &position);
/**
* @brief
* @param deviceName
*/
void printDeviceWorldPos(const QString &deviceName);
/**
* @brief
* @return
*/
Qt3DRender::QCamera* getCamera();
/**
* @brief OBJ文件计算模型中心
* @param filePath OBJ文件路径
* @return
*/
QVector3D parseObjCenter(const QString &filePath);
/**
* @brief
* @param vertices
* @return
*/
QVector3D calculateBoundingBoxCenter(const QVector<QVector3D>& vertices);
/**
* @brief Z轴角度
* @param deviceName
* @param targetZAngle
*/
void rotateArmToAbsoluteZAngle(const QString &deviceName, float targetZAngle);
/**
* @brief X轴旋转
* 0°
* @param deviceName
* @param targetXAngle X轴角度
*/
void rotateArmToAbsoluteXAngle(const QString &deviceName, float targetXAngle);
/**
* @brief Y轴旋转
* 0°
* @param deviceName
* @param targetYAngle Y轴角度
*/
void rotateArmToAbsoluteYAngle(const QString &deviceName, float targetYAngle);
/**
* @brief
* @param deviceName
* @param targetWorldPos
*/
void moveArmLocalOriginTo(const QString &deviceName, const QVector3D &targetWorldPos);
2025-09-30 15:36:46 +08:00
/**
* @brief MTL文件加载材质属性并应用到Phong材质
* @param material QPhongMaterial对象指针
* @param filePath MTL材质文件的绝对路径
* @details MTL文件中的材质属性
* Phong材质对象中MTL文件不存在或解析失败
*
*/
void loadMaterialFromMtl(Qt3DExtras::QPhongMaterial *material, const QString &filePath);
/**
* @brief 3D模型并创建器件实体
* @param deviceName
* @param filePath OBJ模型文件的绝对路径
* @param position
* @param modelCenter
* @param modelRadius
* @return truefalse
* @details 线
*
* 3D对象操作均在主线程执行以确保线程安全
*/
bool loadModelAsync(const QString &deviceName, const QString &filePath,
const QVector3D &position, QVector3D &modelCenter, float modelRadius);
private slots:
/**
* @brief 线
* @param deviceNames
* @param basePath
* @details OBJ文件进行预处理
* preprocessDone信号发送结果
* 线UI线程
*/
void preprocessDevices(const QStringList& deviceNames, const QString& basePath);
/**
* @brief 线
* @param deviceName
* @param basePath
* @details OBJ文件路径
* preprocessDone信号发送结果
*
*/
void preprocessSingleDevice(const QString& deviceName, const QString& basePath);
2025-09-28 17:14:34 +08:00
2025-09-30 15:36:46 +08:00
/**
* @brief
* @details
* cameraInfoUpdated信号发送出去
*
*/
void onCameraChanged();
signals:
/**
* @brief
* @param deviceName
* @param center
* @param radius
* @details
* 线
*/
void preprocessDone(const QString& deviceName, QVector3D center, float radius);
/**
* @brief
* @param position
* @param viewCenter
* @param fov
* @details
*
*/
void cameraInfoUpdated(const QVector3D& position, const QVector3D& viewCenter, float fov);
2025-09-28 17:14:34 +08:00
private:
/**
* @brief
*/
void calculateModelCenter();
/**
* @brief
* @param parentDevice
* @return
*/
QList<Device*> getAllChildren(Device *parentDevice);
/**
* @brief
* @return
*/
float calculateModelRadius();
/**
* @brief MTL材质文件
* @param filePath MTL文件路径
* @return truefalse
*/
bool parseMtlFile(const QString &filePath);
/**
* @brief
* @param s
* @param sep
* @return
*/
static QVector<QString> splitStr(const QString &s, const QString &sep = " ");
/**
* @brief
*/
void createSceneLights();
/**
* @brief
*/
void updateWholeModel();
private:
/**
* @brief m_3dView 3D渲染窗口3D场景的渲染输出
*/
Qt3DExtras::Qt3DWindow *m_3dView;
/**
* @brief m_viewContainer 3D窗口容器3D渲染窗口嵌入到Qt Widget界面中
*/
QWidget *m_viewContainer;
/**
* @brief m_rootEntity 3D实体的父节点
*/
Qt3DCore::QEntity *m_rootEntity;
/**
* @brief m_mainCamera 3D场景的视角设备
*/
Qt3DRender::QCamera *m_mainCamera;
/**
* @brief m_cameraCtrl
*/
Qt3DExtras::QOrbitCameraController *m_cameraCtrl;
/**
* @brief light 3D场景提供照明
*/
Qt3DRender::QDirectionalLight *light;
/**
* @brief m_wholeModelEntity
*/
Qt3DCore::QEntity *m_wholeModelEntity;
/**
* @brief m_wholeModelMesh
*/
Qt3DRender::QMesh *m_wholeModelMesh;
/**
* @brief m_wholeModelTrans
*/
Qt3DCore::QTransform *m_wholeModelTrans;
/**
* @brief m_deviceMap Device对象
*/
QMap<QString, Device> m_deviceMap;
/**
* @brief m_animTimer 3D场景中的动画更新
*/
QTimer *m_animTimer;
/**
* @brief m_positions 3D坐标
*/
QVector<QVector3D> m_positions;
/**
* @brief m_texCoords 2D纹理映射坐标
*/
QVector<QVector2D> m_texCoords;
/**
* @brief m_normals
*/
QVector<QVector3D> m_normals;
/**
* @brief m_faces
*/
QVector<Face> m_faces;
/**
* @brief m_materials Material对象
*/
QMap<QString, Material> m_materials;
/**
* @brief m_tempVertices
*/
QVector<QVector3D> m_tempVertices;
/**
* @brief m_wholeModelCenter
*/
QVector3D m_wholeModelCenter;
/**
* @brief m_wholeModelRadius
*/
float m_wholeModelRadius;
/**
* @brief m_currentMaterial 使
*/
QString m_currentMaterial;
/**
* @brief m_lastError
*/
QString m_lastError;
/**
* @brief m_cameraEntity 使
*/
Qt3DRender::QCamera *m_cameraEntity;
/**
* @brief EnDebug qDebug调试信息
*/
bool EnDebug = false;
2025-09-30 15:36:46 +08:00
QMutex m_mutex; // 线程安全锁
QSet<QString> m_loadingDevices; // 跟踪加载中的器件,避免重复加载
2025-09-28 17:14:34 +08:00
};
#endif // OBJLOADER_H