夜風のMixedReality

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

MRTK StanderdShaderを読み解く その9 発光

本日はMRTKで提供されているMRTK StandardShaderの調査枠です。

〇これまでの記事

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

redhologerbera.hatenablog.com

〇Emission

今回はEmission(発光)に関して調査します。

Emissionはオブジェクトをその名の通り発光させることができます。 これはカラーをオーバーレイするような効果を持ちます。

f:id:Holomoto-Sumire:20200727092321j:plain
Emissionなし

f:id:Holomoto-Sumire:20200727092504j:plain
Emissionあり

〇 Properties

    Properties
    {
        // Main maps.
        _Color("Color", Color) = (1.0, 1.0, 1.0, 1.0)

        [Toggle(_EMISSION)] _EnableEmission("Enable Emission", Float) = 0.0
        [HDR]_EmissiveColor("Emissive Color", Color) = (0.0, 0.0, 0.0, 1.0)
   
         // Rendering options.
            [Toggle(_DIRECTIONAL_LIGHT)] _DirectionalLight("Directional Light", Float) = 1.0          
    }

ここではMaterialとして使用できる変数を記述します。

今回は_EMISSIONが重要になります。MRTKStandardShaerではこのチェックボックスを有効化すると発光が使用できます。

f:id:Holomoto-Sumire:20200727095507j:plain

追加したものは次のようになります。

  [Toggle(_EMISSION)] _EnableEmission("Enable Emission", Float) = 0.0
        [HDR]_EmissiveColor("Emissive Color", Color) = (0.0, 0.0, 0.0, 1.0)

[HDR]のアトリビュートはハイ・ダイナミック・レンジという手法のカラーで暗明の差が大きく表現できるカラーとして使用できます。

f:id:Holomoto-Sumire:20200727100844j:plain

マテリアル側でもこのcolorにはHDRの文字が表示されます。

〇フラグメントシェーダー

フラグメントシェーダーでの変更点は次の通りです。

    #if defined(_EMISSION)
                    output.rgb += _EmissiveColor;
    #endif

影やテクスチャなどのレンダリング結果のoutput.rgb に_EmissiveColorが直接加算されています。

これによって最初に表現したようにオーバーレイが行われています。

〇今回作成したShader

f:id:Holomoto-Sumire:20200727100505j:plain

Shader "Custom/MRTKEmission"
{
    Properties
    {
        // Main maps.
        _Color("Color", Color) = (1.0, 1.0, 1.0, 1.0)

        [Toggle(_EMISSION)] _EnableEmission("Enable Emission", Float) = 0.0
        [HDR]_EmissiveColor("Emissive Color", Color) = (0.0, 0.0, 0.0, 1.0)

            // Rendering options.
            [Toggle(_DIRECTIONAL_LIGHT)] _DirectionalLight("Directional Light", Float) = 1.0
    
    }

        SubShader
            {
                Pass
                {
                    Name "Main"
                    Tags{ "RenderType" = "Opaque" "LightMode" = "ForwardBase" }
                 

                    CGPROGRAM

                    #pragma vertex vert
                    #pragma fragment frag
      


                    #pragma shader_feature _EMISSION
                    #pragma shader_feature _DIRECTIONAL_LIGHT
 

                    #include "UnityCG.cginc"
                    #include "UnityStandardConfig.cginc"
                    #include "UnityStandardUtils.cginc"
                    #include "MixedRealityShaderUtils.cginc"

                // This define will get commented in by the UpgradeShaderForLightweightRenderPipeline method.
                //#define _LIGHTWEIGHT_RENDER_PIPELINE

    #if  defined(_DIRECTIONAL_LIGHT)
                #define _NORMAL
    #else
                #undef _NORMAL
    #endif


    #if defined(_NORMAL)
                #define _WORLD_POSITION
    #else
                #undef _WORLD_POSITION
    #endif

    #if defined(_DIRECTIONAL_LIGHT) 
                #define _FRESNEL
    #else
                #undef _FRESNEL
    #endif

                #define _UV


                struct appdata_t
                {
                    float4 vertex : POSITION;
                    // The default UV channel used for texturing.
                    float2 uv : TEXCOORD0;
 
                    // Used for smooth normal data (or UGUI scaling data).
                    float4 uv2 : TEXCOORD2;
                    // Used for UGUI scaling data.
                    float2 uv3 : TEXCOORD3;

                    fixed3 normal : NORMAL;
 
                    UNITY_VERTEX_INPUT_INSTANCE_ID
                };

                struct v2f
                {
                    float4 position : SV_POSITION;

                    float2 uv : TEXCOORD0;

   
    #if defined(_WORLD_POSITION)
   
                    float3 worldPosition : TEXCOORD2;
    #endif
 
 
                    fixed3 worldNormal : COLOR3;
   
                    UNITY_VERTEX_OUTPUT_STEREO
                };


                fixed4 _Color;
  
                sampler2D _MainTex;
                fixed4 _MainTex_ST;


                fixed _Metallic;
                fixed _Smoothness;


    #if defined(_EMISSION)
                fixed4 _EmissiveColor;
    #endif

    #if defined(_DIRECTIONAL_LIGHT)

                fixed4 _LightColor0;
    #endif


    #if defined(_DIRECTIONAL_LIGHT)
                static const fixed _MinMetallicLightContribution = 0.7;
                static const fixed _IblContribution = 0.1;
    #endif


    #if defined(_FRESNEL)
                static const float _FresnelPower = 8.0;
    #endif

                v2f vert(appdata_t v)
                {
                    v2f o;
                    UNITY_SETUP_INSTANCE_ID(v);
                    UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);

                    float4 vertexPosition = v.vertex;

    #if defined(_WORLD_POSITION)
                    float3 worldVertexPosition = mul(unity_ObjectToWorld, vertexPosition).xyz;
    #endif

                    fixed3 localNormal = v.normal;

    #if defined(_NORMAL) 
                    fixed3 worldNormal = UnityObjectToWorldNormal(localNormal);
    #endif


                    o.position = UnityObjectToClipPos(vertexPosition);

    #if defined(_WORLD_POSITION)
                    o.worldPosition.xyz = worldVertexPosition;
    #endif



    #if defined(_NORMAL)
                    o.worldNormal = worldNormal;
    #endif
                    return o;
                }

                fixed4 frag(v2f i, fixed facing : VFACE) : SV_Target
                {

                // Texturing.
                    fixed4 albedo = tex2D(_MainTex, i.uv);
  
                    albedo *= _Color;

 

                    // Normal calculation.
    #if defined(_NORMAL)
                    fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPosition.xyz));
                    fixed3 worldNormal;

   
                    worldNormal = normalize(i.worldNormal) * facing;
    #endif


                    fixed pointToLight = 1.0;
                    fixed3 fluentLightColor = fixed3(0.0, 0.0, 0.0);





                    // Blinn phong lighting.
    #if defined(_DIRECTIONAL_LIGHT)
 
                    float4 directionalLightDirection = _WorldSpaceLightPos0;

                    fixed diffuse = max(0.0, dot(worldNormal, directionalLightDirection));

                    fixed specular = 0.0;
    #endif



                  fixed3 ibl = unity_IndirectSpecColor.rgb;

                    // Fresnel lighting.
    #if defined(_FRESNEL)
                    fixed fresnel = 1.0 - saturate(abs(dot(worldViewDir, worldNormal)));

                    fixed3 fresnelColor = unity_IndirectSpecColor.rgb * (pow(fresnel, _FresnelPower) * max(_Smoothness, 0.5));

    #endif
                    // Final lighting mix.
                    fixed4 output = albedo;
 
                    fixed3 ambient = glstate_lightmodel_ambient + fixed3(0.25, 0.25, 0.25);
                    fixed minProperty = min(_Smoothness, _Metallic);
    #if defined(_DIRECTIONAL_LIGHT)
                    fixed oneMinusMetallic = (1.0 - _Metallic);
                    output.rgb = lerp(output.rgb, ibl, minProperty);
  
                    fixed3 directionalLightColor = _LightColor0.rgb;

                    output.rgb *= lerp((ambient + directionalLightColor * diffuse + directionalLightColor * specular) * max(oneMinusMetallic, _MinMetallicLightContribution), albedo, minProperty);
                    output.rgb += (directionalLightColor * albedo * specular) + (directionalLightColor * specular * _Smoothness);
                    output.rgb += ibl * oneMinusMetallic * _IblContribution;
    #endif

    #if defined(_FRESNEL)
 
                    output.rgb += fresnelColor * (1.0 - minProperty);
    #endif

    #if defined(_EMISSION)
                    output.rgb += _EmissiveColor;
    #endif


                    return output;
                }

                ENDCG
            }
            }

                Fallback "Hidden/InternalErrorShader"             
}