7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【3D → 2D投影】バグで偶然かっこいいアニメーションになった話

Last updated at Posted at 2025-12-16

本記事は42Tokyo(エンジニア養成機関)のアドベントカレンダー企画 17日目です!

はじめに

こんにちは。今回は42Tokyoの課題を進める中で、バグ(誤り)により、偶然発生した面白い現象について紹介します!

42FDF というグラフィックプログラミングの課題を進めている中で、座標計算に対して 無駄にround() (少数点数を整数値にする関数)してしまった結果、 本来は意図していなかったかっこいいアニメーションになりました。


FDFについて

FDFは、3D座標データをもとに、2D画面にワイヤーフレーム表示するプログラムを作る課題です。

Screencastfrom20251216181620-ezgif.com-optimize.gif

マップとして与えられるのは、横・縦の位置と各座標の高さ情報です。
これをもとに立体的な形状を表現します。

さらに追加要件として、プログラム側では、

  • 拡大・縮小
  • ズームイン・アウト
  • 回転
  • 位置の移動
  • 投影方法の変更

などの機能を追加することができます。

アフィン変換行列を使って任意の変換をモデルに適用することで、簡易3Dレンダリングエンジンの実装のようなことができる課題です。

上の動画は 正投影 で2Dに投影したものですが、 透視投影 で2Dに投影するとこのようになります。

Screencastfrom20251216183027-ezgif.com-video-to-gif-converter (1).gif

国土地理院の標高タイルを加工したマップを自作したりしました。(富士山から伊豆半島あたり)

正投影(Orthographic Projection)

正投影は、奥行きによる縮小が起きない投影方法。カメラから平行に投影するイメージ。手前でも奥でも 同じ大きさ で描画される。図面やマップ表示に向いている。

特徴:

  • 距離感は分かりにくい
  • 形状が正確に見える
  • 実装が比較的シンプル

透視投影(Perspective Projection)

透視投影は、奥に行くほど小さく見える投影方法。実際の人間の視覚に近い。遠い物体ほど小さく描画される。ズーム倍率を変えることで、望遠レンズや広角レンズのような効果が得られる。(広角だと周辺が歪む)。立体感・奥行きが分かりやすい。

特徴:

  • 見た目がリアル
  • 距離によるスケール変化が発生する
  • 計算は正投影よりやや複雑

本題

今回、偶然かっこいいアニメーションになったのは、この透視投影を行なったときでした。

それでは、そのかっこいいアニメーションをご覧いただきましょう。

Screencastfrom20251216191827-ezgif.com-video-to-gif-converter.gif

なんとモデルのスケーリングによってモデルが徐々に形づくられるように出現しました!!

原因

透視投影変換の投影式は、アフィン変換後のクリップ座標に対して、画面のサイズ(幅・高さ)をそれぞれに対して乗算するのですが、その前にround()をして少数を整数化してしまっていたことが問題でした。

回転や拡大・縮小などの変換を行う場合、内部では座標を小数(double)で計算しつつ、描画時には画面ピクセル単位の 整数座標に変換する必要があります。

モデルのスケーリング(拡大・縮小)を行うとモデル座標の値を変更することができます。モデルの内部座標の差が非常に小さいと整数化したときに、点と点が重なって、モデルを構成する線が単純化されます。

座標(x=3.5, y=4.2)(x=3.9, y=4.4)をround()で整数化 
→ (x=4.0, y=4.0)

最終的にはround()(整数化)をするのですが、
誤って透視投影の投影式にある画面サイズの乗算前にround()をしてしまいました。

画面サイズを、W=1000, H=800とすると

正)
(x=3.5, y=4.2)(x=3.9, y=4.4)に画面サイズを乗算後にround()する
→(x=3500.0, y=3360.0)(x=3900.0, y=3520.0)
誤)
(x=3.5, y=4.2)(x=3.9, y=4.4)をround()後に画面サイズ乗算
→ (x=4000, y=4000)

計算結果が変わってしまう上、座標が小さいときはround()による影響がより大きく出ることもわかると思います。
(本来の透視投影変換はもう少し複雑な計算を行ないます。また、座標が画面からはみ出ているのもあくまで例なので気にしないでください。)

つまり、小さい値の座標ほどround()による整数化の影響を強く受け、ワイヤーフレームを構成する点と線が重なってしまうことで、モデルのスケーリング(拡大)とともにモデルが形成されながら出現するアニメーションになったということです。
(モデルを縮小すると構造が単純化しながら消失する逆のアニメーションにもなります。)


おわりに

今回はバグ(誤り)によって、モデルのスケーリングをするとかっこいいアニメーションになる現象に遭遇したという記事でした。
ミスはミスですが、これはこれでありな気がしますね(笑)
技術的な内容にはあまり触れませんでしたが、面白いなと思っていただければ幸いです!ありがとうございました!

座標計算中に余計な整数化を行なうと意図しない結果になるので、整数化は必ず最後(投影式の時)に行なうようにしましょう!

Screencastfrom20251216191110-ezgif.com-video-to-gif-converter.gif


おまけ

透視投影を応用してFPS視点でマップ内を移動できる機能を実装しました。
色々なマップにお出かけできます!(FDF 楽しい!!)

Screencastfrom20251216203125-ezgif.com-video-to-gif-converter.gif

7
0
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
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?