18
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

RenderTexture(Texture2D)を画像保存すると暗い時

Last updated at Posted at 2019-03-18

#概要
D1TflLAVAAACF5T.jpg
© Unity Technologies Japan/UCL
下記のようなスクリプトで画像を保存すると全体的に暗い画像が保存される場合があります。この場合の原因と対策を書きます。

RenderTexture CamTex;

Texture2D tex = new Texture2D(CamTex.width, CamTex.height, TextureFormat.RGB24, false);
RenderTexture.active = CamTex;
tex.ReadPixels(new Rect(0, 0, CamTex.width, CamTex.height), 0, 0);
tex.Apply();

byte[] bytes = tex.EncodeToPNG();
File.WriteAllBytes("RenderTexture.png", bytes);

#原因
Edit > Project Settings > PlayerのPlayer SettingsからOther Settings > RenderingよりColor SpaceをLinearに設定している場合に暗くなります。UTS2.0などのシェーダーに関するスライドを読むと、最初に設定するように書かれていることが多い内容です。仕組みが分かると「まぁ、そうか」という感じですが、「原因」として書くようなことではなく、完全に仕様です。

#対策1

RenderTexture CamTex;

Texture2D tex = new Texture2D(CamTex.width, CamTex.height, TextureFormat.RGB24, false);
RenderTexture.active = CamTex;
tex.ReadPixels(new Rect(0, 0, CamTex.width, CamTex.height), 0, 0);
/////////////////////////////////////////////////////////////////////////////////////////追加ここから
if (QualitySettings.activeColorSpace == ColorSpace.Linear)
{
    // ガンマ補正
    var color = tex.GetPixels();
    for (int i = 0; i < color.Length; i++)
    {
        color[i].r = Mathf.Pow(color[i].r, 1 / 2.2);
        color[i].g = Mathf.Pow(color[i].g, 1 / 2.2);
        color[i].b = Mathf.Pow(color[i].b, 1 / 2.2);
    }
    tex.SetPixels(color);
}
/////////////////////////////////////////////////////////////////////////////////////////追加ここまで
tex.Apply();

byte[] bytes = tex.EncodeToPNG();
File.WriteAllBytes("RenderTexture.png", bytes);

方法は色々ありそうですし、上記があまり良い方法とも思えませんが、とにかくガンマ補正というのをすると解決します。この対策では厳密にはColor SpaceがGammaの時と完全に同じRGB値にならないかもしれませんが、誤差だと思うので気にしないことにします。

※コメントにてご教授頂きましたので、以下加筆します。

#対策2
対策1のRGB各色計算を以下のように書き換えます。恐らくですが、こちらの方が正確な値になると思われます。

color[i].r = Mathf.LinearToGammaSpace(color[i].r);
color[i].g = Mathf.LinearToGammaSpace(color[i].g);
color[i].b = Mathf.LinearToGammaSpace(color[i].b);

#対策3
これが最も簡単でスマートな方法だと思われますが、以下のように作成したRenderTextureのsRGB設定をチェックありにします。すると、対策1でスクリプトを追加した部分は不要になり、この設定だけで解決します。
無題.png

#結果
どの対策も目視では、ほぼ同様の結果になります。
D1UMXVrVsAA-Gpy.jpg
© Unity Technologies Japan/UCL

#仕組み
恐らく散々語られてる分野だと思われますので、私が下手な事言うより、検索した方が良いと思います。キーワードは「ガンマ補正」「トーンカーブ」踏み込むと「sRGB」「比視感度」などだと思います。

#参考
リニアのワークフローとガンマのワークフロー
https://docs.unity3d.com/ja/current/Manual/LinearRendering-LinearOrGammaWorkflow.html
ガンマ補正
http://w3.kcua.ac.jp/~fujiwara/infosci/gamma.html
明るさの調整(γ補正)
http://www.mis.med.akita-u.ac.jp/~kata/image/colorgamma.html

18
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?