解説
最初は 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