ゴマちゃんフロンティア

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

【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()の後」で呼び出さないと、以下のようなエラーが発生してしまいます。

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

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

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に含めて外部のシステムやサービスへ送信できます。

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)記事書きました!

【Unity】AWS Lambdaを使用してWebGLからS3に画像をアップロードしたお話

参考サイト

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

down

コメントする