什么是 CheckerBoard
你可以去翻译一下,就是棋盘格的意思 一般长下图的样子
(是否在很多 DCC 软件可以看到类似的图案,如:Photoshop 的透明底色,或是一些预览图片的软件都使用类似下面的 CheckerBoard 来表示透明部分)
来个最简单的 CheckerBoard
显示全屏UV
Shader "Test/T1_ShowScreenPos01"
{
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
void vert (
float4 positionOS : POSITION,
out float4 positionCS : SV_POSITION,
out float2 screenPos : TEXCOORD0
)
{
positionCS = UnityObjectToClipPos(positionOS);
float4 sp = ComputeScreenPos(positionCS);
screenPos = sp.xy / sp.w * _ScreenParams.xy;
}
fixed4 frag(float4 positionCS : SV_POSITION, float2 screenPos : TEXCOORD0) : SV_Target
{
return fixed4(screenPos / _ScreenParams.xy, 0, 1);
}
ENDCG
}
}
}
显示棋盘格
水平分段一下(但是黑色分割先只有1个像素)
Shader "Test/T2_ShowCheckerBox"
{
Properties
{
_CheckerBoardSize("Checker Board Size", Float) = 2
}
SubShader
{
Pass
{
...
fixed4 frag(float4 positionCS : SV_POSITION, float2 screenPos : TEXCOORD0) : SV_Target
{
return screenPos.x % _CheckerBoardSize;
ENDCG
}
}
}
填充分阶的内容为 0~1 的渐变值
Shader "Test/T2_ShowCheckerBox"
{
Properties
{
_CheckerBoardSize("Checker Board Size", Float) = 2
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
half _CheckerBoardSize;
void vert (
float4 positionOS : POSITION,
out float4 positionCS : SV_POSITION,
out float2 screenPos : TEXCOORD0
)
{
positionCS = UnityObjectToClipPos(positionOS);
float4 sp = ComputeScreenPos(positionCS);
screenPos = sp.xy / sp.w * _ScreenParams.xy;
}
fixed4 frag(float4 positionCS : SV_POSITION, float2 screenPos : TEXCOORD0) : SV_Target
{
return screenPos.x % _CheckerBoardSize / _CheckerBoardSize;
}
ENDCG
}
}
}
将0~1 渐变值一分为二
将 0 ~ 1 的渐变值一分为二的思路可以使用:round(val) 函数,等价于 val > 0.5 ? 1 : 0 ,二值化
将 screenPos.x 调整为 y ,可以输出纵向的色阶
return round(screenPos.y % _CheckerBoardSize / _CheckerBoardSize);
最终棋盘格:输出纵横向的相异为真的像素值
Shader "Test/T2_ShowCheckerBox"
{
Properties
{
_CheckerBoardSize("Checker Board Size", Float) = 2
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
half _CheckerBoardSize;
void vert (
float4 positionOS : POSITION,
out float4 positionCS : SV_POSITION,
out float2 screenPos : TEXCOORD0
)
{
positionCS = UnityObjectToClipPos(positionOS);
float4 sp = ComputeScreenPos(positionCS);
screenPos = sp.xy / sp.w * _ScreenParams.xy;
}
fixed4 frag(float4 positionCS : SV_POSITION, float2 screenPos : TEXCOORD0) : SV_Target
{
screenPos = round(screenPos % _CheckerBoardSize / _CheckerBoardSize);
return screenPos.x != screenPos.y;
}
ENDCG
}
}
}
从上图分析我们可以知道,可以将 相异为真 的结果输出即可
其他 CheckerBoard 的样式
有了前面的 简单的 CheckerBoard 方式
下面我们搞一些其他的 pattern,都是经验公式(实验出来的)
同样的,使用 sin 都所有色阶抖动的函数(但是 0 ~ 1 色阶过度太平滑)
Shader "Test/T3_ShowOhterCheckerBox"
{
Properties
{
_CheckerBoardSize("Checker Board Size", Float) = 2
_CheckerBoardWrap("Checker Board Wrap", Float) = 2
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
half _CheckerBoardSize;
half _CheckerBoardWrap;
void vert (
float4 positionOS : POSITION,
out float4 positionCS : SV_POSITION,
out float2 screenPos : TEXCOORD0
)
{
positionCS = UnityObjectToClipPos(positionOS);
float4 sp = ComputeScreenPos(positionCS);
screenPos = sp.xy / sp.w * _ScreenParams.xy;
}
fixed4 frag(float4 positionCS : SV_POSITION, float2 screenPos : TEXCOORD0) : SV_Target
{
return sin(screenPos.x * _CheckerBoardSize) * _CheckerBoardWrap;
}
ENDCG
}
}
}
和之前一样,可以 round 一下二值化来分色阶
fixed4 frag(float4 positionCS : SV_POSITION, float2 screenPos : TEXCOORD0) : SV_Target
{
return round(sin(screenPos.x * _CheckerBoardSize) * _CheckerBoardWrap);
}
同样的相异为真输出 checkerboard
fixed4 frag(float4 positionCS : SV_POSITION, float2 screenPos : TEXCOORD0) : SV_Target
{
screenPos = round(sin(screenPos * _CheckerBoardSize) * _CheckerBoardWrap);
return screenPos.x != screenPos.y;
}
但是可以看到,这个棋盘格的效果和之前的不太一样
然后上面的 return screenPos.x != screenPos.y; 可以换成:return screenPos.x == screenPos.y; ,我向你应该知道什么结果(反向结果)
其他花样
T1
return any(round(sin(screenPos * _CheckerBoardSize) * _CheckerBoardWrap));
T2
return all(round(sin(screenPos * _CheckerBoardSize) * _CheckerBoardWrap));
T3
screenPos = round(tan(screenPos * _CheckerBoardSize) * _CheckerBoardWrap);
return screenPos.x * screenPos.y;
T4
screenPos = round(tan(screenPos * _CheckerBoardSize) * _CheckerBoardWrap);
return screenPos.x == screenPos.y;
etc.
sp = round(floor(sp % _CheckerBoardWrap) / _CheckerBoardSize);
return round(tan(sp.x) * tan(sp.y));
上面的都是随便试出来的效果
这些东西能用在什么地方
如果我们将, checker board ==0 的黑色像素都 discard 掉
将 checker board 的 grid 弄得足够小,是不是就有点向一些游戏效果中的简单的 dither 作为透明,或是马赛克显示效果(如:原神 中,你如果把镜头往人物胯部看的话,就发现人物被 checker board pattern 的方式给 discard 掉部分像素,让想看的地方看得不太清晰,而不至于被和的得情况)
或是有些游戏会在:XRay 时显示 checker board 的像素,一般会显示 rim 效果的比较多
后续我会再写个,这些 checker board,不时通过程序化生成,而是 Texture 简单应用的场景,其实就时类似:马赛克分色阶 来溶解的效果
Project
TestingCheckerBoardPattern_unity_2019.4.30f1
|