提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

前言

一、使用的主要类

1.Qt3DCore

2.Qt3DRender

3.Qt3DExtras

二、代码流程

1.工程入口与 UI 挂载关系

2.View3DScene:场景搭建总控类

总结



前言

在qt中通过Qt3DExtras、Qt3DRender、Qt3DCore类打造一个简单的3D场景,加载.OBJ的3D模型,控制移动。

效果图如下:

代码:

通过网盘分享的文件:qt3d_sencen.zip
链接: https://pan.baidu.com/s/1OjlupJbOiW-hneFfyxLIcA?pwd=gaii 提取码: gaii

一、使用的主要类

1.Qt3DCore

负责 ECS/场景图基础能力:实体、组件、变换、父子层级关系。

常见类:

  • Qt3DCore::QEntity:场景节点,所有物体的容器
  • Qt3DCore::QTransform:位移/旋转/缩放

代码里:

  • rootEntity 是全场景根节点
  • 车、车道线、坐标轴、障碍物都是 QEntity
  • 每个物体通过 QTransform 控制姿态

2.Qt3DRender

负责渲染相关能力:相机、光照、网格加载、拾取、纹理、材质底层等。

常见类:

  • Qt3DRender::QCameraQCameraLens
  • Qt3DRender::QMesh(加载 .obj
  • Qt3DRender::QDirectionalLight
  • Qt3DRender::QObjectPicker
  • Qt3DRender::QTextureLoader

代码里:

  • 相机投影、视角参数属于 Render 层
  • 车辆 OBJ 模型加载是 QMesh
  • 平行光与鼠标拾取也都在这一层

3.Qt3DExtras

这是“高层便捷封装”,让你不用从底层拼完整渲染管线,适合快速开发和教学示例。

常见类:

  • Qt3DExtras::Qt3DWindow
  • Qt3DExtras::QPhongMaterial
  • Qt3DExtras::QPlaneMesh / QCylinderMesh / QCuboidMesh
  • Qt3DExtras::QFirstPersonCameraController
  • Qt3DExtras::QDiffuseMapMaterial

代码里:

  • 3D 窗口、基础几何体、常用材质、相机控制器都用的是 Extras
  • 所以能很快搭出可运行场景

二、代码流程

1.工程入口与 UI 挂载关系

代码如下:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

main.cpp 启动 MainWindow

mainwindow.ui 里把最关键的 View3DScene 当作自定义控件放进了中心布局View3DScene 是整个代码的核心类,它的父类是一个窗口类QWidget,嵌入到MainWindow中。

2.View3DScene:场景搭建总控类

View3DScene 负责:窗口容器、渲染根节点、相机、光照、静态几何体、动态车辆、交互拾取、动画定时器等。

View3DScene 构造函数里完成了几乎所有初始化:创建 Qt3DWindow、设置背景色、包装到 QWidget 容器、注册输入 Aspect、创建 rootEntity

①3D 窗口嵌入 QWidget

// Qt3DWindow 是真正执行 3D 渲染的窗口
Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow();

// 设置清屏背景色(天空蓝)
view->defaultFrameGraph()->setClearColor(QColor(191, 231, 248 ));

// 在 Widgets 项目里,必须用 createWindowContainer 包装 QWindow 才能塞进布局
QWidget *container = QWidget::createWindowContainer(view);大大小

② 相机与光照

相机透视参数、初始位置、观察中心都在这里配置;然后加了第一人称控制器:

// FOV=45°,近平面0.1,远平面1000,兼顾透视感和裁剪范围
cameraEntity->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
// 初始相机位置:车辆后上方,形成“跟车视角”的基础
cameraEntity->setPosition(QVector3D(0, -5, 2.0f));
// Y 轴向上,观察原点
cameraEntity->setUpVector(QVector3D(0, 1, 0));
cameraEntity->setViewCenter(QVector3D(0, 0, 0));

③地面、坐标轴、车道线

地面(SceneModifier):这是自己创建的一个类,主要功能就是在场景里创建一个“带网格贴图的地面平面”并挂到根实体上。

坐标轴:

createAxis(rootEntity, QVector3D(1, 0, 0), Qt::red);   // X 轴:红
createAxis(rootEntity, QVector3D(0, 1, 0), Qt::green); // Y 轴:绿
createAxis(rootEntity, QVector3D(0, 0, 1), Qt::blue);  // Z 轴:蓝

车道线在 createLaneLine()/createMultipleLaneLines():本质是薄 QPlaneMesh,绕 X 轴旋转 90 度贴在地面上

④车辆模型:多 OBJ 部件组装为一个可控实体

创建车辆模型也是通过一个自定义类CarModel实现的,主要是函数createCarModel1;

CarModel::createCarModel1() 的思路是:

  1. 先创建车辆父实体 carEntity
  2. 反复 loadModel() 加载 14 个部件(每个 OBJ 对应一个子部件,可独立设置材质)
  3. 最后给父实体统一 carTransform(位姿控制只改一处)
void CarModel::createCarModel1(Qt3DCore::QEntity *rootEntity)
{

     carEntity = new Qt3DCore::QEntity(rootEntity);
     carTransform = new Qt3DCore::QTransform(carEntity);

        loadModel(carEntity,
                  ":/tractor/tractor1.obj",
                  QColor(1*255, 0.065*255, 255*0.078),
                  QVector3D(0.0f, 0.0f, 0.0f));
        loadModel(carEntity,
                  ":/tractor/tractor2.obj",
                  QColor(100, 100, 100),
                  QVector3D(0.0f, 0.0f, 0.0f));
        loadModel(carEntity,
                  ":/tractor/tractor3.obj",
                  QColor(0.059*255, 0.059*255, 0.059*255),
                  QVector3D(0.0f, 0.0f, 0.0f));
        loadModel(carEntity,
                  ":/tractor/tractor4.obj",
                  QColor(100,100,100),
                  QVector3D(0.0f, 0.0f, 0.0f));
        loadModel(carEntity,
                  ":/tractor/tractor5.obj",
                  QColor(0, 0, 0),
                  QVector3D(-1.0f, -0.5f, 1.0f));
        loadModel(carEntity,                    //后左轮
                  ":/tractor/tractor6.obj",
                  QColor(0.059*255, 0.059*255, 0.059*255),
                  QVector3D(1.0f, -0.5f, 1.0f));
        loadModel(carEntity,
                  ":/tractor/tractor7.obj",
                  QColor(100, 100, 100),
                  QVector3D(0.0f, 0.0f, 0.0f));
        loadModel(carEntity,
                  ":/tractor/tractor8.obj",
                  QColor(100, 100, 100),
                  QVector3D(0.0f, 0.0f, 0.0f));
        loadModel(carEntity,
                  ":/tractor/tractor9.obj",
                  QColor(100, 100, 100),
                  QVector3D(0.0f, 0.0f, 0.0f));
        loadModel(carEntity,
                  ":/tractor/tractor10.obj",
                  QColor(100, 100, 100),
                  QVector3D(0.0f, 0.0f, 0.0f));
        loadModel(carEntity,
                  ":/tractor/tractor11.obj",
                  QColor(100, 100, 100),
                  QVector3D(0.0f, 0.0f, 0.0f));
        loadModel(carEntity,                    //前右轮
                  ":/tractor/tractor12.obj",
                  QColor(0.059*255, 0.059*255, 0.059*255),
                  QVector3D(-1.0f, -0.5f, -1.0f));
        loadModel(carEntity,                    //前左轮
                  ":/tractor/tractor13.obj",
                  QColor(0.059*255, 0.059*255, 0.059*255),
                  QVector3D(-1.0f, -0.5f, -1.0f));
        loadModel(carEntity,                    //后右轮
                  ":/tractor/tractor14.obj",
                  QColor(0.059*255, 0.059*255, 0.059*255),
                  QVector3D(-1.0f, -0.5f, -1.0f));


        carTransform->setTranslation(QVector3D(0.0f, 0.0f, 0.3f)); // 设置模型位置
        carTransform->setScale(0.03f); // 缩放模型
        carTransform->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1.0f, 0.0f, 0.0f), 90.0f));

        carEntity->addComponent(carTransform);

        QQuaternion angle=QQuaternion::fromAxisAndAngle(QVector3D(1.0f, 0.0f, 0.0f), 180.0f);
        qDebug()<<carElementTramsform[12]->translation();
        qDebug()<<carElementTramsform[11]->translation();



}

⑤轨迹生成与动画驱动

这一块的轨迹是验证,表明我们的车辆可以移动等。模拟的是一个正弦函数路径;

for (float y = 0.0f; y <= length; y += step) {
    float x = amplitude * std::sin(frequency * y);
    float z = 0.0f;  // 高度贴地
    trajectory.append(QVector3D(x, y, z));
}

构造里 100ms 一帧推进路径点,并通过信号把车辆位置回传给场景控制逻辑

connect(timer,&QTimer::timeout,this,[=](){
    if(cnt<carPath.length())
    {
        carmodel->setCarPosition(carPath[cnt].x(),carPath[cnt].y(),0);
        cnt++;
    }
});
connect(carmodel,&CarModel::sig_carPos,this,&View3DScene::slot_changeCameraPosition);

⑥相机跟随、车头转向、轨迹与障碍物

slot_changeCameraPosition()函数

  • 根据车辆位置给相机加偏移(跟车视角)
  • 每次追加一个轨迹段(紫灰色平面)
  • 周期性生成红色立方体障碍物并 5 秒后自动删除
  • 用前后两个路径点估算方向向量,计算夹角,调用 setCarAngle() 让车头朝向运动方向


总结

一些重要的头文件

  • Qt3DCore/qentity.h:实体节点(场景树)
  • Qt3DCore/qtransform.h:位移/旋转/缩放
  • Qt3DRender/qcamera.hqcameralens.h:观察与投影
  • Qt3DRender/qmesh.h:外部模型加载(OBJ)
  • Qt3DRender/QDirectionalLight:平行光照
  • Qt3DRender/QObjectPicker:拾取交互
  • Qt3DExtras/qt3dwindow.h:3D 渲染窗口
  • Qt3DExtras/QPhongMaterial:基础材质
  • Qt3DExtras/QPlaneMeshQCylinderMeshQCuboidMesh:基础几何
  • Qt3DExtras/qfirstpersoncameracontroller.h:相机控制
  • QTimer:动画循环调度
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐