UnityのTerrainで生やした花を光らせる方法
問題
TerrainのDetailsでプレファブの花を登録して生やしたわけですが、花マテリアルに設定したEmissionが機能してくれない!!
この文章を見る感じ、ビルトインシェーダ をいじらないといけないっぽいのでやってみる。
最終的な見た目
実装方法
Unityアーカイブページからビルトインシェーダ をダウンロード 2018.2.11のビルトインシェーダ zipファイルを展開後、そのままasset に追加。これを書き換えればUnityの元々保持しているスクリプトを上書きできるらしい。
以下のWabingGrassシェーダ をいじると、TerrainにおいてDetailsに登録されている花のshaderを変更することができる。ここにEmissionマップをくっつけたい。
EmissionをこのWavingGrass.shaderにつける
具体的には、
o.Emission = _EmissionColor;
のようにして_EmissionColorを宣言する。すると以下のような図になる。ただしこれは全体にかかっていて、花びらのみにかかってるものではない。
解決方法 花びらのみを光らせたいので、_MainTexのうち青い部分のみを光らせるというコードを追加した。
こちらを参考にしました。 onoty3d.hatenablog.com
WavingGrass.shader
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) Shader "Hidden/TerrainEngine/Details/WavingDoublePass" { Properties { _WavingTint ("Fade Color", Color) = (.7,.6,.5, 0) _MainTex ("Base (RGB) Alpha (A)", 2D) = "white" {} _WaveAndDistance ("Wave and distance", Vector) = (12, 3.6, 1, 1) _Cutoff ("Cutoff", float) = 0.5 _EmissionTex ("Emission Texture", 2D) = "white" {} //追加 _EmissionColor("Emission Color", Color) = (0,1.04,1.28,0) //追加 _Near("Near", Range(0, 0.5)) = 0.1 //追加 } SubShader { Tags { "Queue" = "Geometry+200" "IgnoreProjector"="True" "RenderType"="Grass" "DisableBatching"="True" } Cull Off LOD 200 ColorMask RGB CGPROGRAM #pragma surface surf Lambert vertex:WavingGrassVert addshadow exclude_path:deferred #include "TerrainEngine.cginc" sampler2D _MainTex; fixed _Cutoff; //追記-> half4 _EmissionColor; sampler2D _EmissionTex; fixed _Near; fixed GetHue(fixed3 rgb) { fixed hue = 0; fixed minValue = min(rgb.r, min(rgb.g, rgb.b)); fixed maxValue = max(rgb.r, max(rgb.g, rgb.b)); fixed delta = maxValue - minValue; if (delta != 0) { if (maxValue == rgb.r) { hue = (rgb.g - rgb.b) / delta; } else if (maxValue == rgb.g) { hue = 2.0 + (rgb.b - rgb.r) / delta; } else { hue = 4.0 + (rgb.r - rgb.g) / delta; } hue /= 6.0; if (hue < 0) { hue += 1.0; } } return hue; } //<-追記 struct Input { float2 uv_MainTex; fixed4 color : COLOR; }; void surf (Input IN, inout SurfaceOutput o) { fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * IN.color; o.Albedo = c.rgb; o.Alpha = c.a; clip (o.Alpha - _Cutoff); o.Alpha *= IN.color.a; //追記-> fixed4 col = tex2D(_MainTex, IN.uv_MainTex); fixed4 e = tex2D(_EmissionTex, IN.uv_MainTex); fixed distance = GetHue(col.rgb) - GetHue(_EmissionColor); if (distance > 0.5) { distance = 1.0 - distance; } else if (distance < -0.5) { distance = 1.0 + distance; } else { distance = abs(distance); } if (distance < _Near) { o.Emission = _EmissionColor * e; } //<-追記 } ENDCG } SubShader { Tags { "Queue" = "Geometry+200" "IgnoreProjector"="True" "RenderType"="Grass" } Cull Off LOD 200 ColorMask RGB Pass { Tags { "LightMode" = "Vertex" } Material { Diffuse (1,1,1,1) Ambient (1,1,1,1) } Lighting On ColorMaterial AmbientAndDiffuse AlphaTest Greater [_Cutoff] SetTexture [_MainTex] { combine texture * primary DOUBLE, texture } } // Lightmapped Pass { Tags{ "LIGHTMODE" = "VertexLM" "RenderType" = "Opaque" } CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma target 2.0 #include "UnityCG.cginc" #pragma multi_compile_fog #define USING_FOG (defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2)) float4 _MainTex_ST; struct appdata { float3 pos : POSITION; float3 uv1 : TEXCOORD1; float3 uv0 : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct v2f { float2 uv0 : TEXCOORD0; float2 uv1 : TEXCOORD1; #if USING_FOG fixed fog : TEXCOORD2; #endif float4 pos : SV_POSITION; UNITY_VERTEX_OUTPUT_STEREO }; v2f vert(appdata IN) { v2f o; UNITY_SETUP_INSTANCE_ID(IN); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.uv0 = IN.uv1.xy * unity_LightmapST.xy + unity_LightmapST.zw; o.uv1 = IN.uv0.xy * _MainTex_ST.xy + _MainTex_ST.zw; #if USING_FOG float3 eyePos = UnityObjectToViewPos(IN.pos); float fogCoord = length(eyePos.xyz); UNITY_CALC_FOG_FACTOR_RAW(fogCoord); o.fog = saturate(unityFogFactor); #endif o.pos = UnityObjectToClipPos(IN.pos); return o; } sampler2D _MainTex; fixed4 frag(v2f IN) : SV_Target { fixed4 col; fixed4 tex = UNITY_SAMPLE_TEX2D(unity_Lightmap, IN.uv0.xy); half3 bakedColor = DecodeLightmap(tex); tex = tex2D(_MainTex, IN.uv1.xy); col.rgb = tex.rgb * bakedColor; col.a = 1.0f; #if USING_FOG col.rgb = lerp(unity_FogColor.rgb, col.rgb, IN.fog); #endif return col; } ENDCG } } Fallback Off }
これでめでたく花部分の色を抽出してその色に光らせることができた!
できなかったこと
その1
C#スクリプトから当該shaderをいじろうとしてもうまくいかなかった。
Material material = new Material(Shader.Find("Hidden/TerrainEngine/Details/WavingDoublePass")); material.SetTexture("_EmissionTex", emissionMap);
このように話してる人もいる。
その2
これはダメだったというかやり方がわからなかったので、どなたか方法を知ってる人がいたら教えてください。
- WavingGrass.shaderに直接EmissionMapにTextureを指定する
- .cgincを作成し、EmissionMapとなる2Dtextureをreturnさせる