ハーフトーン - saitocastel1900/UnityShader GitHub Wiki
- 影を点々にして、アニメ調演出をするときに使われるやつ
- まずは点々を適当に描画してみる
-
今回は、スクリーン座標をもとに点々を書いていくので、スクリーン座標を求めていますが、このような処理が必要です「float2 screenPos = i.screenPos.xy / i..w;」。ん?すでにスクリーン座標を求めていない?「o.screenPos = ComputeScreenPos(o.vertex);」と思ったのですが、この処理だけではダメなようで(このままだとクリッピング座標)、先ほど提示した通りwで除算することでスクリーン座標が求まります。また、クリッピング座標の範囲は(0.0~w)のようですが、スクリーン座標は、0.0から1.0なので色々直す必要がある.これを物体からの距離が入っているwで除算することで、物体とカメラの距離(視点)に基づいて0.0から1.0に直すことができるみたい
詳しくはこちらを:https://light11.hatenadiary.com/entry/2018/06/10/233954 -
あとはアスペクト比から、点を書き込むマス目の中心を求める。「floor(screenPos.x / cellSize.x) * cellSize.x 」で基準となる点を求めてから、「+ cellSize.x / 2」で相対的なマスの中間地点を足すことで求める
-
そして、求めた中点から、塗るピクセルとの距離を求めて、その距離に応じて点々を描画する範囲かを判定して、塗るべきだったる塗るといった感じ。コードとしては「 float2 diff = (screenPos - cellCenter) / cellSize;」で、距離を矩形の大きさで割ることで矩形のサイズ単位(相対的)にしている模様
Shader "Unlit/HalftoneUnlitShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_HalftoneScale("HlaftoneScale",Range(0.001,0.1))=0.02
}
SubShader
{
Tags
{
"RenderType"="Opaque"
}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
float _HalftoneScale;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 screenPos: TEXCOORD1;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.screenPos = ComputeScreenPos(o.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
//これでスクリーン座標を求めているみたい
float2 screenPos = i.screenPos.xy / i.screenPos.w;
//アスペクト比
float aspect = _ScreenParams.x / _ScreenParams.y;
float2 cellSize = float2(_HalftoneScale,_HalftoneScale * aspect);
float2 cellCenter;
cellCenter.x = floor(screenPos.x/cellSize.x) * cellSize.x + cellSize.x / 2;
cellCenter.y = floor(screenPos.y / cellSize.y) * cellSize.y + cellSize.y / 2;
float2 diff = screenPos - cellCenter;
diff.x /= cellSize.x;
diff.y /= cellSize.y;
float threshold = 0.3;
col.rgb *= lerp(1,0.5,step(length(diff),threshold));
return col;
}
ENDCG
}
}
}
-
影と同じように書き込みたいので、光のベクトルと物体の法線から内積をとって、影かを判定して、それをもとに書き込む。コードとしてはこんな感じ「float3 normal = normalize(i.normal); float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
float threshold = 1 - dot(normal,lightDir); float col = lerp(1,_ShaderColor,step(length(diff),threshold));」
Shader "Unlit/HalftoneUnlitShader"
{
Properties
{
_HalftoneScale("HlaftoneScale",Range(0.001,0.1))=0.02
_ShaderColor("ShaderColor",Color) = (1,1,1,1)
}
SubShader
{
Tags
{
"RenderType"="Opaque"
}
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
float _HalftoneScale;
float3 _ShaderColor;
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 norma : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 screenPos: TEXCOORD1;
float3 normal : NORMAL;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.screenPos = ComputeScreenPos(o.vertex);
o.normal = UnityObjectToWorldNormal(v.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
//これでスクリーン座標を求めているみたい
float2 screenPos = i.screenPos.xy / i.screenPos.w;
//アスペクト比
float aspect = _ScreenParams.x / _ScreenParams.y;
//マス目の大きさ(矩形)
float2 cellSize = float2(_HalftoneScale,_HalftoneScale * aspect);
float2 cellCenter;
//スクリーン座標をセルの大きさで除算することで、セルの中心点をスクリーン座標基準ではなく、セル基準で考えている
cellCenter.x = floor(screenPos.x / cellSize.x) * cellSize.x + cellSize.x / 2;
cellCenter.y = floor(screenPos.y / cellSize.y) * cellSize.y + cellSize.y / 2;
float2 diff = (screenPos - cellCenter) / cellSize;
float3 normal = normalize(i.normal);
float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
float threshold = 1 - dot(normal,lightDir);
float col = lerp(1,_ShaderColor,step(length(diff),threshold));
return fixed4(col,col,col,1);
}
ENDCG
}
}
}