本日はShader枠です。
〇#pragma Targetとは?
ShadferターゲットはShaderLabでシェーダーを記述する際に使用できる#pragmaディレクティブです。
用途としてはシェーダーコンパイルターゲットレベルを指定します。
シェーダーコンパイルターゲットレベルとはプラットフォームによるサポートを制御する値です。
例えばモバイルプラットフォーム向けのシェーダーとPC向けのシェーダーではパフォーマンス等の理由で異なるシェーダーレベルが使用されることが一般的です。
またプラットフォームによって処理アルゴリズムが違うこともあります。一つの例としてDirectXとOpenGLESではUV座標の扱いが違うことが知られています。
同じシェーダーであってもプラットフォームによって最適な処理を行うことで対応するプラットフォームに最適なパフォーマンスを発揮するようになります。
このプラットフォームを制御する値がシェーダーコンパイルターゲットレベルの意味です。
一般的なコンパイルターゲットレベルには、2.0、3.0、4.0、4.5、5.0があります。
2.5がDefault値としてレベルが低いほどモバイルなどどのようなプラットフォームでも動作し、逆にレベルが高くになるほどハイエンドデバイスに適したシェーダーとなります。
〇#pragma Targetの使い方と機能
ShaderTargetが次のように他のディレクティブと同じように使用します。
Shader "Unlit/NewUnlitShader " { Properties { ・・・ } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag # pragma target 3.5 #include "UnityCG.cginc"
上記の場合3.5のターゲットが使用されます。
レベルとサポートするプラットフォームは次のようになります。(なお詳細はUnityのバージョンによって異なります。)
ターゲット | プラットフォーム | 備考 |
---|---|---|
2.0 | Unityがサポートするすべてのプラットフォーム DX9(シェーダーモデル2) | |
2.5 | 3.0と同じだがDX9シェーダーモデル2.0と3.0の間 | Default |
3.0 | DirectX9(シェーダーモデル3.0),OpenGLES 3.0 | |
3.5 | OpnGL ES 3.0の機能を持ちDirectX9, DirextX11 ,OpnGLES2.0はサポートされない | Andtoidモバイル向け |
4.0 | DirectX11(シェーダーモデル4.0),DirextX9,WindowsPhone,OpenGLES 2.0/3.0/2/1 ,Metalはサポートされていない | Windows向け |
4.5 | OpenGLES 3.1 , MacやOpenGLES2.0/3.0のサポートはされていない | ハイエンドAndorid向け |
5.0 | DirectX11(シェーダーモデル5.0) | エンドデバイス向け |
シェーダーターゲットに応じてシェーダー内部では処理が分岐しています。
例えば法線マップの処理に当たるUnpackScaleNormalを見てみると次のようになります。
half3 UnpackScaleNormal(half4 packednormal, half bumpScale) { return UnpackScaleNormalRGorAG(packednormal, bumpScale); } half3 UnpackScaleNormalRGorAG(half4 packednormal, half bumpScale) { #if defined(UNITY_NO_DXT5nm) half3 normal = packednormal.xyz * 2 - 1; #if (SHADER_TARGET >= 30) // SM2.0: instruction count limitation // SM2.0: normal scaler is not supported normal.xy *= bumpScale; #endif return normal; #elif defined(UNITY_ASTC_NORMALMAP_ENCODING) half3 normal; normal.xy = (packednormal.wy * 2 - 1); normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy))); normal.xy *= bumpScale; return normal; #else // This do the trick packednormal.x *= packednormal.w; half3 normal; normal.xy = (packednormal.xy * 2 - 1); #if (SHADER_TARGET >= 30) // SM2.0: instruction count limitation // SM2.0: normal scaler is not supported normal.xy *= bumpScale; #endif normal.z = sqrt(1.0 - saturate(dot(normal.xy, normal.xy))); return normal; #endif }
ここでSHARDER_TARGETの値で処理が分岐していることがわかります。
#if (SHADER_TARGET >= 30) // SM2.0: instruction count limitation // SM2.0: normal scaler is not supported normal.xy *= bumpScale; #endif
以上がShaderTargetになります。