/**/

チュートリアル 33:
ポリゴンモード、カラー、ブレンド

前のチュートリアルでは、JitterでOpenGLシーンを構築するために、カメラやGLグループのオブジェクトの位置を調整する方法について見てきました。このチュートリアルを理解すれば、空間的な位置に基づいて選択されたGLグループオブジェクトのポリゴンを隠したり、選択されたポリゴンを塗り潰されたモデルやワイヤーフレームモデルで描画したり、それらの結果をアンチエイリアシングやブレンディングを用いて描画バッファ(ドローバッファ)に追加したりすることができるようになります。

・Jitter Tutorialフォルダにある 33jPolyColorBlend というチュートリアルパッチを開き、“Start Rendering”と表示された toggle ボックスをクリックして下さい。

チュートリアルパッチの jit.pwindow の中にグレイの球が見えるはずです。これは、 jit.gl.gridshape オブジェクトによって描画されていますが、この jit.gl.gridshape オブジェクトは jit.gl.handle オブジェクトと接続され、回転をコントロールできるようになっています。jit.gl.handle オブジェクトの auto_rotate アトリビュートがオンになっているため、球を一度回転させると、設定した軸に沿って回転し続けます。回転を加えてみて下さい。


グレイの球

ワイヤーフレームモードと表面の選択

サンプルパッチの中の、“OpenGL Objects to Render”というラベルのすぐ下に pakpoly_mode 1 1 というオブジェクトがあります。このオブジェクトは、jit.gl.gridshape オブジェクトのポリゴンモードのアトリビュートを設定するメッセージを生成します。

pak poly_mode オブジェクトにある両方の toggle オブジェクトをクリックして下さい。グレイの球はワイヤーフレームモードで表示されるはずです。


ワイヤーフレームモードで表された球

ワイヤーフレームモードをオンに切り替えると、jit.gl.gridshape オブジェクトがポリゴン(ここでは四辺形)によって球に近い形になっていることがはっきりとわかるようになります。OpenGLで描かれたすべてのポリゴンはそれぞれ前面を持っています。この前面は「頂点が時計回りにポリゴンを囲むように見える側」として定義されています。そのため、一つのシーンでの各ポリゴンは、前面がカメラの方向を向いているか、逆を向いているかによって、表向き、裏向きのどちらかに分類されます。

OpenGLは、表向きのポリゴン、または裏向きのポリゴンのどちらかを自動的に隠すことができます。これによって、描画が非常に高速化され、また、データの視覚化される面を明確にすることができます。Jitterでは、cull_face アトリビュートを使って、オブジェクトごとにポリゴンの可視性をコントロールすることができます。

prepend cull_face オブジェクトの上のナンバーボックスを1に設定して下さい。


球の表向きのポリゴン

GLグループオブジェクトの cull_face アトリビュートは、012 に設定することができます。0 に設定するとオブジェクトのすべてのポリゴンを表示します。1 では球の裏向きのポリゴンを隠します。2 では表向きのポリゴンを隠します。今は1に設定されているため、ワイヤーフレームの球はソリッド(中空でない、中身の詰まったもの)に見えます。これは、隠れた線(ソリッドな素材で作られた球であれば見えないポリゴンの辺)が描画されないためです。回転(球を回転させてみましたか?)させると、現実のソリッドなオブジェクトに見えるような描画を行います。

prepend cull_face オブジェクトの上にあるナンバーボックスを2に設定して下さい。


球の裏向きのポリゴン

今度は表向きのポリゴンが隠されています。この場合、ちょうど球を透視して、手前側を向いた内部の面だけを見ているように表示されます。この画像からは遠近感が何か奇妙だと感じられるでしょうが、実際、パッチの中で回転するようすを見ると、シーンが「普通」に描画されているのではないことがよくわかります。

一般的に cull_face 1の設定では、球のようなソリッドで 凸 状になっているオブジェクトの場合に隠さなければならないポリゴンをうまく消去してくれます。しかし、ソリッドでない(中空の)オブジェクトでは、おそらく、表向きと裏向きのポリゴンを組み合わせて表示する必要があるでしょう。

prepend cull_face オブジェクトの上にあるナンバーボックスを0に設定し、すべてのポリゴンを表示させて下さい。pak poly_modeオブジェクトの上にある左側の toggle ボックスを1(オン)に、右側の toggle ボックスを0(オフ)に設定して下さい。prepend shape オブジェクトの上にある ubumenu を"opencylinder"に設定して下さい。


ワイヤーフレームによる表向きのポリゴンとソリッドな(塗りつぶ
された)裏向きのポリゴンによるオープンシリンダ(中空の円筒)
(訳注:原文では表向きと裏向きが逆になっていますが誤りだと思われます)

この新しいシェイプを使って、表向きと裏向きのポリゴンの違いを見ることができます。2つの整数 a と b を与えられた poly_mode a b というメッセージでは、a が 1 ならば表向きのポリゴンをワイヤーフレームモードに設定し、b が 1 ならば裏向きのポリゴンをワイヤーフレームに設定します。

RGBAカラー

GLグループのオブジェクトの色は、color R G B A というメッセージを使って指定され、R は赤、B は青、G は緑の各色の要素を、A はアルファや不透明度の要素を表します。すべての値の範囲は0から1までです。

pak color... オブジェクトの上のナンバーボックスの値を 1., 0., 0., 0.5 に設定して下さい。これは不透明度が50%の純粋な赤を指定するものです。

シリンダーの色が赤に変わるのがわかるでしょう。しかし、不透明度の変化を見ることはできません。もともと描画バッファにあったピクセルとのミックスを行なう「ブレンディング」がデフォルトではオフになっているためです。

blend_enable $1というメッセージボックスの上にある toggle ボックスをクリックして jit.gl.gridshape オブジェクトのブレンディングをオンに切り替えて下さい。次のようなものが表示されるはずです。


ブレンディングが有効になった赤いシリンダ

ARGB vs. RGBA : すでにJitterのビデオ操作オブジェクトを使ったことがあれば、それらのオブジェクトの色はプレーンに格納され、アーギュメントでは A、R、G、B の順序で指定されることを知っていると思います。GLグループのオブジェクトでは、ここで見てきたように、この順序はRGBAでアルファが最後になっています。これは奇妙に思えるかもしれないため、少し説明しておく必要があるでしょう。Jitterオブジェクトは、OpenGLとビデオというどちらの領域においても可能な限り処理を速く行なうことができるように、できるだけ本来のフォーマットと密接に関連付けられています。OpenGLはオブジェクトの色と頂点をRGBAフォーマットで格納しています。そして、QuickTimeはイメージをARGBフォーマットで格納しています。そのため、Jitterオブジェクトはこれを反映しています。パッチの中でOpenGLとビデオのマトリックス処理を組み合わせる場合、pack、unpack、jit.pack、jit.unpack オブジェクトによって、2つのシステム間での変換を容易に行なうことができます。また、planemap アトリビュートを 1 2 3 0 に設定した jit.matrix オブジェクト(1つだけですべてのプレーンを効果的にシフトします)を通してマトリックスを送信することによって、char の値を持つマトリックスを ARGB からRGBA へ変換することも可能です。チュートリアル6では、jit.matrix オブジェクトの planemap アトリビュートを使ったさらに多くの例が示されています。

色と残像の消去

この時点では、jit.gl.render オブジェクトが erase メッセージを受け取るたびに、描画バッファはデフォルトの消去色であるダークグレイで塗り潰されています。jit.gl.render オブジェクトの上にあるRGBAナンバーボックスを使って、異なった消去色を設定することができます。

jit.gl.renderオブジェクトの上にあるナンバーボックスを 000.50.1 に設定して下さい。

背景がダークブルー(赤 = 0、緑 = 0、青 = 0.5)に変わります。シリンダーが回転している場合、画面の中で残像も見えるでしょう。これは背景が不透明度0.1で消去されているためです。ダークブルーのピクセルが描画バッファに存在するピクセル上に描かれる場合、それぞれのピクセルは10分の1のダークブルーと10分の9のそれまでにあった色を重ねたものになります。その結果、前のフレームが完全に消去されるまでにはいくらか時間がかかります。半透明の描画色を表示するためには、blend_enable アトリビュートを設定しなければなりませんが、半透明の消去の場合にはこのアトリビュートは不要であるという点に注意して下さい。


回転するシリンダー、残る残像

ブレンドモード

GLグループオブジェクトの blend_enable アトリビュートがオンの場合、各ピクセルはブレンド機能を使ってドローバッファに描画されます。ブレンド機能は画像合成の基本的な処理です。この機能は、新しいピクセルである「ソース」を、既存のピクセルである「デスティネーション」へ上書きする方法をコントロールします。この機能は、ソースブレンディング係数、デスティネーションブレンディング係数という2つの部分を持っています。ソースブレンディング係数は、最終的な画像に対してソースの割合がどのくらい含まれるべきかを指定します。デスティネーションブレンディング係数は、デスティネーションの割合を指定します。

Jitterでは、ブレンディング係数として11のブレンディングモードが利用可能です。ソースに対してのみ適用されるもの、デスティネーションに対してのみ適用されるもの、両方に対して適用されるものがあります。各モードは、赤、緑、青、アルファに対する係数の様々なセットを指定します。blend_mode [src_factor] [dest_factor] というメッセージによって、GLグループの任意の描画オブジェクトに対する両方の係数を指定することができます。

ブレンドモード:ソースとデスティネーションのブレンド係数はRGBAの4つで、ソースとデスティネーションのピクセルのRGBA値で、それぞれ要素別に乗算が行われます。対応するソースとデスティネーションの要素は、加算され、その後、出力ピクセルを生成するために [ 0, 1]の範囲に直されます。

この表では、ブレンド係数がどのように計算されるかを示しています。"モード" の列は、blend_mode [src_factor] [dest_factor] のJitterメッセージの中で渡される値のリストです。"OpenGL名 " の列は、モードの名前のリストです。"対象" の列は、モードを適用できる対象がソース係数、デスティネーション係数、両方の係数のいずれであるかを示します。最後に "ブレンド係数の式" の列はピクセルを計算するために使われる実際の式を示します。添え字のsとdは、それぞれソース要素かデスティネーション要素かを表します。例えば、Rsはソースピクセルの赤の要素を表しています。

モード
OpenGL 名
対象
ブレンド係数の式
0
GL_ZERO 両方 ( 0, 0, 0, 0 )
1
GL_ONE 両方 ( 1, 1, 1, 1 )
2
GL_DSP_COLOR ソース ( Rd, Gd, Bd, Ad )
3
GL_SRC_COLOR デスティネーション ( Rs, Gs ,Bs, As )
4
GL_ONE_MINUS_DST_COLOR ソース ( 1, 1, 1, 1) - ( Rd, Gd, Bd, Ad)
5
GL_ONE_MINUS_SRC_COLOR デスティネーション ( 1, 1, 1, 1) - ( Rs, Gs, Bs, As)
6
GL_SRC_ALPHA 両方 (As, As, As, Aa )
7
GL_ONE_MINUS_SRC_ALPHA 両方 ( 1, 1, 1, 1) - ( As, As, As, As )
8
GL_DSP_ALPHA 両方 ( Ad, Ad, Ad, Ad )
9
GL_ONE_MINUS_DST_ALPHA 両方 ( 1, 1, 1, 1) - ( Ad, Ad, Ad, Ad )
10
GL_SRC_ALPHA_SATURATE ソース ( f, f, f, 1 ) ; f = min( As, 1-Ad )

OpenGLグループのすべてのオブジェクトにおけるソースとデスティネーションのデフォルトブレンドモードは、それぞれ6と7です。これは、GLブレンド係数の GL_SRC_ALPHA と GL_ONE_MINUS_SRC_ALPHA に対応します。これは非常に一般的に用いられるブレンディング操作で、他のものは必要としないかもしれません。ソースのアルファ値を変化させることによって、ソースとデスティネーションの間の直感的なクロスフェードが可能になります。

他の値は、さまざまな現実世界のライティングのシチュエーションをシミュレートする場合に役に立つと同時に、現実にはありえないような特殊な効果を作り出すために使うこともできます。

jit.gl.render オブジェクトの上にある、erase_color アトリビュートをコントロールしているRGBA というナンバーボックスの値を 1.0、1.0、0.5、1.0 に設定して下さい。これにより、背景色が黄色に、また、軌跡が消去されるように設定され、ブレンド効果がさらに見やすくなります。

pak blend_mode オブジェクトの上にある左と右のナンバーボックスを、それぞれ0と6(訳注:原文では0と7になっていますが誤りと思われます)に設定して下さい。これはソースブレンド係数にGL_ZERO、デスティネーションブレンド係数にGL_SRC_ALPHAを指定するものです。


blend_mode 0 6 に設定したシリンダ
(訳注:原文ではblend_mode 0 7 となっていますが誤りと思われます)

このブレンドモード(blend_mode)が、ここで見ているような画像をどのようにして生成するかについて検討してみましょう。ソース係数は GL_ZEROです。これはソースピクセルのすべての要素に0が乗算されることを意味します。そのため、ソースピクセルは何の影響も与えません。このことは、シリンダに対して異なったRGBの値を適用してみることによって確認できます。この場合すべて同じ色を生成します。

デスティネーション係数は GL_SRC_ALPHA です。上記の表を見ると、(As, As, As, As)というブレンド係数の式を見つけることができます。デスティネーションピクセルの各要素には、ソースピクセルにソース係数(この場合は0)をかけたものが加算される前に、ソースのアルファ(この場合は0.5)が乗算されます。これにより、各ピクセルの描画が行なわれる際に、輝度が1/2に減少します。

アンチエイリアシング

OpenGLがポリゴンや線を描くとき、ラスタ格子のピクセルを塗り潰すことによって、それらの理想的な幾何学的形状に近づけます。この処理は、デジタルオーディオで理想的な波形を再現にする場合に対応するような問題点を生じる傾向があります。離散的なピクセルから再構成する場合、理想的な画像に含まれない空間周波数、すなわちエイリアシングが必然的に生じてしまいます。このエイリアシングは、一般に"ジャギー"と呼ばれるもので、特に水平や垂直に近い線や縁で見られます。

OpenGLにはジャギーを減少させるためのアンチエイリアシング技術がいくつかあります。Jitterでは、オブジェクトのGLグループのアトリビュートによってこれを利用できるようになっています。このアトリビュートを使うことによって、GLグループの任意のオブジェクトで、描画の際にアンチエイリアシングを使用するよう指定することができます。

antialiasing $1というメッセージボックスの上にある toggle ボックスをオンにして、 jit.gl.gridshape オブジェクトにメッセージ antialias 1を送信して下さい。


アンチエイリアシング オフ


アンチエイリアシング オン

アンチエイリアスされた線は、見た目が滑らかで太めになります。この描画はより遅くなるため、描画速度を考慮する場合には、見た目の改善が時間の増大に見合うだけの価値があるかどうかを判断しなければなりません。

OpenGLにおけるアンチエイリアシングの動作は、その実装方法に依存しています。これは、アンチエイリアスを要求した場合に実際にはどのような処理が行なわれるかという点に関しては、OpenGLハードウェアやドライバのメーカーが多少の自由度を持っているということを意味します。例えば、上の図においては、線上のジャギーが減少しているのに対し、左下のポリゴンの境界が同じように見えることに注意して下さい。アンチエイリアスをオンにしたとき、Jitterはポリゴンの境界がアンチエイリアスされるように要求します。しかし、この画像を生成したOpengGLの実装環境(バージョン5.9.8のドライバによって動作するATI Rage 128アクセラレータ)は、この点では役に立っていません。あなたのマシンでの実装は、これとは異なっているかもしれません。

まとめ

表向きと裏向きのポリゴンについて定義し、ソリッドとワイヤーフレームの両方のモードで(poly_modecull_face アトリビュートを使って)それらがどのように描画されるかを見てきました。レンダラの erase_color アトリビュートと、それを利用した軌跡の描画についても紹介しました。ソースピクセルが描画バッファのデスティネーションに適用される場合にどのようなことが起こっているかについて、不透明度 や ブレンドモードを考慮しながら詳細に説明しました。そして最後に、便利ではあるが、いくぶん予測のつかない OpenGLのアンチエイリアス機を紹介しました。