リアルタイムの3Dキャラクターやアセットをレンダーテクスチャ(RenderTexture)を仲介してUI(RawImage)に描画した際、元のアセットと色調が一致せず、暗く汚れた色になったり白くボケたりするバグは、色空間(カラースペース)の解釈エラーによって発生する非常に頻出する問題です。本記事では、この『リニアとガンマのすれ違い』を『サングラスをかけた二重調光』の例え話を交えて分かりやすく解説し、完璧に色調を同期させるための設定・実装手順を提示します。
1. 例え話で理解する:『サングラスをかけた二重の度違い調光』
このカラースペースのミスマッチを直感的に理解するために、『サングラスをかけたまま行う絵の仕上げ作業』を例えに考えてみましょう。
あなたが明るい屋外で、非常に美しい絵画(3Dモデル)を描いているとします。その際、あなたは『強い日差しよけのサングラス(ガンマ補正)』をかけた状態でキャンバスを眺め、ちょうどいい明るさになるように調色(リニア計算によるライティング)をして仕上げました。絵はあなたのサングラス越しに『完璧なトーン』になっています。
次に、この絵を暗いギャラリー(UI画面)に展示するため、運搬用の専用ケース(RenderTexture)に入れます。しかし、運搬スタッフ(Unityの設定)が『このケース内の絵は、まだ日差しよけされていない生データだ』と勘違いし、勝手にケース内の絵の明るさを数値的に補正(誤ったリニア変換)してしまいました。さらに、ギャラリーの展示スタッフ(UIシェーダー)も『サングラス(デコード処理)』をかけた状態で絵を眺めて展示位置の明るさを調整します。この結果、元の絵画のカラーバランスが二重に歪んでしまい、サングラスを外した普通の観客がギャラリーを訪れて絵を見た瞬間、完成したはずの絵が極端に黒ずんで沈んで見える(あるいは光を当てすぎて白飛びする)という色彩崩壊が発生します。
これが、RenderTextureにおける『カラースペース不整合バグ』のメカニズムです。Linear空間で動作するUnityは、テクスチャがsRGB(ガンマ)かリニアかをマークすることによって、描画時と表示時にそれぞれ自動で補正を行います。RenderTextureの設定(マーク)を誤ると、この補正が重複して適用(二重にべき乗がかかり暗化)されたり、適用漏れ(白飛び)を引き起こしてしまうのです。
2. 解決策A:RenderTextureアセットの『sRGB』設定の有効化
プロジェクトフォルダ内にRenderTextureアセット(`.renderTexture` ファイル)を作成し、それを RawImage に直接割り当てて使用している場合は、インスペクターの設定からマークを正しく修正します。
設定手順:
- プロジェクトウィンドウから、該当するRenderTextureアセットを選択します。
- インスペクターウィンドウを確認します。
- 『Color Format』の設定において、名前に『sRGB』が付いているフォーマット(例: `R8G8B8A8_SRGB` など)を明示的に選択します(Unityのバージョンによっては『sRGB (Color Texture)』という直接のチェックボックスが表示されますので、それを **オン** にします)。
これにより、Unityの描画エンジンはこのRenderTextureを『ガンマ空間のカラーデータ(sRGB)』として正しく認識し、UIシステムがサンプリングして画面にレンダリングする際に、正しいリニア変換を自動で行うため、黒ずみバグが瞬時に解消されます。
3. 解決策B:C#スクリプトで動的にsRGBを有効化する
C#スクリプトを使用して動的にRenderTextureを作成する場合は、`RenderTextureDescriptor` で `sRGB` プロパティを明示的に `true` に指定してアロケーションを実行します。
using UnityEngine;
using UnityEngine.UI;
public class CharacterPreviewColorFix : MonoBehaviour
{
public Camera subCamera;
public RawImage rawImage;
private RenderTexture targetRt;
void Start()
{
InitializeRenderTexture();
}
void InitializeRenderTexture()
{
// 1. 解像度と精度を指定して記述子を作成
RenderTextureDescriptor desc = new RenderTextureDescriptor(1024, 1024, RenderTextureFormat.ARGB32, 24);
// 2. ★超重要:sRGB設定を明示的に true にする(自動ガンマ補正をフックする)
desc.sRGB = true;
desc.useMipMap = false;
desc.autoGenerateMips = false;
// 3. テクスチャを生成
targetRt = new RenderTexture(desc);
targetRt.filterMode = FilterMode.Bilinear;
targetRt.Create();
// カメラのターゲットとUIの参照を設定
subCamera.targetTexture = targetRt;
rawImage.texture = targetRt;
}
void OnDestroy()
{
if (targetRt != null)
{
targetRt.Release();
Destroy(targetRt);
}
}
}
このスクリプトを通して動的確保されたバッファは、リニア空間で計算された3Dのカラーデータを自動でsRGBフォーマットへエンコードして保存します。そのため、uGUIのRawImage描画時に生じる二重変換を完全に防止し、元のアセットと100%同一のカラーバランスでUI上にプレビューを表示できます。