複雑系科学演習1
コンピュータグラフィックス
担当 畔上秀幸
今日の話題
ベジェ曲線・曲面の描画
lesson9_1.c(ベジェ曲線)
lesson9_2.c(色付きベジェ曲線)
lesson9_3.c(ベジェ曲面)
NURBS曲線・曲面の描画
lesson9_4.c(NURBS曲線)
lesson9_5.c(NURBS曲線の分割)
lesson9_6.c(NURBS曲面)
lesson9_7.c(2次曲面:球,円柱,円盤)
lesson9_1.c
ベジェ曲線を描画する.
1.
制御点の決定
(
ctrlpoint[4][3]
)
2.
1次元エバリュエータの定義
(
glMap1f
)
3.
頂点を算出
(
glEvalCoord1f
)
1
2
4
3
lesson9_1.c(cont.)
制御点(コントロールポイント)
25行目から
/* 制御点 */
/* x y z */
static GLfloat ctrlpoint[
4
][
3
] = {
{
-1.5, -1.8, 0.0
}
,
/* 左下 */
{
-0.9, 1.3, 0.0
}
,
/* 左上 */
{
0.5, -1.0, 0.0
}
,
/* 右下 */
{
1.9, 1.5, 0.0
}
};
/* 右上 */
制御点を移動してみる.
lesson9_1.cでは無理ベジェ曲線になっているの
で重みは制御できない.
lesson9_1.c(cont.)
1次元エバリュエータの定義
void
glMap1
{fd}(GLenum
target
, TYPE
u1
, TYPE
u2
,
GLint
stride
, GLint
order
, const TYPE *
points
)
例
:
glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoint[0][0]);
target
: 制御点pointsの表す内容
GL_MAP1_VERTEX_3 x,y,zの頂点座標 GL_MAP1_VERTEX_4 x,y,z,wの頂点座標 GL_MAP1_COLOR_4 R,G,B,A
u1,u2
: 変数uの範囲を示す.通常 0.0と1.0にする
stride
: 制御点間のデータの増分値.今の場合,制御点1
つに付き,
GLfloat3つ分(x,y,z)なので3.
order
: 曲線の次数+1
points
: 制御点データへのポインタ
lesson9_1.c(cont.)
頂点の算出
115行目から /* ベジェ曲線 */ glDisable(GL_LIGHTING); /* 線,点を描画する時はライトOFF */ glEnable(GL_MAP1_VERTEX_3); glColor3f(R(32), G(165), B(237)); glBegin(GL_LINE_STRIP);for(ii1=0; ii1<=30; ii1++){
glEvalCoord1f((GLfloat)ii1/30.0); } glEnd(); glDisable(GL_MAP1_VERTEX_3); 領域座標値 0.0~1.0の範囲で分割した値を指 定していく.これが頂点となる.分 割数を小さくすると角張ってくる.
lesson9_1.c(cont.)
126行目から /* 制御点(黄色) */ glDisable(GL_LIGHTING); /* 線,点を描画する時はライトOFF */ glColor3f(R(255), G(255), B(0)); glPointSize(5.0); glBegin(GL_POINTS);for(ii1=0; ii1<4; ii1++){
glVertex3fv(ctrlpoint[ii1]);
} glEnd();
glVertex3fv(const GLfloat *v)
glVertex3f(1.0, 2.0, 3.0); という使い方をしてきた.
glVertex3f(ctrlpoint[0][0], ctrlpoint[0][1], ctrlpoint[0][2]);と書 いてもいいが, GLfloat point[3]={1.0, 2.0, 3.0}; で座標を定義した時は glVertex3fv(point); GLfloat ctrlpoint[4][3]の時は glVertex3fv(ctrlpoint[0]); glVertex3fv(ctrlpoint[1]); …
const GLfloat v[3]と同じ
と考える.
lesson9_2.c
ベジェ曲線に色をつける.
30行目から
static GLfloat colorpoint[4][4] = {{1.0, 0.0, 0.0, 1.0}, /* 左下 */
{0.0, 1.0, 0.0, 1.0}, /* 左上 */ {0.0, 1.0, 0.0, 1.0}, /* 右下 */ {0.0, 0.0, 1.0, 1.0}}; /* 右上 */ 63行目から /* 1次元エバリュエータ */ glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &ctrlpoint[0][0]); glMap1f(GL_MAP1_COLOR_4, 0.0, 1.0, 4, 4, &colorpoint[0][0]);
lesson9_2.c(cont.)
121行目から/* ベジェ曲線 */
glDisable(GL_LIGHTING);
/* 線,点を描画する時はライトOFF */
glEnable(GL_MAP1_VERTEX_3);
glEnable(GL_MAP1_COLOR_4);
glLineWidth(2.0);
glBegin(GL_LINE_STRIP);
for(ii1=0; ii1<=30; ii1++){
glEvalCoord1f((GLfloat)ii1/30.0);
}
glEnd();
glDisable(GL_MAP1_COLOR_4);
lesson9_3.c
ベジェ曲面を描画する.
ベジェ曲線とほとんど同じ
1.
制御点の決定
(
ctrlpoint[4][4][3]
)
2.
1次元エバリュエータの定義
(
glMap2f
)
3.
頂点を算出
(
glEvalCoord2f
)
lesson9_3.c(cont.)
制御点(コントロールポイント)
25行目から
static GLfloat ctrlpoint[4][4][3] = {
{{-2.0, 2.0, -2.0},{-0.7, -1.0, -2.0},{0.7, -1.0, -2.0},{2.0, 2.0, -2.0}}, {{-1.7, 1.0, -1.0},{-1.0, -0.5, -1.0},{1.0, -0.5, -1.0},{1.7, 1.0, -1.0}}, {{-1.4, -1.0, 1.0},{-1.3, 0.5, 1.0},{1.3, 0.5, 1.0},{1.4, -1.0, 1.0}}, {{-1.0, -2.0, 2.0},{-1.6, 1.0, 2.0},{1.6, 1.0, 2.0},{1.0, -2.0, 2.0}}};
lesson9_3.c(cont.)
2次元エバリュエータの定義
void
glMap2
{fd}(GLenum
target
,
TYPE
u1
, TYPE
u2
, GLint
ustride
, GLint
uorder
,
TYPE
v1
, TYPE
v2
, GLint
vstride
, GLint
vorder
,
const TYPE *
points
)
例
:
glMap2f(GL_MAP2_VERTEX_3, 0.0, 1.0, 3*4, 4, 0.0, 1.0, 3, 4, &ctrlpoint[0][0][0]);
target
: 制御点pointsの表す内容
GL_MAP2_VERTEX_3 x,y,zの頂点座標 GL_MAP2_VERTEX_4 x,y,z,wの頂点座標 GL_MAP2_COLOR_4 R,G,B,A
u1,u2,v1,v2
: 変数u,vの範囲を示す.通常 0.0と1.0にする.
ustride, vstride
: 制御点間のデータの増分値
uorder,vorder
: 曲線の次数+1
points
: 制御点データへのポインタ
lesson9_3.c(cont.)
ustride, vstrideの意味
例
:
glMap2f(GL_MAP2_VERTEX_3, 0.0, 1.0, 3*4, 4, 0.0, 1.0, 3, 4, &ctrlpoint[0][0][0]); 制御点一つ分(ctrlpoint[3]={x,y,z}) m*nの制御点配列m
n
制御点配列は大きな配列の一部分を使う
こともできる.そのために
{u,v}strideを
指定する必要がある.
ustrideは次の行までのデータ量を示す.
左図の点線が示すデータ量
ustride=3xn
つまり,
v方向に1移動する量
vstrideは
u方向に1移動する量
よって vstride=3u
v
= ctrlpoint[4][4][3]lesson9_3.c(cont.)
116行目から /* ベジェ曲面 */ glColor3f(R(32), G(165), B(237)); glDisable(GL_LIGHTING); /* 線,点を描画する時はライトOFF */ glEnable(GL_MAP2_VERTEX_3); glLineWidth(2.0);for(ii1=0; ii1<=20; ii1++){
#if 0
glBegin(GL_LINE_STRIP); for(ii2=0; ii2<=30; ii2++){
glEvalCoord2f((GLfloat)ii2/30.0, (GLfloat)ii1/20.0); } glEnd(); #endif #if 1 glBegin(GL_LINE_STRIP); for(ii2=0; ii2<=30; ii2++){
glEvalCoord2f((GLfloat)ii1/20.0, (GLfloat)ii2/30.0);
}
glEnd();
#endif
lesson9_4.c
NURBS曲線を描画する.
制御点の決定
(
ctrlpoint[4][3]
)
NURBS曲線を描画するための設定
NURBSオブジェクトの生成
各種設定
ノットベクトルの定義
NURBS曲線の描画
lesson9_4.c(cont.)
制御点の重みを変えてみる.
static GLfloat ctrlpoint[4][4] = {{-1.5, -1.8, 0.0, 1.0}, /* 左下 */
{-0.9, 1.3, 0.0, 1.0}, /* 左上 */
{ 0.9, -1.0, 0.0, 1.0}, /* 右下 */
{ 1.9, 1.5, 0.0, 1.0}}; /* 右上 */
この行の数値を何倍か
してみる.
lesson9_4.c(cont.)
NURBSオブジェクトの生成
25行目から
static
GLUnurbsObj *NurbsObj;
61行目から
NurbsObj =
gluNewNurbsRenderer()
;
/
* NURBSオブジェクトを作る */
各種設定
62行目から
gluNurbsProperty(NurbsObj, GLU_SAMPLING_TOLERANCE, 25.0);
/*サンプリング数*/
lesson9_4.c(cont.)
ノットベクトルの定義
96行目から GLfloat knots[] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0}; /* * knots : B-Spline関数におけるノットベクトル * * Berstein関数の場合 * knots[] = {0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0}; * * 一様 B-spline関数の場合 * knots[] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0}; * * 非一様 B-spline関数の場合 (NURBS) * knots[] = {0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0}; */lesson9_4.c(cont.)
NURBS曲線の描画
131行目から/* NURBS曲線 */
glColor3f(R(32), G(165), B(237));
glDisable(GL_LIGHTING);
/* 線,点を描画する時はライトOFF */
gluBeginCurve(NurbsObj);
gluNurbsCurve(NurbsObj, 8, knots, 4, &ctrlpoint[0][0],
4, GL_MAP1_VERTEX_4);
lesson9_4.c(cont.)
NURBS曲線の定義
void gluNurbsCurve(GLUnurbsObj *
nobj
,
GLint
uknot_count
, GLfloat *
uknot
, GLint
u_stride
,
GLfloat *
ctrarray
, GLint
uorder
, GLenum
type
)
例
: gluNurbsCurve(NurbsObj, 8, knots, 4, &ctrlpoint[0][0],
4, GL_MAP1_VERTEX_4);
uknot_count
: ノットベクトルの数
uknot
: ノットベクトルの配列
u_stride
: 制御点間のデータの増分値.
ctrarray
: 制御点の配列
uorder
: 曲線の次数+1
type
: エバリュエータ形式.無理制御点ではGL_MAP1_VERTEX_3,
有理制御点では
GL_MAP1_VERTEX_4を指定する.
制御点の数は,ノットベクトルの数から曲線の階数
(uorder)を引いて
算出される.
lesson9_4.c(cont.)
ノットベクトルの値を変えてみる.
Berstein関数の場合
一様
B-spline関数の場合
NURBS曲線の分割
NURBS曲線の分割の前に…
lesson9_5を実行した後に, 右
下の図を
PowerPoint上で書い
てみる.
オートシェイプ
→
線
→
曲線
3点クリックした後,
Enterキー
曲線を選択し,右クリック→
頂点
の編集
黒い点の上で右クリック→
頂点で
線分を伸ばす
コントロールポイントを移動する.
P
0P
1P
2P
3P
4P
5NURBS曲線の分割(cont.)
NURBS曲線の分割
制御点
6個の3次B-Spline曲線をQ点で分割する.
実際はQ点ではなく,パラメータ t∈[0,1]の位置で分割する.
元の曲線形状を維持したままパラメータ t の位置で分割
するには,t を次数分だけ多重化したノットベクトルをつく
る.
オスロアルゴリズム(参考文献1参照)
まず,元の曲線のノットベクトルが[0,0,0,0,
t,t
,1,1,1,1]である
とすると,t を追加すると[0,0,0,0,
t,t
,
t
,1,1,1,1]になる.
B-Spline曲線には次式の関係があることから,制御
点を一つ増やす必要がある.
(ノットの数)
=(制御点の数)+(次数+1)
P
0P
1P
2P
3P
4P
5Q
NURBS曲線の分割(cont.)
オスロアルゴリズムによれば,挿入された制御点は
次式で求められる.(ただし,この曲線に限る.)
Q = (1-t) P
2+ tP
3
lesson9_6.cでは t = 0.7 としている.
P
0P
1P
2P
3P
4P
5Q
lesson9_5.c
制御点,ノットベクトルを既に設定しており,
#if0,#endifで切
り替えて眺める.
27行目から
static GLfloat ctrlpoint1[6][4]={…}; static GLfloat ctrlpoint2[7][4]={…}; static GLfloat ctrlpoint3[4][4]={…}; static GLfloat ctrlpoint4[4][4]={…}; … 119行目から GLfloat knots1[10] = {0.0, 0.0, 0.0, 0.0, 0.7, 0.7, 1.0, 1.0, 1.0, 1.0}; GLfloat knots2[11] = {0.0, 0.0, 0.0, 0.0, 0.7, 0.7, 0.7,1.0, 1.0, 1.0, 1.0}; GLfloat knots3[8] = {0.0, 0.0, 0.0, 0.0, 0.7, 0.7, 0.7, 0.7}; GLfloat knots4[8] = {0.7, 0.7, 0.7, 0.7, 1.0, 1.0, 1.0, 1.0}; 148行目から #if 1 /* 初期状態 */ … #endif #if 0 /* ノット,制御点Q挿入 */ … #endif #if 0 /* 分割 */ … #endif ctrlpoint1,knots1 使用 ctrlpoint2,knots2 使用
lesson9_6.c
NURBS曲面を描画する.
制御点の決定
(
ctrlpoint[4][4][3]
)
NURBS曲面を描画するための設定
NURBSオブジェクトの生成
各種設定
ノットベクトルの定義
NURBS曲面の描画
lesson9_6.c(cont.)
制御点
59行目から
init_nurbs_ctrl_point()関数内で設定
NURBSオブジェクトの生成
26行目からstatic GLUnurbsObj *NurbsObj;
61行目から
NurbsObj = gluNewNurbsRenderer(); /* NURBSオブジェクトを作る */
各種設定
67行目から
/* 描画方法の設定 */
gluNurbsProperty(NurbsObj, GLU_DISPLAY_MODE, GLU_FILL); /*
gluNurbsProperty(NurbsObj, GLU_DISPLAY_MODE, GLU_FILL);
gluNurbsProperty(NurbsObj, GLU_DISPLAY_MODE, GLU_OUTLINE_PATCH); gluNurbsProperty(NurbsObj, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON); */
lesson9_6.c(cont.)
NURBS曲面の定義
void gluNurbsCurve(GLUnurbsObj *
nobj
,
GLint
uknot_count
, GLfloat *
uknot
,
GLint
vknot_count
, GLfloat *
uknot
,
GLint
u_stride
, GLint
v_stride
, GLfloat *
ctrarray
,
GLint
uorder
, GLint
vorder
, GLenum
type
)
例
: gluNurbsSurface(NurbsObj, 8, knots, 8, knots, 4*3, 3,
&ctrlpoint[0][0][0], 4, 4, GL_MAP2_VERTEX_3);
uknot_count, vknot_count
: ノットベクトルの数
uknot, vknot
: ノットベクトルの配列
u_stride ,v_stride
: 制御点間のデータの増分値.
ctrarray
: 制御点の配列
uorder, vorder
: 曲線の次数+1
type
: エバリュエータ形式.無理制御点ではGL_MAP2_VERTEX_3,
有理制御点では
GL_MAP2_VERTEX_4を指定する.
lesson9_7.c
2次曲面:球,円筒,円盤
NURBS曲面を描画する時と手順は似ている.
25行目から
static
GLUquadricObj *qobj
;
53行目から/* 2次曲面を描画するための設定 */
qobj =
gluNewQuadric();
/* 2次曲面オブジェクトを作る */
/* 描画方法の設定 */
lesson9_7.c(cont.)
各種設定
/* 描画方法の設定 */ gluQuadricDrawStyle(qobj, GLU_FILL); /* gluQuadricDrawStyle(qobj, GLU_POINT); gluQuadricDrawStyle(qobj, GLU_LINE); gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); gluQuadricDrawStyle(qobj, GLU_FILL); */ /* 法線の設定 */ gluQuadricOrientation(qobj, GLU_OUTSIDE); /* gluQuadricOrientation(qobj, GLU_OUTSIDE); gluQuadricOrientation(qobj, GLU_INSIDE); */ /* 法線の計算方法の設定 */ gluQuadricNormals(qobj, GLU_SMOOTH); /* gluQuadricNormals(qobj, GLU_NONE); gluQuadricNormals(qobj, GLU_FLAT); gluQuadricNormals(qobj, GLU_SMOOTH); */lesson9_7.c(cont.)
球
void
gluSphere
( GLUquadric*
quad
,
GLdouble
radius
,
GLint slices, GLint stacks )
radius
: 球の半径
slices
: z軸回りの分割数
stacks
: z軸に沿った方向での分割数
円筒
void gluCylinder( GLUquadric* quad, GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks )
base: z=0 における円柱の半径
top: z=height における円柱の半径 height: 円柱の高さ
slices: z 軸回りの分割数 stacks: z 軸沿いの分割数
lesson9_7.c(cont.)
円盤
void gluDisk( GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops )
inner: 円盤の内径(0 も可)
outer: 円盤の外径
slices: z軸回りの円周の分割数
loops: 円盤を分割する同心円の数.中心は原点とする.
扇形
void gluPartialDisk( GLUquadric* quad, GLdouble inner, GLdouble outer, GLint slices, GLint loops, GLdouble start,
GLdouble sweep ) inner: 扇形の内径(0 も可) outer: 扇形の外径 slices: z軸回りの分割数 loops: 扇形を分割する原点回りの同心円の数 start: 扇形の開始角.単位は度数. sweep: 扇形の内角.単位は度数.