複雑系科学演習 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) 2 4 3 1
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++){ } glend(); glevalcoord1f((glfloat)ii1/30.0); 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(); const GLfloat v[3] と同じと考える. 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]);
lesson9_2.c ベジェ曲線に色をつける. 30 行目から 63 行目から static GLfloat colorpoint[4][4] = {{1.0, 0.0, 0.0, 1.0}, /* 左下 */ /* 1 次元エバリュエータ */ {0.0, 1.0, 0.0, 1.0}, /* 左上 */ {0.0, 1.0, 0.0, 1.0}, /* 右下 */ {0.0, 0.0, 1.0, 1.0}}; /* 右上 */ 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); gldisable(gl_map1_vertex_3);
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]); m*nの制御点配列 m v u n 制御点配列は大きな配列の一部分を使うこともできる. そのために {u,v}strideを指定する必要がある. ustrideは次の行までのデータ量を示す. 左図の点線が示すデータ量 ustride=3xn つまり,v 方向に1 移動する量 vstrideはu 方向に1 移動する量 よって vstride=3 制御点一つ分 (ctrlpoint[3]={x,y,z}) = 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 行目から 61 行目から static GLUnurbsObj *NurbsObj; 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); gluendcurve(nurbsobj);
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 関数の場合 非一様 B-spline 関数の場合
NURBS 曲線の分割 NURBS 曲線の分割の前に lesson9_5を実行した後に, 右下の図をPowerPoint 上で書いてみる. オートシェイプ 線 曲線 3 点クリックした後,Enterキー 曲線を選択し, 右クリック 頂点の編集 黒い点の上で右クリック 頂点で P 1 P 2 線分を伸ばす コントロールポイントを移動する. P 0 P 4 P 5 P 3
P 1 P 2 NURBS 曲線の分割 (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 0 Q P 4 P 5 P 3
NURBS 曲線の分割 (cont.) オスロアルゴリズムによれば, 挿入された制御点は次式で求められる.( ただし, この曲線に限る.) Q = (1-t) P 2 + tp 3 lesson9_6.c では t = 0.7 としている. P 1 P 2 P 4 P 5 P 0 Q P 3
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 /* 初期状態 */ ctrlpoint1,knots1 使用 #endif #if 0 /* ノット, 制御点 Q 挿入 */ #endif #if 0 /* 分割 */ #endif ctrlpoint2,knots2 使用 ctrlpoint3, ctrlpoint4, knots3, knots4 使用
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 次曲面オブジェクトを作る */ /* 描画方法の設定 */ gluquadricdrawstyle(qobj, GLU_FILL);
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: 扇形の内角. 単位は度数.
参考文献 1. 3 次元形状処理入門ー 3 次元 CG と CAD への基礎ー, 今野晃市著, サイエンス社,2003.