类崩坏三 NPR渲染
大致想法
Ramp + 高光 + 边缘光 + HSV调节
Ramp
分阶色Shader代码
// multi steps
float diff = smoothstep(_RampThreshold - ndl, _RampThreshold + ndl, ndl);
float interval = 1 / _ToonSteps;
// float ramp = floor(diff * _ToonSteps) / _ToonSteps;
float level = round(diff * _ToonSteps) / _ToonSteps;
float ramp ;
if (_RampSmooth == 1)
{
ramp = interval * linearstep(level - _RampSmooth * interval * 0.5, level + _RampSmooth * interval * 0.5, diff) + level - interval;
}
else
{
ramp = interval * smoothstep(level - _RampSmooth * interval * 0.5, level + _RampSmooth * interval * 0.5, diff) + level - interval;
}
ramp = max(0, ramp);
ramp *= atten;
_SColor = lerp(_HColor, _SColor, _SColor.a);
float3 rampColor = lerp(_SColor.rgb, _HColor.rgb, ramp);
高光效果
高光Shader代码
// specular
float spec = pow(ndh, s.Specular * 128.0) * s.Gloss;
spec *= atten;
spec = smoothstep(0.5 - _SpecSmooth * 0.5, 0.5 + _SpecSmooth * 0.5, spec);
边缘光效果
边缘光Shader代码
float rim = (1.0 - ndv) * ndl;
rim *= atten;
rim = smoothstep(_RimThreshold - _RimSmooth * 0.5, _RimThreshold + _RimSmooth * 0.5, rim);
fixed4 color;
fixed3 diffuse = s.Albedo * rampColor *(ndv + 1.5);
fixed3 specular = _SpecColor.rgb * spec;
fixed3 rimColor = _RimColor.rgb * _RimColor.a * rim;
效果截图
截图一
截图二
完整代码
Shader "Toon"
{
Properties
{
// Colors
_Color ("Color", Color) = (1, 1, 1, 1)
_HColor ("Highlight Color", Color) = (0.8, 0.8, 0.8, 1.0)
_SColor ("Shadow Color", Color) = (0.2, 0.2, 0.2, 1.0)
// texture
_MainTex ("Main Texture", 2D) = "white" { }
// ramp
_ToonSteps ("Steps of Toon", range(1, 9)) = 2
_RampThreshold ("Ramp Threshold", Range(0.1, 1)) = 0.5
_RampSmooth ("Ramp Smooth", Range(0, 1)) = 0.1
// specular
_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
_SpecSmooth ("Specular Smooth", Range(0, 1)) = 0.1
_Shininess ("Shininess", Range(0.001, 10)) = 0.2
// rim light
[HDR]_RimColor ("Rim Color", Color) = (1,1,1,1)
_RimThreshold ("Rim Threshold", Range(0, 1)) = 0.5
_RimSmooth ("Rim Smooth", Range(0, 1)) = 0.289
_Outline ("Outline", Range(0, 1)) = 0.002
_OutColor ("Outline Color", Color) = (0, 0, 0, 1)
_Factor("Factor",range(0,1)) = 0.5
//rgb to hsv
_HueOffset("Hue Offset", Range(0,1)) = 0
_SaturationOffset("Hue Offset", Range(-1,1)) = 0.3
_ValueOffset("Hue Offset", Range(-1,1)) = 0.15
_BloomFactor("_BloomFactor", Range(0.0, 0.9)) = 0
[HDR]_FresnealColor("FresnealColor",Color) = (1,0.4191,0.6715,1)
_FresnealScale("FresnealScale",Range(0,10)) = 1.88
}
SubShader
{
Tags { "RenderType" = "Opaque" }
Pass {
NAME "OUTLINE"
Tags{ "LightMode" = "Always" }
Cull Front
ZWrite On
CGPROGRAM
#pragma multi_compile_fog
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _Outline;
fixed4 _OutColor;
float _Factor;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f {
float4 pos : SV_POSITION;
UNITY_FOG_COORDS(0)
};
v2f vert (a2v v) {
v2f o;
float3 dir = normalize(v.vertex.xyz);
float3 dir2 = v.normal;
float D = dot(dir,dir2);
dir = dir * sign(D);
dir = dir * _Factor + dir2 * (1 - _Factor);
v.vertex.xyz += dir * _Outline;
o.pos = UnityObjectToClipPos(v.vertex);
UNITY_TRANSFER_FOG(o, o.pos);
return o;
}
float4 frag(v2f i) : SV_Target {
float4 c = _OutColor;
UNITY_APPLY_FOG(i.fogCoord, c);
return c;
}
ENDCG
}
CGPROGRAM
#pragma surface surf Toon addshadow fullforwardshadows exclude_path:deferred exclude_path:prepass
#pragma surface surf Standard fullforwardshadows keepalpha
#pragma target 3.0
fixed4 _Color;
fixed4 _HColor;
fixed4 _SColor;
sampler2D _MainTex;
float _RampThreshold;
float _RampSmooth;
float _ToonSteps;
float _SpecSmooth;
fixed _Shininess;
fixed4 _RimColor;
fixed _RimThreshold;
float _RimSmooth;
float _HueOffset;
float _SaturationOffset;
float _ValueOffset;
float _BloomFactor;
fixed4 _FresnealColor;
float _FresnealScale;
struct Input
{
float2 uv_MainTex;
float3 viewDir;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
return o;
}
float linearstep(float min, float max, float t)
{
return saturate((t - min) / (max - min));
}
inline fixed4 LightingToon(SurfaceOutput s, half3 lightDir, half3 viewDir, half atten)
{
half3 normalDir = normalize(s.Normal);
half3 halfDir = normalize(lightDir + viewDir);
float ndl = max(0, dot(normalDir, lightDir));
float ndh = max(0, dot(normalDir, halfDir));
float ndv = max(0, dot(normalDir, viewDir));
fixed3 Fresneal = pow(1.0 - max(0,dot(normalDir, viewDir)),_FresnealScale)*_FresnealColor.rgb;
fixed4 finalFresneal = fixed4(Fresneal,1);
// multi steps
float diff = smoothstep(_RampThreshold - ndl, _RampThreshold + ndl, ndl);
float interval = 1 / _ToonSteps;
// float ramp = floor(diff * _ToonSteps) / _ToonSteps;
float level = round(diff * _ToonSteps) / _ToonSteps;
float ramp ;
if (_RampSmooth == 1)
{
ramp = interval * linearstep(level - _RampSmooth * interval * 0.5, level + _RampSmooth * interval * 0.5, diff) + level - interval;
}
else
{
ramp = interval * smoothstep(level - _RampSmooth * interval * 0.5, level + _RampSmooth * interval * 0.5, diff) + level - interval;
}
ramp = max(0, ramp);
ramp *= atten;
_SColor = lerp(_HColor, _SColor, _SColor.a);
float3 rampColor = lerp(_SColor.rgb, _HColor.rgb, ramp);
// specular
float spec = pow(ndh, s.Specular * 128.0) * s.Gloss;
spec *= atten;
spec = smoothstep(0.5 - _SpecSmooth * 0.5, 0.5 + _SpecSmooth * 0.5, spec);
// rim
float rim = (1.0 - ndv) * ndl;
rim *= atten;
rim = smoothstep(_RimThreshold - _RimSmooth * 0.5, _RimThreshold + _RimSmooth * 0.5, rim);
fixed4 color;
fixed3 diffuse = s.Albedo * rampColor *(ndv + 1.5);
fixed3 specular = _SpecColor.rgb * spec;
fixed3 rimColor = _RimColor.rgb * _RimColor.a * rim;
float3 rgb = diffuse.rgb;
float4 k = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(rgb.bg, k.wz), float4(rgb.gb, k.xy), step(rgb.b, rgb.g));
// 比较r和max(b,g)
float4 q = lerp(float4(p.xyw, rgb.r), float4(rgb.r, p.yzx), step(p.x, rgb.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
float3 hsv = float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
hsv.x = hsv.x + _HueOffset;
hsv.y = hsv.y + _SaturationOffset;
hsv.z = hsv.z + _ValueOffset;
rgb = saturate(3.0*abs(1.0-2.0*frac(hsv.x+float3(0.0,-1.0/3.0,1.0/3.0)))-1); //明度和饱和度为1时的颜色
rgb = (lerp(float3(1,1,1),rgb,hsv.y)*hsv.z); // hsv
color.rgb = rgb + specular + rimColor;
color.a = s.Alpha;
fixed4 col;
col.rgb = color.rgb;
col.a = 1;
return col + finalFresneal;
}
void surf(Input IN, inout SurfaceOutput o)
{
fixed4 mainTex = tex2D(_MainTex, IN.uv_MainTex);
o.Albedo = mainTex.rgb * _Color.rgb;
o.Alpha = _BloomFactor;
o.Specular = _Shininess;
o.Gloss = mainTex.a;
}
ENDCG
}
FallBack "Diffuse"
}