本日はMRTKのShader調査枠です。
〇EnvironmentColor
EncironmentColorはオブジェクトに対しユーザーが見る向きによって色味が変わる機能です。
デフォルトではX軸に赤,Y軸に緑,Z軸に青が使用されています。
ユーザーが移動するとオブジェクトを見る向きに合わせて色が変わります。
〇Shader
〇 Properties
Properties{ ... [Toggle(_ENVIRONMENT_COLORING)] _EnvironmentColoring("Environment Coloring", Float) = 0.0 _EnvironmentColorThreshold("Environment Color Threshold", Range(0.0, 3.0)) = 1.5 _EnvironmentColorIntensity("Environment Color Intensity", Range(0.0, 1.0)) = 0.5 _EnvironmentColorX("Environment Color X (RGB)", Color) = (1.0, 0.0, 0.0, 1.0) _EnvironmentColorY("Environment Color Y (RGB)", Color) = (0.0, 1.0, 0.0, 1.0) _EnvironmentColorZ("Environment Color Z (RGB)", Color) = (0.0, 0.0, 1.0, 1.0) }
Propertiesではトグルと[EnvironmentColorThreshold],[EnvironmentColorIntensity],[EnvironmentColorX],[EnvironmentColorY],[_EnvironmentColorZ]の5つのpropertyがあります。
このうち _EnvironmentColorはX,Y,Zそれぞれの軸の色の設定になります。
〇フラグメントシェーダー
#if defined(_ENVIRONMENT_COLORING) fixed3 environmentColor = incident.x * incident.x * _EnvironmentColorX + incident.y * incident.y * _EnvironmentColorY + incident.z * incident.z * _EnvironmentColorZ; output.rgb += environmentColor * max(0.0, dot(incident, worldNormal) + _EnvironmentColorThreshold) * _EnvironmentColorIntensity; #endif
[encironmentColor]には各軸incidentの2条に_EnvironmentColorが積算されます。
incidentは次のようになっています。
fixed3 incident = -worldViewDir;
worldViewDirは直前で定義されておりUnityのワールド空間でのビュー方向の逆値です。
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPosition.xyz));
つまりincidentがユーザーの見ている角度に相当します。incidentを二乗することで角度の差を出しています。incident自体は-worldViewDirでマイナスの値を持っていますが、二乗かすることで正の値になります。
この値に[_EnvironmentColor]の各値が積算されます。
これが[environmentColor]です。
output.rgb += environmentColor * max(0.0, dot(incident, worldNormal) + _EnvironmentColorThreshold) * _EnvironmentColorIntensity;
最終的な出力のoutputのrgbにencironmentColorが加算されます。 この時max関数によってincidentとworldNormalの内積の最大値に_EnvironmentColorThresholdが加算されencironmentColorに積算されます。
max(0.0, dot(incident, worldNormal)) は描画する際にRimLight同様モデルの持つ法線でグラデーションがかかるようになります。_EnvironmentColorThresholdはこの閾値になります。
_EnvironmentColorIntensityはそのまま値を積算しており、発光どうよう色の強度になります。
以上がEnvironmentColorです。
やっていることはビュー方向を取得してそれに合わせてXYZのColorを積算しているという感じのようです。
〇今回編集したShader
Shader "Custom/StandardEnviroment" { Properties { // Main maps. _Color("Color", Color) = (1.0, 1.0, 1.0, 1.0) _MainTex("Albedo", 2D) = "white" {} [Enum(AlbedoAlphaMode)] _AlbedoAlphaMode("Albedo Alpha Mode", Float) = 0 // "Transparency" [Toggle] _AlbedoAssignedAtRuntime("Albedo Assigned at Runtime", Float) = 0.0 _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 [Toggle(_CHANNEL_MAP)] _EnableChannelMap("Enable Channel Map", Float) = 0.0 [NoScaleOffset] _ChannelMap("Channel Map", 2D) = "white" {} [Toggle(_NORMAL_MAP)] _EnableNormalMap("Enable Normal Map", Float) = 0.0 [NoScaleOffset] _NormalMap("Normal Map", 2D) = "bump" {} _NormalMapScale("Scale", Float) = 1.0 [Toggle(_EMISSION)] _EnableEmission("Enable Emission", Float) = 0.0 [HDR]_EmissiveColor("Emissive Color", Color) = (0.0, 0.0, 0.0, 1.0) [Toggle(_TRIPLANAR_MAPPING)] _EnableTriplanarMapping("Triplanar Mapping", Float) = 0.0 [Toggle(_LOCAL_SPACE_TRIPLANAR_MAPPING)] _EnableLocalSpaceTriplanarMapping("Local Space", Float) = 0.0 _TriplanarMappingBlendSharpness("Blend Sharpness", Range(1.0, 16.0)) = 4.0 [Toggle(_ENVIRONMENT_COLORING)] _EnvironmentColoring("Environment Coloring", Float) = 0.0 _EnvironmentColorThreshold("Environment Color Threshold", Range(0.0, 3.0)) = 1.5 _EnvironmentColorIntensity("Environment Color Intensity", Range(0.0, 1.0)) = 0.5 _EnvironmentColorX("Environment Color X (RGB)", Color) = (1.0, 0.0, 0.0, 1.0) _EnvironmentColorY("Environment Color Y (RGB)", Color) = (0.0, 1.0, 0.0, 1.0) _EnvironmentColorZ("Environment Color Z (RGB)", Color) = (0.0, 0.0, 1.0, 1.0) } SubShader { Pass { Name "Main" Tags{ "RenderType" = "Opaque" "LightMode" = "ForwardBase" } LOD 100 CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma shader_feature _DIRECTIONAL_LIGHT #pragma shader_feature _ENVIRONMENT_COLORING #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) || defined(_ENVIRONMENT_COLORING) #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; #if defined(_NORMAL_MAP) fixed4 tangent : TANGENT; #endif UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float4 position : SV_POSITION; #if defined(_UV) float2 uv : TEXCOORD0; #endif #if defined(_WORLD_POSITION) float3 worldPosition : TEXCOORD2; #endif #if defined(_SCALE) float3 scale : TEXCOORD3; #endif #if defined(_NORMAL) #if defined(_NORMAL_MAP) fixed3 tangentX : COLOR3; fixed3 tangentY : COLOR4; fixed3 tangentZ : COLOR5; #else fixed3 worldNormal : COLOR3; #endif #endif UNITY_VERTEX_OUTPUT_STEREO }; fixed4 _Color; sampler2D _MainTex; fixed4 _MainTex_ST; fixed _Metallic; fixed _Smoothness; #if defined(_NORMAL_MAP) sampler2D _NormalMap; float _NormalMapScale; #endif #if defined(_DIRECTIONAL_LIGHT) #if defined(_LIGHTWEIGHT_RENDER_PIPELINE) CBUFFER_START(_LightBuffer) float4 _MainLightPosition; half4 _MainLightColor; CBUFFER_END #else fixed4 _LightColor0; #endif #endif #if defined(_ENVIRONMENT_COLORING) fixed _EnvironmentColorThreshold; fixed _EnvironmentColorIntensity; fixed3 _EnvironmentColorX; fixed3 _EnvironmentColorY; fixed3 _EnvironmentColorZ; #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 #if defined(_SCALE) o.scale.x = length(mul(unity_ObjectToWorld, float4(1.0, 0.0, 0.0, 0.0))); o.scale.y = length(mul(unity_ObjectToWorld, float4(0.0, 1.0, 0.0, 0.0))); o.scale.z = length(mul(unity_ObjectToWorld, float4(0.0, 0.0, 1.0, 0.0))); #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(_UV) o.uv = TRANSFORM_TEX(v.uv, _MainTex); #endif #if defined(_NORMAL) #if defined(_NORMAL_MAP) fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz); fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w; fixed3 worldBitangent = cross(worldNormal, worldTangent) * tangentSign; o.tangentX = fixed3(worldTangent.x, worldBitangent.x, worldNormal.x); o.tangentY = fixed3(worldTangent.y, worldBitangent.y, worldNormal.y); o.tangentZ = fixed3(worldTangent.z, worldBitangent.z, worldNormal.z); #else o.worldNormal = worldNormal; #endif #endif return o; } fixed4 frag(v2f i, fixed facing : VFACE) : SV_Target { fixed4 albedo = tex2D(_MainTex, i.uv); #ifdef LIGHTMAP_ON albedo.rgb *= DecodeLightmap(UNITY_SAMPLE_TEX2D(unity_Lightmap, i.lightMapUV)); #endif albedo *= _Color; // Normal calculation. #if defined(_NORMAL) fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPosition.xyz)); #if defined(_ENVIRONMENT_COLORING) fixed3 incident = -worldViewDir; #endif fixed3 worldNormal; #if defined(_NORMAL_MAP) fixed3 tangentNormal = UnpackScaleNormal(tex2D(_NormalMap, i.uv), _NormalMapScale); worldNormal.x = dot(i.tangentX, tangentNormal); worldNormal.y = dot(i.tangentY, tangentNormal); worldNormal.z = dot(i.tangentZ, tangentNormal); worldNormal = normalize(worldNormal) * facing; #else worldNormal = normalize(i.worldNormal) * facing; #endif #endif fixed pointToLight = 1.0; fixed3 fluentLightColor = fixed3(0.0, 0.0, 0.0); // Blinn phong lighting. #if defined(_DIRECTIONAL_LIGHT) #if defined(_LIGHTWEIGHT_RENDER_PIPELINE) float4 directionalLightDirection = _MainLightPosition; #else float4 directionalLightDirection = _WorldSpaceLightPos0; #endif fixed diffuse = max(0.0, dot(worldNormal, directionalLightDirection)); fixed specular = 0.0; #endif // Image based lighting (attempt to mimic the Standard shader). 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 // Environment coloring. #if defined(_ENVIRONMENT_COLORING) fixed3 environmentColor = incident.x * incident.x * _EnvironmentColorX + incident.y * incident.y * _EnvironmentColorY + incident.z * incident.z * _EnvironmentColorZ; output.rgb += environmentColor * max(0.0, dot(incident, worldNormal) + _EnvironmentColorThreshold) * _EnvironmentColorIntensity; #endif return output; } ENDCG } } Fallback "Hidden/InternalErrorShader" }