[CG実習 >  CG実習 課題(2021) >  曲面の変形 ]

[課題10]: 曲面の変形

課題

以下に示すサンプルプログラムをもとにして,ベジェ曲面の制御点を移動させて,曲面を変形させられるプログラムを作成して下さい.

まずサンプルプログラムをダウンロードしてください.

サンプルプログラムは次のように操作します.

なおこのプログラムでは,画像を曲面に貼り付けるようになっています. 画像はコマンドラインで指定するようになっています.

$ ruby bezier_surface.rb  画像ファイル名

具体的にはたとえば「4arrows.jpg」を画像として使うとして,次のように指定します.

$ ruby bezier_surface.rb  4arrows.jpg

今回の課題では,このサンプルプログラムを拡張して,制御点を動かして曲面を変形できるようにして下さい. 制御点は一つずつ動かすことにします.

なお制御点は少なくともz軸上で動かせる,つまり制御点のz座標の値が変えられるようにして下さい. 余裕があれば,あわせてx軸上やy軸上でも動かせるようにして下さい.

以下では制御点の扱いについて説明します.

制御点の扱い

曲面を決定する制御点は{ Pij | 0≦i≦M,0≦j≦N }のような2つの添字をもった点の集合として扱われます. サンプルプログラムでは制御点の集合は次のように定義されています.


__surf_points = CtrlPointSet.new([
    [[-3.0, 3.0, -2.0],[-1.0, 3.0,-1.0],[ 1.0, 3.0, 1.0],[ 3.0, 3.0, 2.0]],
    [[-3.0, 1.0, -2.0],[-1.0, 1.0,-1.0],[ 1.0, 1.0, 1.0],[ 3.0, 1.0, 2.0]], 
    [[-3.0,-1.0, 2.0],[-1.0,-1.0, 1.0],[ 1.0,-1.0, -1.0],[ 3.0,-1.0,-2.0]], 
    [[-3.0,-3.0, 2.0],[-1.0,-3.0, 1.0],[ 1.0,-3.0, -1.0],[ 3.0,-3.0,-2.0]]])

この場合,二つの添字i,jで区別される4x4=16個の制御点で曲面が決定されることになります. 添字は次のようにつけられています.

  P00 P10 P20 P30
  P01 P11 P21 P31
  P02 P12 P22 P32
  P03 P13 P23 P33

制御点のうち一つがアクティブ(active)な制御点として扱われるようになっています. そのアクティブな制御点を移動させる対象とします. 初期状態ではP00がアクティブです. アクティブな制御点は変更できます.

制御点と同様に座標軸についてもアクティブな座標軸が予め設定されています. x,y,z軸のうち一つだけがアクティブになっています. 初期状態ではz軸がアクティブです. アクティブな座標軸は変更できます.

今回の課題では,制御点の集合に関して以下のような機能が利用できます.

アクティブな制御点の移動

アクティブな制御点はアクティブな座標軸に沿って,次のようにして移動できます.


  # アクティブな制御点をアクティブな座標軸に沿ってdだけ移動する
  # d=移動量(正または負)
  __surf_points.move(d)

アクティブな制御点の変更

アクティブな制御点は次のようにして変更できます.


  # アクティブな制御点の添字を(i,j)から(i+a,j+b)にずらす
  # ただし添字が範囲を越える場合には,剰余演算を適用して
  # 巡回的にずらす
  __surf_points.shift_active(a,b)

  # アクティブな制御点を(上下左右の)隣に一つずらす
  __surf_points.shift_active(-1,0) # Pij → Pi-1j
  __surf_points.shift_active(1,0)  # Pij → Pi+1j
  __surf_points.shift_active(0,-1) # Pij → Pij-1
  __surf_points.shift_active(0,1)  # Pij → Pij+1

アクティブな座標軸の変更

アクティブな座標軸は次のように変更できます.


  # アクティブな座標軸を巡回的に変更する(z軸→x軸→y軸→z軸→x軸→...)
  __surf_points.switch_active_axis

その他の機能

以下は必ずしも利用しなくて構いません.参考までに示しておきます.

制御点データの再初期化(reset)

次のメソッドで制御点をすべて初期位置に戻せます. アクティブな制御点,アクティブな座標軸も初期設定に戻ります(P00とz軸).


  # 制御点をすべて初期位置に戻す
  # アクティブな制御点,アクティブな座標軸も初期設定に戻す
  __surf_points.reset

任意の制御点の移動

(アクティブかどうかに関わらず)任意の制御点を任意の座標軸に沿って動かすことができます.


  # Pijをa番目の軸に沿ってdだけ移動する
  # (a=0→x軸,a=1→y軸,a=2→z軸)
  __surf_points.move(d,i,j,a)

なお添字の範囲は次のようになっています.

  
  i = 0,1,...,n_u-1 # (ただしn_u = __surf_points.colsで得られる値)
  j = 0,1,...,n_v-1 # (ただしn_v = __surf_points.rowsで得られる値)

アクティブな制御点の指定

アクティブな制御点はshift_active(a,b)で変更する(ずらす)だけではなく, 直接指定することもできます. 指定する添字の範囲は上に示した通りです.


  # Pijをアクティブにする
  __surf_points.active = [i,j]  

アクティブな制御点の情報取得

アクティブな制御点の情報を次のようにして得ることもできます.


  # アクティブな制御点の座標を得る
  p_act = __surf_points.active 

  # 上で得られたp_actは3次元座標を並べた配列
  p_act[0] # x座標
  p_act[1] # y座標
  p_act[2] # z座標

制御点の情報取得

アクティブな制御点以外でも制御点を個別に添字i,jで直接指定できます. また制御点の各成分(x,y,z)をそれぞれ独立に処理できます.


  pt = __surf_points.point(i,j) 

  # 上で得られたptは3次元座標を並べた配列
  pt[0] # x座標
  pt[1] # y座標
  pt[2] # z座標

  pt[0] = pt[0] + 0.5 # x座標を0.5増やす

制御点のコピー

次のように制御点のコピーを作ることで, 制御点の位置を保ったままデータを変更して利用することができます.


  p_act = __surf_points.active

  p_act1 = p_act.dup        # p_act1はp_actの複製物(p_act,p_act1は別モノ)
  p_act1[2] = p_act1[2]-0.5 # p_act1のz座標を変更する.p_actは影響を受けない

なお次のようにした場合は同じ制御点に二つ名前をつけることになります.


  # 複製を作らない(dupを使わない)場合
  p_act2 = p_act            # p_act2はp_actと同一(同一のデータに名前が二つあるだけ)
  x_0 = p_act[0]            # x_0にp_actのx座標を保存する
  p_act2[0] = -p_act2[0]    # p_act2のx座標を反転する

  p_act[0] == x_0  # ==> false
  p_act[0] == -x_0 # ==> true
  

p_act2とp_actは同じ点です. つまり一つの点にp_actとp_act2と二つ名前があるだけで, p_actでもp_act2でも操作する対象は同一です.

アクティブな座標軸の指定・情報取得

アクティブな座標軸は次のように直接指定できます. またアクティブな座標軸の情報を調べることもできます.


  # アクティブな座標軸をaに設定する(a == 0,1,2のいずれか)
  __surf_points.active_axis = a

  # アクティブな座標軸を得る
  # (軸は番号で表される: x軸→0,y軸→1,z軸→2)
  a = __surf_points.active_axis # a == 0,1,2のいずれか

[CG実習 >  CG実習 課題(2021) >  曲面の変形 ]