課題1-7補足問題

[—ATOC—] 1 [—AUTO_SECTION_NUMBER—] 1

課題1-7補足問題

ここの問題は課題1-7 レイと球の交差判定 が難しいと感じたら取り組んでください.

十分にヒントを得られたと思ったら,途中でやめて課題1-7 レイと球の交差判定に戻っても構いません.

シーン設定

課題1-7 レイと球の交差判定で想定しているシーンを再掲する.

  • 視点位置
    • $$\vec{\bf p_{\cal e}}=(0,0,-5)$$
  • スクリーン位置
    • 左上$$(-1,1,0)$$, 右上$$(1,1,0)$$, 右下$$(1,-1,0)$$, 左下$$(-1,-1,0)$$
    • 中心位置$$\vec{\bf p_{\cal c}}=(0,0,5)$$
    • 半径$$radius=1.0$$

シーン設定
図1. シーン設定

補足問題1

スクリーン座標$$(382,255)$$を,三次元空間上の座標に変換するプログラムを作成せよ.

変換方法は4-1.2. スクリーン座標の変換の通りである. 変換式を以下に再掲する.

\(\left\{\begin{array}{lll} \\ x_{w} & = & \frac{2x_{s}}{W-1}-1.0 \\ y_{w} & = & -\frac{2y_{s}}{H-1}+1.0 \\ z_{w} & = & 0 \\ \end{array}\right.\)


リスト1. one_conv.cの穴埋め
#include <stdio.h>
#include "vector_utils.h"

#define WIDTH 512
#define HEIGHT 512

int main()
{
  int x_s = 382;
  int y_s = 255;

  vector_t pw;

  pw.x = /* *** 穴埋め *** */;
  pw.y = /* *** 穴埋め *** */;
  pw.z = /* *** 穴埋め *** */;

  printf("(%d,%d) -> %s\n", x_s, y_s, vector_str(&pw));
    
  return 0;
}

結果は以下のようになるはずである.

$ ./one_conv (382,255) -> (0.495108, 0.001957, 0.000000)

プログラムのビルド方法および実行方法

以下のコマンドでプログラムの実行形式を生成する.

gcc -std=c89 -Wall one_conv.c vector_utils.c -lm -o one_conv

問題なくビルドできたら,以下のコマンドで実行する.

$ ./one_conv

補足問題2

2014-04-25: 穴埋めコードの穴埋め位置に番号を振った.ヒント1~5を追加.

視点$$\vec{\bf p_{\cal e}}$$から,スクリーン上の点$$\vec{\bf p_{\cal w}}=(-0.4, 0, 0)$$への半直線は 球と交点を持つかどうかプログラムを使って調べよ.交差する場合は「Yes!」,しない場合は「No…」と表示すること.

ソースファイル名はone_sample.cとする.

リスト2. one_sample.cの穴埋め
#include <stdio.h>
#include "vector_utils.h"

int main()
{
  vector_t eye_pos    = { 0, 0, -5 };/* 視点位置 */
  vector_t sphere_pos = { 0, 0, 5 };  /* 球の中心 */
  float sphere_r = 1;                 /* 球の半径 */
  vector_t pw         = { -0.4, 0, 0 };/* スクリーン上の点 */

  vector_t eye_dir; /* 視線方向ベクトル */
  vector_t s_c;     /* 視点 - 球の中心 */
  float A,B,C,D;    /* 二次方程式Ax^2+Bx+C=0および判別式D */

  /* ****************************** */
  /*                                */
  /*                                */
  /* 穴埋め1                         */
  /*                                */
  /*                                */
  /* ****************************** */

  A = /* *** 穴埋め2 *** */;
  B = /* *** 穴埋め3 *** */;
  C = /* *** 穴埋め4 *** */;

  D = /* *** 穴埋め5 *** */;

  if ( /* 穴埋め6 */ )
    {
      printf("Yes!\n");
    }
  else
    {
      printf("No...\n");
    }

  return 0;
}

結果は交差するはずである(視点と球の位置関係を思い浮かべてみよう).

プログラムのビルド方法および実行方法

以下のコマンドでプログラムの実行形式を生成する.

gcc -std=c89 -Wall one_sample.c vector_utils.c -lm -o one_sample

問題なくビルドできたら,以下のコマンドで実行する.

$ ./one_sample

ヒント1

+ 考え方 クリックで非表示


キーボードから手を離せ.話はそれからだ.

  • 「理屈」を理解することなしにコードは書けない.「交点の有無を調べる方法」を理解しているかどうか自分に問いただしてみよ.
  • それを自分の言葉で説明できないうちは,まだ「理屈」を理解していない.
  • 「理屈」の理解をなしにして,テキストエディタを開きキーボードに手を置いたところで全くの無駄である.まずは「理屈」の理解に努めよ.


理屈

  • tの方程式,$$At^2+Bt+C=0$$の係数$$A$$,$$B$$,$$C$$がわかれば,交差の有無を調べることができる.
    • その方法は,判別式$$D=B^2-4AC$$の値が正の数かゼロか負の数かを調べることである.

以下を試みよ.

  • まず,プログラミングとは関係なしに,ノートと手計算を駆使して交差の有無を調べよ.
-クリックで非表示

ヒント2

+ 検討 クリックで非表示

以下のことを検討せよ.

  • 係数$$A$$,$$B$$,$$C$$を計算するために必要なベクトルをすべて洗い出せ.
    • 必要なベクトルを全てノートに書き出せ.必要ならば適切な名前や記号を付けよ.
  • 洗い出したベクトルそれぞれについて以下のことを調べよ.
    • 【Q1】そのベクトルを格納するために必要な変数が,穴埋めコードの中にあるかどうか?(ある/ない)
    • 【Q2】その変数にはすでに必要な値が代入されているか?(いる/いない)
    • 【Q3】必要な値が代入されていない場合,それを代入することは可能か.以下の項目を調べよ.
      • 【Q3-1】その値を計算するための数式を書き出せ(C言語のコードではなく,数式で).
      • 【Q3-2】その数式の値を計算するのに必要な値はそろっているか?(そろっている/そろっていない)
      • 【Q3-3】計算に必要な値は,穴埋めコードの中のどこに当たるか.
      • 【Q3-4】Q3-1で検討した数式を,C言語で書き表すことはできるか?
-クリックで非表示

ヒント3

+ 穴埋めの位置でやるべきことを文章で書き下したもの クリックで非表示

穴埋めの位置ですべきこと

  • 穴埋め1
    • $$\vec{\bf d_{\cal e}}$$を計算する.
    • $$\vec{\bf m}$$を計算する.
  • 穴埋め2
    • 係数Aの値を計算する.
  • 穴埋め3
    • 係数Bの値を計算する.
  • 穴埋め4
    • 係数Cの値を計算する.
  • 穴埋め5
    • 判別式Dの値を計算する.
  • 穴埋め6
    • 判別式Dの値から,交点を持つ条件を書く.

凡例

  • $$\vec{\bf c}$$
    • 球の中心点$${\cal c}$$の位置ベクトル
  • $$r$$
    • 球の半径
  • $$\vec{\bf p_{\cal e}}$$
    • 視点の位置ベクトル
  • $$\vec{\bf p_{\cal w}}$$
    • スクリーン上の点$${\cal p_{w}}$$の位置ベクトル
  • $$\vec{\bf d_{\cal e}}$$
    • 視線ベクトル
  • $$\vec{\bf m}$$
    • $$\vec{\bf p_{\cal e}}$$から$$\vec{\bf c}$$を引いたベクトル
-クリックで非表示

ヒント4

+ 穴埋めの位置に必要な計算式 クリックで非表示

$$\leftarrow$$は代入を表す.

  • 穴埋め1
    • $$\vec{\bf d_{\cal e}}\leftarrow\vec{\bf p_{\cal w}}-\vec{\bf p_{\cal e}}$$
    • $$\vec{\bf m}\leftarrow\vec{\bf p_{\cal e}}-\vec{\bf c}$$
  • 穴埋め2
    • $$A\leftarrow\left|\vec{\bf d_{\cal e}}\right|^{2}$$
      • あるいは$$A\leftarrow\vec{\bf d_{\cal e}}\cdot\vec{\bf d_{\cal e}}$$
  • 穴埋め3
    • $$B\leftarrow2\left(\vec{\bf d_{\cal e}}\cdot\vec{\bf m}\right)$$
  • 穴埋め4
    • $$C\leftarrow\left|\vec{\bf m}\right|^{2}-r^{2}$$
      • あるいは$$C\leftarrow\left(\vec{\bf m}\cdot\vec{\bf m}\right)-r^{2}$$
  • 穴埋め5
    • $$D\leftarrow B^2-4AC$$
  • 穴埋め6
    • $$D\geq0$$
-クリックで非表示

ヒント5

+ 穴埋めコード中の変数の対応 クリックで非表示
  • $$\vec{\bf c}$$
    • 変数sphere_pos(vector_t型)
  • $$r$$
    • 変数sphere_r(float型)
  • $$\vec{\bf p_{\cal e}}$$
    • 変数eye_pos(vector_t型)
  • $$\vec{\bf p_{\cal w}}$$
    • 変数p_w(vector_t型)
  • $$\vec{\bf d_{\cal e}}$$
    • 変数eye_dir(vector_t型)
  • $$\vec{\bf m}$$
    • 変数s_c(vector_t型)
-クリックで非表示

補足問題3

2014-04-20: スクリーン座標を修正

スクリーン座標$$(382,255)$$を三次元空間上の座標$$\vec{\bf p_{\cal w}}$$に変換し,さらに視点から$$\vec{\bf p_{\cal w}}$$への 半直線が球と交差するかどうか調べるプログラムを作成せよ.交差する場合は「Yes!」,しない場合は「No…」と表示すること.

ソースファイル名はone_conv_sample.cとする.
(穴埋めソースは掲載しない.補足問題1および2を応用すれば作ることができる.)

結果は交差するはずである.

プログラムのビルド方法および実行方法

以下のコマンドでプログラムの実行形式を生成する.

gcc -std=c89 -Wall one_conv_sample.c vector_utils.c -lm -o one_conv_sample

問題なくビルドできたら,以下のコマンドで実行する.

$ ./one_conv_sample

補足問題4

スクリーン座標$$x,y$$を,三次元空間上の座標に変換するプログラムを作成せよ. スクリーン幅は512,高さは512である.

ソースファイル名はall_conv.cとする.
(穴埋めソースは掲載しない.補足問題1および課題1-1 最初のプログラムを応用すれば作ることができる.)

結果は以下のようになる(出力結果全体は非常に長大になるため割愛している.).

$ ./all_conv (0,0) -> (-1.000000, 1.000000, 0.000000) (1,0) -> (-0.996086, 1.000000, 0.000000) (2,0) -> (-0.992172, 1.000000, 0.000000) (3,0) -> (-0.988258, 1.000000, 0.000000) (4,0) -> (-0.984344, 1.000000, 0.000000) (5,0) -> (-0.980431, 1.000000, 0.000000) (6,0) -> (-0.976517, 1.000000, 0.000000) (7,0) -> (-0.972603, 1.000000, 0.000000) (8,0) -> (-0.968689, 1.000000, 0.000000) (9,0) -> (-0.964775, 1.000000, 0.000000) (10,0) -> (-0.960861, 1.000000, 0.000000) (11,0) -> (-0.956947, 1.000000, 0.000000) (12,0) -> (-0.953033, 1.000000, 0.000000) (13,0) -> (-0.949119, 1.000000, 0.000000) (14,0) -> (-0.945205, 1.000000, 0.000000) (15,0) -> (-0.941292, 1.000000, 0.000000) (16,0) -> (-0.937378, 1.000000, 0.000000) …

プログラムのビルド方法および実行方法

以下のコマンドでプログラムの実行形式を生成する.

gcc -std=c89 -Wall all_conv.c vector_utils.c -lm -o all_conv

問題なくビルドできたら,以下のコマンドで実行する.

$ ./all_conv

補足問題5

スクリーン座標$$x,y$$を,三次元空間上の座標に変換し,変換後の各点を通る 半直線が球と交点を持つかどうかを調べるプログラムを作成せよ.
コンソールにはスクリーン座標と,「Yes!」(交差する場合)あるいは「No…」(交際しない場合)を表示すること.

ソースファイル名はall_sample.cとする.

リスト3. all_sample.cの穴埋め #include #include “vector_utils.h” #define WIDTH 512 #define HEIGHT 512 int main() { int y,x; vector_t eye_pos = { 0, 0, -5 };/* 視点位置 */ vector_t sphere_pos = { 0, 0, 5 }; /* 球の中心 */ float sphere_r = 1; /* 球の半径 */ vector_t pw; pw.z = /* *** 穴埋め *** */; for(y = 0; y < HEIGHT; ++y) { pw.y = /* *** 穴埋め *** */; for(x = 0; x < WIDTH; ++x) { vector_t eye_dir; /* 視線方向ベクトル */ vector_t s_c; /* 視点 - 球の中心 */ float A,B,C,D; /* 二次方程式Ax^2+Bx+C=0および判別式D */ pw.x = /* *** 穴埋め *** */; /* ****************************** */ /* */ /* */ /* */ /* 穴埋め */ /* */ /* */ /* */ /* ****************************** */ A = /* *** 穴埋め *** */; B = /* *** 穴埋め *** */; C = /* *** 穴埋め *** */; D = /* *** 穴埋め *** */; if ( /* *** 穴埋め *** */ ) { printf("(%d,%d) : Yes!\n", x, y); } else { printf("(%d,%d) : No...\n", x, y); } }/* for */ }/* for */ return 0; }/* int main() */ [/c]

出力結果は非常に長大なため以下のようにして結果の一部だけを表示させて確認すること.

$ ./all_sample | head -65800 | tail -30 (234,128) : No… (235,128) : No… (236,128) : No… (237,128) : No… (238,128) : No… (239,128) : No… (240,128) : No… (241,128) : Yes! (242,128) : Yes! (243,128) : Yes! (244,128) : Yes! (245,128) : Yes! (246,128) : Yes! (247,128) : Yes! (248,128) : Yes! (249,128) : Yes! (250,128) : Yes! (251,128) : Yes! (252,128) : Yes! (253,128) : Yes! (254,128) : Yes! (255,128) : Yes! (256,128) : Yes! (257,128) : Yes! (258,128) : Yes! (259,128) : Yes! (260,128) : Yes! (261,128) : Yes! (262,128) : Yes! (263,128) : Yes!

プログラムのビルド方法および実行方法

以下のコマンドでプログラムの実行形式を生成する.

gcc -std=c89 -Wall all_sample.c vector_utils.c -lm -o all_sample

問題なくビルドできたら,以下のコマンドで実行する.

$ ./all_sample

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>