⛰️

FdFメモ

2024/08/29に公開

FDFの概要

MiniLibXを使用して、高さデータを与えられたマップを3Dのシンプルなワイヤーフレームモデルとして変換(描画)する課題です。
MiniLibXを使用する初めての課題となるため、独自の関数の基本的な使い方から学ぶことができました。

MiniLibXについてのドキュメント

https://harm-smits.github.io/42docs/libs

Makefileの書き方

自分が間違えていたので、備忘録。
リポジトリ内にMinilibX本体のフォルダを作成してそれをMakefileに指定をしたりする必要はありません。
「MiniLibXはMacOSXのCocoa(AppKit)とOpenGL(X11はもう使わない)を必要とする」と書いてありますが、例えば以下のように宣言をして、

LDFLAGS = -L./libft -lft -lmlx -framework openGL -framework AppKit

framework = -lmlx -framework openGL -framework AppKit
実行時に $(framework) を一緒に宣言するだけでOK。

実装の流れ

  1. ファイルの読み込みと解析:
    .fdfファイルからマップデータを読み込みます。
    get_next_lineとft_splitを使用してデータを解析し、高度情報を取得します。

  2. データ構造の定義:
    マップの幅と高さを格納します。各ポイントの高度情報を2次元配列に格納します。

  3. 等角投影図(アイソメトリック図)の計算:
    各ポイントのx, y, z座標をアイソメトリック投影に変換します。

  4. グラフィックの管理:
    MiniLibXを使用してウィンドウを作成し、モデルを描画します。
    描画にはmlx_pixel_putやmlx_line_putを使用します。

  5. イベントハンドリング:
    キーイベントとウィンドウクローズイベントを処理します。
    ESCキーでウィンドウを閉じ、プログラムを終了します。

技術的なポイント

アイソメトリック投影について

FDFでは、3次元の地形マップを等角投影図(アイソメトリック図)で描画する指定がある。
https://cc.musabi.ac.jp/zoukei_file/03/seizu/NewFiles/jikusokutouei.html

120°(360°÷3)の関係にx、y、zのそれぞれの軸方向を取り、同じ寸法(尺度)で描画

https://ti-master.biz/ti_byouga_002.html

右上がりの線は30°方向

描画の流れ:

  1. 水平または垂直方向の線分を設定して描画
  2. 2点間の線分を描画するためのステップ計算とピクセルを描画
  3. 与えられた2点(point.x0, point.y0, point.x1, point.y1)をスケーリング、アイソメトリック変換、およびオフセット調整
  4. set_points → calc_line_steps → ajust_point → calc_isometric の順に変換・描画
  5. 与えられた2D座標(x, y)と高さ(z)をアイソメトリック座標に変換
  6. 全体を表示
void	initialize(t_data *data)
{
	data->view.angle_x = ANGLE_30;
	data->view.angle_y = ANGLE_30;
// 他の必要な初期化
}

// 2D座標に奥行き(z)を加える
*x = round((original_x - original_y) * cos(data->view.angle_x));
*y = round((original_x + original_y) * sin(data->view.angle_y) - z);

オフセット調整

画面に描画する際に、座標の基準点を適切にシフトさせる処理のこと

処理の流れ

  • それぞれ x方向 と y方向 のオフセット値(移動量)を保持
  • これらの値をアイソメトリック変換後の各点 x0, x1, y0, y1 に加算
    → オフセットの加算により、地形全体の位置がスクリーン上で指定された位置に移動

なぜ必要なのか?

アイソメトリック図法では、元々の (0, 0) 座標が画面の左上に固定されています。
しかし、描画するマップは画面全体に広がるため、以下のような問題が生じます。

  • 描画結果が画面外に出る。
  • マップ全体が適切に中央に配置されない。

offset_x と offset_y の計算

data->view.offset_x = (((WIN_WIDTH - map_width) / 2)
			- (data->map.min_x * data->view.scale));
data->view.offset_y = (((WIN_HEIGHT - map_height) / 2)
			- (data->map.min_y * data->view.scale));
  • 処理内容:
    • (WIN_WIDTH - map_width) / 2
      ウィンドウの幅(WIN_WIDTH)からマップの幅(map_width)を引き、その半分を計算します。
      マップをウィンドウの中央に配置するための基準となります。
    • (data->map.min_x * data->view.scale)
      アイソメトリック変換後の最小座標(min_x)にスケール倍率を適用した値を引きます。
      これにより、左上隅の座標がウィンドウの中央に基づいて適切に調整されます。
      結果、offset_x と offset_y によって、描画範囲全体がウィンドウ中央に配置されるよう調整されます。

動作確認

わーい
(xyzに同じ倍率かかってたら歪んでいないはず)

レビュー観点

  • FDFのレビューの主な目的は、描画が正しくできていること。
    なので、入力チェックを厳しく対応する必要はない。
    「このプロジェクトの目標はマップを解析することではない」という記載があるので、
    最低限セグフォしないようになっていたらいいんじゃないか?という解釈をした(PDFの記載について言及をしてディフェンスする)
  • 入力チェック
    • 引数少ない、多すぎる
    • マップファイル自体がないとき
    • マップファイルの中身がないとき
    • マップファイルの権限がない時
    • それ以外の時は、”正しい”マップが与えられるという前提で作りました

レビュー項目

細かい項目は忘れたがメモ

  • ノームないこと
  • リークないこと
  • 基本的な動きできていること
  • ウィンドウの☓ボタンでの終了およびEscキーでの終了どちらの終了にも対応していること
  • mlxの描画形式で、mlx_img_to_windowで画像をウィンドウに表示していること

とても参考になったページ

今後の展望(予定なし)

現在のプログラムをベースに、以下の機能追加を追加できるとボーナス課題にも対応できた

  • カラー表示対応
  • ズーム・回転機能の実装
  • より複雑な地形データの対応

自分のリポジトリ

https://github.com/tokochiz/FdF/tree/master

Discussion