「ゲームプログラミング/3Dグラフィック」の版間の差分

削除された内容 追加された内容
編集の要約なし
929 行
</syntaxhighlight>
 
 
 
 
1,330 ⟶ 1,328行目:
 
が、このような場合(z軸の向きが画面下向き。カメラが上向きの場合)での回転の公式になる。
 
 
なお、べつにプログラム中の変換式をこの<math> (x_0 - x_c) = 0 </math> の場合の公式に置き換えなくても構わない。回転行列の公式を使えば、条件が上述のとおりなら、結果的にこの場合と同じ結果になるということである。
 
 
上面図の回転のプログラムは、(抜粋すると)下記のようになる。WM_PAINT 節の適切な場所に、下記のように書く。
<syntaxhighlight lang="c">
 
// y軸中心での回転後の座標の計算
kaiten_arrow_x = cos(kaitenKaku) * (0) + (-1) * sin(kaitenKaku) * (-1 * arrowLength);
// kaiten_zahyou_list[1].y_zahyou = point_zahyou_list[1].y_zahyou; // 中心軸なので、そのまま。
kaiten_arrow_z = sin(kaitenKaku) * (0) + cos(kaitenKaku) * (-1 * arrowLength);
 
 
// 回転する上面図のデバッグ用の描画プログラム
int offsetRotX = 150; // 比較のため回転前の矢印も残したいので、位置をx方向に150だけズラした
MoveToEx(hdc, offsetRotX + arrowSiri_X + kaiten_arrow_x, arrowSiri_Z + kaiten_arrow_z , NULL); // 矢先側
LineTo(hdc, offsetRotX + arrowSiri_X, arrowSiri_Z ); // 矢の尻
 
// 矢印先端の三角部分を描くのがメンドウなので、
// 代わりに矢の根元(カメラ側)にミドリ色の四角を描画することで代用
HBRUSH brasi_parts_2;
brasi_parts_2 = CreateSolidBrush(RGB(100, 255, 100)); // 壁の表示用のgreen色のブラシを作成
SelectObject(hdc, brasi_parts_2); // ウィンドウhdcと、さきほど作成したブラシを関連づけ
 
</syntaxhighlight>
 
なお、あらかじめグローバル変数で回転角を宣言しておく必要がある。C言語の角度計算ではラジアン単位なので、角度は実数側で宣言する必要がある。
 
なので <code>double kaitenKaku;</code> のように宣言する必要がある。
 
また、この回転角を増減するためのキーボード入力が必要なので、 case WM_KEYDOWN: に、たとえば下記のようなコードを追加する必要がある。(原理的にはマウス入力でもいいが、教えるのがメンドウくさい。)
 
<syntaxhighlight lang="c">
case 'W':
/* 反時計まわりの回転*/
kaitenKaku = kaitenKaku + 0.2;
 
break; // これは VK_LEFT: からのbreak
 
case 'Q':
/* 順時計まわりの回転*/
kaitenKaku = kaitenKaku - 0.2;
 
break; // これは VK_LEFT: からのbreak
</syntaxhighlight>
 
 
 
 
なので、上下左右のキー入力コードとあわせると、下記のようになる。
 
<syntaxhighlight lang="c">
case WM_KEYDOWN:
 
switch (wParam) {
case VK_UP: // 「上キーが入力されたら」という意味
Camera_z = Camera_z -5;
screen_z_Zahyou = screen_z_Zahyou - 5;
 
/* ここに上(↑)キー入力後の処理を書く*/
break; // これは VK_UP: からのbreak
 
case VK_DOWN:
Camera_z = Camera_z + 5;
screen_z_Zahyou = screen_z_Zahyou + 5;
 
/* ここに下(↓)キー入力後の処理を書く*/
break; // これは VK_DOWN: からのbreak
case VK_RIGHT:
/* ここに右(→)キー入力後の処理を書く*/
Camera_x = Camera_x + 10;
 
break; // これは VK_RIGHT からのbreak
case VK_LEFT:
/* ここに左(←)キー入力後の処理を書く*/
Camera_x = Camera_x - 10;
 
break; // これは VK_LEFT: からのbreak
 
case 'W':
/* 反時計まわりの回転*/
kaitenKaku = kaitenKaku + 0.2;
 
break; // これは VK_LEFT: からのbreak
 
case 'Q':
/* 反時計まわりの回転*/
kaitenKaku = kaitenKaku - 0.2;
 
break; // これは VK_LEFT: からのbreak
 
} // これは switch (wParam) の終わりのカッコ
 
//}
 
// MessageBox(NULL, TEXT("aaaaaatにいる。"), TEXT("キーテスト"), MB_OK);
 
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
 
 
break; // これは WM_KEYDOWN: からのbreak
</syntaxhighlight>
 
 
 
 
さて、上面図の回転のテストに成功したら、同じ方法で、視界中の被写体も公転させればいい。視界を回転させるためには、カメラの自転ではなく、被写体すべての点を公転させたほうが(人間プログラマー側の検証のための)計算がラクである。
 
視界の回転のコード例は、下記のようになる。
 
<syntaxhighlight lang="c">
 
// 先に被写体を回転させる
kaiten_zahyou_list[1].x_zahyou = cos(kaitenKaku) * (point_zahyou_list[1].x_zahyou - Camera_x) + (-1) * sin(kaitenKaku) * (point_zahyou_list[1].z_zahyou - Camera_z) + Camera_x;
kaiten_zahyou_list[1].y_zahyou = point_zahyou_list[1].y_zahyou ;
kaiten_zahyou_list[1].z_zahyou = sin(kaitenKaku) * (point_zahyou_list[1].x_zahyou - Camera_x) + cos (kaitenKaku) * (point_zahyou_list[1].z_zahyou - Camera_z) + Camera_z;
 
kaiten_zahyou_list[2].x_zahyou = cos(kaitenKaku) * (point_zahyou_list[2].x_zahyou - Camera_x) + (-1) * sin(kaitenKaku) * (point_zahyou_list[2].z_zahyou - Camera_z) + Camera_x ;
kaiten_zahyou_list[2].y_zahyou = point_zahyou_list[2].y_zahyou;
kaiten_zahyou_list[2].z_zahyou = sin(kaitenKaku) * (point_zahyou_list[2].x_zahyou - Camera_x) + cos(kaitenKaku) * (point_zahyou_list[2].z_zahyou - Camera_z) + Camera_z;
 
 
kaiten_zahyou_list[3].x_zahyou = cos(kaitenKaku) * (point_zahyou_list[3].x_zahyou - Camera_x) + (-1) * sin(kaitenKaku) * (point_zahyou_list[3].z_zahyou - Camera_z) + Camera_x;
kaiten_zahyou_list[3].y_zahyou = point_zahyou_list[3].y_zahyou;
kaiten_zahyou_list[3].z_zahyou = sin(kaitenKaku) * (point_zahyou_list[3].x_zahyou - Camera_x) + cos(kaitenKaku) * (point_zahyou_list[3].z_zahyou - Camera_z) + Camera_z;
 
kaiten_zahyou_list[4].x_zahyou = cos(kaitenKaku) * (point_zahyou_list[4].x_zahyou - Camera_x) + (-1) * sin(kaitenKaku) * (point_zahyou_list[4].z_zahyou - Camera_z) + Camera_x;
kaiten_zahyou_list[4].y_zahyou = point_zahyou_list[4].y_zahyou;
kaiten_zahyou_list[4].z_zahyou = sin(kaitenKaku) * (point_zahyou_list[4].x_zahyou - Camera_x) + cos(kaitenKaku) * (point_zahyou_list[4].z_zahyou - Camera_z) + Camera_z;
 
 
// 被写体の回転のあとから、スクリーンに投影する
//int pro1
touei_zahyou_list[1].x_zahyou = (screen_z_Zahyou - Camera_z) / (point_zahyou_list[1].z_zahyou - Camera_z) * (kaiten_zahyou_list[1].x_zahyou - Camera_x) ;
touei_zahyou_list[1].y_zahyou = (screen_z_Zahyou - Camera_z) / (point_zahyou_list[1].z_zahyou - Camera_z) * (kaiten_zahyou_list[1].y_zahyou - Camera_y) ;
 
 
// int pro2X
touei_zahyou_list[2].x_zahyou = (screen_z_Zahyou - Camera_z) / (point_zahyou_list[2].z_zahyou - Camera_z) * (kaiten_zahyou_list[2].x_zahyou - Camera_x) ;
touei_zahyou_list[2].y_zahyou = (screen_z_Zahyou - Camera_z) / (point_zahyou_list[2].z_zahyou - Camera_z) * (kaiten_zahyou_list[2].y_zahyou - Camera_y) ;
 
 
 
// int pro3
touei_zahyou_list[3].x_zahyou = (screen_z_Zahyou - Camera_z) / (point_zahyou_list[3].z_zahyou - Camera_z) * (kaiten_zahyou_list[3].x_zahyou - Camera_x) ;
touei_zahyou_list[3].y_zahyou = (screen_z_Zahyou - Camera_z) / (point_zahyou_list[3].z_zahyou - Camera_z) * (kaiten_zahyou_list[3].y_zahyou - Camera_y) ;
 
// int pro4
touei_zahyou_list[4].x_zahyou = (screen_z_Zahyou - Camera_z) / (point_zahyou_list[4].z_zahyou - Camera_z) * (kaiten_zahyou_list[4].x_zahyou - Camera_x) ;
touei_zahyou_list[4].y_zahyou = (screen_z_Zahyou - Camera_z) / (point_zahyou_list[4].z_zahyou - Camera_z) * (kaiten_zahyou_list[4].y_zahyou - Camera_y) ;
 
 
// HBRUSH brasi_parts_2;
int hisyatai_onViewX = 350; int hisyatai_onViewY = 150;
 
 
brasi_parts_2 = CreateSolidBrush(RGB(100, 255, 100)); // 壁の表示用のgreen色のブラシを作成
SelectObject(hdc, brasi_parts_2); // ウィンドウhdcと、さきほど作成したブラシを関連づけ
 
Rectangle(hdc,
hisyatai_onViewX + touei_zahyou_list[3].x_zahyou, hisyatai_onViewY + touei_zahyou_list[3].y_zahyou,
hisyatai_onViewX + touei_zahyou_list[4].x_zahyou, hisyatai_onViewY + touei_zahyou_list[4].y_zahyou + 40); // 基準の状態
 
 
 
brasi_parts_2 = CreateSolidBrush(RGB(100, 100, 255)); // 壁の表示用のブルー色のブラシを作成
SelectObject(hdc, brasi_parts_2); // ウィンドウhdcと、さきほど作成したブラシを関連づけ
 
Rectangle(hdc,
hisyatai_onViewX + touei_zahyou_list[1].x_zahyou, hisyatai_onViewY + touei_zahyou_list[1].y_zahyou,
hisyatai_onViewX + touei_zahyou_list[2].x_zahyou, hisyatai_onViewY + touei_zahyou_list[2].y_zahyou + 30); // 基準の状態
 
 
</syntaxhighlight>
 
 
なお、このプログラムだとカメラの反対側にある被写体も描画してしまう。なので、それら反対側の描画をカットする機能を、今後のプログラミングで追加する必要がある。
 
描画カットの方法は簡単で、単に被写体の回転後のz座標がマイナスになる場合には、描画しないように、if文で記述すればいい。
 
つまり、描画する場合の条件として、回転後のz座標がプラスの場合にだけ描画するようにプログラミングすればいいだけである。
 
 
 
 
===== 望遠と広角のハナシ =====
1,400 ⟶ 1,584行目:
どうしても大きな視野が必要な場合は、対策として例えば望遠鏡のように、遠くから眺めるようプログラムにして、視野角そのものは広げないようにしたほうがイイだろう。
 
{{コラム|レンズ付き実物カメラの特性|
 
なお、テレビ局用などのレンズ付き撮影ビデオカメラなどでも、望遠的なレンズを使って遠くから被写体を写す方式である(実際に望遠レンズかどうかは知らないが、すくなくても決して広角レンズではない)。(よく、テレビ番組などの制作裏話などの紹介の番組などで、スタジオセットの撮影で、セットから結構離れた場所でカメラマンが やや大きい撮影カメラで撮影しているシーンがときどきがあるだろう。バズーカ砲みたいに肩に担いだり、あるいはカメラを荷台に載せて撮影するカメラをもってるアレ。あの距離みたいに、実際の撮影でも、けっこうカメラマンは離れている。)
 
1,419 ⟶ 1,603行目:
 
なお、説明の都合上、「視野角」と言ったが、テレビなどの撮影業界では「画角」(がかく)という。
}}
 
 
<syntaxhighlight lang="c">