ゴマちゃんフロンティア

アザラシが大好きなエンジニアの開発日記です

【Unity】WebGLでゲーム画面のキャプチャ(スクリーンショット)を取得する方法

time 2019/11/07

今回はUnityのWebGLで画面キャプチャに関するお話です。
キャプチャした画像をゲーム内で使用したり、外部ストレージにアップロードしたりするケースを想定します。

実装方法

Unityでスクショと言えばScreenCapture.CaptureScreenshot()がありますが、WebGL上ではファイルを扱えません。
そこでTexture2DReadPixels()を使用します。
https://docs.unity3d.com/ja/2017.4/ScriptReference/Texture2D.ReadPixels.html

注意点として、「OnPostRender()メソッド内」か「コルーチンのWaitForEndOfFrame()の後」で呼び出さないと、以下のようなエラーが発生してしまいます。

1
ReadPixels was called to read pixels from system frame buffer, while not inside drawing frame.

私はコルーチン内でWaitForEndOfFrame()を待つ方法で実装してみました。メソッド化して任意のタイミングで呼べるようにします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected Texture2D currentScreenShotTexture;
 
protected void Start()
{
    // スクリーンショット用のTexture2D用意
    currentScreenShotTexture = new Texture2D(Screen.width, Screen.height);
 
    StartCoroutine(UpdateCurrentScreenShot());
}
 
protected IEnumerator UpdateCurrentScreenShot()
{
    // これがないとReadPixels()でエラーになる
    yield return new WaitForEndOfFrame();
 
    currentScreenShotTexture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
    currentScreenShotTexture.Apply();
}

キャプチャ画像はEncodeToPNG().png形式のbyte配列に変換できます。
また、base64エンコードすると文字列で取得できるので、HTTPリクエストのJSONに含めて外部のシステムやサービスへ送信できます。

1
2
byte[] imageBytes = currentScreenShotTexture.EncodeToPNG();
var encodedImage = Convert.ToBase64String(imageBytes)

受け取った側ではConvert.FromBase64String()でbyte配列に戻し、それをStreamに書き込んで出力すればOKです。
私の場合はAWSのS3にアップロードする用途で使用しました。下はS3にアップロードした画像です。特に問題なさそうですね。

AWSのSDKがWebGLに非対応のため、直接はS3にアップロードできません。Lambdaで一度受けてデコードし、そこからS3に保存する形になるかと思います。
このあたりも最近実装したので、改めて記事でまとめます!
→(2019/11/24)記事書きました!

参考サイト

・画面キャプチャの取得
https://qiita.com/tempura/items/e8f4bbb4419407916d12

down

コメントする