この記事はNCC Advent Calendar 2018の5日目の記事です.
アドベントカレンダー内で勝手にやってるMetalの連載も5日目です.
勝手にやってるMetal連載
最近Metalを初めて楽しくなっちゃったのでたくさんoutputしてみる会です.
- Rendererを作る
- プロシージャルモデリング的な何か
- フラグメントシェーダで遊ぶ
- テクスチャで遊ぶ
- エフェクトで遊ぶ ← イマココ
(そろそろしんどくなってきた)
Koaraにエフェクトをかけて遊ぶぞ!
フラグメントシェーダしか使いません.
他のソースコードはgithubのリポジトリや前回のTextureの記事を参考にしてください
RGBディストーション
やること
- 赤色成分をx方向にずらす
- 緑色成分をy方向にずらす
- ずらす方向はそれぞれ,スクリーンの中心からの距離に比例する
コード
fragment half4 fragmentDay5(VertexOut vertexIn [[stage_in]],
texture2d<float, access::sample> koaraTexture [[texture(0)]]) {
// 座標変換とそのまま用いたテクスチャ座標
float4 p = (vertexIn.screenCoord+1.0)/2.0;
p.y = 1.0-p.y;
// uniforms
float2 touch = vertexIn.touch;
float time = vertexIn.time;
constexpr sampler nearestSampler(coord::normalized, filter:: nearest);
float4 koara = koaraTexture.sample(nearestSampler, p.xy);
// return half4(koara) // ここからスタート
// RGBディストーション用のコード
// x方向とy方向にずらした座標でサンプリング
float2 d = vertexIn.screenCoord.xy*0.03;
float2 distortion_x = float2(p.x+d.x, p.y);
float2 distortion_y = float2(p.x, p.y+d.y);
float4 koara = koaraTexture.sample(nearestSampler, p.xy);
float4 Koara_distortion_x = koaraTexture.sample(nearestSampler, distortion_x);
float4 Koara_distortion_y = koaraTexture.sample(nearestSampler, distortion_y);
// 合わせて描画
return half4(Koara_distortion_x.x ,Koara_distortion_y.y, koara.z, 1.0);
}
ホワイトノイズ
やること
ノイズを生成して,サンプルした色と掛け合わせます.
使用するノイズは,コピペ伝承のfract-sinノイズです.
出来上がり
コード
float rnd(float2 n) {
return fract(sin(dot(n, float2(12.9898,4.1414)))*43758.5453);
}
fragment half4 fragmentDay5(VertexOut vertexIn [[stage_in]],
texture2d<float, access::sample> koaraTexture [[texture(0)]]) {
// 座標変換とそのまま用いたテクスチャ座標
float4 p = (vertexIn.screenCoord+1.0)/2.0;
p.y = 1.0-p.y;
// uniforms
float2 touch = vertexIn.touch;
float time = vertexIn.time;
constexpr sampler nearestSampler(coord::normalized, filter:: nearest);
float4 koara = koaraTexture.sample(nearestSampler, p.xy);
// ホワイトノイズ
// return half4(half3(koara.xyz*rnd(p.xy)),1.0);
// ホワイトノイズで2値化
return half4(half3(koara.xyz*step(0.5, rnd(p.xy))),1.0);
// 砂嵐化
// return half4(half3(koara.xyz*step(0.5, rnd(p.xy+time))),1.0);
}
横にずらす(エフェクトの名前がわからない)
ホワイトノイズで使ったrnd関数を利用して,各textureのrowを同じだけ横にずらします.
説明分かりづらいので,画像を見て
float rnd(float2 n) {
return fract(sin(dot(n, float2(12.9898,4.1414)))*43758.5453);
}
fragment half4 fragmentDay5(VertexOut vertexIn [[stage_in]],
texture2d<float, access::sample> koaraTexture [[texture(0)]]) {
// 座標変換とそのまま用いたテクスチャ座標
float4 p = (vertexIn.screenCoord+1.0)/2.0;
p.y = 1.0-p.y;
// uniforms
float2 touch = vertexIn.touch;
float time = vertexIn.time;
constexpr sampler nearestSampler(coord::normalized, filter:: nearest);
float4 koara = koaraTexture.sample(nearestSampler, p.xy);
float2 dx_p = float2(p.x+0.03*(rnd(float2(p.y))*2-1), p.y);
float4 dx_Koara = koaraTexture.sample(nearestSampler, dx_p);
return half4(dx_Koara);
}
ポスタリゼーション
やること
それぞれの画素で赤色成分,緑色成分,青色成分をn段階に分けます.
まあ見ればわかるはず
出来上がり
コード
half3 posterization(float3 c, int n) {
return half3(ceil(c.x / (1.0/n)) / n,
ceil(c.y / (1.0/n)) / n,
ceil(c.z / (1.0/n)) / n);
}
fragment half4 fragmentDay5(VertexOut vertexIn [[stage_in]],
texture2d<float, access::sample> koaraTexture [[texture(0)]]) {
// 座標変換とそのまま用いたテクスチャ座標
float4 p = (vertexIn.screenCoord+1.0)/2.0;
p.y = 1.0-p.y;
// uniforms
float2 touch = vertexIn.touch;
float time = vertexIn.time;
constexpr sampler nearestSampler(coord::normalized, filter:: nearest);
float4 koara = koaraTexture.sample(nearestSampler, p.xy);
return half4(posterization(koara.xyz,4),1.0);
}
ソラリゼーション
やること
ソラリゼーションは,トーンカーブを色々したものです.
白黒画像ではなく,赤色成分,緑色成分,青色成分それぞれ独立にソラリゼーションしました,
こんな感じに,部分的に反転します.
出来上がり
こちらからスクショしました.
画像処理検定の参考書にもこのような図がありましたね.
コード
half3 solarisation(float3 c) {
return half3((1-cos(3*3.14*c.x))/2,
(1-cos(3*3.14*c.y))/2,
(1-cos(3*3.14*c.z))/2);
}
fragment half4 fragmentDay5(VertexOut vertexIn [[stage_in]],
texture2d<float, access::sample> koaraTexture [[texture(0)]]) {
// 座標変換とそのまま用いたテクスチャ座標
float4 p = (vertexIn.screenCoord+1.0)/2.0;
p.y = 1.0-p.y;
// uniforms
float2 touch = vertexIn.touch;
float time = vertexIn.time;
constexpr sampler nearestSampler(coord::normalized, filter:: nearest);
float4 koara = koaraTexture.sample(nearestSampler, p.xy);
// ソラリゼーション
return half4(solarisation(koara.xyz),1.0);
}
コードはこちら
githubにあります.