对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,投影等等事物做调整,无法用于实际项目。
(转发自:原日志地址)