原因
GPUによって描画する際のy座標の0
の基準が異なるらしいです。
- Direct3D系:座標の一番
上が0
。Direct3D、Metalなど - OpenGL 類:座標の一番
下が0
。OpenGL、OpenGL ESなど
で、基本的にこれはUnityは勝手に吸収してくれる
ようなのですが、レンダテクスチャに描くときにその吸収する仕組みが悪さすることがあるようです。
▼参考:公式ドキュメント
対策
この仕組みが原因で上下反転する場合は、シェーダ書いて解決してね、と上記の公式ドキュメントに書いてありました。
具体的には DirectX系/Metalのときのみ、vertexシェーダーでUVを反転をさせるようです。
#if UNITY_UV_STARTS_AT_TOP
// DirectX系, Metalの場合はY軸反転.
o.uv.y = 1 - o.uv.y;
#endif
UNITY_UV_STARTS_AT_TOP
を使って、座標の一番上が0のGPUであるかどうかを分岐させ、trueの場合のみ反転させています。
これで解決できました。
余談
今回の件でハマったときいろいろ調べてたら、「CommandBufferでレンダリング結果を利用する場合には、Camera.forceIntoRenderTexture
を有効にすると良い」という記事も見かけました。
自分のケースには当てはまりませんでしたが、そういうこともあるみたいです。
また、CommandBuffer.Blit
の内部で行われるいろいろな処理分岐によるハマりポイント的な記事も見かけたので、こちらも備忘録として記載しておきます。
これ↓とかよく分からないけど何らかのハマりポイントになりそう…。
AfterEverything開始時の、CurrentActive, CameraTargetをsrcとしたBlit命令は、内部でBlit Copyではなく、Back BufferをsrcとしたGrab RenderTextureが発生する
シェーダー全文
Shader "Camera/ReverseResolve"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
#if UNITY_UV_STARTS_AT_TOP
// DirectX系, Metalの場合はY軸反転.
o.uv.y = 1 - o.uv.y;
#endif
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}