Max 5 API Reference

OB3D Details

この章の目的は、OB3D と呼ばれる Jitter の OpenGL の詳細についての説明を加えることです。

ここでは、OB3D のデフォルトのアトリビュートやメソッドを無効にしたり、あるいはオーバーライドする方法について、マトリックスの入出力のサポートについて、そして、テクスチャ、ディスプレイリスト、シェーダなどのリソースの管理について説明します。この章は、OpenGL API や OB3D クイックスタートの章の内容について熟知していることを前提に書かれています。OpenGL API については、このドキュメントで説明する範囲を超えています。OpenGL API に関する情報を得るためには、OpenGL Red Book や多くのオンラインチュートリアルを参照することを推奨します。

Jitter OB3D クラスの定義

OB3D クイックスタートで述べたように、Jitter OB3D は多くのデフォルトのアトリビュートとメソッドを持っており、いくつかの特定のメソッドの定義を必要とします。このセクションでは、これらの共通したアトリビュートとメソッドについて、さらに、必要な場合にカスタマイズした動作の実行を可能にする方法について明確にしようと思います。

Draw メソッドの宣言

すべての Jitter OB3D で、ob3d_draw というシンボルにバインドされたメソッドを定義しなければなりません。このメソッドはオブジェクト構造体だけを引数として取り、プライベートな A_CANT 型指定子を使って定義しなければなりません。プライベートな、ob3d_draw メソッドは、すべての OB3D に付加される標準の draw および drawraw メソッドによって呼び出されます。draw メソッドでは、ob3d_draw の呼び出しの前に、デフォルトの OB3D アトリビュートに関連した OpenGL のステートを設定しますが、drawraw メソッドではこの設定を行ないません。

デスティネーションとジオメトリ関係のメソッドの宣言

Jitter OB3D のアトリビュートの変更や、オブジェクトがレンダリングを行なうデスティネーションの変更を行なうことができます。この場合、リソースの解放やリビルド(再構築)が必要になります。このようなイベントが生じた場合に OB3D と通信を行なうメソッドが3つあり、これらのメソッドによって OB3D はリソースの管理を行なうことができます。dest_closing はデスティネーションが解放されたことを OB3D に報告し、コンテキストに属する、テクスチャ、ディスプレイリスト、シェーダなどのリソースを解放しなければならないことを伝えます。dest_changed は、デスティネーションがリビルド(再構築)されたことを OB3D に報告し、新しいリソースの割り当てが可能であることを伝えます。
rebuild_geometry は、テクスチャユニットの変更、あるいは jit_gl_drawinfo_setup() や jit_gl_texcoord などの t_jit_gl_drawinfo 関連の関数に影響を与えるような変更を受けた OB3D に対して、このような関数が使用するジオメトリをリビルド(再構築)するように要求します。 これらのメソッドはオブジェクト構造体だけを引数として取ります。dest_closing および dest_changed メソッドはプライベートな A_CANT 型指定子を使って定義しなければなりません。また、rebuild_geometry メソッドは通常、型によって定義しますが、引数を必要としません。そのため、ユーザが必要であると考える場合に、明確に呼び出すことができます。SDK のプロジェクト jit.gl.gridshape はこれらのメソッドの良い例です。ここでは、レンダリングを行なうデスティネーションが変更された場合、ディスプレイリストの解放と割り当てを行なう必要があり、マルチテクスチャリングをサポートするために jit_gl_texcoord を利用します。この利用の際には、テクスチャユニットの数や他のアトリビュートの変更によってリビルド(再構成)されたジオメトリが要求されます。

Register メソッドの宣言

jit.gl.sketch や、デフォルトの registration(登録)メソッド jit_object_register() を追加する必要があるオブジェクトでは、すべての jitter OB3D は名前をつけられ、名前による参照をサポートしています。オブジェクトの登録と通知に関する詳細は、後の章で説明します。

回転、およびスケール関連のアトリビュートのオーバーライド

それぞれの Jitter OB3D は、デフォルトでは jit_ob3d_setup() によってクラスに追加された rotate、rotatexyz、scale、viewalign というアトリビュートを持っています。これらのアトリビュートは ob3d_draw_preamble() 関数で使用され、オブジェクトの draw メソッドを呼び出す前に OpenGL のステートを 設定しますが、これを無効にするためには JIT_OB3D_NO_ROTATION_SCALE フラグを使用します。これらのアトリビュートは、独自のアトリビュートを同じ名前で定義することによって、オーバーライドできます。しかし、あなたの draw メソッド の中では、適切な glMatrixMode、glTranslate、glRotate、glScale を呼び出すことによって、必要な OpenGL のステートを管理する必要があります。

色関連のアトリビュートのオーバーライド

それぞれの Jitter OB3D は、デフォルトでは jit_ob3d_setup() によってクラスに追加された color、aux_color、smooth_shading というアトリビュートを持っています。これらのアトリビュートは、オブジェクトの draw メソッドを呼び出す前にob3d_draw_preamble() 関数で使用されますが、これを無効にするためには JIT_OB3D_NO_COLORフラグを使用します。これらのアトリビュートは、独自のアトリビュートを同じ名前で定義することによって、オーバーライドできます。しかし、あなたの draw メソッド の中では、適切な glColor、glShadeModel を呼び出すことによって、必要な OpenGL のステートを管理する必要があります。

テクスチャ関連のアトリビュートのオーバーライド

それぞれの Jitter OB3D は、デフォルトでは jit_ob3d_setup() によってクラスに追加された texture、capture、tex_map、tex_plane_s、tex_plane_t というアトリビュートを持っています。これらのアトリビュートは、オブジェクトの draw メソッドを呼び出す前にob3d_draw_preamble() 関数で使用されますが、これを無効にするためには JIT_OB3D_NO_TEXTURE フラグを使用します。これらのアトリビュートは、独自のアトリビュートを同じ名前で定義することによって、オーバーライドできます。しかし、あなたの draw メソッド の中では、適切なglEnable、 glTexGen、jit_gl_bindtexture、 jit_gl_unbindtexture、 jit_gl_begincapture、jit_gl_endcapture を呼び出すことによって、必要な OpenGL のステートを管理する必要があります。

ライティング、およびマテリアル関連のアトリビュートのオーバーライド

それぞれの Jitter OB3D は、 デフォルトでは jit_ob3d_setup() によってクラスに追加された lighting_enable、auto_material、 shininess, mat_ambient 、mat_diffuse、 mat_specular、 mat_emission というアトリビュートを持っています。これらのアトリビュートは、オブジェクトの draw メソッドを呼び出す前に ob3d_draw_preamble() 関数で使用されますが、これを無効にするためには JIT_OB3D_NO_LIGHTING_MATERIAL フラグを使用します。これらのアトリビュートは、独自のアトリビュートを同じ名前で定義することによって、オーバーライドできます。しかし、あなたの draw メソッド の中では、適切なglEnable、 glLight、glLightModel、glMaterial を呼び出すことによって、必要な OpenGL のステートを管理する必要があります。

フォグ関連のアトリビュートのオーバーライド

それぞれの Jitter OB3D は、デフォルトでは jit_ob3d_setup() によってクラスに追加された fog、fog_params、というアトリビュートを持っています。これらのアトリビュートは、オブジェクトの draw メソッドを呼び出す前に ob3d_draw_preamble() 関数で使用されますが、これを無効にするためには JIT_OB3D_NO_FOG フラグを使用します。これらのアトリビュートは、独自のアトリビュートを同じ名前で定義することによって、オーバーライドできます。しかし、あなたの draw メソッド の中では、適切なglEnable、glHint、glFog を呼び出すことによって、必要な OpenGL のステートを管理する必要があります。

ポリゴン変数関連のアトリビュートのオーバーライド

それぞれの Jitter OB3D は、デフォルトでは jit_ob3d_setup() によってクラスに追加された cull_face、point_size、line_width というアトリビュートを持っています。これらのアトリビュートは、オブジェクトの draw メソッドを呼び出す前に ob3d_draw_preamble() 関数で使用されますが、これを無効にするためには JIT_OB3D_NO_POLY_VARS フラグを使用します。これらのアトリビュートは、独自のアトリビュートを同じ名前で定義することによって、オーバーライドできます。しかし、あなたの draw メソッド の中では、適切な glPolygonMode、glEnable、glCullFace、glPointSize、glLineWidth.を呼び出すことによって、必要な OpenGL のステートを管理する必要があります。

ブレンド関連のアトリビュートのオーバーライド

それぞれの Jitter OB3D は、デフォルトでは jit_ob3d_setup() によってクラスに追加された blend_mode 、blend_enable というアトリビュートを持っています。これらのアトリビュートは、オブジェクトの draw メソッドを呼び出す前に ob3d_draw_preamble() 関数で使用されますが、これを無効にするためには JIT_OB3D_NO_BLEND フラグを使用します。これらのアトリビュートは、独自のアトリビュートを同じ名前で定義することによって、オーバーライドできます。しかし、あなたの draw メソッド の中では、適切な glEnable、glBlendFuncを呼び出すことによって、必要な OpenGL のステートを管理する必要があります。

デプスバッファ、および アンチエイリアシング関連のアトリビュートのオーバーライド

それぞれの Jitter OB3D は、デフォルトでは jit_ob3d_setup() によってクラスに追加された depth_enable 、antialias というアトリビュートを持っています。これらのアトリビュートは、オブジェクトの draw メソッドを呼び出す前に ob3d_draw_preamble() 関数で使用されますが、これを無効にするためには、それぞれ JIT_OB3D_NO_DEPTH および JIT_OB3D_NO_ANTIALIAS フラグを使用します。これらのアトリビュートは、独自のアトリビュートを同じ名前で定義することによって、オーバーライドできます。しかし、あなたの draw メソッド の中では、適切な glEnable、glHint を呼び出すことによって、必要な OpenGL のステートを管理する必要があります。

マトリックス出力、および Automatic アトリビュートのオーバーライド

それぞれの Jitter OB3D は、デフォルトでは jit_ob3d_setup() によってクラスに追加された matrixoutput 、automatic というアトリビュートを持っています。これらのアトリビュートは、オブジェクトの draw メソッドを呼び出す前に ob3d_draw_preamble() 関数で使用されますが、これを無効にするためには、それぞれ JIT_OB3D_NO_MATRIXOUTPUT および JIT_OB3D_AUTO_ONLY フラグを使用します。これらのアトリビュートは、独自のアトリビュートを同じ名前で定義することによって、オーバーライドできます。

ユーザインターフェイスオブジェクトの宣言

It is possible to declare a user interface OB3D, such as jit.gl.handle. To do so, you must use the JIT_OB3D_DOES_UI flag to jit_ob3d_setup(), and define a method bound to the symbol ob3d_ui, with the private A_CANT type signature and prototype similar to the following example from jit.gl.handle:

t_jit_err jit_gl_handle_ui(t_jit_gl_handle *x, 
   t_line_3d *p_line, t_wind_mouse_info *p_mouse);

Jitter クラスのコンストラクタ、デストラクタ

あなたの Jitter クラスのコンストラクタの中では、新規にオブジェクトを割り当てられるポインタとレンダリング先(デスティネーション)を使って jit_ob3d_new() を呼び出さなければなりません。jit_ob3d_new() 関数は標準の OB3D アトリビュートやいくつかの OB3D ステートを格納するための構造体を割り当て、それらをデフォルトの値に初期化します。この構造体の内容は見えない形になっています。さらに、クラス定義の中で jit_ob3d_setup() 関数を呼び出した際に指定されたバイトオフセットの位置にポインタをセットします。オブジェクトがマトリックス出力をサポートする場合や、描画の際に t_jit_glchunk 構造体を使用する場合、通常、コンストラクタの中で jit_glchunk_new() または jit_glchunk_grid_new() 関数を使って、最初の t_jit_glchunk の割り当てを行なわなければなりません。 t_jit_glchunk 構造体やマトリックス出力の使い方に関しては、この章で後述します。同様に、あなたの OB3D Jitter クラスのデストラクタでは、 jit_ob3d_free() を呼び出して、共通の OB3D ステートの格納に使用される内容の見えない形の構造体を開放し、jit_glchunk_free()を使って割り当て済みの t_jit_glchunkのインスタンスをすべて開放し、ディスプレイリストやテクスチャなどの割り当て済みのリソースをすべて開放しなければなりません。

OB3D の draw メソッド

オブジェクトが実行する描画処理は、すべて ob3d_draw メソッドに記述します。また、通常コンテキストが有効でかつ設定済みであることがわかっているため、このメソッドでコンテキストに従ってリソースを割り当て、コンテキストのステートの問合せを行なわなければなりません。ob3d_draw メソッドで実行する描画処理の大部分は、純粋でシンプルな OpenGL ですが、いくつかの注意点があります。これについては後述します。

t_jit_glchunk 構造体とマトリックス出力

Jitter は汎用のマトリックス処理フレームワークであるため、当然ながら、ジオメトリ表現がマトリックスによる表現に適している場合にはマトリックスとして Jitter ネットワーク上でジオメトリ情報の受け渡しを行なう機能を持っています。マトリックスのセルには、位置、テクスチャ座標、法線ベクトル、色、エッジフラグなどの頂点情報を格納することができます。これについては、Jitter チュートリアル の「覆いの下のジオメトリ」で述べられています。また、頂点の接続性がマトリックス表現に含まれない場合には、頂点の接続状態を参照するための接続マトリックスを指定するというオプションもあり、頂点の描画を行なう際に使用するための描画プリミティブを指定することもできます。

これらすべての情報、およびジオメトリマトリックスを直ちにレンダリングするか、Jitter ネットワークを通じて送信するかは t_jit_glchunk によって管理されます。SDK サンプルの jit.gl.gridshape には、この t_jit_glchunk の使用例が示されています。 t_jit_glchunk 構造体は、これに含まれる頂点マトリックスと共に jit_glchunk_new() または、 jit_glchunk_grid_new() 関数によって割り当てられ、 jit_glchunk_delete() 関数によって開放されます。また、描画処理は jit_glchunk_delete() 関数によって行なわれます。参考のために t_jit_glchunk 構造体と、これに関連した chunk フラグを次に示します。

// jit_glchunk は1つの gl-コマンドのデータを格納するパブリックな構造体で、このフォーマット 
// によってglDrawRangeElemets に対して容易にデータを送ることができます。


typedef struct _jit_glchunk
{
   t_symbol   *prim;         	// GL_TRI_STRIP, GL_TRIANGLES, など(訳注:プリミティブの形状) 
   t_jit_object *m_vertex;      // xyzst... データの jit_matrix.  
   t_symbol    *m_vertex_name;  // 頂点マトリックスの名前
   t_jit_object *m_index;      	// マトリックスの 1D 接続。オプション。
   t_symbol    *m_index_name;   // 接続マトリックス名
   unsigned long m_flags;      	// 特別なフラグ
   void      *next_chunk;      	// 個々のリンクリスト, 通常は NULL です。
} t_jit_glchunk;

// chunk 生成のためのフラグ	
#define JIT_GL_CHUNK_IGNORE_TEXTURES      	1 << 0
#define JIT_GL_CHUNK_IGNORE_NORMALS      	1 << 1
#define JIT_GL_CHUNK_IGNORE_COLORS      	1 << 2
#define JIT_GL_CHUNK_IGNORE_EDGES      		1 << 3

OB3D OpenGL の注意点

ob3d_draw メソッドの中では、標準の OpenGL 呼び出しを任意に使用できるとはいえ、Jitter の仕様に従うために注意すべき点がいくつかあります。その第1はテクステャ座標のバインディングです。Jitter OB3D は、デフォルトでマルチテクスチャリングをサポートするため、必ずしも glTexCoord によって1つのテクスチャ座標だけを提示すれば十分というわけではありません。Jitterには、jit_gl_texcood(1/2/3)(f/fv) によってバインドされるテクスチャユニットに対応するだけのテクスチャ座標をセットするためのユーティリティルーチンがいくつかあります。デフォルトの OB3D アトリビュートでバインドされているテクスチャの数の判定には、すべての jit_gl_texcood の呼び出しごとにこれを行なう場合より若干多くのオーバーヘッドが必要になります。jit_gl_texcood 関数は t_jit_gl_drawinfo 構造体を引数として取ります。この構造体は jit_gl_drawinfo_setup 関数によって多くの頂点がレンダリングされる前に、一度設定されます。jit_gl_texcoord および jit_gl_drawinfo_setup 関数の使用例は、SDK の jit.gl.videoplane プロジェクトの中で示しています。もう1つの Jitter に特有なメカニズムは、jit.gl.texture の名前をつけられたインスタンスを使用したテクスチャのバインド方法です。この方法では、独自のテクスチャを OB3D 内で生成してバインドすることができますが、他の場合であれば jit.gl.texture が行なってくれるこれらに関する管理をすべて自分で行なわなければなりません。jit.gl.texture のインスタンスのバインド、およびアンバインドを行なうためには、jit_gl_bindtexture および jit_gl_unbindtexture 関数を呼び出さなければなりません。この関数は、引数として t_jit_gl_drawinfo、jit.gl.texture のインスタンスの名前のシンボル、バインドされるテクスチャユニットのための整数を引数として取ります。これは、OpenGL で通常のテクスチャのバインドを行なう場合と異なり、jit.gl.texture のインスタンスをアンバインドする上で重要です。これを行わない場合、何らかの問題が発生するかもしれません。

OB3D アトリビュートに関する情報の取得

デフォルトの OB3D アトリビュートは通常、 ob3d_draw メソッドの呼び出しの前にあなたのオブジェクトのために自動的に処理されるコードにとって適切なものではありますが、時として、これらの値にアクセスする必要がある場合があります。デフォルトの OB3D アトリビュートは、外から見えない ob3d 構造体のメンバとして格納されているため、オブジェクトによって単にポインタの指す値を参照する方法ではアクセスすることができません。これらのアトリビュートにアクセスするためには、その代わりに、jit_attr_get * 関数を使用する必要があります。これらの関数に対しては、最初の引数として ob3d 構造体メンバを渡すのではなく、あなたのオブジェクト構造体を渡さなければなりません。次はその例です。

   float pos[3];
   jit_attr_getfloat_array(x,gensym("position"),3,pos);

この値を頻繁に取得する場合には、各呼び出しごとにシンボルを生成するのではなく前もってシンボルを生成しておくほうが望ましいという点に留意して下さい。

コンテキストに関する情報の取得

レンダリングコンテキストは ob3d_draw、dest_closing、dest_changed メソッドの中から常にセットされており、その中で aglGetCurrentContext、あるいは wglGetCurrentContext 関数を使って ネイティブなコンテキストを取得することができます。また、これらのメソッドの中で、標準的な OpenGL の glGet* 関数を使用して、ビューポートや変換マトリックスといったようなコンテキストの OpenGL ステートの判定を行なうこともできます。他のメソッドの中からネイティブなコンテキストの取得やOpenGL のステートを取得しようとすることは、その結果が有効でない可能性があるため推奨できません。

他の描画オブジェクトとの関連

OpenGL のステートが持続的であり、あなたのオブジェクトの描画処理の後にそのOpenGLのステートに従って描画されるオブジェクトが存在するかもしれないことを認識しておくことは重要です。あなたのオブジェクトがOpenGL のステートに対して何らかの変更を行なった場合、それに続くオブジェクトに影響を与える可能性があります。そのため、OpenGL のステートをあなたのルーチンが呼び出される前の状態に復元しておかなければなりません。例えば、あなたのオブジェクトがテクスチャ変換マトリックスに対する変更を行なった場合、glMatrixMode、glPushMatirx、glPopMatrix を使用してテクスチャ変換マトリックスのプッシュとポップを行って他のオブジェクトに対する問題が生じるのを防いでおかなければなりません。

OB3D Max ラッパークラスの定義

「OB3D クイックスタート」で述べたように、あなたの Max ラッパークラスの定義では、標準の描画メソッドを追加するための max_ob3d_setup() 関数の呼び出しを追加し、特に独自にカスタマイズした assist メソッドを定義しようとするのでない限り、assistメソッドとして max_jit_ob3d_assist() 関数の呼び出しを追加するだけです。それ以外は、「Max ラッパークラス」の章で示したような Jitter クラスのラップを行なう標準的なテクニックと全く同様です。OB3D Max ラッパークラスに関する必要な情報については、「OB3D クイックスタート」の章、および SDK の jit.gl.simple プロジェクトにすべて示してありますので参考にして下さい。

マトリックス入力

時として、jit.gl.videoplane や jit.gl.mesh の場合のように、OB3D によって入力されるマトリックスのサポートを行なうことが望ましい場合があります。OB3D と MOP を混在させることは望ましくありません。アーギュメントや標準のインレット、アウトレットでのコンフリクトが生じます。あなたの OB3D でマトリックス入力をサポートしたい場合、その代わりにあなたの Jitter クラスに jit_matrix シンボルにバインドされたメソッドを追加し、必要に応じて入力マトリックスのデータを処理するべきです。例えば、jit.gl.videoplane の場合ではテクスチャとして扱い、jit.gl.mesh の場合ではジオメトリデータとして扱っています。SDK の jit.gl.videoplane プロジェクトでは、マトリックス入力もサポートする OB3D の例を示しています。複数の入力マトリックスを処理する必要がある場合には、通常それぞれの入力に対して別々の名前を与えたメソッドを宣言するか、jit_matrix メソッドが呼び出された場合にどちらかの入力を指定するアトリビュートを公開する方法によって管理します。この場合、Max ラッパークラスの中でのインレットを割り振りは自動的には行なわれないため、これを実現するための独自の方法が必要になる点に注意して下さい。

Copyright © 2008, Cycling '74