本日はMRTKで提供されているMRTK StandardShaderの調査枠です。
〇これまでの記事
〇Emission
今回はEmission(発光)に関して調査します。
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ではこのチェックボックスを有効化すると発光が使用できます。

追加したものは次のようになります。
[Toggle(_EMISSION)] _EnableEmission("Enable Emission", Float) = 0.0
[HDR]_EmissiveColor("Emissive Color", Color) = (0.0, 0.0, 0.0, 1.0)
[HDR]のアトリビュートはハイ・ダイナミック・レンジという手法のカラーで暗明の差が大きく表現できるカラーとして使用できます。

マテリアル側でもこのcolorにはHDRの文字が表示されます。
〇フラグメントシェーダー
フラグメントシェーダーでの変更点は次の通りです。
#if defined(_EMISSION)
output.rgb += _EmissiveColor;
#endif
影やテクスチャなどのレンダリング結果のoutput.rgb に_EmissiveColorが直接加算されています。
これによって最初に表現したようにオーバーレイが行われています。
〇今回作成したShader

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"
}