2015/5/26 コンピュータグラフィックスS 演 習 資 料 第 2 回 ポリゴンモデルの 描 画 九 州 工 業 大 学 情 報 工 学 部 システム 創 成 情 報 工 学 科 講 義 担 当 : 尾 下 真 樹 1. 準 備 : 前 回 の 演 習 本 日 の 演 習 は 前 回 の 演 習 で 作 成 したプログラムを 引 き 続 き 修 正 していく もし 前 回 の 演 習 を 行 っていな い もしくは 前 回 の 演 習 で 作 成 したプログラムを 無 くしてしまった 場 合 は 最 初 のサンプルプログラムを Moodle からダウンロードし 直 して 前 回 の 演 習 の 内 容 を 行 った 上 で 今 回 の 演 習 を 行 うこと なお 前 回 の 課 題 で 自 分 が Moodle に 提 出 したファイルをダウンロードすると コメント 中 の 日 本 語 の 文 字 コードが 自 動 的 に 変 換 されて 文 字 化 けすることがあるので 文 字 化 けしたソースファイルは 使 わないこと 2. 基 本 的 なポリゴンモデルの 描 画 ポリゴンモデルの 描 画 の 演 習 に 入 る 前 に まずは GLUT を 使 った 基 本 的 なポリゴンモデルの 描 画 を 試 して みる GLUT には あらかじめ 用 意 されたポリゴンモデルを 描 画 するための 関 数 がいくつか 用 意 されている 以 下 のように これまでのプログラムの ポリゴンを 描 画 していた 処 理 をコメントアウトし 立 方 体 を 描 画 する GLUT の 関 数 を 呼 び 出 してみる glutsolidcube( GLdouble size ) は 立 方 体 をポリゴンモデルとして 描 画 する 関 数 である 引 数 size には 立 方 体 の 辺 の 長 さを 指 定 する また 立 方 体 を 描 画 する 前 に 色 を 指 定 している ウィンドウ 再 描 画 時 に 呼 ばれるコールバック 関 数 変 換 行 列 を 設 定 ( 物 体 のモデル 座 標 系 カメラ 座 標 系 ) ( 物 体 が (0.0, 1.0, 0.0) の 位 置 にあり 静 止 しているとする) gltranslatef( 0.0, 1.0, 0.0 ); 物 体 (1 枚 のポリゴン)を 描 画 glbegin( GL_TRIANGLES ); glcolor3f( 0.0, 0.0, 1.0 ); glnormal3f( 0.0, 0.0, 1.0 ); glvertex3f(-1.0, 1.0, 0.0 ); glvertex3f( 0.0,-1.0, 0.0 ); glvertex3f( 1.0, 0.5, 0.0 ); 立 方 体 を 描 画 glutsolidcube( 1.5f ); プログラムを 上 記 のように 修 正 し コンパイル 実 行 して 立 方 体 が 描 画 されることを 確 認 せよ 1
次 は 球 を 描 画 してみる glutsolidsphere( GLdouble radius, GLdouble slices, GLdouble stacks ) は 球 を 近 似 するポリゴンモデルを 生 成 し 描 画 する 関 数 である 引 数 slices, stacks により 球 をどれだけ 細 かい ポリゴンモデルで 近 似 するかを 指 定 することができる これらの 値 を 大 きくすることで より 滑 らかな 球 が 描 画 されることになる(ただし その 分 処 理 時 間 がかかることになる) 立 方 体 を 描 画 glutsolidcube( 1.5f ); 球 を 描 画 glutsolidsphere( 1.0, 8, 8 ); プログラムを 上 記 のように 修 正 し 球 (を 近 似 したポリゴンモデル)が 描 画 されることを 確 認 せよ 次 に 球 を もっと 細 かいポリゴンモデルで 近 似 して 描 画 してみる 球 を 描 画 glutsolidsphere( 1.0, 16, 16 ); 上 記 のように 引 数 の 値 を 変 更 し 再 度 実 行 して 描 画 されるポリゴンモデルがどのように 変 化 するかを 確 認 せよ 3. ポリゴンモデルの 描 画 次 に 1 枚 のポリゴンの 代 わりに もう 少 し 複 雑 なポリゴンモデル( 四 角 すい)の 描 画 を 行 う OpenGL の 関 数 を 使 ってポリゴンを 描 画 する 方 法 として 以 下 のようないくつかのやり 方 がある 1. glvertex() 関 数 に 直 接 頂 点 座 標 を 記 述 する 方 法 2. 頂 点 データの 配 列 を 使 う 方 法 3. 頂 点 データとインデックスの 配 列 を 使 う 方 法 4. 頂 点 配 列 とインデックス 配 列 を 使 う 方 法 5. 頂 点 配 列 を 使 う 方 法 本 章 では 基 本 的 な 最 初 の 3 つの 方 法 を 使 って 以 下 のような 四 角 すいのポリゴンモデルを 描 画 する ( 残 りの2つの 方 法 については 後 日 余 裕 があれば 別 の 演 習 で 扱 う ) 2
3.1. 方 法 1: glvertex() 関 数 に 直 接 頂 点 座 標 を 記 述 する 方 法 最 も 単 純 は ここまでのプログラムと 同 様 glvertex() 関 数 の 呼 び 出 しをポリゴンモデルの 頂 点 数 分 記 述 す ることで OpenGL にポリゴンデータを 渡 す 方 法 である 以 下 のように この 方 法 を 使 って 四 角 すいを 描 画 するための 関 数 を 追 加 する(dysplay 関 数 の 前 に 追 加 す る) この 関 数 では glbegin( GL_TRIANGES ) ~ glend() を 使 用 し 頂 点 座 標 と 面 の 法 線 を 指 定 することで 6 枚 の 三 角 面 として 四 角 すいを 描 画 する なお 以 下 のプログラムリスト(list2-1.txt)は 講 義 のページに 用 意 されているので プログラムを 修 正 す るときには 用 意 されているプログラムリストをコピー&ペーストするなどして 利 用 しても 構 わない List2-1.txt 角 すいの 描 画 ( 頂 点 データを 関 数 内 に 直 接 記 述 する 方 法 ) void renderpyramid1() glbegin( GL_TRIANGLES ); +Z 方 向 の 面 glnormal3f( 0.0, 0.53, 0.85 ); glvertex3f( 0.0, 1.0, 0.0 ); glvertex3f(-1.0,-0.8, 1.0 ); glvertex3f( 1.0,-0.8, 1.0 ); -Z 方 向 の 面 glnormal3f( 0.0, 0.53,-0.85 ); glvertex3f( 0.0, 1.0, 0.0 ); glvertex3f( 1.0,-0.8,-1.0 ); glvertex3f(-1.0,-0.8,-1.0 ); +X 方 向 の 面 glnormal3f( 0.85, 0.53, 0.0 ); glvertex3f( 0.0, 1.0, 0.0 ); glvertex3f( 1.0,-0.8, 1.0 ); glvertex3f( 1.0,-0.8,-1.0 ); -X 方 向 の 面 glnormal3f(-0.85, 0.53, 0.0 ); glvertex3f( 0.0, 1.0, 0.0 ); glvertex3f(-1.0,-0.8,-1.0 ); glvertex3f(-1.0,-0.8, 1.0 ); 底 面 1 glnormal3f( 0.0,-1.0, 0.0 ); glvertex3f( 1.0,-0.8, 1.0 ); glvertex3f(-1.0,-0.8, 1.0 ); glvertex3f( 1.0,-0.8,-1.0 ); 3
底 面 2 glnormal3f( 0.0,-1.0, 0.0 ); glvertex3f(-1.0,-0.8,-1.0 ); glvertex3f( 1.0,-0.8,-1.0 ); glvertex3f(-1.0,-0.8, 1.0 ); 次 に この 関 数 を 描 画 関 数 (dysplay() 関 数 )から 呼 び 出 す これまでの 描 画 処 理 を 削 除 (コメントアウト)して 四 角 すいを 描 画 する 関 数 を 呼 び 出 すように 書 き 換 える ウィンドウ 再 描 画 時 に 呼 ばれるコールバック 関 数 変 換 行 列 を 設 定 ( 物 体 のモデル 座 標 系 カメラ 座 標 系 ) ( 物 体 が (0.0, 1.0, 0.0) の 位 置 にあり 静 止 しているとする) gltranslatef( 0.0, 1.0, 0.0 ); 今 までの 描 画 処 理 は 全 てコメントアウト 角 すいの 描 画 renderpyramid1(); 以 上 の 処 理 の 追 加 により 四 角 すいが 描 画 されることを コンパイル 実 行 して 確 認 する 3.2. 方 法 2: 頂 点 データの 配 列 を 使 う 方 法 方 法 1 では 全 ての 頂 点 ごとに glvertex() 関 数 の 呼 び 出 しを 記 述 する 必 要 があり ポリゴン 数 が 大 きくなる とプログラムが 長 くなってしまう そのため ポリゴンデータの 修 正 が 難 しいという 問 題 がある また ポリゴンデータがプログラム 中 に 直 接 記 述 されているため 例 えば 将 来 的 にポリゴンデータをファ イルから 読 み 込 んで 表 示 するようなこともできない そこで 頂 点 データを 配 列 に 格 納 しておき その 配 列 のデータを 使 って 描 画 を 行 う まず 以 下 のような ポリゴンデータを 構 成 する 頂 点 配 列 を renderpyramid() 関 数 の 前 にグローバル 変 数 として 定 義 する ここでは 四 角 すいを 構 成 する 三 角 面 8 枚 分 について 各 頂 点 の 座 標 と 法 線 の 配 列 を そ れぞれ 配 列 に 記 述 している List2-2.txt 角 すいの 全 頂 点 配 列 全 頂 点 数 const int num_full_vertices = 18; 全 頂 点 の 頂 点 座 標 static float pyramid_full_vertices[][ 3 ] = 0.0, 1.0, 0.0, -1.0,-0.8, 1.0, 1.0,-0.8, 1.0, +Z 方 向 の 面 0.0, 1.0, 0.0, 1.0,-0.8,-1.0, -1.0,-0.8,-1.0, -Z 方 向 の 面 0.0, 1.0, 0.0, 1.0,-0.8, 1.0, 1.0,-0.8,-1.0, +X 方 向 の 面 4
0.0, 1.0, 0.0, -1.0,-0.8,-1.0, -1.0,-0.8, 1.0, -X 方 向 の 面 1.0,-0.8, 1.0, -1.0,-0.8, 1.0, 1.0,-0.8,-1.0, 底 面 1-1.0,-0.8,-1.0, 1.0,-0.8,-1.0, -1.0,-0.8, 1.0 ; 底 面 1 全 頂 点 の 法 線 ベクトル static float pyramid_full_normals[][ 3 ] = 0.00, 0.53, 0.85, 0.00, 0.53, 0.85, 0.00, 0.53, 0.85, +Z 方 向 の 面 0.00, 0.53,-0.85, 0.00, 0.53,-0.85, 0.00, 0.53,-0.85, -Z 方 向 の 面 0.85, 0.53, 0.00, 0.85, 0.53, 0.00, 0.85, 0.53, 0.00, +X 方 向 の 面 -0.85, 0.53, 0.00, -0.85, 0.53, 0.00, -0.85, 0.53, 0.00, -X 方 向 の 面 0.00,-1.00, 0.00, 0.00,-1.00, 0.00, 0.00,-1.00, 0.00, 底 面 1 0.00,-1.00, 0.00, 0.00,-1.00, 0.00, 0.00,-1.00, 0.00 ; 底 面 1 次 に これらの 配 列 を 使 って 四 角 すいを 描 画 する renderpyramid2() 関 数 を 追 加 する 角 すいを 描 画 ( 方 法 2: 頂 点 データの 配 列 を 使 う 方 法 ) void renderpyramid2() int i; glbegin( GL_TRIANGLES ); for ( i=0; i<num_full_vertices; i++ ) glnormal3f( pyramid_full_normals[i][0], pyramid_full_normals[i][1], pyramid_full_normals[i][2] ); glvertex3f(????,????,???? ); 上 のプログラムでは 頂 点 座 標 を 指 定 する 部 分 を 空 欄 にしているので 各 自 正 しく 描 画 が 処 理 されるよう に プログラムを 追 加 すること ( 適 切 な 配 列 の 要 素 を 関 数 の 引 数 に 指 定 する ) また 追 加 した 新 しい 描 画 関 数 (renderpyramid2() 関 数 )が 呼 び 出 されるように 描 画 処 理 も 書 き 換 える ウィンドウ 再 描 画 時 に 呼 ばれるコールバック 関 数 角 すいの 描 画 renderpyramid1(); 削 除 またはコメントアウト renderpyramid2(); 以 上 の 処 理 により 前 のプログラムと 同 様 に 四 角 すいが 描 画 されることを コンパイル 実 行 して 確 認 せよ プログラムの 実 行 結 果 自 体 は 前 の 方 法 と 変 わらないが このようなプログラムにすることで ポリゴンデー タと 描 画 処 理 が 分 離 されるので ポリゴンデータの 修 正 などがやりやすくなる 3.3. 方 法 3: 頂 点 データとインデックスの 配 列 を 使 う 方 法 ポリゴンモデルのデータを 記 述 しやすくするため 同 じ 四 角 すいのポリゴンデータを 頂 点 の 配 列 と 三 角 面 インデックスの 配 列 に 分 けて 定 義 し それらを 使 って 描 画 する 方 法 を 試 してみる 以 下 のような ポリゴンデータを 表 す 配 列 を renderpyramid() 関 数 の 前 にグローバル 変 数 として 定 義 する 5
List2-3.txt 角 すいの 頂 点 配 列 + 三 角 面 インデックス 配 列 角 すいの 頂 点 数 const int num_pyramid_vertices = 5; 角 すいの 三 角 面 数 const int num_pyramid_triangles = 6; 角 すいの 頂 点 座 標 の 配 列 float pyramid_vertices[][ 3 ] = 0.0, 1.0, 0.0, 1.0,-0.8, 1.0, 1.0,-0.8,-1.0, -1.0,-0.8, 1.0, -1.0,-0.8,-1.0 ; 三 角 面 インデックス( 各 三 角 面 を 構 成 する 頂 点 の 頂 点 番 号 )の 配 列 int pyramid_tri_index[][ 3 ] = 0,3,1, 0,2,4, 0,1,2, 0,4,3, 1,3,2, 4,2,3 ; 三 角 面 の 法 線 ベクトルの 配 列 ( 三 角 面 を 構 成 する 頂 点 座 標 から 計 算 ) float pyramid_tri_normals[][ 3 ] = 0.00, 0.53, 0.85, +Z 方 向 の 面 0.00, 0.53,-0.85, -Z 方 向 の 面 0.85, 0.53, 0.00, +X 方 向 の 面 -0.85, 0.53, 0.00, -X 方 向 の 面 0.00,-1.00, 0.00, -Y 方 向 の 面 ( 底 面 1) 0.00,-1.00, 0.00 -Y 方 向 の 面 ( 底 面 2) ; 次 に これらの 配 列 を 使 って 四 角 すいを 描 画 する renderpyramid3() 関 数 を 追 加 する 角 すいの 描 画 ( 頂 点 の 座 標 データ+ 三 角 面 インデックス+ 三 角 面 の 法 線 色 データの 配 列 を 使 用 ) void renderpyramid3() int i, j; int v_no; glbegin( GL_TRIANGLES ); for ( i=0; i<num_pyramid_triangles; i++ ) glnormal3f( pyramid_tri_normals[i][0], pyramid_tri_normals[i][1], pyramid_tri_normals[i][2] ); for ( j=0; j<3; j++ ) v_no = pyramid_tri_index[ i ][ j ]; glvertex3f(????,????,???? ); 上 のプログラムでも 頂 点 座 標 を 指 定 する 部 分 を 空 欄 にしているので 各 自 正 しく 描 画 が 処 理 されるよう に プログラムを 追 加 すること ( 適 切 な 配 列 の 要 素 を 関 数 の 引 数 に 指 定 する ) また 新 しい 関 数 が 呼 び 出 されるように 描 画 処 理 も 書 き 換 える 6
ウィンドウ 再 描 画 時 に 呼 ばれるコールバック 関 数 角 すいの 描 画 renderpyramid1(); 削 除 またはコメントアウト renderpyramid2(); 削 除 またはコメントアウト renderpyramid3(); 同 様 に 以 上 の 処 理 により 同 じ 四 角 すいが 描 画 されることを コンパイル 実 行 して 確 認 せよ 4. 別 のポリゴンモデルの 描 画 ( 直 方 体 ) 次 に これまでに 学 習 した 方 法 の 練 習 として 今 度 は 以 下 のような 別 のポリゴンモデル( 直 方 体 )を 描 画 してみる ここでは 前 章 で 学 習 した 方 法 1~ 方 法 3 のうち 直 方 体 のポリゴンモデルを 最 も 容 易 に 記 述 できる 方 法 3 のやり 方 を 使 って 描 画 を 行 う また 今 回 のポリゴンモデルは 全 て 四 角 面 で 構 成 されるので 三 角 面 の 代 わ りに 四 角 面 を 使 って 描 画 する まずは 以 下 のように 直 方 体 の 頂 点 データ+ 四 角 面 インデックスデータを 定 義 する 直 方 体 は 全 ての 面 が 四 角 面 で 構 成 されるので 6 枚 の 四 角 面 として 描 画 する (もちろん 前 の 四 角 すいと 同 様 に 12 枚 の 三 角 面 として 描 画 することも 可 能 である ) 四 角 面 を 用 いることで さきほどの 四 角 すいと 異 なるのは 四 角 面 のインデックス(cube_index)が 4 個 の 頂 点 をとることである また 各 面 の 色 のデータも 配 列 として 表 現 するように 追 加 する List2-4.txt 直 方 体 の 頂 点 配 列 + 四 角 面 インデックス 配 列 const int num_cube_vertices = 8; const int num_cube_quads = 6; 頂 点 座 標 の 配 列 7
float cube_vertices[][ 3 ] = 0.8, 0.0, 0.4, 0-0.8, 0.0, 0.4, 1 0.8, 2.0, 0.4, 2-0.8, 2.0, 0.4, 3 0.8, 0.0,-0.4, 4-0.8, 0.0,-0.4, 5 0.8, 2.0,-0.4, 6-0.8, 2.0,-0.4, 7 ; 四 角 面 インデックス( 各 四 角 面 を 構 成 する 頂 点 の 頂 点 番 号 )の 配 列 int cube_index[][ 4 ] = 2,3,1,0, 7,6,4,5, 2,0,4,6, 3,7,5,1,??,??,???,??, 0,1,5,4 ; 四 角 面 の 法 線 ベクトルの 配 列 ( 四 角 面 を 構 成 する 頂 点 座 標 から 計 算 ) float cube_normals[][ 3 ] = 0.00, 0.00, 1.00, 0.00, 0.00,-1.00, 1.00, 0.00, 0.00, -1.00, 0.00, 0.00,???,????,???, 0.00,-1.00, 0.00 ; 四 角 面 のカラーの 配 列 float cube_colors[][ 3 ] = 0.00, 1.00, 0.00, 1.00, 0.00, 1.00, 1.00, 0.00, 0.00, 0.00, 1.00, 1.00, 0.00, 0.00, 1.00, 1.00, 1.00, 0.00 ; 直 方 体 を 描 画 ( 頂 点 の 座 標 データ+ 四 角 面 インデックス+ 四 角 面 の 法 線 色 データの 配 列 ) void rendercube() int i, j; int v_no; glbegin( GL_QUADS ); for ( i=0; i<num_cube_quads; i++ ) glnormal3f( cube_normals[i][0], cube_normals[i][1], cube_normals[i][2] ); glcolor3f( cube_colors[i][0], cube_colors[i][1], cube_colors[i][2] ); for ( j=0; j<4; j++ ) v_no = cube_index[ i ][ j ]; glvertex3f( cube_vertices[ v_no ][0], cube_vertices[ v_no ][1], cube_vertices[ v_no ][2] ); なお 上 のプログラムでは 1 枚 の 四 角 面 の 頂 点 番 号 と 法 線 を 空 欄 にしているので 各 自 抜 けている 四 角 面 が 正 しく 描 画 されるような 頂 点 番 号 の 組 及 び 法 線 ベクトルを 追 加 すること 5. ポリゴンモデルの 描 画 のまとめ 最 後 に 今 回 の 演 習 で 扱 ったポリゴンモデルをまとめて 描 画 してみる 変 換 行 列 を 利 用 して 3つのポリゴンモデルを 異 なる 位 置 に 描 画 する 変 換 行 列 については 後 日 の 講 義 演 習 で 学 習 するので ひとまず 今 回 は 以 下 のサンプルプログラムをそのまま 使 用 する 8
List2-5.txt もとの 変 換 行 列 の 設 定 はコメントアウト 変 換 行 列 を 設 定 ( 物 体 のモデル 座 標 系 カメラ 座 標 系 ) ( 物 体 が (0.0, 1.0, 0.0) の 位 置 にあり 静 止 しているとする) gltranslatef( 0.0, 1.0, 0.0 ); 今 までの 描 画 処 理 も 全 てコメントアウト 球 を 描 画 glpushmatrix(); gltranslatef( 1.5, 1.0, -1.0 );????????? glpopmatrix(); 角 すいの 描 画 glpushmatrix(); gltranslatef( -1.5, 1.0, -1.0 ); glcolor3f(???,???,???? ); renderpyramid3(); glpopmatrix(); 直 方 体 の 描 画 glpushmatrix(); gltranslatef( 0.0, 0.0, 1.0 ); rendercube(); glpopmatrix(); 右 のスクリーンショットと 同 様 の 画 面 を 実 現 するように 上 記 の プログラム 中 の 空 欄 を 埋 めて プログラムを 実 行 してみよ 9