【Unity】VFX Graph でモデルのテクスチャのカラーを適用する方法【UV 値を使用】

VFX Graph でモデルのテクスチャのカラーを適用する方法

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

VFX Graph で Kyle くんのボクセル化に成功しました。ポイントは各メッシュの頂点におけるキューブに対し、テクスチャのカラーを適用させたことです。

boxel_color_vfx_dynamic

備忘録として、モデルのテクスチャにおけるカラーを VFX Graph でうまく適用させる方法を紹介します!

Point Cache や動的 Position Map で頂点のポジション情報を扱う方法は以下記事を御覧ください!
【Unity】VFX Graph で Point Cache(ポイントキャッシュ)を使い、メッシュをパーティクル化する

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

全体像

実は 2021/5/10 時点で、モデルのテクスチャにおけるカラーを VFX Graph でうまく適用するデフォルトの機能はありません

そのため、以下の手順でモデルのテクスチャから、適切にカラー情報を反映させます。

STEP.1
各頂点におけるポジション情報と UV 値を、それぞれ Texture2D に保存
STEP.2
Texture2D に保存された UV 値を Position にセット
STEP.3
UV 値がセットされている Position からモデルのテクスチャを参照し、カラー適用
STEP.4
UV 値が保存されている Position に対し、Texture2D に保存された ポジション情報に上書き

方法については、以下の記事を参考にしています!

参考 VFX Graph の可能性を探る!PointCache動的生成、VAT拡張|fuqunaganote
MEMO
下記事の応用版のため、併せてチェックすることをオススメします!
【Unity】VFX Graph で 動的に Attribute Map を生成し、Position Map にセットする方法【Unity】VFX Graph で 動的に Attribute Map を生成し、Position Map にセットする方法

VFX Graph のノード構成

VFX Graph のノード構成は下図の通りです。

boxel_color_vfx

UVMap を通じて、UV 値をポジション情報に書き込み、そこからテクスチャのカラー情報を取得。最後に PositionMap を通じて、正しいポジション情報に書き換えています!

全体のコード

各頂点の UV 値を Texture2D に保存し、VFX Graph の UVMap 渡すコードは以下の通りです。

下記事で紹介している全体のコードに対し、ポジション情報に加えて UV 値も取得しています。基本的なコードは殆ど変わりません。詳細は下記事をチェックしてみてください!

また、差分となる追記コードはコメントしています。

【Unity】VFX Graph で 動的に Attribute Map を生成し、Position Map にセットする方法【Unity】VFX Graph で 動的に Attribute Map を生成し、Position Map にセットする方法
BakeMeshSimple.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.VFX;

[RequireComponent(typeof(VisualEffect))]
public class BakeMeshToTexture : MonoBehaviour
{

    public Texture2D BakedTexture { get; private set; }

    private VisualEffect _vfx = null;
    private Mesh _mesh = null;
    private Color[] _colorBuffer = null;

    // 追加
    private Color[] _colorUVBuffer = null;
    public Texture2D BakedUVTexture { get; private set; }

    private void Awake()
    {

        Initialize();
        _vfx = GetComponent();
        _vfx.SetTexture($"PositionMap", BakedTexture);
        // 追加
        _vfx.SetTexture($"UVMap", BakedUVTexture);
    }

    public void Initialize()
    {

        _mesh = GetComponent().mesh;
        Vector3[] vertices = _mesh.vertices;

        int count = vertices.Length;
        float r = Mathf.Sqrt(count);
        int size = (int)Mathf.Floor(r);


        _colorBuffer = new Color[size * size];

        BakedTexture = new Texture2D(size, size, TextureFormat.RGBAFloat, false);
        BakedTexture.filterMode = FilterMode.Point;
        BakedTexture.wrapMode = TextureWrapMode.Clamp;

        // 追加
        _colorUVBuffer = new Color[size * size];

        BakedUVTexture = new Texture2D(size, size, TextureFormat.RGBAFloat, false);
        BakedUVTexture.filterMode = FilterMode.Point;
        BakedUVTexture.wrapMode = TextureWrapMode.Clamp;

        UpdatePositionMap();

        // 追加
        UpdateUVMap();
    }

    private void UpdatePositionMap()
    {
        int idx = 0;
        foreach (Vector3 vert in _mesh.vertices.Take(_colorBuffer.Length))
        {
            _colorBuffer[idx] = VectorToColor(vert);
            idx++;
        }

        BakedTexture.SetPixels(_colorBuffer);
        BakedTexture.Apply();
    }

    // 追加
    private void UpdateUVMap()
    {
        int idx = 0;
        foreach (Vector3 uv in _mesh.uv.Take(_colorUVBuffer.Length))
        {
            _colorUVBuffer[idx] = VectorToColor(uv);
            idx++;
        }
        BakedUVTexture.SetPixels(_colorUVBuffer);
        BakedUVTexture.Apply();
    }

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

オブジェクトのインスペクター

あとは下図のように、オブジェクトのインスペクターを設定すれば完成です!

下 GIF のように、Kyle くんがボクセル化すれば成功になります!

boxel_color_vfx_dynamic

最後に

以上です。

モデルのテクスチャにおけるカラーも VFX Graph で扱うことで、より表現の幅が広がるように感じます!

VFX Graph 学習者の参考になれば幸いです

参考リンク

参考 VFX Graph の可能性を探る!PointCache動的生成、VAT拡張|fuqunaganote

コメントを残す