LoginSignup
4
3

More than 3 years have passed since last update.

社内勉強会「レンダリング合宿1」 ソフトウェアラスタライザー基本実装編 07.パースペクティブコレクト

Last updated at Posted at 2019-11-06

ソフトウェアラスタライザー基本実装編 07.パースペクティブコレクト

前回はテクスチャマッピングを行いましたが、そのままではテクスチャが歪んでいます。
今回はその歪みを補正する方法を解説していきます。

リポジトリ

今回の実行結果になります。
歪みがなくなって綺麗なテクスチャマッピングの処理が確認できます。
top.png

やりかた

前回は (u, v) をそのまま補間していましたがこれでは奥行きに関しての考慮がなされていません。

例えば四角形を斜めから見たときに奥のほうはパースが付いてるので辺が短くなりますが、2D的な処理の場合はただの台形の画像変換として処理されてしまうためにおかしくなってしまいます。

todo:できれば図を用意する・・・

ではどうするのかというと具体的にはプロジェクション変換時の w 値を用います。
ポジションの計算時のxyzwのw値はビュー空間における奥行きを表しており、 (u, v) ではなく (u/w, v/w) を補間し、テクスチャのサンプリング時に補間された 1/w を使ってUVを (u*w, v*w) で戻すことで奥行きを考慮したUVの補間をすることが出来ます。

これがパースペクティブコレクトと言われているやつです。

実装

まずは座標変換を行っている箇所を見てみます。

Renderer.cpp
for (int32 j = 0; j < PointCount; ++j)
{
    auto& pt = TempA[j];
    auto invW = 1.0f / pt.Position.w;
    pt.Position.x = (+pt.Position.x * invW * 0.5f + 0.5f) * WidthF;
    pt.Position.y = (-pt.Position.y * invW * 0.5f + 0.5f) * HeightF;
    pt.Position.w = invW;
    pt.TexCoord.x *= invW;
    pt.TexCoord.y *= invW;
}

w の逆数を使ってテクスチャの UV を w で割っています。
この時にポジションの w には w の逆数を入れています。

次にテクスチャをサンプリングしている箇所を見てみましょう。

Renderer.cpp
// 重心座標系でwを求める
const auto w = 1.0f / ((b0 * p0.w) + (b1 * p1.w) + (b2 * p2.w));

// 重心座標系でUVを求める
// パースペクティブコレクト対応のため1/wする
Vector2 TexCoord = {
    ((b0 * t0.x) + (b1 * t1.x) + (b2 * t2.x)) * w,
    ((b0 * t0.y) + (b1 * t1.y) + (b2 * t2.y)) * w,
};

補間された w を用いてテクスチャのUVを復元しています。
これにより奥行きを考慮したテクスチャのUVを求めています。

最後に

今回はパースペクティブコレクトを行いました。
こういうのは今時はハードウェアが勝手にいい感じにやってくれるのでいちいち気にしなくても良くなっているんですが、単語すら知らない状態だと何かあったときに検索すらできないので今回は個別の章として扱いました。

4
3
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
4
3