【Unity】VFX Graph で 動的に Attribute Map を生成し、Position Map にセットする方法

【Unity】VFX Graph で 動的に Attribute Map を生成し、Position Map にセットする方法

どーも、ぐるたか@guru_takaです。

本記事では、C# スクリプトで動的に Attribute Map を生成し、Position Map にセットし、メッシュをパーティクル化していきます。成果物はこちら!

Unity 公式の下動画のように、動的なメッシュに対して VFX Graph を使いたいことがモチベーションです。そのための基本技術と備忘録として、まとめています。


MEMO
VFX Graph では、メッシュから静的に Point Cache を生成し、メッシュをパーティクル化する記事も書いています。

【Unity】VFX Graph で Point Cache(ポイントキャッシュ)を使い、メッシュをパーティクル化する

本記事ではシンプルかつミニマムな構成でわかりやすく、動的な Attribute Map の生成方法を紹介したいために、メッシュのパーティクル化をトピックとしています。

実行環境
・Unity:2020.3.2f1
・Visual Effect Graph:10.4.0

前提知識

VFX Graph で、メッシュの情報を扱うためには、Attribute Map を作成する必要があります

Attribute Map とは、パーティクルの固有値(ポジションなどの情報)が格納された Texture2D(データバッファ)です。Texture2D は RGBA まで情報が格納できるため、4次元まで拡張可能

そして、生成した Attribute Map を Position Map や Vector Map などに渡すことで、様々な頂点における情報(ポジションや法線など)が VFX Graph で使用できます!

VFX Graph によるパーティクル化のノード構成

まず Position Map からメッシュをパーティクル化するノードは下図の通りです。基本的な構成は下記事と殆ど同じになっています。詳細は下記事をご覧ください!
【Unity】VFX Graph で Point Cache(ポイントキャッシュ)を使い、メッシュをパーティクル化する

VFX Graph によるパーティクル化のノード構成

外部から Texture2D を渡したい時は、blackboard > Texture2D とすることで、プロパティ化できます。

全体のコード

後は、動的に Texture2D(Attribute Map)を生成 → PositionMap にセットする C# スクリプトを記述するだけです。全体像は以下のようになります!

STEP.1
パーティクル化したいメッシュの情報を読み込み
STEP.2
各頂点のポジション情報を Texture2D(Attribute Map)に保存
STEP.3
ポジション情報が保存された Texture2D を PositinoMap に渡す

全体のコードは以下のようになります。コメントで解説ています。

BakeMeshSimple.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.VFX;

[RequireComponent(typeof(VisualEffect))]
public class BakeMesh : MonoBehaviour
{
    public Texture2D BakedTexture { get; private set; }

    private VisualEffect _vfx = null;
    private Mesh _mesh = null;

    private Color[] _colorBuffer = null;

    private void Awake()
    {
        Initialize();
        // プロパティ「PositionMap」 に頂点のポジション情報が保存された Texture2D をセット
        _vfx = GetComponent();
        _vfx.SetTexture($"PositionMap", BakedTexture);
    }

    public void Initialize()
    {
        // アタッチされたオブジェクトの MeshFilter からメッシュの情報を取得
        _mesh = GetComponent().mesh;

        // 頂点のポジション情報を取得
        Vector3[] vertices = _mesh.vertices;

        // 頂点数
        int count = vertices.Length;

        // Texture2D で h × w にポジション情報を落とし込むため、頂点数の平方根を取得
        float r = Mathf.Sqrt(count);

        // w、h を整数化するため、頂点数の平方根を切り捨て
     // 切り上げの場合、 w × h が頂点数より大きくなり、Texture2D に (0,0,0, 0) の情報が余るので注意
        int size = (int)Mathf.Floor(r);

        // Texture2D に保存するためのバッファ
        _colorBuffer = new Color[size * size];

        // Texture2D(AttributeMap)のセットアップ
        BakedTexture = new Texture2D(size, size, TextureFormat.RGBAFloat, false);
        BakedTexture.filterMode = FilterMode.Point;
        BakedTexture.wrapMode = TextureWrapMode.Clamp;

        // Texture2D に頂点のポジション情報を保存
        UpdatePositionMap();
    }

    private void UpdatePositionMap()
    {
        // for よりも foreach の方が処理が圧倒的に速いため、foreach を採用
        // _mesh.vertices の方が Texture2D のサイズ(w × h)より大きいため、_colorBuffer.Length まで繰り返すように調整
        int idx = 0;
        foreach (Vector3 vert in _mesh.vertices.Take(_colorBuffer.Length))
        {
            _colorBuffer[idx] = VectorToColor(vert);
            idx++;
        }

        // Texture2D に頂点のポジション情報を Texture2D にセット
        BakedTexture.SetPixels(_colorBuffer);
        BakedTexture.Apply();
    }

    private Color VectorToColor(Vector3 v)
    {
        return new Color(v.x, v.y, v.z, 0.0f);
    }

}

ポイントは以下3つです!

  • 頂点数のポジション情報を取得し、バッファに保存
  • バッファに保存されたポジション情報を、RGBA として そのまま Texture2D にセット
  • ポジション情報が保存された Texture2D を プロパティ PositionMap にセット

上記の基本的なポイントさえ押せておきば、特に難しいことはありません!

頂点数の平方根を切り上げする場合は、頂点数よりも w × h のカラーサイズが大きくなるため、注意してください!余るピクセルの (0,0,0,0) が悪さする恐れがあります。私は最初、平方根の切り上げで、だいぶハマりました。。

また、for 構文ではなく、forwach 構文を使うのも、大事なポイントです。for 構文の場合、Update メソッドで Texture2D を更新する時に、重すぎて使い物にならなくなります

最後に、下図のようにアタッチすれば、メッシュのパーティクル化が完成です!

成果物:VFX Graph で 動的に Attributeし、Position Map にセットする方法

最後に

以上です。今回は非常に簡単なケースでしたが、応用範囲は非常に広いと感じます。

ぜひ色々と試してみてください!

参考リンク

参考 VFX Graph の可能性を探る!PointCache動的生成、VAT拡張|fuqunaganote 参考 Unity VFX Graphでposition mapを使って導蟲風パーティクルを作るe.blog

コメントを残す