FdFメモ
FDFの概要
MiniLibXを使用して、高さデータを与えられたマップを3Dのシンプルなワイヤーフレームモデルとして変換(描画)する課題です。
MiniLibXを使用する初めての課題となるため、独自の関数の基本的な使い方から学ぶことができました。
MiniLibXについてのドキュメント
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。
実装の流れ
-
ファイルの読み込みと解析:
.fdfファイルからマップデータを読み込みます。
get_next_lineとft_splitを使用してデータを解析し、高度情報を取得します。 -
データ構造の定義:
マップの幅と高さを格納します。各ポイントの高度情報を2次元配列に格納します。 -
等角投影図(アイソメトリック図)の計算:
各ポイントのx, y, z座標をアイソメトリック投影に変換します。 -
グラフィックの管理:
MiniLibXを使用してウィンドウを作成し、モデルを描画します。
描画にはmlx_pixel_putやmlx_line_putを使用します。 -
イベントハンドリング:
キーイベントとウィンドウクローズイベントを処理します。
ESCキーでウィンドウを閉じ、プログラムを終了します。
技術的なポイント
アイソメトリック投影について
FDFでは、3次元の地形マップを等角投影図(アイソメトリック図)で描画する指定がある。
120°(360°÷3)の関係にx、y、zのそれぞれの軸方向を取り、同じ寸法(尺度)で描画
右上がりの線は30°方向
描画の流れ:
- 水平または垂直方向の線分を設定して描画
- 2点間の線分を描画するためのステップ計算とピクセルを描画
- 与えられた2点(point.x0, point.y0, point.x1, point.y1)をスケーリング、アイソメトリック変換、およびオフセット調整
- set_points → calc_line_steps → ajust_point → calc_isometric の順に変換・描画
- 与えられた2D座標(x, y)と高さ(z)をアイソメトリック座標に変換
- 全体を表示
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 によって、描画範囲全体がウィンドウ中央に配置されるよう調整されます。
- (WIN_WIDTH - map_width) / 2
動作確認
わーい
(xyzに同じ倍率かかってたら歪んでいないはず)
レビュー観点
- FDFのレビューの主な目的は、描画が正しくできていること。
なので、入力チェックを厳しく対応する必要はない。
「このプロジェクトの目標はマップを解析することではない」という記載があるので、
最低限セグフォしないようになっていたらいいんじゃないか?という解釈をした(PDFの記載について言及をしてディフェンスする) - 入力チェック
- 引数少ない、多すぎる
- マップファイル自体がないとき
- マップファイルの中身がないとき
- マップファイルの権限がない時
- それ以外の時は、”正しい”マップが与えられるという前提で作りました
レビュー項目
細かい項目は忘れたがメモ
- ノームないこと
- リークないこと
- 基本的な動きできていること
- ウィンドウの☓ボタンでの終了およびEscキーでの終了どちらの終了にも対応していること
- mlxの描画形式で、mlx_img_to_windowで画像をウィンドウに表示していること
とても参考になったページ
-
Fil de Fer(Fdf), the first graphical project at 42 The Network
-
42MapGenerator (v2)
https://github.com/jgigault/42MapGenerator -
マップ作成で参考になる
http://maxima.zuisei.net/pg11.html
今後の展望(予定なし)
現在のプログラムをベースに、以下の機能追加を追加できるとボーナス課題にも対応できた
- カラー表示対応
- ズーム・回転機能の実装
- より複雑な地形データの対応
自分のリポジトリ
Discussion