小嶋秀樹 | 研究室
日本語 | English
Pd から画像を出す

Pd は音だけでなく画像(静止画・動画)を扱うことも得意としています.ここでは,GEM という画像処理パッケージを使って,画像処理(とくに下図のような3次元グラフィクス)の基礎を学んでいきます.(GEM は Pd-extended に組み込まれていますので,別途インストールする必要はありません.)

図:pd-gem-sample-win
【GEM とは】

GEM (Graphics Environment for Multimedia) は,Mark Danks によって開発され,現在は IOhannes m zmölnig によってメンテナンスされている,Pd のための画像処理パッケージ(プラグイン)です.コンピュータグラフィクスの標準的な API である OpenGL の主な機能を Pd からアクセスできるようになっています.

下にあげた簡単なパッチで GEM の基本的な働きを説明しましょう.パッチの左側に,画像表示ウィンドウ [gemwin] があります.[create[ を押すと,GEM という名前のウィンドウ(おそらく真っ黒)が開きます.続いて [1[ を押すことで描画が開始されます.([0[ で描画を停止.[destroy[ で GEM ウィンドウを閉じます.)

図:pd-gem-test.pd

描画が開始されると,パッチの右側にある [gemhead] から特殊なメッセージが一定間隔で出力されます.このメッセージは,描画コンテクスト(位置・角度・色など)を表わすものです.これを受け取った [colorRGB 1 0.5 0.5] は,描画コンテクストの色項目を薄赤色に変更して出力します.この描画コンテクストの流れる先が描画オブジェクト [square 1.5] で,下図のように,サイズ 1.5 の正方形を(デフォルト位置の)原点に描画します.(「サイズ」の単位は後述します.)

GEM の基本的な仕組み
【GEM ウィンドウと描画コンテクスト】

[gemwin]create を送ると GEM ウィンドウが開き,さらに 1 を送ることで描画が開始されます.描画が開始されると,毎フレームごと(デフォルトでは 50ms ごと)に [gemhead] から描画コンテクストが出力されます.この描画コンテクストを順次加工していく流れをつくり,その中でさまざまなグラフィクス要素を描画していくことが,GEM による映像制作となります.なお,Pd で生成できる GEM ウィンドウは1つだけです.

図:pd-gem-test2.pd

上のパッチで [create, 1[ を押せば,GEM ウィンドウが開き,描画が開始されます.毎フレームごとに [gemhead] から描画コンテクストが出力され,前景色として薄赤色が設定され,続いて原点を中心に,数値ボックスに与えられた角度(単位は deg)だけ回転させた「座標系」に,正方形を描画しています.数値ボックスをマウスドラッグしてみてください.

[gemwin] で GEM ウィンドウを生成するとき,よく使う設定項目をまとめておきます.(照明や投影法の設定については後述します.)

  • color  R  G  B: 背景色を (R, G, B) に設定する.各成分は 0〜1 の値をとる.初期設定は黒=(0, 0, 0).
  • frame  フレーム数: 1秒間に描画するフレーム数を設定する.初期設定は 20.(つまり 50ms ごとに描画.)
  • dimen  幅  高さ: GEM ウィンドウのサイズを設定する.単位は画面のピクセル数.デフォルトは 500 × 500.GEM ウィンドウを開く前に設定すること.
  • offset  横位置  縦位置: GEM ウィンドウの(左上角)の画面位置を設定する.単位は画面のピクセル数で,画面左上角を (0, 0) とする.GEM ウィンドウを開く前に設定すること.
  • title  名前: GEM ウィンドウのタイトルバーに名前を設定する.GEM ウィンドウを開く前に設定すること.
  • FSAA  整数値: アンチエイリアシング(輪郭のギザギザを緩和すること)を設定する.初期値は 0(オフ)で,整数値 2, 4, 8 を与えることでオンとなる.たとえば 2 の場合,縦横 2 倍の大きさの画面で内部的に描画し,それを元の大きさに(2×2=4 ピクセルごとに平均化して)戻すようになる.GEM ウィンドウを開く前に設定すること.計算量が増えるので注意.
  • reset: GEM ウィンドウの設定をデフォルト状態に戻す.(GEM ウィンドウを開く前に設定が必要な項目については,つぎにウィンドウが開かれたときに有効となる.)
【描画コンテクストへの操作】

描画コンテクストには,(デフォルトは白=(1, 1, 1))・拡大率(デフォルトは各軸等倍=(1, 1, 1))・姿勢(デフォルトは正立=(0, 0, 0))・位置(デフォルトは原点=(0, 0, 0))などの各パラメタが含まれます.これらパラメタへの操作を積み重ねることで,描画オブジェクトを配置する「場」をつくります.また,パラメタへの操作の流れを分岐させ,複数の描画オブジェクトの間に相対的な関係(たとえば太陽・惑星・衛星のような従属関係)を与えることができます.

上のパッチにあるように,描画コンテクストへの操作を分岐させ,その先に異なる座標変換を積み重ねていく場合は,それぞれの支流の先頭に [separator] を配置します.[separator] よりも下流域は,他の支流での座標変換から影響を受けなくなります.3つの数値ボックスの値を増減させて,3つの正方形がどのような位置関係に描画されるのかを確かめてみてください.

このパッチにおける描画オブジェクトの位置関係は,下図とあわせて,つぎのように説明できます.まず (1) GEM ウィンドウの中央を原点とする座標系をイメージしてください.横軸が X 軸,縦軸が Y 軸となり,Z 軸はその交点を通る手前向きの垂直軸となります.(2) [rotateXYZ] に Z=20 を与えることで,この座標系を Z 軸を中心に(XY 平面上で)20deg 回転させた,新しい座標系を得ます.上段左側の [separator] 以下では,この新しい座標系で (0.8, 0.8), (0.8, −0.8), (−0.8, −0.8), (−0.8, 0.8) を頂点とする正方形を薄赤色で描画します.上段右側の [separator] 以下では,(3) [translateXYZ] に X=2.5 を与えることで,この座標系を X 方向に 2.5 だけ平行移動させた新しい座標系を得ます.さらに,(4) この座標系を Z 軸まわりに 30deg 回転させた,新しい座標系を得ます.下段左側の [separator] 以下では,この座標系の中心にサイズ 0.4 の正方形を薄緑色で描画します.下段右側の [separator] 以下では,(5) この座標系を X 方向に 1 だけ平行移動させ,さらに (6) Z 軸まわりに 40deg 回転させた新しい座標系を得て,その中央にサイズ 0.2 の正方形を薄青色で描画します.

このように,座標系を平行移動させたり回転させたり,あるいは拡大・縮小させることで,新しい座標系をつくり,そこに描画オブジェクトを配置したり,さらに別の座標系を派生させることが,GEM(そして OpenGL)における画像生成の基本プロセスとなります.

接続線を流れる描画コンテクストは,実際には,描画位置・角度・色といった GEM の内部データへのポインタです.[gemhead] は,フレーム (50ms) ごとに白紙(デフォルト状態)の描画コンテクストを GEM 内部に生成し,それへのポインタを出力します.[separate] は,入力された描画コンテクストの中で座標系のデータを一時保存し,それ以降の処理が終わった後で,一時保存した部分を元の描画コンテクストに戻します.

【3次元グラフィクス】

いままでのパッチはすべて3次元空間に描画オブジェクトを配置していました.gem-test3.pd をわずかに改造した下のパッチで,これを確かめてみます.上段中央にある新しい数値ボックスは,出発点となる座標軸を Y 軸回りに回転させる角度を与えるものです.軸上でプラスの方向に進むネジの回転方向がプラスの角度となります.

このパッチで,Y 軸まわりに 50deg だけ回転させると,下図のような結果が得られます.デフォルト状態では,視点は (0, 0, 4) の位置にあり,視線は原点 (0, 0, 0) を向き,Y軸方向が上になるように透視投影 (perspective projection) されます.もちろん視点の位置や視線の向きは自由に変えることもできます.この3次元空間の中で,[square] などの描画オブジェクトは,すべて XY 平面上(Z=0)に配置されていました.(薄赤色の正方形の中心が原点 (0, 0, 0) となっています.)

つぎに,[square]を厚みをもった描画オブジェクトに置き換えてみます.[cube S] は各軸それぞれに −SS の範囲をとる立方体です.

上のパッチによって下図のようなグラフィック表示が得られます.画面中央の薄赤色の立方体は1面しか見せていませんが,他の2つは3面を見せています. パッチ上段左側にある数値ボックスを操作して,全体を Y 軸まわりに回転させてみてください.

上の例では,斜めから見た立方体がその3面あるいは2面を見せていますが,どの面も同じ色・明るさで表示されているので,やや不自然に見えます.これは,まだ照明 (lighting) の機能をオンにしていないためです.照明への応答をオンにするには,[gemwin] に {lighting 1} を送ります.また,照明となる光源を入れる必要もあります.下のパッチでは,無限遠からの平行光線を発生させる [world_light] を導入しています.デフォルトでは (0, 0, 1) が光の進む方向ですが,ここではそれを X 軸まわりに −30deg,続いて Y 軸まわりに 15deg だけ回転させています.およそ,手前側の右斜め上からの光です.

パッチ左上側の [toggle] で,照明機能をオンにしてください.3つの立方体が,手前側の右斜め上からの光を受けて,その各面の明度を変化させているのがわかります.照明には,無限遠の [world_right] のほかに,空間内の1点に置かれた点光源の [light] があります.いずれも {debug 1} を与えることで,光源の方向または位置を表示できます.[trigger] を使うことで,照明をつけてから描画するようにしています.

上のパッチで,[cube][sphere] に置き換えてみてください.球が配置されます.デフォルトでは表面が粗いので,たとえば [sphere 0.8 32] のように,分割数(円を多角形で近似するときの頂点数)を引数に追加するとよいでしょう.

2011年5月の時点での GEM 最新版 (0.92.3) には,円錐 (cone) と円柱 (cylinder) の照明に対する応答(明度計算)にバグがあり,自然な陰影がつきません.このバグは次のリリースで修正される予定です.それまでは,直前に [scaleXYZ -1 -1 -1] を入れることで補正してください.

描画コンテクストの操作

描画コンテクストに操作 (Manips: manipulations) を加え,そこに描画オブジェクト (Geos: geometrical objects) を配置することが,GEM(そして OpenGL)におけるグラフィクス生成の基本的な手順です.ここでは,描画コンテクストの操作 (Manips) について解説していきます.(なお,以下の一覧のなかで括弧に入れられた引数は省略できます.省略した場合はデフォルト値が使われます.いつでも入力端子から上書きできます.)

【Manips (1) : 座標系の操作】

描画コンテクストの操作には,座標変換と色変換があります.まず座標変換について,参考パッチ gem-coord.pd を使って,以下の操作 (Manips) を解説します.座標変換を積み重ね,必要に応じて [separator] によって分岐させることで,描画オブジェクトの位置や姿勢を決めていきます.

座標変換の順序には注意が必要です.連続する平行移動は順序を変えても結果は変わりませんし,1つの平行移動にまとめることもできます.一方,回転と回転,あるいは回転と平行移動は,順序を変えると結果も変わります.

図:testbang.pd 図:testbang.pd

左上の図は [rotateXYZ 0 30 0] を適用してから [translateXYZ 1 0 0] を適用した場合,右上の図はこれらを逆の順序で適用した場合を図示したものです.両者の違いをよく確かめてください.

【Manips (2) : 色や質感の操作】

つぎに色と照明について説明します.GEM(OpenGL)における物体表面の「色」は,以下にあげるいくつかの反射特性によって照明光が反射された光が足し合わされたものになります.この反射特性によって,物体の色だけでなく,質感(マット・光沢など)も与えられます.まず,反射特性の操作を,いくつかの参考パッチ(下図)を使って解説します.ピンク色の部分が,反射特性の操作に関係する部分です.

パッチを開いたら,最上段にあるメッセージボックスをクリックします.これで初期設定された GEM ウィンドウが現われ,2つの [teapot](描画オブジェクトのひとつ)が白いシルエットで表示されます.つぎにパッチ左側にある [toggle] で,照明機能をオンにしてください.これで [teapot] が薄赤色の立体として見えるようになります.パッチ上段中央の2つの数値ボックスで,どの角度から見るかを調節してください.(以下の例では,それぞれ 15, 0 を与えています.)

なお,以下の一覧のなかで括弧に入れられた引数は省略できます.省略した場合は,入力端子から設定します.未設定の場合はデフォルト値(多くの場合 1)が使われます.また A と表記した引数(あるいは入力端子)は「アルファ値」という不透明度を表わすものです.これについては後述します.

座標系の操作は [separator] によってその効果の範囲を切り分けることができました.一方,色の操作は [separator] によって切り分けられませんgemhead から出力される描画コンテクストが流れる順序で色変換が適用され,別の支流(順序的に後になるもの)にもその効果が波及します.基本的に,支流ごとにすべての反射特性を設定しなおす必要があります.

支流ごとに反射特性を設定する以外に,複数の [gemhead] を使うことでも,この問題に対処できます.[gemhead] ごとにデフォルト状態の描画コンテクストが用意されるため,色変換・座標変換の有効範囲が切り分けられるのです.

【Manips (3) : 照明の操作】

照明について説明します.すでに「色や質感の操作」のところで照明を使っていました.ここでは,GEM で利用できる2種類の照明について,いくつかの参考パッチ(下図)を使って解説します.ピンク色の部分が,照明の操作に関係する部分です.

パッチを開いたら,最上段にあるメッセージボックスをクリックします.これで初期設定された GEM ウィンドウが現われ,2つの [teapot] が白いシルエットで表示されます.つぎにパッチ左側にある [toggle] で,照明機能をオンにしてください.これで,薄赤色と薄青色の [teapot] が立体として見えるようになります.パッチ上段中央の2つの数値ボックスで,どの角度から見るかを調節してください.(以下の例では,それぞれ 15, 0 を与えています.)

描画オブジェクトの配置

描画コンテクスト(座標系や色・照明など)を設定したら,そこに描画オブジェクト (Geos: geometrical objects) を配置することで,グラフィクス表示が得られます.ここでは,よく使う描画オブジェクト (Geos) とその使い方を紹介します.

【Geos (1) : 立体オブジェクト】

立体オブジェクトは,現在有効な描画コンテクストにおける原点に配置されます.たとえば,[cube 1] であれば,原点を中心に,上下前後左右に 1 の拡がり(つまり 2×2×2 の大きさ)をもつ立方体が配置されます.ここでは,よく使う立体オブジェクトについて説明していきます.

【Geos (2) : 平面・線オブジェクト】

平面オブジェクトや線オブジェクトは,現在の座標系の原点に配置されます.たとえば,[square] であれば,原点を中心といて,XY 平面上(Z=0)に配置されます.3次元空間内に配置された平面であることに注意してください.ここでは,よく使う平面・線オブジェクトについて説明していきます.

スクリーンへの投影

3次元空間上に配置された描画オブジェクト G は,視点 E からスクリーン S に投影することで,GEM ウィンドウ上に表示されます.いわゆる透視投影 (perspective projection) とよばれる投影法です.

図:pd-gem-perspective

デフォルト状態では,視点 E は (0, 0, 4) の位置にあります.E から注視点 (0, 0, 0) に向かう直線(X=0, Y=0)が視線となります.この視線に垂直で,E から視線方向に 1 だけ離れた平面(Z=3)が S となります.Y 軸の正方向が S の上方向となります.

図:pd-gem-perspective2
【視点の設定】

視点を (X, Y, Z) に移動するには,[gemwin] に {view  X Y Z} を与えます.たとえば,デフォルトの視点 (0, 0, 4) を (0, 0, 8) に移動すると,下図(左 → 右)のように,原点に配置した描画オブジェクトは遠くに(小さく・弱い遠近感で)見えるようになります.使用したパッチを下にあげておきます.

図:pd-gem-view-win1 図:pd-gem-view-win2

{view  X Y Z} による視点移動は平行移動となるため,視線方向は変化しません.たとえば,デフォルト状態から {view  1 0 4} を与えると,注視点は (0, 0, 0) から (1, 0, 0) に移ります.左下図は視点を (1, 0, 4) に,右下図は (1, 0, 8) に移した場合を表わしています.[cube] の位置だけでなく,各面の見え方も微妙に変わっています.

図:pd-gem-view-win3 図:pd-gem-view-win4

{view ...} による視点の設定は,一般には,以下の 10 項目からなるメッセージを [gemwin] に送ることで実行します.いつでも変更可能です.デフォルト状態は {view  0 0 4  0 0 0  0 1 0} となっています.

  • セレクタ: view
  • 視点の位置: XE, YE, ZE (デフォルト 0, 0, 4
  • 視線の向き(注視点の位置): XG, YG, ZG (デフォルト 0, 0, 0
  • 視野の上方向(ベクトル): XU, YU, ZU (デフォルト 0, 1, 0

視点の位置だけを変える場合は {view,  XE, YE, ZE} を送ればよいです.また,{view,  XE, YE, ZE,  Ayaw} あるいは {view,  XE, YE, ZE,  Ayaw, Apit} のように設定することもできます.Ayaw は水平方向(右へ)の偏角 (deg),Apit は垂直方向(上へ)の仰角 (deg) です.

【視野と遠近感】

GEM(そして OpenGL)には,上下左右のほかに,前後にも視野の境界があります.下図は,GEM における視野を「視錐台 (frustum)」として表わしたものです.left, right, bottom, top のデフォルト値は -1, 1, -1, 1 です.また,near, far のデフォルト値は 1, 20 となっています.この視錐台の内部にある描画オブジェクト(あるいはその一部)のみが GEM ウィンドウに表示されます.

図:pd-gem-frustum

この視錐台の形をデフォルト状態から変えるには,{perspec  left right bottom top near far} のように,perspec に続いて各パラメタを連ねたメッセージを [gemwin] に与えます.下のパッチで,[view 0 0 4[[perspec -1 1 -1 1 3 10[ を押し,数値ボックスを(シフトを押しながらドラッグすることで)操作して,[cube] を奥側や手前側に動かしてみてください.奥側の限界は Z=−6 の位置,手前側の限界(スクリーン)は Z=1 の位置となります.

左下図は [cube] を Z=−6.5 に配置した場合で,その先端部分だけが表示されています.右下図は Z=0 に配置した場合で,スクリーン(Z=1)で切断された [cube] の内側が見えています.(いずれも極端な例です.ふつうは十分な視野範囲を設定します.)

図:pd-gem-perspec-win1 図:pd-gem-perspec-win3

この視錐台の形によって,遠近感を調節することができます.ちょうどマクロ撮影が大きな遠近感を与え,望遠撮影が遠近感を弱めるのと同じ原理です.たとえば,下のパッチでは,視点からスクリーンまでの距離と,視点から描画オブジェクトまでの距離を,1 : 2 に保ったまま増減させることで,遠近感の強弱を調節しています.[view 0 0 0[ を押してから,数値ボックスを(およそ −2〜−20 の範囲で)操作してみてください.

左下図は,視点からスクリーンまでの距離が 2, 視点から [cube] までの距離が 4 の場合で,遠近感が強く出ています.右下図は,視点からスクリーンまでの距離が 8 で,視点から [cube] までの距離が 16 の場合で,ほぼ遠近感のない(平行投影に近い)表示となっています.

図:pd-gem-perspec2-win1 図:pd-gem-perspec2-win2
【GEM ウィンドウの大きさ】

GEM ウィンドウの大きさを設定するには,ウィンドウを開く前に,横のピクセル数 W, 縦のピクセル数 H を {dimen  W H} というメッセージに入れて [gemwin] に与えます.下のパッチは,250×150 ピクセルおよび 150×250 ピクセルの GEM ウィンドウに,同じ条件で [cube] を描画します.

生成された GEM ウィンドウの下端・上端は,視錐台前面(スクリーン S)の bottom・top に対応しますが,左端・右端に対応する left・right の値は自動的に再設定されます.つまり,縦方向を優先して,描画オブジェクトが 1 : 1 の縦横比で表示されるように,視錐台の幅が自動調整されるようになっています.

図:pd-gem-dimen-win1 図:pd-gem-dimen-win2

GEM ウィンドウ生成後に,手動で {perspec ...} を設定すると,まず bottom・top がウィンドウの上端・下端と対応づけられてから,(bottom − top) : (right − left) の縦横比で描画オブジェクトが表示されるように,視錐台の幅が調整されます.多くの場合,縦横比が 1 : 1 の描画オブジェクトを表示することになるので,つぎのような手順で {dimen ...} や {perspec ...} を設定すればよいでしょう.

  1. 利用したい GEM ウィンドウの大きさを {dimen  W H} で設定し,GEM ウィンドウを生成する.
  2. GEM ウィンドウの下端・上端に対応する視錐台前面(スクリーン S)上の Y 座標を bottom・top とし,同じ値(あるいは同じ間隔をもつ値)を left・right として,{perspec ...} を設定する.
【その他の機能】

GEM ウィンドウからキーボードの入力を読み取ることができます.[gemkeyboard] は押されたキーの key code を数値で出力します.ASCII コードではないので,注意してください.より詳しいキー入力情報が必要な場合は,[gemkeyname] を使うとよいでしょう.キーに対応したシンボルと,キーの状態(up=1, down=0)を出力します.(いずれも,GEM ウィンドウが選択されているときに,キー入力が読み取られます.)

また,[gemmouse] を使うことで,マウスの入力を読み取ることもできます.マウスイベント(ポインタの動き・ボタンの操作)が発生すると,GEM ウィンドウ内側の左上端を (0, 0) として,マウスポインタの位置を X 座標・Y 座標に分けて出力し,またボタン(左・中・右)の状態変化も出力します.(GEM ウィンドウが選択されているときに,マウスイベントが読み取られます.)

GEM ウィンドウのフルスクリーン表示については「Pure Data 小ネタ集」を参照してください.