勉強メモ: 市松模様を描くシェーダーについて
市松模様(チェッカー柄)で画面を埋めるといったことがしたかったので、
こちらの記事のシェーダーを使わせていただいた。
qiita.com
このシェーダーが何をしているかについて勉強したときのメモ。
このシェーダーは基本Surfaceシェーダーに、パラメータとsurf関数内に下記の記述を加えたもの。
if (int(fmod(floor(IN.uv_MainTex.x * _Division) + floor(IN.uv_MainTex.y * _Division), 2.0)) == 0) { discard; }
上記の記述では、条件に一致した座標にあるピクセルの場合、処理を中断して、ピクセルを描画しないようにしている。
一行になっていてわかりづらいので、変数に分けるとこのようになる。
float x_value = floor(IN.uv_MainTex.x * _Division); float y_value = floor(IN.uv_MainTex.y * _Division); float surplus = fmod(x_value + y_value, 2.0); if(int(surplus) == 0){ discard; }
簡単にいうと、UV座標のxとyに対して、分割数に応じた値を掛けたものを合計し、
その合計が2.0で割り切れた場合はそのピクセルを描画せず、割り切れなかった場合は描画するようにしている。
x_valueとy_valueの合計が2.0で割り切れるためには、
x_valueとy_valueが共に奇数、または共に偶数になる必要がある。
片方が奇数で片方が偶数の場合、これは2.0で割り切れない。
自分でも何を言っているかよくわからなくなってきたので、図を使って説明する。
とりあえず、分割数_Divisionが2の場合を考えてみる。
その場合、市松模様はこのような感じになる。
UV座標は縦と横にそれぞれ0から1までの値を取る。
それを2つに分割するので、1÷2 = 0.5ごとに描画するかどうかを決めるxとyの閾値が決まる。
ここでは、①と④の範囲は描画されず、②と③の範囲のみが描画される。
①の範囲ではx_valueが0、y_valueが0になる。
実際にそうなるかどうか、先ほどのコードに具体的な値をいれて確かめてみる。
適当にここでは(x, y) = (0.4, 0.2)という点で試してみる。
// 0.4 * 2は0.8なのでfloorで切り捨てられ、値は0となる float x_value = floor(0.4 * 2); // 0.2 * 2は0.4なのでfloorで切り捨てられ、値は0となる float y_value = floor(0.2 * 2); //fmod(a, b)はaをbで割った余りを返す。0を2.0で割った余りは0 float surplus = fmod(x_value + y_value, 2.0) if(int(surplus) == 0){//int(surplus)の値は0となるので条件と一致する。 discard; }
同じように計算すると、④の範囲ではどの点でもx_valueが1、y_valueが1になる。
合計が偶数となるので、2.0で割った余りは0となりif文の条件と一致してdiscardされる。
逆に②と③の合計は2.0で割り切れない値となるので、条件と一致せず普通に描画される。
分割数が増えていくと、閾値の位置が変わる。
分割数が3の場合、閾値は1/3 = 0.333...ごとに設定される。
分割数が4の場合、閾値は1/4 = 0.25ごとに設定される。
このように分割数が増えていけば、描画するしないの閾値が増えていく。