PivotPainter2 for Unity

#目次
[1.はじめに](#1-はじめに)
[2.テクスチャインポート時の処理](#2-テクスチャインポート時の処理)
[3.VertexShaderでの処理](#3-VertexShaderでの処理)
[4.親子関係について](#4-親子関係について)
[5.まとめ](#5-まとめ)
## 1. はじめに
この記事は、Unreal Engine機能のPivotPainterをUnityに移植したため、手順をまとめたものになっています。
※**この記事にはHoudiniは出てきません**
UE　　　　　　　　　　　　　　　　　Unity
<img width="300" alt="UE.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179006/52fa35f2-ae8f-62d5-5107-3e70e4bfce38.gif"><img width="300" alt="Unity.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179006/4eda9bbe-c260-b113-aed7-5db1ee6f49cd.gif">


## 2. テクスチャインポート時の処理
UnityにPivotPainter2のテクスチャを読み込む際には、圧縮設定をOffにして、サンプリングのフィルター設定をPointにする必要があります。
```c#:CustomTextureImport.cs
using UnityEngine;
using UnityEditor;
using System.Collections;

public class CustomTextureImport : AssetPostprocessor
{
    void OnPreprocessTexture ()
    {
        TextureImporter importer = assetImporter as TextureImporter;
            //制限を掛けなければすべてのテクスチャに適用してしまうため、exrと大文字のPNG拡張子のみ適用する
        if (System.IO.Path.GetExtension(assetPath) == ".exr" || System.IO.Path.GetExtension(assetPath) == ".EXR" || System.IO.Path.GetExtension(assetPath) == ".PNG")
        {
            Debug.Log(assetPath);

            importer.textureCompression = TextureImporterCompression.Uncompressed;
            importer.sRGBTexture = false;
            importer.npotScale = TextureImporterNPOTScale.None;
            importer.mipmapEnabled = false;
            importer.filterMode = FilterMode.Point;
            importer.maxTextureSize = 4096;
        }
    }
}
```
## 3. VertexShaderでの処理
PivotPainter2をUnityで使う場合、UEからの変換を行う必要があります。Z-upの左手系からY-upの左手系に変換し、その後座標情報を1/100に縮小します。UEではVertexOffsetにpivot座標を渡す処理になっていますが、私はpivot座標を使用して原点に戻す方法を採用しています。

```glsl:CustomTextureImport.shader
Texture2D _PivotPosATex;
Texture2D _XVecterATex;
SamplerState SamplerState_Point_Repeat;

float LineearSine(float value, float preiod)
{
    float frac_value = frac((value + (preiod * 0.25)) % preiod);
    float Lerp_value = lerp(frac_value * 2, (1 - frac_value) * 2, floor(frac_value * 2));
    return ((3 - (Lerp_value * 2)) * Lerp_value) * Lerp_value;
}
InFrag vert (InVertex v)
{
    InFrag o;

    float4 PivotPos = _PivotPosATex.SampleLevel(SamplerState_Point_Repeat, v.uv2.xy,0);
    //UE空間からUnity空間への変換
    PivotPos.xyz *= 0.01;
    PivotPos.xyz = float3(-PivotPos.x, -PivotPos.y, PivotPos.z);

    float4 XVecter = _XVecterATex.SampleLevel(SamplerState_Point_Repeat, v.uv2.xy,0);
    //UE空間からUnity空間への変換
    XVecter.xyz = float3(-XVecter.x, -XVecter.y, XVecter.z);

    //親子構造から拡縮順番を作成するコード
    float hierarchy_value = 1-(clamp((( XVecter.a * 6.0) + 1) - ((6.0 + 1) * LineearSine(_Time.y / 5, 5.0f)), 0, 1));
    //一度ピボットポイントを使用しグループを原点に戻し、回転や拡縮を加えて戻す。
    v.vertex.xyz -= PivotPos.xyz ;
    v.vertex.xyz *= hierarchy_value;
    v.vertex.xyz += PivotPos.xyz ;

    o.vertex = TransformObjectToHClip(v.vertex.xyz);
    
    return o;
}
```
## 4. 親子関係について
PivotPainterの親子関係に関する具体的な記事は見つかりませんでしたが、ここでは簡単にそのコードについて説明します。

PivotPainter2では、テクスチャのアルファチャンネルに情報を設定できます。今回は「Hierarchy Depth（階層の深さ）」を使用しています。このパラメータは、Blenderでメッシュの親子関係を数値として保存したものです。

Hierarchy Depthを使って、親子関係を深度情報として取得します。また、Parent indexなどの親子関係を浮動小数点として保存する方法もあります。
## 5. まとめ
PivotPainterは、状況や目的に応じてテクスチャに必要最低限の情報を格納し、それを最大限にシェーダーで活用することで、軽量かつダイナミックな頂点アニメーションを実現する仕組みです。

情報が少なく、活用事例も主にUnreal Engine（UE）に限られるため、今回の記事ではUnityでの活用方法を提示することを目的としました。ご指摘やご意見がありましたら、コメントにてお寄せください。

また下記の記事およびツールを引用、使用しています。
https://qiita.com/Muteriku/items/857e02ac746b091a73f3
https://github.com/Gvgeo/Pivot-Painter-for-Blender