アバターの着せ替え手順紹介

アバターの着せ替え手順を紹介したいと思います
アバターというとVRMやVRChat向けなどいろいろあると思いますが、今回はどんなアバターにも使える汎用的な手法を紹介したいと思います
その分少しハードルは高いかも…

モデルはSUZURIさんの墨澄(スミスミ)ちゃんと

https://suzuri.jp/surisurikun/digital_products/53046?srsltid=AfmBOopg_itR2FitDycSTh7Qdd_83xhDGPyG5z_hA5nztOeqj06PWxEP

3BONさんのTech Mesh (for Female avatar)をお借りしました

https://booth.pm/ja/items/5848688

スミスミちゃんにこのズボンを履かせてみましょう

1. FBXで書き出します

用意したモデルたちをUnityで読み込みます
Unityには公式でFBX Exporterが用意されているのでこちらを利用します(Autodesk FBX SDKを利用しているのでそこそこ信頼性は高いです

2. 3dsMAXで読み込みます

3dsMAXかよ!!!と突っ込まれそうですが、Blenderでも何でも他のDCCツールでも構いません
残念ながら私が慣れ親しんだツールが3dsMAXだったというだけです…

とりあえず読み込んでみます
もちろんサイズは全然合いません

とりあえず難しいことは考えずにFFDで形を合わせていきます
いったんスキンウェイトのことは忘れましょう

ぐにょっと
股の高さも合わないのでこれも合わせます

足部分も
便利ですねFFD

これが終わったらスキニングです
スキンウェイトは元のものを維持しながらBoneを入れ子にしたりして、衣装とアバターを一体化する方法もありますが、Boneの位置が合わなかったりしてどんな形状のものでも好きに移植できるというわけではないので今回は汎用性の高いスキンのつけなおしを選んでいます
ちょっぴり面倒ですがね

3dsMAXにはSkinWrapという機能があります
既存のスキンを持ったオブジェクトを参照していい感じに補完して、スキンウェイトを設定してくれるというものです
今回はこれを「面変形」に設定し、参照先に元のスミスミちゃんのメッシュを割り当てました

これだけで動画のようにそれっぽく動きます
意外と簡単にできそうな気がしませんか?

最後はうまくいってない部分をちょちょっと修正します
修正するときにはあらかじめ足を折り曲げるようなアニメーションキーを設定しておくと便利です
折り曲げた状態を見ながらスキンウェイトを調整できます

さぁ調整していきましょう
SkinWrapをSkinに変換します

ウェイトツールを選び

「エンベロープを編集」→「頂点」にチェック

Boneを右のListから選択し、ウェイトを設定していきます

3dsMAXには他のDCCツール同様、ミラー機能もありますので片側だけ調整できたらさっと移植することもできます
「ミラー閾値」でどのくらいずれている頂点でも同一とみなすか設定できます

一通りスキンウェイトを調整して
Unityへエクスポートして、マテリアルをアサインしなおしたら…

可愛くてちょっとパンクなスミスミちゃんの完成です


PreviewRenderUtilityを利用してParticleを表示したい!

UnityでParticle SystemのPreview欲しいですよね
でもデフォでいい感じのものがない(カメラの位置とか再生位置どこにしとくんや、BoundingBoxが一番でかいTimeを毎回計算するんかホンマか!?みたいな話があるのでそれはそうなんですが

そこでPreviewRenderUtilityを使っていい感じのアイコンを作ってしまいましょうというのが今回の記事です

そもそもPreviewRenderUtilityって何ぞやという話はこちらから

https://light11.hatenadiary.com/entry/2020/02/29/211114

とはいえPreviewRenderUtility自体は公開されているものではないため、Unityの気分次第で変更されることも粉砕されることもあると思いますので、そこらへんは自己責任でお願いします

Prefabインスタンスを生成する際にはGameObject.InstantiateではなくPreviewRenderUtility.InstantiatePrefabInSceneを使おう

お察しのよい方はお気づきかもしれませんがGameObject.Instantiateなんて使おうものなら、今Editorで開かれているSceneにPrefabのインスタンスが作られてしまいます

GameObjectをプレビュー用のSceneに配置する際にはPreviewRenderUtility.AddSingleGO

PreviewRenderUtility.AddSingleGOにGameObjectを渡すだけでプレビュー用のSceneに配置されます

StaticPreviewとPreviewの使い分け

Textureが欲しい場合はBeginPreview&EndPreview
Texture2Dが欲しい場合はBeginStaticPreview&EndStaticPreview
です
StaticPreviewでない場合はPreviewRenderUtilityのCleanupを書けるとレンダリング結果も消えてしまいます

それらを踏まえて

var previewRenderUtility = new PreviewRenderUtility();
var gameObject = previewRenderUtility.InstantiatePrefabInScene(prefab);
            
previewRenderUtility.BeginStaticPreview(rect); //初期化

SetupParticles(gameObject); //ここでなんやかんやParticleSystemの設定をします
previewRenderUtility.AddSingleGO(gameObject);
        
previewRenderUtility.camera.farClipPlane = distance * 2;
previewRenderUtility.camera.transform.rotation = Quaternion.Euler(10, 0, 0);
previewRenderUtility.camera.transform.position = new Vector3(0, なんかいい感じの高さ, いい感じの距離);

previewRenderUtility.Render();

var texture2D = previewRenderUtility.EndStaticPreview(); //出力

previewRenderUtility.Cleanup(); //使い終わったら破棄してあげましょう 破棄しないとSceneが残り続けます

return texture2D;

SetupParticlesの中には、ParticleSystem.Simulateを入れたりだとか、子とかSubEmitterとかの処理を入れておくとよいと思います。


Unity&MacでShell scriptを使いたい!

UnityでShell scriptを使ってなにがしかを実行したいことってありますよね。
いろいろ試してみてこれが良さそうだとなったものを記録しておきます。

Unity起動時にズバババっと処理されるように、InitializeOnLoadにしてあります。

[InitializeOnLoad]
public class Startup
{
    static readonly string shPath =
        Application.dataPath + "/Hoge.sh";

    static Startup()
    {
#if UNITY_EDITOR_OSX
        StartExecForMac();
#endif
        AssetDatabase.Refresh();
    }

    static void StartExecForMac()
    {
        var p = new Process();
        p.StartInfo.FileName = "/bin/zsh";
        p.StartInfo.Arguments = $"-c \"zsh {shPath}\" ";
        p.StartInfo.Verb = "RunAs";
        p.StartInfo.UseShellExecute = true;
        p.Start();
        p.WaitForExit();
    }
}

UnityでWire Frame Renderingをしたい!

UnityでWire Frame Renderingをしたい場合の方法をご紹介します。
通常の状態でもScene ViewはWire Frame Renderingを行えますが、Unity RecorderでRenderingしたい場合などがあると思います。そういった場合はGame ViewでWire Frame Renderingができた方が都合がいいですね。

こちらに記載通りのScriptをCameraにAttachします。
https://docs.unity3d.com/ja/2019.4/ScriptReference/GL-wireframe.html

using UnityEngine;

public class ShadedWireframe : MonoBehaviour
{
    // Attach this script to a camera, this will make it render in wireframe
    void OnPreRender()
    {
        GL.wireframe = true;
    }

    void OnPostRender()
    {
        GL.wireframe = false;
    }
}

そして、CameraのClear Flagsを"Depth only"に変更します。さぁ実行してみましょう!
綺麗なWire Frameが表示されますね。


Unityの作業効率を上げる系Editor ScriptのTips集

クラスター Advent Calendar 2021 12日目の記事を書きました。

Editor Scriptの意義と軽い導入、Editor Scriptを作る上ではまりがちなTipsをまとめてみました。

https://qiita.com/MSA-i/items/bf9da9a5c5ba00485da3


Unity Editor実行時にbatを走らせてみる

Unity Editor実行時にUnity外で何か処理を走らせたい!ということがありますよね?🤗(ほんまか?
そこで今回はProject外で何かしらのファイルを操作したいときについての話を書いていこうと思います!(備忘録もかねて

基本的には流れとしては、EditorScriptからbatを起動させるだけです。
が、Unity起動後にUnity以外からProject内のファイルを操作すると何かと面倒です。

そこで、Editor起動直後、Unityが動き出す前に何かする方法はないのかと探し回るわけですが、なんと!!
ありがたいことにUnityさんがInitializeOnLoadという属性を用意して下さってます🙏

https://docs.unity3d.com/ja/2019.4/Manual/RunningEditorCodeOnLaunch.html

というわけで

using System;
using System.IO;
using System.Diagnostics;
using UnityEditor;
using UnityEngine;

namespace Hogehoge
{
    [InitializeOnLoad]
    public class Startup
    {
        private static readonly string batPath = Application.dataPath + "/hoge.bat";
        private static Process p;
        
        static Startup()
        {
            if (canDo)
            {
                ExecuteBat();
                AssetDatabase.Refresh();
            }
        }
        
        private static void ExecuteBat()
        {
            p = new Process();
            p.StartInfo.FileName = batPath;
            p.StartInfo.Verb = "RunAs";
            p.StartInfo.UseShellExecute = true;
            p.Start();
            p.WaitForExit();  //これを忘れると処理終了を待たずに何回も実行されることになるので注意
        }
    }
}

これだけでbatをEditor起動直後に実行させられます。バンザイ
注意点は、WaitForExit()を入れることぐらいですかね。これ忘れると悲惨です。

以上です!


UnityのAnimatorを利用する際に気を付けるべきこと

クラスター Advent Calendar 2020 にVRライブなどの非インタラクティブ分野でUnityのAnimatorを利用する際に気を付けるべきことについての記事を書きました。

非ゲーム分野でUnity Animatorの想定外の挙動を避けるために

想定外の挙動を避けるために
1. Rootを配置しよう
2. Apply Root MotionはONにしよう
3. Remove Start OffsetはOFFにしよう
ぐらいのことが書かれています。


Shader Forgeでcluster用のShaderを作る

Shader Forgeでclusterに対応したすべての端末で使用できるShaderをつくりたいという場合は
基本的には以下、二点にチェックを入れるだけで大丈夫です。

「Compile to all platforms」でMetal対応に
「Force Shader Model 2.0」で古いAndroid端末にも対応できます

ただし、上記二点にチェックを入れたとしても軽量化がされるわけではありませんので、重いShaderは重いままです。モバイルで使うShaderは処理を軽くしておきましょう。


自作のUnityPackageを作ってみる

重要なことはここに書かれているので補足をつらつらと書いていきます
https://docs.unity3d.com/Manual/CustomPackages.html

C#スクリプト(.cs)はAssembly Definition Filesがないと読み込まれない

.asmdefがないとcan not be loadedとなります。作り忘れないようにしましょう。
MyCompany.MyFeature.Runtime.asmdefとかと書くのがよさそうです

(Assembly Definition Filesについては↓
http://tsubakit1.hateblo.jp/entry/2018/01/18/212834

ssh接続にすればプライベートリポジトリでもPackageにできる

ssh接続にすればgithubのプライベートリポジトリでもPackageにできるようです。

注意点としては、パスの通ってるGitクライアントからgithubへssh接続できるようにしておかなければいけないということです。SourceTreeなどのGUIクライアントを利用していて、なおかつパスを通してるGitが別にある方は注意


GrabPass {}が便利

clusterやVRChatといったサービスではC#のスクリプトが利用できませんが、Standard Assetsに入っているような

ちょっとリッチなWaterを手軽に利用したいんじゃ~ということがあると思います。(Asset Storeからよさげなヤツ探すのすらめんどくさいときとかありますよね?)

そんなときにGrabPassを使うとShaderだけでSSR(Screen Space Reflection)的なことや屈折表現が簡単にできるよというお話です。

Subshader {
	GrabPass {}
	Tags {"Queue"="Transparent" "RenderType"="Transparent"}
	Pass {
CGPROGRAM

~

#include "UnityCG.cginc"

sampler2D _GrabTexture

実際にStandard AssetsのWaterを魔改造すると↓のようになります

Unityに感謝