策划给的参考图:
这是游戏中的效果图:
说明:
原理很简单 菲列尔 + 兰伯特,控制边光范围和强度。
但是我们美术有个特殊需求:要求星球在任意位置,边光的范围都保持一致(场景也是移动的)。
如果仅仅使用普通的兰伯特,星球的受光范围在平面上是变化的。如下图:
这个情况不符合美术需求,原因是在不同位置看到的法线分布不一样。
为了纠正这个问题可以使用 N 叉乘 V 来作为新的法线使用, 这样能得面向视角的法线。
Shader代码如下:
Shader "WingFighter/ShiftLight"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {
}
_LightDir ("LightDir", Vector) = (1,1,0,0)
_RimColor ("RimColor", Color) = (1,1,1,1)
_RimIntensity ("RimIntensity", range(0,100)) = 1
_RimPower("RimPower", float) = 1
_RimLambertPower("RimLambertPower", float) = 1
_RimLambertOffset("RimLambertOffset", range(0,1)) = 0
_ShadowStrength("ShadowStrength", range(0,0.5)) = 0.1
[Header(CommonRim)]
_CommonRimColor ("CommonRimColor", Color) = (1,1,1,1)
_CommonRimPower("CommonRimPower", float) = 1
_CommonRimIntensity("CommonRimIntensity", float) = 1
}
SubShader
{
Tags {
"RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityShaderVariables.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldNormal : TEXCOORD2;
float4 worldPos : TEXCOORD3;
float4 distance : TEXCOORD4;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _LightDir;
float4 _RimColor;
half _RimPower;
half _RimIntensity;
half _RimLambertPower;
half _RimLambertOffset;
half _ShadowStrength;
half _CommonRimIntensity;
float4 _CommonRimColor;
half _CommonRimPower;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
float3 viewPos = UnityObjectToViewPos(v.vertex);
float3 centerViewPos = UnityObjectToViewPos(float4(0,0,0,0));
o.distance.x = distance(viewPos, centerViewPos);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 mainColor = tex2D(_MainTex, i.uv);
float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
float3 newNormal = cross(i.worldNormal, worldViewDir);
float NDotL = dot( newNormal, _LightDir);
float halfLambert = NDotL * 0.5 + 0.5;
float adjustedLabmbert = saturate(halfLambert - _RimLambertOffset);
float halfLambertPow = pow(adjustedLabmbert, _RimLambertPower);
half NDotV = dot(i.worldNormal, worldViewDir);
half rimlight = pow(1 - NDotV, _RimPower);
float rimIntensity = rimlight * _RimIntensity * halfLambertPow;
half commonRimStrength = pow(1 - NDotV, _CommonRimPower);
half3 commonRim = mainColor * rimlight * commonRimStrength * _CommonRimColor * _CommonRimIntensity;
half3 finalColor = mainColor * (_ShadowStrength + rimIntensity * _RimColor) + commonRim.rgb;
return half4(finalColor, 1);
}
ENDCG
}
}
}