UnityのWebGLビルドでgif撮影/保存する
PartyParrotぽいVRMサイト作ってみるならgif保存がしたい
ホントにそれだけでgif保存に手を出してみました。意外とやっている話が見つからずjsのライブラリを使ってやることにしました。
jslibとの連携はUnityのjslib経由で別ファイルjsを呼び出すで書いてある手法を使用しています。
実装したのがこちら、VRMを移動させてPartyParrot風のgifをダウンロードします
↓ ダウンロードしたgif
かなり雑ですがキャプチャできています。今のままではファイルサイズが大きいため、容量削減のために解像度を低くしたりなどの一工夫が必要にはなる気がしています。
使ったjsのライブラリはccapture.jsというものです。
そこのissueにgif capture result contains complete black framesというUnityのWebGLを表示しているcanvasをキャプチャしても真っ暗な画面になるというものがありました。実際自分も同じ現象にあって調べるうちに辿り着きました。そしてissueの最後にWaitForEndOfFrame()
で最後のフレームまで待ってからjsでcaptureを実行することで成功しました。感謝🙏
実装
PartyParrotVRMはuGUIボタンからイベントが始まるのでその処理を基準に書きます。
jslibとNativeExecuter.csはUnityのjslib経由で別ファイルjsを呼び出すを使っているものとして省きます。
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
namespace Sample
{
public class DownloadGif : MonoBehaviour
{
[SerializeField]
public class CaptureParameter
{
public int index;
public int max;
}
private const int CAPTURE_COUNT = 10;
[SerializeField] private Button downloadGifButton;
private NativeExecuter executer = new NativeExecuter();
private int captureIndex = 0;
public string CallbackMethodName
{
get
{
Action callback = StartNotify;
return callback.Method.Name;
}
}
void Start()
{
downloadGifButton.onClick.AddListener(() =>
{
var callbackParameter = new CallbackParameter
{
callbackGameObjectName = gameObject.name,
callbackFunctionName = CallbackMethodName
};
var parameterJson = JsonUtility.ToJson(callbackParameter);
executer.Execute("downloadStartGif", parameterJson);
});
}
public void StartNotify()
{
StartCoroutine(CaptureScreen());
}
IEnumerator CaptureScreen()
{
while (captureIndex < CAPTURE_COUNT)
{
yield return new WaitForEndOfFrame();
captureIndex += 1;
var captureParameter = new CaptureParameter
{
index = captureIndex,
max = CAPTURE_COUNT
};
var parameterJson = JsonUtility.ToJson(captureParameter);
executer.Execute("captureFrame", parameterJson);
}
captureIndex = 0;
}
}
}
WebGLTempleteにあるindex.htmlに以下の二行を追加しておきます。
<script src="https://cdn.jsdelivr.net/npm/ccapture.js/build/CCapture.all.min.js"></script>
<script id="execute" src="execute.js"></script>
ccapture.jsに必要な処理のようなのですがgif.worker.jsというものをダウンロードしてindex.htmlの階層配下に置いておく必要があるそうです。ないとエラーが出ました。
let capturer = {}
let captureIndex = 0
function downloadStartGif(parameter) {
unityCanvas = document.getElementById('#canvas')
// workersPathはgif.worker.jsの置き場です。この場合は`js/gif.worker.js`という置き方をしています。
capturer = new CCapture( { format: 'gif', workersPath: 'js/' } )
capturer.start()
unityInstance.SendMessage(parameter.callbackGameObjectName, parameter.callbackFunctionName)
}
function captureFrame(parameter) {
capturer.capture(unityCanvas)
if (parameter.index === parameter.max) {
capturer.stop()
capturer.save()
}
}
function recieveMessage(event) {
var data = JSON.parse(event.detail)
var methodName = data.methodName
var parameter = data.parameter
try {
parameter = JSON.parse(parameter)
} catch (e) {
parameter = null
}
eval(`${methodName}(parameter)`)
}
window.addEventListener('unityMessage', recieveMessage, false)
まとめ
Unityでgif作成処理と保存処理を作成するよりもネイティブのライブラリを使った方がいいかなと思い今回はネイティブ側で実装しました。issueにたどり着くまでに時間が少しかかりましたがわかってしまえば結構簡単でした。
実はキャプチャのライブラリをいくつか試しているうちにUnityのWebGL canvasのContextはwebgl2
で取得できるという知見を得ました。WebGL2RenderingContextで詳しい描画のデータが取れるようです。ネイティブ書くときに必要になるかもな…というメモ…
Author And Source
この問題について(UnityのWebGLビルドでgif撮影/保存する), 我々は、より多くの情報をここで見つけました https://qiita.com/MizoTake/items/41638d4f8fa6ee54ac15著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .