Qt Quick 3Dパーティクルによる雨エフェクト表現

このブログは「Rain effect with Quick3D Particles」の抄訳です。

本記事は、Qt 6.10 および 6.11 向けに Quick3D.Particles モジュールに追加された新機能の概要です。目的は、高コストなシミュレーションや計算を伴わずに、シーンと相互作用しているように見えるエフェクトをサポートすることです。具体的には、新機能の説明において雨エフェクトを例として使用します。

雨エフェクトは、雨がシーンに当たる粒子と、シーンモデルに当たった後の飛沫パーティクル(スプラッシュ)エフェクトで構成されます。

では、高コストなレイモデル交差計算なしで、どのようにして粒子をモデルに衝突させるのでしょうか? 実は、ParticleModelShape3D という型があり、これは指定されたモデルの形状に沿って粒子を放出します。エミッターで速度を設定することで、特定の方向に粒子を放出できます。速度を空の方向に設定し、パーティクルシステムの時間を逆方向に走らせると、粒子がモデルに衝突しているように見えます。

reversedSnow

Snow accumulation using trail emitter with zero velocity.

ParticleEmitter3D.reversed プロパティ

システム全体を逆方向に実行すると、同じシステムに他のパーティクルエフェクトを追加するのが煩雑になるため、エミッターに新しいプロパティreversedを追加しました。これにより、このエミッターのみを逆方向に実行でき、他のパーティクルエミッターは通常通り順方向に実行できます。

以下に、ラインパーティクルによる雨、モデル形状、およびスプラッシュ効果を実現するトレイルエミッターの実装方法を示します。


// 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

エミッタの発射モードにより、放出されるパーティクルをより精密に制御できます。デフォルトに加え、モデルの形状に基づいて方向を制御する2つのモードを追加します。

ParticleEmitter3D.SurfaceNormal プロパティは、放出方向を表面法線に沿うように変更します。放出速度が z 軸方向を向いている場合、粒子は表面法線の方向に放出されます。

ParticleEmitter3D.SurfaceReflected はトレイルエミッターで使用され、放出方向は反射ベクトル方向となります。この反射ベクトルは、表面法線と追跡対象粒子の速度から計算されます。

emitModes

Suzanneメッシュにおけるデフォルトおよび表面法線のエミットモード

トレイルエミッターの放出モードをParticleEmitter3D.SurfaceReflectedに設定すると、飛沫パーティクルが表面から反射されるようになります。


TrailEmitter3D {
    ...
    emitMode: ParticleEmitter3D.SurfaceReflected
}

reflectedParticles

サーフェス反射モードを使用した球体からの粒子反射

では、1つのモデルに対する雨エフェクトの構成要素が揃ったところで、複数のモデルが存在するシーンにこれを追加する方法について考えます。各モデルに個別に追加すると、副作用が生じます。雨エフェクトを適用したモデルはそれぞれ独自の雨密度を持つため、シーン全体で均一な雨表現が得られなくなるのです。また、雨は重なり合ったモデルを透過してしまいます。例えば、地面に配置したモデルの真下に雨が表示されるといった現象が発生します。この問題を回避するには、シーン全体のメッシュを事前に計算する方法がありますが、これは静的なメッシュとなるため、シーン内のモデルを動かせなくなります。

ParticleSceneShape3D

SceneShapeは、シーン内のモデルに基づいてシーン全体の形状を動的に計算します。

形状はシーン上に配置されたグリッドとして計算され、グリッドの各頂点は対応するモデルのポリゴンの最頂点に位置します。隣接する頂点間の高さが大きすぎる場合、またはグリッド頂点の下にモデルのポリゴンが存在しない場合、グリッドに穴が生成されます。

シーン内でモデルが移動すると形状は再計算されるため、動的なシーンでも使用可能です。グリッドの解像度、形状サイズを設定するグリッド範囲、形状の中心点を設定でき、形状計算から除外すべきノードを指定することもできます。また、デバッグ目的などで利用可能なプロパティとしてジオメトリを取得することも可能です。

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
    }

car-rain

カーコンフィギュレータデモにおける雨効果

Qt 6.11のcar-configuratorデモに、雨効果と雪効果が追加されました。


Blog Topics:

Comments