以下是 Quick3D.Particles 模块在 Qt 6.10 和 6.11 中新增功能的概述。本次更新的目标是支持与场景产生视觉交互效果的粒子特效,同时避免引入高开销的模拟计算。本文将以雨滴效果为例,逐步介绍各项新特性。
雨滴效果由两部分构成:粒子撞击场景模型上的过程,以及撞击后触发的飞溅粒子效果。
那么,如何在不进行高开销光线-模型交点计算的前提下,让粒子“命中”模型?这里需要用到一个名为 ParticleModelShape3D 的类型,它可以按照指定模型的轮廓发射粒子,并通过在发射器中设置速度,将其发射到特定方向 。只要将速度方向朝向天空,并令粒子系统时间倒流,就会产生粒子从上方落下、撞击模型的视觉效果。

使用零速度轨迹发射器(Trail Emitter)实现雪花积累效果。
ParticleEmitter3D.reversed 属性
若将整个系统时序倒转运行,则会给同一系统中添加其他粒子效果带来不便 。为此,我们在发射器上新增了 reversed 属性,允许仅对该发射器启用时序倒转,而其他粒子发射器仍按照正常时间顺序运行。
以下示例展示了如何使用线条粒子(Line Particles)、模型形状(Model Shape)与轨迹发射器(Trail Emitter)来实现雨滴及溅水效果。
// Rain particle
LineParticle3D {
id: rainParticle
...
}
Component {
id: modelComponent
Model {
// The mesh containing only the top parts of the sphere
source: "meshes/sphere_top.mesh"
}
}
// Rain particle emitter
ParticleEmitter3D {
id: emitter
particle: rainParticle
reversed: true
shape: ParticleModelShape3D {
model: modelComponent
fill: false
}
velocity: VectorDirection3D {
direction: Qt.vector3d(0, 800, 0)
directionVariation: Qt.vector3d(2, 0, 2)
}
}
// Splash particle
SpriteParticle3D {
id: splashParticle
...
}
// Splash particle trail emitter following the rain particle
TrailEmitter3D {
follow: rainParticle
DynamicBurst3D {
id: splashBurst
amount: 20
amountVariation: 2
triggerMode: DynamicBurst3D.TriggerEnd
}
emitBursts: splashBurst
particle: splashParticle
velocity: VectorDirection3D {
direction: Qt.vector3d(0, 0, 10)
directionVariation: Qt.vector3d(50, 50, 1)
}
}
现在我们可以实现雨水击中模型并向特定方向溅起水花的效果。但如果溅水能随模型表面形状自适应——即粒子以特定角度击中曲面时,沿反射角度溅出——效果会更理想。
ParticleEmitter3D.EmitMode
发射器的发射模式(EmitMode)支持更精细的粒子方向控制。在默认模式之外,新增了两种基于模型形状的方向控制模式。
ParticleEmitter3D.SurfaceNormal :将发射方向改为遵循表面法线。当发射速度朝向 Z 轴时,粒子将沿表面法线方向发射。
ParticleEmitter3D.SurfaceReflected:用于轨迹发射器,发射方向为根据表面法线与被跟随粒子速度计算所得的反射向量

Default 与 SurfaceNormal 发射模式在 Suzanne 网格上的对比效果。
将轨迹发射器的发射模式设置为 ParticleEmitter3D.SurfaceReflected ,溅水粒子即可从模型表面产生反射效果。
TrailEmitter3D {
...
emitMode: ParticleEmitter3D.SurfaceReflected
}

粒子在球体表面使用 SurfaceReflected 模式弹射的效果演示。
至此,我们已具备针对单个模型实现雨滴效果的基本构件。但如何将其扩展到包含多个模型的应用场景?若为每个模型单独添加雨滴效果,会带来副作用:各模型拥有各自的雨滴密度,导致场景雨势不均匀;此外,雨水还会穿透彼此重叠的模型 —— 例如,当模型位于地面上方时,地面仍会在模型正下方产生雨滴。为解决上述问题,可以提前计算整个场景的网格,但这样得到的是静态网格,导致模型无法在场景中移动 。
ParticleSceneShape3D
场景形状(Scene Shape) 可以根据场景中的模型,动态计算整个场景的形状。
该形状以一张覆盖在场景上方的网格来表示,网格的每个顶点对应其下方所有模型多边形的最高点。当相邻顶点之间高度差过大,或网格顶点下方不存在模型多边形时,将在网格中创建孔洞。
当场景中的模型发生移动时,形状会自动重新计算,因此也适用于动态场景。开发者可以设置网格分辨率、网格范围(决定形状大小)、中心位置,以及指定需要从计算中排除的节点。此外,还可以通过属性获取几何数据,例如用于调试目的。
ParticleEmitter3D {
id: emitter
shape: ParticleSceneShape3D {
id: sceneShape
scene: sceneRoot
sceneCenter: Qt.vector3d(0, 0, 0)
sceneExtents: Qt.vector3d(1000, 500, 1000)
excludedNodes: [debugNode]
shapeResolution: 50
}
}
Model {
id: debugNode
geometry: sceneShape.geometry
}

雨滴效果在汽车配置器演示项目中的应用。
汽车配置器演示项目已随 Qt 6.11 加入雨滴效果,并同步附带了雪花效果。