UnityでShaderを書くときはなるべく #pragma vertex vert_img を使わないようにする
Unityでもビジュアルスクリプティングが叫ばれる昨今ですが、 レビューしたり、後からの修正のしやすさを考えると、スクリプトでゴリゴリ書きたいわたしです。
Render Texture を操作する Shader を書きたくなった時、
下記のように記述して、vertex shader を UnityCG.cginc
に宣言済みの vert_img
関数を指定すると、
fragment shader の記述に集中できるので楽チンですね。
#include "UnityCG.cginc" #pragma vertex vert_img
思わぬ落とし穴
私は PostProcess をモリモリ自作していて、そこで Render Texture を操作する Shader をよく記述します。 のだけども、iOS 用にビルドしてiPhoneの実機で表示確認してみると、Mac の Unity Editor の表示と全く違う表示がされた・・
なんで・・
原因は先ほど利用した vertex shader の v2f_img
です。
UnityCG.cginc
で定義されている記述はこちら。
struct appdata_img { float4 vertex : POSITION; half2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f_img { float4 pos : SV_POSITION; half2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; v2f_img vert_img( appdata_img v ) { v2f_img o; UNITY_INITIALIZE_OUTPUT(v2f_img, o); UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.pos = UnityObjectToClipPos (v.vertex); o.uv = v.texcoord; return o; }
そう、 half
が悪さをしていました。
PC(Mac)とMobile(iOS)で表示が異なる場合は、だいたい精度の問題ですね・・。
struct appdata_img
の half2 texcoord : TEXCOORD0;
、
struct v2f_img
の half2 uv : TEXCOORD0;
となっているため、Render Texture の座標精度が悪くて崩れてしまうのだ。
Unity公式だってテクスチャ座標を扱うときは float使え って言ってる。 (また iPhone12 の画面の解像度は 2,532 x 1,170 。 仮数が10bitしかない half では、2532は表現しきれない。)
対処法
残念だが v2f_img
の利用はやめよう。
便利だったけれど。お世話になったけれど。
無理せず float2
で宣言し、 appdata_base
を受け取るようにしよう。
( appdata_base
の texcoord
は float4
で宣言されている )
struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; v2f vert(appdata_base v) { v2f o; UNITY_INITIALIZE_OUTPUT(v2f, o); UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.pos = UnityObjectToClipPos (v.vertex); o.uv = v.texcoord; return o; }
まとめ
アイコンなど、少ない低解像度の画像を扱うときは v2f_img
を使っても良いが、
Post Process などで高解像度の画像を扱うときは v2f_img
を使ってはけない。