LoginSignup
1
2

More than 3 years have passed since last update.

社内勉強会「レンダリング合宿1」 ソフトウェアラスタライザー基本実装編 08.バイリニアフィルタリング

Last updated at Posted at 2019-11-07

ソフトウェアラスタライザー基本実装編 08.バイリニアフィルタリング

前回はパースペクティブコレクトによりパースの補正処理を入れました。
テクスチャマッピングの最低限の要件は満たせたかと思いますので、今回はバイリニアフィルタリングを実装していきたいと思います。

リポジトリ

今回の実行結果になります。
前回までのざらざらした感じがなくなって滑らかな見た目になったかと思います。
top.png

やりかた

前回は (u, v) 値からテクスチャのピクセル座標を求めてその色を使っていました。
しかし実際にUV値は整数ではなく浮動小数点ですのでその部分を考慮して隣接テクスチャから補間をしてUVに対して正確なテクセルを取得します。

実装

テクスチャのサンプル処理を見てみます。
前回と同じように与えられたUV値からテクセル座標を求めていますが、さらにX+1,Y+1のテクセル座標も取得しています。
この4つのテクセルからUVの余剰部分の小数点を使ってブレンドしていきます。

Texture.cpp
Color Texture::Sample(fp32 u, fp32 v) const
{
    u += 256.0f;
    v += 256.0f;

    const auto& Src = _Surface[0];

    const auto uf = u * fp32(Src.Width);
    const auto vf = v * fp32(Src.Height);
    const auto ui0 = int32(uf);
    const auto vi0 = int32(vf);

    const auto mui0 = ui0 % Src.Width;
    const auto mui1 = (ui0 + 1) % Src.Width;
    const auto mvi0 = vi0 % Src.Height;
    const auto mvi1 = (vi0 + 1) % Src.Height;

    const auto x0y0 = Src.Color[mui0 + (mvi0 * Src.Width)];
    const auto x1y0 = Src.Color[mui1 + (mvi0 * Src.Width)];
    const auto x0y1 = Src.Color[mui0 + (mvi1 * Src.Width)];
    const auto x1y1 = Src.Color[mui1 + (mvi1 * Src.Width)];

    return Color::Lerp(x0y0, x1y0, x0y1, x1y1, uf - fp32(ui0), vf - fp32(vi0));
}

以下のメソッドで4つの色をそれぞれX方向とY方向のブレンド率を使ってブレンドしています。

pch.cpp
static Color Lerp(Color x0y0, Color x1y0, Color x0y1, Color x1y1, fp32 rateX, fp32 rateY)
{
    // y0
    Color y0;
    y0.r = uint8(x0y0.r + fp32(x1y0.r - x0y0.r) * rateX);
    y0.g = uint8(x0y0.g + fp32(x1y0.g - x0y0.g) * rateX);
    y0.b = uint8(x0y0.b + fp32(x1y0.b - x0y0.b) * rateX);
    y0.a = uint8(x0y0.a + fp32(x1y0.a - x0y0.a) * rateX);
    // y1
    Color y1;
    y1.r = uint8(x0y1.r + fp32(x1y1.r - x0y1.r) * rateX);
    y1.g = uint8(x0y1.g + fp32(x1y1.g - x0y1.g) * rateX);
    y1.b = uint8(x0y1.b + fp32(x1y1.b - x0y1.b) * rateX);
    y1.a = uint8(x0y1.a + fp32(x1y1.a - x0y1.a) * rateX);
    // result
    Color result;
    result.r = uint8(y0.r + fp32(y1.r - y0.r) * rateY);
    result.g = uint8(y0.g + fp32(y1.g - y0.g) * rateY);
    result.b = uint8(y0.b + fp32(y1.b - y0.b) * rateY);
    result.a = uint8(y0.a + fp32(y1.a - y0.a) * rateY);
    return result;
}

最後に

今回はバイリニアフィルタリングを行いました。
バイリニアフィルタリング自体はただのブレンド処理なので安価に見た目を改善できますので是非とも入れておきたい機能になります。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2