資料・サンプルプログラム等:http://www.coins.tsukuba.ac.jp/~fukui/CG

平成 26 年度コンピュータグラフィックス基礎(GB13704、BC12 624)
I.科目概要
平成 26 年 10 月
三谷 純・福井幸男
秋学期 AB 火曜 1・2 時限(8:40-9:55, 10:10-11:25)
1 時限目
講義(3A202)、2 時限目
情報科学類の計算機室で演習(3C113、(3C205))
情報科学類以外の履修者は、アカウント登録と入室許可の申請をするので、まとまって
技術職員室にいきますので、初日の 1 限終了後に学生証を持って教壇近くに集合すること
担当教員
1~5 回目:
福井幸男 fukui.yukio @ jcom.home.ne.jp 090-3138-1524 非常勤
6~10 回目:
三谷 純
mitani @ cs.tsukuba.ac.jp 029-853-2333
総合 B 棟 906
TA:佐々木悠真、王天一、唐爽
講義に関連した演習課題を行う。レポート課題として提出するものを含む。期末試験を行う。
参考書 Computer Graphics (技術編 CG 標準テキストブック) CG-ARTS 協会,¥3,000
購入希望者は2週目までに回覧する出席表に氏名を○で囲んで申し込む(キャンセル不可)
II.日程予定
10 月 7 日(火) オリエンテーション、授業概要、諸注意、操作説明、OpenGL 基本演習等(福井)
10 月 14 日(火) ラスターグラフィックスの原理、線分、円弧生成のアルゴリズムの演習(福井)
10 月 21 日(火) 座標変換操作について 同次座標系、変換行列表現、合成変換等(福井)
10 月 28 日(火) 幾何学的変換と投影変換
2 次元変換の拡張と 3 次元変換の特徴(福井)
11 月 6 日(木)
曲線のモデリング 主としてエルミート曲線、ベジエ曲線と曲面表現 (福井)
11 月 11 日(火)
B スプライン曲線、B スプライン曲面等(三谷)
11 月 18 日(火)
ソリッドモデリング、B-rep,CSG 表現 (三谷)
11 月 25 日(火)
レンダリングのための表現反射モデル、曲面近似手法等(三谷)
12 月 2 日(火)
レイ・トレーシング、ラジオシティ等のリアルなシェーディングモデル(三谷)
12 月 9 日(火)
最近のトピックス(三谷)
12 月 16 日(火) 試験日(1 限のみ)
――――――――――――――――――――――
本日の演習は、以下のサイトにある資料を参考に計算機環境に慣れていくことに重点をおく
資料・サンプルプログラム等:http://www.coins.tsukuba.ac.jp/~fukui/CG/cg.htm
1.サンプルプログラムをコピーして、コンパイル実行できたら、各行の意味を調べて理解する
こと。(OpenGL+GLUT ライブラリを使う)
2.MAC 上では、コンパイルコマンドは、次のようにスペースで区切りライブラリをオプション
指定して、例えばソース test.c をコンパイルする。
gcc -framework
OpenGL -framework
GLUT
-framework
Foundation test.c
3.ソースファイルをコンパイル後、./a.out と入力して実行ファイル a.out を実行する。
4.詳しくは、上記ウェブサイトを参照のこと。
5.一通り、サンプルプログラムの実行ができ、かつ、プログラムの内容も大体理解できたら、
サンプルプログラムを組み合わせて新しいプログラムを作ってみること。
1 -1
OpenGLの基本(1/4)
OpenGL関連について
#include <GL/glut.h>
•
•
•
•
グラフィックライブラリの一つ
シリコングラフィックス社が元々開発した
Windows, Linux などでソースレベルの互換性
ウィンドウ、入出力処理をサポートしていない
(GLUTライブラリを併用することで対処)
• GLUTライブラリは対話処理を前提としている
(実行で無限ループで入力待ちの状態になる)
// ライブラリ用ヘッダファイル
• 表示関数で表示
• 無限ループで、
終了しない
void display (void) {
// 表示部分をこの関数で記入
glClear (GL_COLOR_BUFFER_BIT ); // 画面消去
glFlush ( );
// 画面出力
}
int main (int argc, char *argv[]) { // メインプログラム
glutInit (&argc, argv);
// ライブラリの初期化
glutCreateWindow (argv[0]); // ウィンドウを作成
glutDisplayFunc (display);
// 表示関数を指定
glClearColor (1.0, 1.0, 1.0, 1.0); // 消去色指定
glutMainLoop ( );
// イベント待ち
return 0;
}
実行画面
1
OpenGLの基本(2/4)
void display (void) {
OpenGLの基本(3/4)
// 表示関数
void display (void) {
glClear (GL_COLOR_BUFFER_BIT ); // 画面消去
glColor3d(0.0, 1.0, 0.0); // 色指定(R,G,B)で0~1まで
glBegin(GL_LINE_LOOP); // 形状(巡回線)定義開始
glVertex2d(-0.9, -0.8);
glVertex2d(0.9, -0.8);
glVertex2d(0., 0.8);
glEnd();
glFlush ( );
2
マウスで
ウィンドウ
の大きさを
変えると形
も変わる
// 表示関数
glClear (GL_COLOR_BUFFER_BIT ); // 画面消去
glColor3d(1.0, 0.0, 0.0); // 色指定(R,G,B)で0~1まで
glBegin(GL_TRIANGLES); // 形状(三角形)定義開始
// 頂点定義
glVertex2d(-0.9, -0.8);
glVertex2d(0.9, -0.8);
glVertex2d(0., 0.8);
// 形状定義終わり
// 画面出力
glEnd();
glFlush ( );
}
// 頂点定義
// 形状定義終わり
// 画面出力
}
実行画面
OpenGLの基本(4/4)
マウスで
ウィンドウ
の大きさを
変えても、
形は変わら
ない
#include <GL/glut.h>
void display(void) { 前のまま }
void reshape(int w, int h) { // 表示枠の幅(w)、高さ(h)を入力
glViewport(0, 0, w, h); // 枠全体を表示領域に指定
glLoadIdentity(); // 変換行列を単位行列に指定
glOrtho(-w/300.0, w/300.0, -h/300.0, h/300.0, -1.0, 1.0);
}
実行画面
3
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutReshapeFunc(reshape); // 再描画関数指定
glClearColor(1.0, 1.0, 1.0, 1.0);
glutMainLoop();
return 0;
}
グラデーション表現
#include <GL/glut.h>
int main(int argc, char *argv[])
{
void display(void)
glutInit(&argc, argv);
{
glutInitDisplayMode(GLUT_RGBA);
glClear(GL_COLOR_BUFFER_BIT);
glutCreateWindow(argv[0]);
glBegin(GL_TRIANGLES);
glutDisplayFunc(display);
① glColor3f( 1.,0.,0. ); glVertex2f( 0., 0.666 ); glClearColor( 1.,1.,1.,1. );
② glColor3f( 0.,1.,0. ); glVertex2f(-0.5,-0.2 ); glutMainLoop();
③ glColor3f( 0.,0.,1. ); glVertex2f( 0.5,-0.2 ); return 0;
glEnd();
}
glFlush();
①
}
•頂点に色を指定する
•頂点間は線形補間された色
•面の内部は2重の線形補間
②
5
ウィンドウとビューポートとの関係(1/3)
③
ウィンドウとビューポートとの関係(2/3)
glOrtho(xmin,xmax,ymin,ymax,zmin,zmax) ←正射影の投影変換
glOrtho(xmin,xmax,ymin,ymax,zmin,zmax)
ワールド座標系のどの範囲を抽出するか
マウスを動かしても引数の値は変化しない
(既定値は-1~1まで)
y
glVeiwport(x0,y0,w,h)
xmin
既定値は1
0
ymin
既定値は-1
ワールド座標系(実数値)
既定値は(0,0,w,h)
w,hの既定値は300
glVeiwport(x0,y0,w’,h’)
y
スクリーン座標系のどの領域に描くか
y
ymax
xmax
xmin
h
0
変化しない
y
ymax
x
y0
4
0
ymin
(x0,y0)
w
変化しない
x
x0
ワールド座標系(実数値)
スクリーン座標系(画素単位、整数値)
7
1 -2
xmax
マウスでウィンドウの大きさを
変えて幅w’、高さh’にする
x
h’
y0
0
(x0,y0)
w’
x
x0
スクリーン座標系(画素単位の整数値)
8
ウィンドウとビューポートとの関係(3/3)
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glBegin( GL_POINTS ); // 点表示
glVertex2i( px,py );
glEnd( );
glFlush( );
}
マウスでウィンドウの大きさを
変えて幅w’、高さh’にする
glOrtho(-cw’,cw’,-ch’,ch’,zmin,zmax)
glVeiwport(x0,y0,w’,h’)
マウスの動きに対応して引数の値を変化させる
y
-ch’
マウスの動きで引数が変化
y
選択する領域 ch’
が変化する
cw’
-cw’ 0
x
cは定数
0
ワールド座標系(実数値)
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glLoadIdentity();
glOrtho(0.,(float)w,(float)h,0.,-10.,10. );
} //
xmin, xmax, ymin, ymax, zmin, zmax
h’
y0
(x0,y0)
w’
x
x0
スクリーン座標系(画素単位の整数値)
9
マウス処理(ドラッグで座標を連続取得)
#include <GL/glut.h>
int px = 200, py = 150; // 点の初期位置
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glBegin( GL_POINTS );
glVertex2i( px,py ); // 点を表示
glEnd( );
glFlush( );
}
マウス処理 クリック操作で座標を取り込む
#include <GL/glut.h>
int px = 0, py = 0; // 初期位置
void init() {
glClearColor(1., 1., 1., 1.); // 背景は白
glColor3f( 0.,0.2,1. );
// 青色で描く
glPointSize(15.);
// 点の大きさ
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
void motion(int x, int y) {
glutInitWindowSize( 400,300 );
px = x; py = y;
glutCreateWindow(argv[0]);
glutPostRedisplay( );
glutDisplayFunc(display);
}
glutReshapeFunc(reshape);
// マウスの座標系に合わせる
glutMotionFunc(motion);
void reshape(int w, int h) {
init();
glViewport(0, 0, w, h);
glutMainLoop();
glLoadIdentity();
return 0;
glOrtho(0.,(float)w,(float)h,0.,-10.,10. );
}
} //
xmin, xmax, ymin, ymax, zmin, zmax
OpenGLの表現
void init(void) {
glClearColor(1., 1., 1., 1.); // 消去色
glColor3f( 0.,0.,1. ); // 描画色
glPointSize( 20. ); // 点の大きさ
}
void mouse(int btn, int st, int x, int y) {
switch ( btn ) {
case GLUT_LEFT_BUTTON: // 左釦
if( st == GLUT_DOWN ){
px = x; py = y; // カーソルの座標値
} break;
default: break;
} glutPostRedisplay( );
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
init();
glutMainLoop();
return 0;
}
10
文字列表示
#include <GL/glut.h>
void strout(float x, float y, char *str) {
void *font = GLUT_BITMAP_TIMES_ROMAN_24;
glRasterPos2f(x,y);
while( *str ) glutBitmapCharacter(font, *str++);
}
void display(void)
{ char *ptr, *ft="Outline font";
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glColor3f( 1.,0.,0. );
strout( -0.4,0.3,"Bitmap font" );
glColor3f( 0.,0.,1. );
glTranslatef( -0.4,-0.4,0. );
glScalef(0.001,0.001,1.);
ptr = ft;
while(*ptr)glutStrokeCharacter(
GLUT_STROKE_ROMAN,*ptr++);
glFlush();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glClearColor(1.0, 1.0, 1.0, 1.0);
glLineWidth(2.);
glutMainLoop();
return 0;
}
OpenGL GLUTのサイト等
• 頂点
http://www.opengl.org/
glVertex2d( x, y)
http://www.wakayama-u.ac.jp/~tokoi/opengl/libglut.html
double(倍精度)、 他にf(float)、i(integer)、b(byte)ほか
引数が2個(x,y)、 他に3(x,y,z)、4(x,y,z,w)など
http://wisdom.sakura.ne.jp/system/opengl/ 他
• 色
OpenGLプログラミングガイド
– glColor3f( r,g,b )
ピアソン・エデュケーション
float(単精度)、他にd(double、倍精度)
他に4( r,g,b,α ) α値は不透明度を表す
OpenGL リファレンスマニュアル
アジソン・ウェスレイ
0≦ r, g, b, α ≦1, 0は効果ゼロ、1は最大
13
1 -3
14
演習環境
// deform_disp.c 図形の描画 //以下はコメント
#include <GL/glut.h> // GLUT ライブラリを使用
・OpenGL を使うプログラムは、
通常と違い、割り込み(対話処理)
待ちの無限ループに入る。
・右のプログラムでは、display( )
関数内に描画する。
・glBegin( )と glEnd( )の間に描画
void display(void) // 表示関数
{
glClear(GL_COLOR_BUFFER_BIT); //背景色で塗る
glColor3d( 1.0, 0.0, 0.0 ); // 描画色を赤で指定(赤, 緑, 青)
glLineWidth( 1.5 );
// 線幅指定(画素単位)
glPointSize( 6.0 );
// 点の大きさ指定(画素単位)
対象の点情報を指定する。
glBegin(GL_TRIANGLES); // 表示対象(三角形)作成
glVertex2d(-0.69, 0.4 ); // 2次元の頂点座標(x,y)
glVertex2d(-0.69,-0.4 );
glVertex2d( 0. , 0.8 );
glVertex2d( 0. ,-0.8 );
glVertex2d( 0.69, 0.4 );
glVertex2d( 0.69,-0.4 );
glEnd();
// 表示対象作成終了
glFlush();
// 画面に出力
・glBegin( )の引数で幾何描画要素を
指定する。
V0
V2
V4
V1
V5
V3
}
GL_POINTS
V0
V2
V4
V1
V5
V3
GL_LINES
V0
V2
V4
V1
V0
V2
V1
V5
V3
V4 GL_LINE_STRIP
実行結果画面
V5
V3
int main(int argc, char *argv[])
// 主関数(ここからスタート)
{
glutInit(&argc, argv);
// グラフィック初期化
glutInitDisplayMode(GLUT_RGBA); // 画素毎に色指定モード
glutInitWindowSize( 480,480 );
// ウィンドウの大きさ指定
glutCreateWindow(argv[0]);
// 描画ウィンドウ作成
glutDisplayFunc(display);
// 表示関数指定
glClearColor(1.0, 1.0, 1.0, 1.0);
// 背景色指定(白)
glutMainLoop();
// 割り込み待ち
return 0;
}
マウスで画面の
大きさを変更し
たとき
GL_LINE_LOOP
V0
V2
V4
V1
V5
V3
V0
GL_TRIANGLES
V0
V0
V4
V3
V4
V7
V3
V1
V2
V4
V2
V1
GL_TRIANGLE_FAN
V5
V2
GL_QUADS
V0
V2
V4
V7
V6
V4
V0
V3
V1
V3
V5
V1
GL_TRIANGLE_STRIP
V3
V5
GL_QUAD_STRIP
V6
V1
GL_POLYGON
OpenGL3.0 以降では使えない
1 -4
V2
// const_disp.c
画面の大きさが変化しても、図形は変化しない
// curve_disp.c リサージュ図形
// 曲線を描くときは、短い折れ線を描く
#include <GL/glut.h>
#define AR 0.01745329252 // π/180
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3d( 1.0, 0.0, 0.0 ); // 赤色
glBegin(GL_TRIANGLES); // 三角形作成
glVertex2d(-0.69, 0.4 );
glVertex2d(-0.69,-0.4 );
glVertex2d( 0. , 0.8 );
glVertex2d( 0. ,-0.8 );
glVertex2d( 0.69, 0.4 );
glVertex2d( 0.69,-0.4 );
glEnd();
glFlush();
}
#include <math.h>
// sin(), cos()
#include <GL/glut.h>
double a,b,x[3],y[3];
void reshape(int w, int h) // w, h は、ウィンドウの横、縦の長さ
{
glViewport(0, 0, w, h); // 表示領域をウィンドウ全体に指定
glLoadIdentity();
// 変換行列の初期化
// 表示範囲: -w/480 < x < w/480, -h/480 < y < h/480
glOrtho(-(float)w/480.,(float)w/480.,-(float)h/480.,
(float)h/480., -1.0, 1.0);
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize( 640,480 ); // 表示画面の大きさを指定
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutReshapeFunc(reshape); // 再描画関数指定
glClearColor(1., 1., 1., 1.);
glutMainLoop();
return 0;
}
const_disp.c では、画面の大きさをマウスで変更しても
表示される図形の大きさは変わらない。
const_disp.c では、ウィンドウの大きさを変更しても、
図形は変化しない。その鍵は、glOrtho( )にある。
スライドを見て理解しよう。
1 -5
void display(void)
{
int i,k0,k1,k2;
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINE_STRIP); // 折れ線
glVertex2d( x[0],y[0] ); // 最初の 2 点
glVertex2d( x[1],y[1] );
for( i=0; i<=180; i++ ){ // 漸化式
k0 = i%3; // %は i を 3 で割った余り
k1 = (i+1)%3;
k2 = (i+2)%3;
x[k2] = a*x[k1]-x[k0];
y[k2] = b*y[k1]-y[k0];
glVertex2d( x[k2]*.99,y[k2]*.99 );
}
glEnd();
// 折れ線生成終わり
glFlush();
// 画面に出力
}
void init(void)
{
double p1=6.,p2=8.; // 振動の周期
glClearColor( 1.,1.,1.,1. );
glColor3f( 1.,0.4,0. );
glLineWidth(2.);
a = 2.*cos(AR*p1); // 漸化式の係数(x)
b = 2.*cos(AR*p2); // 漸化式の係数(y)
x[0] = 0.; x[1] = sin(AR*p1);
y[0] = 0.; y[1] = sin(AR*p2);}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize( 500,500 );
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
init();
glutMainLoop();
return 0;
}
// mouse_passive_motion.c
// マウスを動かすだけで割込処理で座標値を取得する
#include <GL/glut.h>
int p[] = {200,150}; // 点の初期位置
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glBegin( GL_POINTS );
glVertex2iv( p );
glEnd( );
glFlush( );
}
// マウスが動けばこの割込処理関数が起動
void pmotion(int x, int y) {
p[0] = x; p[1] = y;
glutPostRedisplay( );
}
http://www.center.wakayama-u.ac.jp/~tokoi/o
pengl/libglut.html から解説を引用
void glutInit(int *argcp, char **argv)
GLUT(Graphic Library Utility Toolkit)
および OpenGL 環境を初期化. 引数には
main の引数をそのまま渡す.
void
glutInitDisplayMode(unsigned
int
mode)
ディスプレイの表示モードを設定.
mode に GLUT_RGBA を指定した場合
は, 色の指定を RGB (赤緑青, 光の3原色)
で行えるようにする.
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glLoadIdentity();
// マウスの座標系は y=0 はウィンドウの一番上の位置
// マウス座標の y の正方向は下方向なので、
// y の範囲の指定は top=0 で、bottom=h として引数を与える
//引数は順に left、right、bottom、top、near、far の境界値
glOrtho(0.,(float)w,(float)h,0.,-10.,10. );
}
void init() {
glClearColor(1., 1., 1., 1.); // 背景は白
glColor3f( 0.,0.,1. );
// 青色で描く
glPointSize(15.);
// 点の大きさ
}
int main(int argc, char *argv[]) {
glutInit(&argc, argv);
glutInitWindowSize( 400,300 );
glutCreateWindow(argv[0]);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
// マウスが動いたとき割込む
glutPassiveMotionFunc(pmotion);
init();
glutMainLoop();
return 0;
}
int glutCreateWindow(char *name)
ウィンドウを開く. 引数 name はそのウィ
ンドウの名前の文字列で, タイトルバーな
どに表示される.
以降の OpenGL による図形の描画等は,
開いたウィンドウに対して行われる. 返戻
値は開いたウィンドウの識別子.
void glutDisplayFunc(void (*func)(void))
引数 func は開いたウィンドウ内に描画す
る関数へのポインタ. ウィンドウを再描画
する必要があるときに, この関数が実行さ
れる.この関数内で図形表示を行う.
void glutMainLoop(void)
これは無限ループ. この関数を呼び出すこ
とで, プログラムはイベントの待ち受け状
態になる.このプログラムは終了しないの
で、とりあえずマウスでウィンドウを閉じ
て強制終了させる
void glClear(GLbitfield mask)
ウィンドウを塗りつぶす. mask には塗り
つぶすバッファを指定. OpenGL が管理す
る画面上のバッファ (メモリ) には, 色を
格納するカラーバッファの他, 隠面消去処
理に使うデプスバッファ, 他がある.
mask に GL_COLOR_BUFFER_BIT を
指定したときは, カラーバッファだけが塗
りつぶされる.
void glViewport(int x, int y, int w, int h)
ビューポートを設定. ビューポートとは, 開いたウィンドウの中で, 実際に描画が行われる領域のこと. 正規
化デバイス座標系の2点 (-1, -1), (1, 1) を結ぶ線分を対角線とする矩形領域がここに表示される. 最初の2つ
の引数 x, y にはその領域の左下隅の位置, w には幅, h には高さをデバイス座標系, すなわちディスプレイ上
の画素数で指定する.
関数 reshape() の引数 w, h にはそれぞれウィンドウの幅と高さが入るから, glViewport(0, 0, w, h) は再描
画後のウィンドウの全面を表示領域に使うことになる.
void glOrtho(double l, double r, double b, double t, double n, double f)
glOrtho() はワールド座標系を正規化デバイス座標系に平行投影 (orthographic projection : 正射影) する行
列を変換行列に乗じる. 引数には左から, l に表示領域の左端 (left) の位置, r に右端 (right) の位置, b に下
端 (bottom) の位置, t に上端 (top) の位置, n に前方面 (near) の位置, f に後方面 (far) の位置を指定する.
この関数は, ビューポートに表示される空間の座標軸を設定する.
1 -6