概要
先日、画像を差し替えてVCIを吐き出してくれる ArtFrameGenerator 0.01 を作りました。
VRMのようにエクスポーター、インポーターのサンプルがないので、ついでにVCIのエクスポーターのサンプルを置いておきます。
※公式のサンプルが出た場合、そちらを使用しましょう。
UnityEditorの機能はビルドすると使えない
当たり前ですが AssetDatabase.Refresh()
とか EditorUtility
とか便利な機能が使えません。
知ってる人にとっては当たり前ですが、自分は知らなかったのでビルドする時になってハマりました。
エクスポーターのサンプル
using System;
using System.IO;
using System.Windows.Forms;
using UnityEngine;
using VCI;
using VCIGLTF;
public class VciExporterSample : MonoBehaviour {
[SerializeField, Tooltip("VCI Root Object")]
private GameObject _exportVci;
private void Start()
{
if (_exportVci == null)
{
_exportVci = FindObjectOfType<VCIObject>().gameObject;
Debug.Log(_exportVci.name + "をエクスポートのターゲットに設定しました。");
}
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.E))
{
VciExporter();
}
}
//Exporter
public void VciExporter()
{
//Path
string exportPath = GetExportPath();
//cancel
if (exportPath == "")
{
Debug.Log("ファイルの保存がキャンセルされました。");
return;
}
//Vci Binary
byte[] vciBinary = GetVciObject();
//Write
File.WriteAllBytes(exportPath, vciBinary);
Debug.Log("保存先 : " + exportPath);
}
//_exportVciに設定されたVCIをByteにする
private byte[] GetVciObject()
{
//Export
var gltf = new glTF();
using (var exporter = new VCI.VCIExporter(gltf))
{
exporter.Prepare(_exportVci);
exporter.Export();
}
var bytes = gltf.ToGlbBytes();
return bytes;
}
//保存先のファイルパスを取得
private string GetExportPath()
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
//デフォルトのファイル名
DateTime dateTime = DateTime.Now;
string time = dateTime.ToString("MMddHHmmss");
saveFileDialog.FileName = _exportVci.name + time + ".vci";
//ウインドウのメッセージ
saveFileDialog.Title = "VCIの保存先を指定してください。";
//デフォルトのディレクトリ
saveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
//ファイルの種類指定
saveFileDialog.Filter = "vci|*.vci";
saveFileDialog.CheckFileExists = false;
//ダイアログを開く
//OKを選択した場合、ファイルパスを返す。
if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
string path = saveFileDialog.FileName;
saveFileDialog.Dispose();
return path;
}
//OK以外を選択した場合、"" を返す。
saveFileDialog.Dispose();
return "";
}
}
使い方
ファイルのパスを取得するのに System.Windows.Forms
の SaveFileDialog
を使用するので、DLLのインポートが必要です。
そのままサンプル使おうとするとコンパイルした時に「Formsなんて名前空間無いぞ!」と言われます。
System.Windows.Forms.dll (DLL) のインポート
1.C:\Program Files\Unity\Editor\Data\Mono\lib\mono\2.0
から System.Windows.Forms.dll
をコピーする。
※UnityHubを使用してる場合は微妙にディレクトリが違うかもしれません。
2./Asset/Plugins
の Plugins
フォルダにdllを張り付ける。
あとはサンプルのスクリプトをコピペして、gameobjectにアタッチして、実行中に E
キーを押すとエクスポートを実行します。
解説
Exporter部分
エクスポートの部分はVCIのパッケージから落とせる VCIObjectExporterMenu.cs
の // export
部分に書いてあります。
// export
var gltf = new glTF();
using (var exporter = new VCI.VCIExporter(gltf))
{
//rootはVCIのrootオブジェクト
exporter.Prepare(root);
exporter.Export();
}
var bytes = gltf.ToGlbBytes();
//pathは保存先
File.WriteAllBytes(path, bytes);
VCIをエクスポートするのに必要な事は**「保存先を指定して、byteになったVCIを、File.WriteAllBytes()するとエクスポートできる」**という感じです。
なので root
のgameobjectをhierarchyから指定して Path
を SaveFileDialog
から指定すればビルド後のクライアントでエクスポートできます。
DLLを使いたくない場合…
Application.dataPath
でVCIを保存するパスを決め打ちして Directory.Exists()
でパスの有無を確認してから Directory.CreateDirectory()
で動的に作成するなど…でしょうか。
(自分がやるとしたらひとまずそれで作ります)
SaveFileDialog
メッセージボックスのタイトル、開くファイルの種類、開くディレクトリを指定した上で ShowDialog()
を実行してファイルパスを取得します。
これらのオプションは適宜、追加変更するのがよいと思います。
リファレンス:SaveFileDialog Class
フィルターのプロパティ:FileDialog.Filter Property
saveFileDialog.InitialDirectory
で指定してる Environment
は環境変数など様々なOSの情報を返してくれるヤツです。
これを使ってデスクトップのパスを取得します。
Environment.GetFolderPath Method
最終的に saveFileDialog.FileName
の中にファイルまでのディレクトリが格納されるので、その内容を return
するのがよいと思います。
その他注意点
ビルド後のクライアントだと、VCIのShaderに standardVcolor
が含まれてるとエラーになります。
ビルド後にエラーがでるようでしたら BuildingSetting から DevelopmentBuil のオプションにチェックを入れてビルドするとエラーのログが簡単に見れるようになります。
ArtFrameGenerator作ってて苦戦したので覚えた。
公式からちゃんとしたExporterのサンプルが出るのを待つべき…
まとめ
あとは、動的にTexture2Dを差し替えたり、Subitemの子になってるオブジェクトを変更すればVCIのGeneratorのようなものが作れます。
VRChatで「Unityをインストールしてください」に慣れてる層はいるとはいえ、やはりハードルがあるかないかで言えばハードルはあるのでジェネレーターから興味を持ってもらえると嬉しいですね…。
ちなみにArtFrameGeneratorのニコニコの紹介動画が1万再生、紹介ツイート350RTでDL数が50にも満たなかったです。
ツールを広めたり定着させるのは大変なんだな…と思いました。ツールをちゃんとリーチさせたい層に届けるテクニック?なんかも、学ばないといけないんですね。
バーチャルモーションキャプチャーとかコンスタントに動画があがってくるのですごい。