夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

ShaderでプロパティにEnumを使用する その② シェーダーコード内の処理

本日はShader学習枠です。

昨日はMRGTShaderを例にとってインスペクタ上に表示されるマテリアルプロパティからEnum型の変数を使用できるようにしました。

今回は実際にここで選択されたプロパティをもとにシェーダー内部の処理を変えていきます。

〇Shader内の実装

MRGTStandardShaderはウーバーシェーダーが採用されていますが、この際使用する機能はShaderFeatureキーワードとして定義されています。

#pragma shader_feature_local _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHABLEND_TRANS_ON _ADDITIVE_ON
#pragma shader_feature_local _DISABLE_ALBEDO_MAP
#pragma shader_feature_local_fragment _ _METALLIC_TEXTURE_ALBEDO_CHANNEL_A _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
#pragma shader_feature_local _CHANNEL_MAP
#pragma shader_feature_local _NORMAL_MAP
#pragma shader_feature_local _EMISSION
#pragma shader_feature_local _TRIPLANAR_MAPPING
#pragma shader_feature_local _LOCAL_SPACE_TRIPLANAR_MAPPING
#pragma shader_feature_local_fragment _USE_SSAA
#pragma shader_feature_local _ _DIRECTIONAL_LIGHT _DISTANT_LIGHT
#pragma shader_feature_local_fragment _SPECULAR_HIGHLIGHTS
#pragma shader_feature_local _SPHERICAL_HARMONICS
#pragma shader_feature_local _REFLECTIONS
#pragma shader_feature_local _RIM_LIGHT
#pragma shader_feature_local _VERTEX_COLORS
#pragma shader_feature_local _VERTEX_EXTRUSION
#pragma shader_feature_local_vertex _VERTEX_EXTRUSION_SMOOTH_NORMALS
#pragma shader_feature_local _NEAR_PLANE_FADE
#pragma shader_feature_local_vertex _NEAR_LIGHT_FADE
#pragma shader_feature_local _HOVER_LIGHT
#pragma shader_feature_local_fragment _HOVER_COLOR_OVERRIDE
#pragma shader_feature_local _PROXIMITY_LIGHT
#pragma shader_feature_local_fragment _PROXIMITY_LIGHT_COLOR_OVERRIDE
#pragma shader_feature_local_fragment _PROXIMITY_LIGHT_SUBTRACTIVE
#pragma shader_feature_local _PROXIMITY_LIGHT_TWO_SIDED
#pragma shader_feature_local _ROUND_CORNERS
#pragma shader_feature_local_fragment _INDEPENDENT_CORNERS
#pragma shader_feature_local_fragment _ROUND_CORNERS_HIDE_INTERIOR
#pragma shader_feature_local_fragment _ _EDGE_SMOOTHING_AUTOMATIC
#pragma shader_feature_local _BORDER_LIGHT
#pragma shader_feature_local_fragment _ _BORDER_LIGHT_USES_HOVER_COLOR _BORDER_LIGHT_USES_COLOR _BORDER_LIGHT_USES_GRADIENT
#pragma shader_feature_local_fragment _BORDER_LIGHT_REPLACES_ALBEDO
#pragma shader_feature_local_fragment _BORDER_LIGHT_OPAQUE
#pragma shader_feature_local _INNER_GLOW
#pragma shader_feature_local _ _IRIDESCENCE _GRADIENT_FOUR_POINT _GRADIENT_LINEAR
#pragma shader_feature_local _ENVIRONMENT_COLORING
#pragma shader_feature_local _ _BLUR_TEXTURE _BLUR_TEXTURE_2 _BLUR_TEXTURE_PREBAKED_BACKGROUND
#pragma shader_feature_local _USE_WORLD_SCALE

 シェーダー内部のコードで定義されているキーワードに基づきプリプロセッサによってコンパイル分岐が分かれています。

#if defined(_TRIPLANAR_MAPPING) || defined(_DIRECTIONAL_LIGHT) || defined(_DISTANT_LIGHT) || defined(_SPHERICAL_HARMONICS) || defined(_REFLECTIONS) || defined(_RIM_LIGHT) || defined(_PROXIMITY_LIGHT) || defined(_ENVIRONMENT_COLORING) || defined(LIGHTMAP_ON)
#define _NORMAL
#else
#undef _NORMAL
#endif

 つまりEnum型で使用する変数も選択されている機能は定義、選択されていないキーワードは未定義にすることで同様に機能を分岐できます。

①新たなShaderfeatureを追加します。

#pragma shader_feature_local _UV0 _UV1 _UV2

ここで追加したemissicveUV0、emissicveUV1、_emissicveUV2のいずれかを使用するようにします。

②ShaderGUI.csの先日追加したMainMapOptions関数のEmissionを有効にした際に表示されるプロパティに追加を行います。

            if (PropertyEnabled(enableEmission))
            {
                EditorGUI.indentLevel += 2;
                materialEditor.TexturePropertySingleLine(Styles.emissiveColor, emissiveMap, emissiveColor);
                EditorGUI.indentLevel -= 2;
                Debug.Log(emissiveUV);
                emissiveUV.floatValue = EditorGUILayout.Popup(Styles.emissiveUV, (int)emissiveUV.floatValue, Styles.emissiveUVNames);
                                switch ((EmissiveUV)emissiveUV.floatValue)
                {
                    default:
                    case EmissiveUV.UV0:
                        {
                            material.EnableKeyword(Styles.emissiveUV0);
                            material.DisableKeyword(Styles.emissiveUV1);
                            material.DisableKeyword(Styles.emissiveUV2);
                        }
                        break;
                    case EmissiveUV.UV1:
                        {
                            material.EnableKeyword(Styles.emissiveUV1);
                            material.DisableKeyword(Styles.emissiveUV0);
                            material.DisableKeyword(Styles.emissiveUV2);
                        }
                        break;
                    case EmissiveUV.UV2:
                        {
                            material.EnableKeyword(Styles.emissiveUV2);
                            material.DisableKeyword(Styles.emissiveUV1);
                            material.DisableKeyword(Styles.emissiveUV0);
                        }
                        break;
                }
            }

 ここで追加したSwitch文はEnumで選ばれている各種値に応じて処理が分かれています。

 処理の内容はマテリアルのシェーダーからキーワードの定義or定義の無効かを行っています。

docs.unity3d.com

 例えばUV0が選択されている場合Styles.emissiveUV1=UV0のシェーダーキーワードを有効かしてその他のUV1,_UV2のシェーダーキーワードを無効化しています。

以上でEnum型の変数の値に応じてシェーダー内での処理を分けることができました。

 最後に

```

if define(_UV0)

else

endif

のようにシェーダーのHLSL文内で処理を記述することで処理を分けることができます。

本日は以上です。