Blenderのパーティクルシステム、ダイナミックペイント、ジオメトリノードの連携手法の検討 その１

# はじめに
<!-- 発端や概要を記載 -->
本記事ではBlenderのパーティクルシステム、ダイナミックペイント、ジオメトリノードを連携する方法について色々検証したので振り返り用にまとめてみました。
同じ様に悩んでいる人の助けになれば幸いです。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [モチベーション](#モチベーション)
1. [目標](#目標)
1. [解説](#解説)
1. [２種類のダイナミックペイント](#２種類のダイナミックペイント)
1. [重みによるマージ](#重みによるマージ)
1. [まとめと考察](#まとめと考察)
1. [雨のシーンの参考動画](#reference)


# モチベーション
<a id="#モチベーション"></a>
ことの発端はBlenderでアニメの１シーンのようなリッチな雨の風景をつくりたい！という感じです。(新海誠監督の「言の葉の庭」の雨のシーンみたいな・・・)
Everything CGさんの作品(https://www.youtube.com/watch?v=TP2wG8yFlAw&list=PLsuDLbyvLYgq3vxV3afbdCUHWJKZ6_IXz&index=5) のHoudiniファイルで考え方を学んでBlenderで再現してみました!

まず、雨のシーンの構成要素として今回は雨粒、リアルな水面の波紋、雨粒が水面に落ちたことで発生する水飛沫を制作しました。雨粒をパーティクルシステム、波紋をダイナミックペイント、水飛沫となるセルルックオブジェクトのアニメーションをジオメトリノードでそれぞれ制作しました。ここで雨のシーンは

**雨粒が水面に落ちる → 波紋が発生する → セルルックの水飛沫が発生する**

の順でアニメーションが動きます。
よってこの3つの動きをスムーズにアニメーションさせるにはパーティクルシステム、ダイナミックペイント、ジオメトリノードの３つの連携が必須になります。

パーティクルシステムとダイナミックペイントの連携は既に他の方のたくさんのチュートリアルがあるのでそちらをご覧ください。
問題は**ダイナミックペイントとジオメトリノードの連携**もしくは**パーティクルシステムとジオメトリノードの連携**です。自分が調べた範囲ではほとんど記事がなく１か月くらい悩んだので今回記事にすることにしました。

<iframe width="1236" height="695" src="https://www.youtube.com/embed/sg0AbyenwQ8" title="Rain like a Scene from an Anime | Blender" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

このプロジェクトでは
①ダイナミックペイントと既存のジオメトリノードで組み合わせた手法
②パーティクルシステムと自作アドオンParticle Trackerを用いた手法
③パーティークル含めすべてジオメトリノードで作成する手法
の３つの手法について検討しました。
一つずつ記事にしていく予定です。今回は①の手法を解説します。

<a id="#目標"></a>
# 目標
**雨粒(パーティクル)が落ちた位置で水面を揺らして更に水飛沫オブジェクトを配置する**


<!-- 各チャプター -->
<a id="#解説"></a>
# 解説

まず今回つくったダイナミックペイントとジオメトリノードについて軽く解説します。
まずダイナミックペイント

<div align="center">
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/830c25d9-5ca4-aa90-4a85-abf2d90311c6.png" alt="属性" title="タイトル">
</div>

<div align="center">
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/4feb3fff-ff18-ce37-71a2-475e8a36fe90.png" alt="属性" title="キャンバスの設定">
</div>
<div align="center">
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/bea1ffd6-c0c0-a336-f0bc-58d25e537035.png" alt="属性" title="ブラシの設定">
</div>

このようにパーティクルシステムシステムをブラシとしてキャンバスであるグリッド(水面)を動かします。
後述しますが今回の手法ではグリッドの分割数も重要なパラメータとなってきます。

次に水飛沫のセルルックオブジェクトとジオメトリノード
![スクリーンショット 2024-05-10 162747.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/be9d3df3-3523-369d-fb81-706e46b57806.png)
![スクリーンショット 2024-05-10 164538.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/cb6e1303-09dd-d06c-2fff-61e96e621f76.png)
![スクリーンショット 2024-05-10 164607.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/4dd02d56-1848-1ac4-4718-39114055917f.png)

今回はキーフレームを使わずシミュレーションゾーンを使って２コマ打ちでアニメーションを動かしています。
また水飛沫オブジェクトのアニメーションは「ポイントにインスタンス作成」ノードを使っています。
水飛沫は基本的にモディファイアとジオメトリノードでプロシージャルに作成しました。

次にどのようにダイナミックペイントとジオメトリノードを連携させたかの考え方を説明します。
まずワークフローと図は下記のようになります。


ポイントは
**・水を揺らすダイナミックペイント「波」と重みを表すダイナミックペイント「ウェイト」を使うこと**
**・ジオメトリノードで頂点グループの重みを使った頂点のマージを行う**
の２つです。
それぞれ解説します。


<a id="#ダイナミックペイント"></a>
# ２種類のダイナミックペイント
まずダイナミックペイントのサーフェスタイプには複数の種類があります。最もポピュラーなのは今回も使ったリアルな水の動きを再現できる「波」です。波紋の動きについてはこの「波」を使いました。
![スクリーンショット 2024-05-10 160800.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/3a0bebff-2247-24d3-7c90-4a7c9d56ca08.png)


今回はサーフェスタイプ「ウェイト」も使いました。「ウェイト」は頂点ウェイトグループを生成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/3b474c71-52f6-5896-9c18-4d078b43dccf.png)
頂点ウェイトグループとは重み付き頂点グループです。
重みをもっているのでパーティクルが当たった部分の頂点の重みは大きく、そこから離れている頂点の重みは小さくなります。
よって
**「出力」の頂点グループの情報(上の図のdp_weight)を「名前付き属性」ノードでジオメトリノードに渡すことでパーティクルが落ちたおおよその位置の情報をジオメトリノード内で扱えるようになります。**

ここで**おおよその位置**という表現をしたのは水面が複数の頂点からなるグリッドであることが関係しています。ジオメトリノードに渡しているのは**あくまで重みを持っているグリッドの頂点グループでありパーティクルが落ちた一点の座標を渡しているわけではありません！**
つまり複数のポイント(頂点)を渡しているので、このまま「ポイントにインスタンス作成」ノードにポイントを渡すと付近の複数のポイントで水飛沫オブジェクトが発生してしまいます。

この問題を解決するのが<strong>「距離でマージ」ノード</strong>です。

<a id="#マージ"></a>
# 重みによるマージ
まず頂点の重みがどうなっているか見てみましょう。
![スクリーンショット 2024-05-10 172255.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/1f2983af-dd3c-fa34-2be0-42b0fa7128c4.png)

上の図は頂点の重みを円柱の高さで表したのもです。重みがパーティクルを中心に円状に広がっているのが分かります。

これを「距離をマージ」ノードで１つの頂点にします。
![スクリーンショット 2024-05-10 172223.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/d2a916af-a1a3-fcb2-29aa-18e4890ff830.png)

**名前付き属性で「ウェイト」の頂点グループ情報を持ってきます(図のdp_weight)これを「距離でマージ」ノードの選択に繋ぐと重みに基づくマージができます。** 重みのない点はマージされません(便利！)。
複数の点が一点にマージされたのが分かります。
![スクリーンショット 2024-05-10 172659.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788547/02bee594-2c90-188b-aa39-3566a236b4e9.png)
重み付き頂点グループと「ジオメトリ削除」を組み合させてこのマージされたポイント以外を削除できます。
あとはこのマージされたポイントを使って水飛沫オブジェクトを配置してシミュレーションゾーンでアニメーションを動かします。



# まとめと考察
<a id="#まとめと考察"></a>
以上よりダイナミックペイントとジオメトリノードの連携ができました。

しかしこの手法にも下記のような問題点があります。
**・「距離でマージ」ノードのパラメータの調整が必須**
**・グリッド(水面)の分割数問題**
前者について、距離でマージしているのですが確実に一点にマージされるのではなく場合によっては2点にマージされる場合があります。その場合は「距離でマージ」ノードを2つ使うと１つのポイントにマージされます。また、いい感じにマージするにはマージに使う距離の調整も必須です。
後者について、グリッドの頂点が頂点グループになるのでこの頂点の分割数が「距離でマージ」ノードのパラメータが影響してきます。分割数が多すぎるとマージしても複数の点になる可能性があり。逆に少なすぎるとそもそも「波」の動きが悪くなりまた、パーティクルがグリッドの間をすり抜けて頂点が重みを持たない場合がありました。

数カット程度つくる場合はパラメータの調整ができますが、もっと汎用性が必要な場合は改良が必要です。

次回は自作アドオン「Particle Tracker」を使った手法を解説します。
読んでいただきありがとうございます。


少し話は逸れますが雨粒のオブジェクト、雨のアニメーションの考え方は下記の動画解説を参考にしています。
とても参考になりますので雨のシーンについて知りたい人はぜひご覧ください。

<a id="#reference"></a>
# 雨のシーンの参考動画
-Everything CG さん
https://youtu.be/TP2wG8yFlAw?list=PLsuDLbyvLYgq3vxV3afbdCUHWJKZ6_IXz
-Tawan Sunflower さん
<iframe width="1236" height="695" src="https://www.youtube.com/embed/7xFROhVB9pA" title="Rain and Splashes Simulation | Blender Tutorial" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>