スタイライズのルック開発
Kuwahara Filter
Kuwaharaフィルターはもともと、エッジを保持しながら画像のノイズを減らすために開発されました。
上の図は、Kuwaharaフィルターがピクセルを平均化する様子を示しています。結果は絵画のようなイメージになります。
Unreal Engine用のKuwaharaフィルターコードの書き方を詳しく説明した素晴らしいチュートリアルがYouTubeにあります⇩
Kuwahara C# Code
float sobelX[9] = {-1, -2, -1, 0, 0, 0, 1, 2, 1};
float sobelY[9] = {-1, 0, 1, -2, 0, 2, -1, 0, 1};
float3 mean[4] = {
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0}
};
float3 sigma[4] = {
{0,0,0},
{0,0,0},
{0,0,0},
{0,0,0}
};
float2 offsets[4] = {{-Radius.x, -Radius.y}, {-Radius.x, 0}, {0, -Radius.y}, {0, 0}};
float2 pos;
float3 col;
float gradientX = 0;
float gradientY = 0;
int index = 0;
float2 texelSize = 1.0/ViewSize;
for(int x = -1; x <= 1; x++)
{
for(int y = -1; y <= 1; y++)
{
if(index == 4)
{
index++;
continue;
}
float2 offset = float2(x, y) * texelSize;
float3 pxCol = SceneTextureLookup(UV + offset, 14, false).xyz;
float pxLum = dot(pxCol, float3(0.2126, 0.7152, 0.0722));
gradientX += pxLum * sobelX[index];
gradientY += pxLum * sobelY[index];
index++;
}
}
float angle = 0;
if(abs(gradientX) > 0.001)
{
angle = atan(gradientY / gradientX);
}
float s = sin(angle);
float c = cos(angle);
for(int i = 0; i < 4; i++)
{
for(int j = 0; j <= Radius.x; j++)
{
for(int k = 0; k <= Radius.y; k++)
{
pos = float2(j, k) + offsets[i];
float2 offs = pos * texelSize;
offs = float2(offs.x * c - offs.y * s, offs.x * s + offs.y * c);
float2 uvpos = UV + offs;
col = SceneTextureLookup(uvpos, 14, false);
mean[i] += col;
sigma[i] += col * col;
}
}
}
float n = (Radius.x+1)*(Radius.y+1);
float sigma_f;
float min = 1;
for(int i = 0; i < 4; i++)
{
mean[i] /= n;
sigma[i] = abs(sigma[i] / n - mean[i] * mean[i]);
sigma_f = sigma[i].r + sigma[i].g + sigma[i].b;
if(sigma_f < min)
{
min = sigma_f;
col = mean[i];
}
}
return col;
Kuwaharaフィルターの実装
上の動画で見られるように、その結果は絵画のようです。
ただし、半径が増加すると、パフォーマンスに大きな影響を与える可能性があります。
Kuwahara + アウトライン
カメラ距離のブレンドを使用したポストプロセスのアウトラインを追加しました。最終的な効果はどう思いますか?