梦开始的地方
近年来卡通风格渲染的游戏越来越多,三渲二这个的出现频率也越来越高
无论是去年提名TGA年度最佳移动端游戏的《崩坏:星穹铁道》还是风靡全球的《原神》,他们都是卡通渲染风格的游戏,也都运用到了三渲二相关技术
原神
不知道你是否和我一样跃跃欲试,想写出一个三渲二风格的shader。
说干就干,不知道您是不是这样想的,所谓三渲二,不就是亮面一个颜色,暗面一个颜色,有明显的明暗交界线吗?简单!
计算一个像素的法向量与光的法向量夹角,诺大于90度,则这个像素位于暗面,反之则位于亮面
我们便可以写出一个简单的shader(以unity的CG语言为例)
//这个shader只是个入门级示例shader,游戏公司的shader比这个复杂很多
Shader "CelShader/CelShaderWithTex"
{
Properties
{
_Darklight("Dark Light",Color) = (0.1,0.1,0.1,1)
_MainTex("Main Tex",2D) = "white"{}
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
#include "Lighting.cginc"
float3 _Darklight;
sampler2D _MainTex;
struct c2v
{
float4 vertex:POSITION;
float3 normal:NORMAL;
float2 uv:TEXCOORD0;
};
struct v2f
{
float4 pos:SV_POSITION;
float3 worldNormal:NORMAL;
float2 uv:TEXCOORD;
float3 objViewDir:COLOR1;
float3 normal:NORMAL2;
};
v2f vert(c2v input)
{
v2f output;
output.pos = UnityObjectToClipPos(input.vertex);
output.worldNormal = normalize( mul((float3x3)unity_ObjectToWorld,input.normal) );
output.uv = input.uv;
float3 ObjViewDir = normalize(ObjSpaceViewDir(input.vertex));
output.objViewDir = ObjViewDir;
output.normal = normalize(input.normal);
return output;
}
fixed3 frag(in v2f input):SV_TARGET0
{
fixed3 diffuseColor = _LightColor0.rgb * tex2D(_MainTex, input.uv).rgb ;
fixed3 col = UNITY_LIGHTMODEL_AMBIENT.xyz + diffuseColor;
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
if(dot(input.worldNormal,worldLightDir)<0)
{
return col * _Darklight;
}
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
//LZX completed this shader in 2024/04/04
当然了,在shader实战中我们应该尽量避免if(因为显卡不擅长逻辑判断,显卡擅长的是浮点运算)