Qt6 3D动画绘制详解
Qt6 提供了强大的 3D 图形渲染能力,通过 Qt3D 模块可以轻松实现 3D 动画效果。本文将详细介绍如何在 Qt6 中使用 Qt3D 模块创建和渲染 3D 动画。
一、Qt3D 模块概述
Qt3D 是 Qt 提供的 3D 图形框架,支持:
- 3D 场景管理
- 材质和光照系统
- 相机控制
- 动画系统
- 粒子效果
在 Qt6 中,Qt3D 已经成为核心模块的一部分,使用更加方便。
二、环境配置
1. 添加依赖
在项目文件(.pro)中添加:
QT += 3dcore 3drender 3dinput 3dextras
2. 头文件包含
#include <QGuiApplication>
#include <QQuickView>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DCore/QEntity>
#include <Qt3DRender/QCamera>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DCore/QTransform>
#include <Qt3DAnimations/QAnimationClip>
#include <Qt3DAnimations/QAnimator>
#include <Qt3DAnimations/QChannelMapper>
#include <Qt3DCore/QAnimationAspect>
三、基础 3D 场景设置
1. 创建 3D 窗口
Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow();
QWidget *container = QWidget::createWindowContainer(view);
2. 设置场景根实体
Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
view->setRootEntity(rootEntity);
3. 添加相机
Qt3DRender::QCamera *camera = view->camera();
camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
camera->setPosition(QVector3D(0, 0, 40.0f));
camera->setUpVector(QVector3D(0, 1, 0));
camera->setViewCenter(QVector3D(0, 0, 0));
4. 添加相机控制器
Qt3DExtras::QOrbitCameraController *camController = new Qt3DExtras::QOrbitCameraController(rootEntity);
camController->setCamera(camera);
四、创建 3D 对象
1. 创建立方体
// 创建立方体实体
Qt3DCore::QEntity *cubeEntity = new Qt3DCore::QEntity(rootEntity);
// 创建几何体
Qt3DExtras::QCuboidMesh *cubeMesh = new Qt3DExtras::QCuboidMesh();
// 创建材质
Qt3DExtras::QPhongMaterial *cubeMaterial = new Qt3DExtras::QPhongMaterial();
cubeMaterial->setDiffuse(Qt::red);
// 创建变换组件
Qt3DCore::QTransform *cubeTransform = new Qt3DCore::QTransform();
// 将组件添加到实体
cubeEntity->addComponent(cubeMesh);
cubeEntity->addComponent(cubeMaterial);
cubeEntity->addComponent(cubeTransform);
五、实现 3D 动画
1. 使用 QPropertyAnimation 实现简单动画
#include <QPropertyAnimation>
// 创建动画
QPropertyAnimation *anim = new QPropertyAnimation(cubeTransform, "rotation");
anim->setDuration(2000); // 2秒
anim->setLoopCount(-1); // 无限循环
anim->setStartValue(QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), 0));
anim->setEndValue(QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), 360));
// 启动动画
anim->start();
2. 使用 Qt3DAnimations 模块实现复杂动画
2.1 创建动画剪辑
Qt3DAnimations::QAnimationClip *animationClip = new Qt3DAnimations::QAnimationClip();
animationClip->setDuration(2000); // 2秒
// 创建关键帧数据
QVector<Qt3DCore::QTransform *> keyframes;
for (int i = 0; i < 100; ++i) {
Qt3DCore::QTransform *transform = new Qt3DCore::QTransform();
transform->setRotation(QQuaternion::fromAxisAndAngle(
QVector3D(0, 1, 0), i * 3.6)); // 每帧旋转3.6度
keyframes.append(transform);
}
// 添加关键帧到动画剪辑
animationClip->setKeyframeData(keyframes);
2.2 创建动画控制器
Qt3DAnimations::QAnimator *animator = new Qt3DAnimations::QAnimator(rootEntity);
animator->setClip(animationClip);
// 创建通道映射器
Qt3DAnimations::QChannelMapper *channelMapper = new Qt3DAnimations::QChannelMapper();
channelMapper->setTarget(cubeTransform);
animator->setChannelMapper(channelMapper);
animator->start();
3. 使用 QML 实现 3D 动画
Qt3D 也支持通过 QML 实现动画,更加简洁:
import QtQuick 2.15
import Qt3D.Core 2.15
import Qt3D.Render 2.15
import Qt3D.Input 2.15
import Qt3D.Extras 2.15
import Qt3D.Animations 2.15
Entity {
id: root
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16/9
nearPlane: 0.1
farPlane: 1000.0
position: Qt.vector3d(0, 0, 40.0)
upVector: Qt.vector3d(0, 1, 0)
viewCenter: Qt.vector3d(0, 0, 0)
}
OrbitCameraController {
camera: camera
}
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer {
camera: camera
clearColor: "black"
}
},
InputSettings { }
]
Entity {
id: cubeEntity
CuboidMesh {
id: cubeMesh
}
PhongMaterial {
id: cubeMaterial
diffuse: "red"
}
Transform {
id: cubeTransform
}
components: [cubeMesh, cubeMaterial, cubeTransform]
// 添加动画
NumberAnimation {
target: cubeTransform
property: "rotationX"
from: 0
to: 360
duration: 2000
loops: Animation.Infinite
}
NumberAnimation {
target: cubeTransform
property: "rotationY"
from: 0
to: 360
duration: 2000
loops: Animation.Infinite
running: false // 不同步运行
delay: 1000 // 延迟1秒开始
}
}
}
六、高级动画技术
1. 骨骼动画
// 创建骨骼层次结构
Qt3DCore::QEntity *skeletonRoot = new Qt3DCore::QEntity(rootEntity);
Qt3DCore::QEntity *bone1 = new Qt3DCore::QEntity(skeletonRoot);
Qt3DCore::QEntity *bone2 = new Qt3DCore::QEntity(bone1);
// 创建骨骼变换
Qt3DCore::QTransform *bone1Transform = new Qt3DCore::QTransform();
bone1->addComponent(bone1Transform);
Qt3DCore::QTransform *bone2Transform = new Qt3DCore::QTransform();
bone2->addComponent(bone2Transform);
// 创建骨骼动画
Qt3DAnimations::QAnimationClip *skeletonClip = new Qt3DAnimations::QAnimationClip();
// 设置骨骼关键帧...
2. 形变动画
// 创建形变目标
Qt3DCore::QEntity *target1 = new Qt3DCore::QEntity(rootEntity);
Qt3DCore::QEntity *target2 = new Qt3DCore::QEntity(rootEntity);
// 创建混合形状
Qt3DCore::QBlendShape *blendShape = new Qt3DCore::QBlendShape(cubeEntity);
blendShape->addTarget(target1, 0.0f);
blendShape->addTarget(target2, 1.0f);
// 创建形变动画
QPropertyAnimation *morphAnim = new QPropertyAnimation(blendShape, "weights");
morphAnim->setDuration(2000);
morphAnim->setKeyValueAt(0.0, QVector<float>({0.0f}));
morphAnim->setKeyValueAt(0.5, QVector<float>({0.5f}));
morphAnim->setKeyValueAt(1.0, QVector<float>({1.0f}));
morphAnim->setLoopCount(-1);
morphAnim->start();
七、性能优化
- 批量渲染:合并相同材质的对象
- LOD技术:根据距离使用不同细节级别的模型
- 实例化渲染:重复使用相同网格的多个实例
- 异步加载:后台加载大型资源
- 剔除技术:视锥剔除、遮挡剔除
八、完整示例
1. 基于C++的旋转立方体
#include <QGuiApplication>
#include <Qt3DExtras/Qt3DWindow>
#include <Qt3DExtras/QOrbitCameraController>
#include <Qt3DCore/QEntity>
#include <Qt3DRender/QCamera>
#include <Qt3DExtras/QPhongMaterial>
#include <Qt3DCore/QTransform>
#include <QPropertyAnimation>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
Qt3DExtras::Qt3DWindow view;
QWidget *container = QWidget::createWindowContainer(&view);
container->resize(800, 600);
Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity();
view.setRootEntity(rootEntity);
// 创建相机
Qt3DRender::QCamera *camera = view.camera();
camera->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f);
camera->setPosition(QVector3D(0, 0, 40.0f));
camera->setUpVector(QVector3D(0, 1, 0));
camera->setViewCenter(QVector3D(0, 0, 0));
// 添加相机控制器
Qt3DExtras::QOrbitCameraController *camController =
new Qt3DExtras::QOrbitCameraController(rootEntity);
camController->setCamera(camera);
// 创建立方体
Qt3DCore::QEntity *cubeEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DExtras::QCuboidMesh *cubeMesh = new Qt3DExtras::QCuboidMesh();
Qt3DExtras::QPhongMaterial *cubeMaterial = new Qt3DExtras::QPhongMaterial();
cubeMaterial->setDiffuse(Qt::red);
Qt3DCore::QTransform *cubeTransform = new Qt3DCore::QTransform();
cubeEntity->addComponent(cubeMesh);
cubeEntity->addComponent(cubeMaterial);
cubeEntity->addComponent(cubeTransform);
// 创建旋转动画
QPropertyAnimation *anim = new QPropertyAnimation(cubeTransform, "rotation");
anim->setDuration(2000);
anim->setLoopCount(-1);
anim->setStartValue(QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), 0));
anim->setEndValue(QQuaternion::fromAxisAndAngle(QVector3D(0, 1, 0), 360));
anim->start();
container->show();
return app.exec();
}
2. 基于QML的3D动画
import QtQuick 2.15
import Qt3D.Core 2.15
import Qt3D.Render 2.15
import Qt3D.Input 2.15
import Qt3D.Extras 2.15
import Qt3D.Animations 2.15
ApplicationWindow {
visible: true
width: 800
height: 600
Entity {
id: root
Camera {
id: camera
projectionType: CameraLens.PerspectiveProjection
fieldOfView: 45
aspectRatio: 16/9
nearPlane: 0.1
farPlane: 1000.0
position: Qt.vector3d(0, 0, 40.0)
upVector: Qt.vector3d(0, 1, 0)
viewCenter: Qt.vector3d(0, 0, 0)
}
OrbitCameraController {
camera: camera
}
components: [
RenderSettings {
activeFrameGraph: ForwardRenderer {
camera: camera
clearColor: "black"
}
},
InputSettings { }
]
Entity {
id: cubeEntity
CuboidMesh {
id: cubeMesh
}
PhongMaterial {
id: cubeMaterial
diffuse: "red"
}
Transform {
id: cubeTransform
}
components: [cubeMesh, cubeMaterial, cubeTransform]
// 添加动画
NumberAnimation {
target: cubeTransform
property: "rotationX"
from: 0
to: 360
duration: 2000
loops: Animation.Infinite
}
NumberAnimation {
target: cubeTransform
property: "rotationY"
from: 0
to: 360
duration: 2000
loops: Animation.Infinite
running: false
delay: 1000
}
}
}
}