強火で進め

このブログではプログラム関連の記事を中心に書いてます。

Unity の WebGL ビルドで画面キャプチャを行うサンプル

急いでる人向けの記述

ソースコードこちら
実際の動作はこちらから試せます。Capture ボタンを押すと画面下部にキャプチャ画像が表示されます。

解説

最初は HTML の Canvas タグの内容をファイルに保存するだけなので簡単でしょ?って思っていたのですが実際にやってみると意外と大変でした。

よくある手法を JavaScript で記述して実装してみた所、透明な画像として保存されてしまいました。調査した所、 WebGL レンダリングだと上手く行かないみたいで WebGL を使っている時は以下の様に preserveDrawingBuffer: true 付きでコンテキストを取得するとOKみたいです。

var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});

javascript - HTML Save WebGL Canvas as Image - Stack Overflow
https://stackoverflow.com/questions/45221542/html-save-webgl-canvas-as-image

javascript - Canvas toDataURL() returns blank image only in Firefox - Stack Overflow
https://stackoverflow.com/questions/26783586/canvas-todataurl-returns-blank-image-only-in-firefox

しかし、これだとレンダリングコスト上がるだろうし「他の方法無いかな?」と調べたところ、 Unity のフォーラムで良い感じの投稿を見つけました。

WebGL - Print Canvas? | Unity Community
https://forum.unity.com/threads/webgl-print-canvas.377045/

内容としては Unity 側の処理で取得したピクセル情報を JavaScript 側に渡して使用するというものです。こちらの実装で有れば preserveDrawingBuffer: true にしなくてもちゃんと望ましい結果が取得できました。

動作の流れとしてはこの様になります。

1. Capture ボタンが押される
2. レンダリング終わりを待ってピクセル情報を取得
3. JavaScript (プラグイン)側へピクセル情報を渡す
4. HTML の img タグに画像を表示

実装手順

プラグインの作成
Unity のコードと JavaScript のコードを繋げる為にプラグインを作成します。

プラグイン作成についての公式ドキュメントはこちら。

Unity - Manual: WebGL: Interacting with browser scripting
https://docs.unity3d.com/Manual/webgl-interactingwithbrowserscripting.html

プラグインはフォルダ Assets/Plugins/WebGL に .jslib という拡張子のファイルとして作成します。

今回作成したものはこちら。

caputure.jslib

var MyPlugin = {
	CanvasCapture: function(img, size) {
		var binary = '';
		for (var i = 0; i < size; i++)
			binary += String.fromCharCode(HEAPU8[img + i]);
		var dataUrl = 'data:image/png;base64,' + btoa(binary);
	
		var capture = document.getElementById("capture");
		capture.src = dataUrl;
	},
};
mergeInto(LibraryManager.library, MyPlugin);

base64形式にした画像データの文字列を渡す事で画像を表示する機能を使って img タグに画像出力しています。
ファイル保存させたい所ですが

今回は img タグに出力しましたが Ajax でサーバにポストして保存するなどの実装も良いでしょう。

■ HTML / CSS ファイルの編集
既存の HTML ファイルにキャプチャ画像表示用の img タグを追加し、 css ファイルで多少デザインを整えたテンプレートを作成しました。
WebGL 出力のテンプレートについてご存知無い方は以下の記事を参照下さい。

WebGL 出力のテンプレートを作る - 強火で進め
http://d.hatena.ne.jp/nakamura001/20170306/1488800264