对2D的光照一直很感兴趣,然后不停的找资料,发现大部分演示都很脏,不够卡通。所以后来就去买了Shader的书,顺便还看到了love2d论坛上的这个帖子https://love2d.org/forums/viewtopic.php?f=5&t=11076,然后就找到了思路。
素材也是改造自上面那个帖子里的(稍微有点觉得奇怪的是不知道为啥帖子里的生成的法线贴图的G通道是反的,我手动调换了一下灰度变成正的了)。
光照没有用unity内置的,而是用了一个新的obj跟随鼠标,然后要渲染的物体用脚本获取此obj的坐标赋值给材质。
做出来是这个效果的。其中法线贴图和AO贴图我扩大成256x256像素并高斯模糊了,因为如果法线保留原本低像素的话,阴影的锯齿因为不可控所以非常显眼,增加平滑插值又体现不出卡通的味道了,所以只想到这种办法。
贴图分别是这三张:
其中最后一张AO贴图里r通道是AO贴图本身,b通道是为了不被光照影响而重新绘制的黑色勾边。
Shader的写法是:
Shader "2D_Cel_Shader" { Properties { _MainTex ("Main Tex", 2D) = "white" {} _dark_color ("Dark Color", Color) = (0,0,1,1) _light_color ("Light Color", Color) = (1,1,0,1) _BumpMap ("Normal Map", 2D) = "bump" {} _AOMap ("AO Map", 2D) = "white" {} _light_position ("Light Position", Vector) = (0,0,0,0) } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } Pass { Tags { "LightMode"="ForwardBase" } ZWrite Off Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" sampler2D _MainTex; float4 _MainTex_ST; float4 _light_color; float4 _dark_color; sampler2D _BumpMap; float4 _BumpMap_ST; sampler2D _AOMap; float4 _AOMap_ST; float4 _light_position; struct a2v { float4 vertex : POSITION; float4 texcoord : TEXCOORD0; }; struct v2f { float4 pos : SV_POSITION; float4 uv : TEXCOORD0; float2 ao : TEXCOORD1; float3 worldpos : TEXCOORD2; }; v2f vert (a2v v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _MainTex_ST.zw; o.ao.xy = v.texcoord.xy * _AOMap_ST.xy + _AOMap_ST.zw; o.worldpos = mul(unity_ObjectToWorld, v.vertex).xyz; return o; } float4 frag (v2f i) : SV_Target { float4 diffuse = tex2D(_MainTex, i.uv.xy).rgba; float3 channels = tex2D(_AOMap, i.ao.xy).rgb; float ao = channels.r; float bypass = channels.g; float3 normal = tex2D(_BumpMap, i.uv.zw).rgb; normal = normalize(2*normal-1); float3 light = float3(0,0,0); float3 light_dir = _light_position.xyz - i.worldpos; float3 view_dir = normalize(UnityWorldSpaceViewDir(i.worldpos)); float dist = light_dir.z; float atten = smoothstep(60, 30 ,dist); light_dir = normalize(light_dir); float3 current_light = atten * lerp(0,1,dot(normal, light_dir))*(ao+0.05)*1.2; light = max(0,current_light-0.38); light *= ao; diffuse += tex2D(_MainTex, i.uv.xy).rgba/2 ; float3 gooch_light = ( _dark_color * (1 - light) + _light_color * light * 1.6) * 0.4; float3 cel_light = smoothstep(0.1, 0.19, (current_light)/2) + diffuse.rgb; return float4(float3 (( cel_light * diffuse *0.5 + gooch_light) * bypass), diffuse.a); } ENDCG } } }
这个Shader只是测试了光照的算法,并没有对多光源,Sprites,投影等等事物做调整,无法用于实际项目。
感谢,收藏一下,过一段时间肯定可以用到。