一个简单QT 3D场景的打造
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
在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::QCamera、QCameraLensQt3DRender::QMesh(加载.obj)Qt3DRender::QDirectionalLightQt3DRender::QObjectPickerQt3DRender::QTextureLoader
代码里:
- 相机投影、视角参数属于 Render 层
- 车辆 OBJ 模型加载是
QMesh - 平行光与鼠标拾取也都在这一层
3.Qt3DExtras
这是“高层便捷封装”,让你不用从底层拼完整渲染管线,适合快速开发和教学示例。
常见类:
Qt3DExtras::Qt3DWindowQt3DExtras::QPhongMaterialQt3DExtras::QPlaneMesh/QCylinderMesh/QCuboidMeshQt3DExtras::QFirstPersonCameraControllerQt3DExtras::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() 的思路是:
- 先创建车辆父实体
carEntity - 反复
loadModel()加载 14 个部件(每个 OBJ 对应一个子部件,可独立设置材质) - 最后给父实体统一
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.h、qcameralens.h:观察与投影Qt3DRender/qmesh.h:外部模型加载(OBJ)Qt3DRender/QDirectionalLight:平行光照Qt3DRender/QObjectPicker:拾取交互Qt3DExtras/qt3dwindow.h:3D 渲染窗口Qt3DExtras/QPhongMaterial:基础材质Qt3DExtras/QPlaneMesh、QCylinderMesh、QCuboidMesh:基础几何Qt3DExtras/qfirstpersoncameracontroller.h:相机控制QTimer:动画循环调度
更多推荐

所有评论(0)