Max 5 API Reference

OB3D クイックスタート

この章の目的は、Jitter によるシンプルなOpenGL オブジェクトを開発する方法に関して、簡単で高レベルな概要を示すことです。これは、名前をつけられたレンダリングコンテキスト内でジオメトリを描画するもので、このようなオブジェクトをOB3D と呼んでいます。

説明を行なうにあたっては、SDK にある jit.gl.simple をサンプルとして使用します。ディスプレイリストやテクステャなどのリソースを取り扱うオブジェクト、マトリックス入出力のサポートを行なうオブジェクト、OpenGL のステートに対してより綿密なアクセスを必要とするオブジェクトなどの開発方法に関する詳細は、次の章以降で説明します。 この章は、Max パッチャー内で使用される Jitter の OpenGL オブジェクトセットを熟知していることを前提に書かれています。これに関しては、Jitterチュートリアルや、このドキュメントでこれまで説明してきた Jitter オブジェクトモデル や Max ラッパークラスの章で述べられています。

Defining the OB3D Jitter Class

一般的に、Jitter OB3Dは、OB3D に共通するアトリビュートとメソッドのすべて、あるいは大部分を持つように定義されます。共通のアトリビュートやメソッドについては、Jitter HTML オブジェクトリファレンスの Group-OB3D セクションで述べられていますが、その中には、レンダリング先(デスティネーション)の名前、オブジェクト名、色、ライティング、テクスチャ、モデルビュー変換、デプスバッファ、ポリゴンモードなどの、様々な共通のタスクをセットするものが含まれています。これらの共通するアトリビュートとメソッドをあなたの Jitter クラスに追加するためには、クラス定義の中で jit_ob3d_setup() 関数を呼び出します。この呼び出しは jit_class_new の呼び出しの後、通常、他のメソッドやアトリビュートを定義する前に行ないます。OB3D の使用のために、Jitter はあなたのオブジェクトに関する追加情報を保存しておく必要があります。この情報は、あなたのオブジェクトのオブジェクト構造体の中のポインタに保存されます。これは通常 ob3d という名前を持ち、その内容は見えないようになっています。OB3D データポインタのバイトオフセットは jit_ob3d_setup() の中へ渡されます。 jit_ob3d_setup() によって追加されるすべてのアトリビュート、メソッドの初期値は、次のようなフラグを使ってオーバーライドすることができます。

#define JIT_OB3D_NO_ROTATION_SCALE      1 << 0
#define JIT_OB3D_NO_POLY_VARS         1 << 1
#define JIT_OB3D_NO_BLEND              1 << 2
#define JIT_OB3D_NO_TEXTURE         1 << 3
#define JIT_OB3D_NO_MATRIXOUTPUT      1 << 4
#define JIT_OB3D_AUTO_ONLY         1 << 5
#define JIT_OB3D_DOES_UI         1 << 6
#define JIT_OB3D_NO_DEPTH         1 << 7
#define JIT_OB3D_NO_ANTIALIAS         1 << 8
#define JIT_OB3D_NO_FOG            1 << 9
#define JIT_OB3D_NO_LIGHTING_MATERIAL      1 << 10
#define JIT_OB3D_HAS_LIGHTS         1 << 11
#define JIT_OB3D_HAS_CAMERA         1 << 12
#define JIT_OB3D_IS_RENDERER         1 << 13
#define JIT_OB3D_NO_COLOR         1 << 14

jit_ob3d_setup() によって追加されるアトリビュートとメソッドの他に、あなたのクラスでは、シンボル ob3d_draw にバインドされた、プライベートな、型を持たないメソッドを定義する必要があります。あなたのオブジェクトによるすべての描画は、このメソッドで行なわれます。このメソッドは、OB3D 標準のメソッドである draw、および drawraw メソッドによって呼び出されます。OB3D の draw メソッドは、プライベートな ob3d_draw メソッドを呼び出す前に、共通な OB3D アトリビュートに関連した OpenGL のすべてのステートを設定します。drawraw メソッドは、プライベートな ob3d_draw メソッドを呼び出す前に、コンテキストの設定だけを行ないます。OB3D は jit.gl.sketch の drawobject コマンド内で使用する名前付けをサポートするため、あなたのオブジェクトでは、プライベートで型を持たない " register " メソッドを追加し、 jit_object_register() 関数と結びつけなければなりません。例として、jit.gl.simple SDK プロジェクトを見てみましょう。

t_jit_err jit_gl_simple_init(void) 
{
   long ob3d_flags = JIT_OB3D_NO_MATRIXOUTPUT; // マトリックスの出力は行ないません
   void *ob3d;
   
   _jit_gl_simple_class = jit_class_new("jit_gl_simple", 
      (method)jit_gl_simple_new, (method)jit_gl_simple_free,
      sizeof(t_jit_gl_simple),0L);
   
   // フラグで指定された3d オブジェクトのためのオブジェクトエクステンションをセット
   ob3d = jit_ob3d_setup(_jit_gl_simple_class, 
            calcoffset(t_jit_gl_simple, ob3d), 
            ob3d_flags);
   
   // OB3D draw メソッドの定義。jit.gl.render によって自動的に呼び出されるか、あるいは 
   // bang を受信した場合に ob3d から呼び出されます。私たちの draw 設定は、OpenGL のステ 
   // ートの初期化を行なうために、ob3d の中で前もって実行されている必要があります。そのため 
   // このメソッドは A_CANT 型になっています 
   jit_class_addmethod(_jit_gl_simple_class, 
      (method)jit_gl_simple_draw, "ob3d_draw", A_CANT, 0L);
   
   // dest_closing と dest_changed メソッドを定義します。これらのメソッドは、デスティ 
   // ネーションのコンテキストが閉じられるか変更された場合に、jit.gl.render によって呼び 
   // 出されます。コンテキストの変更の例としては、ユーザがあるモニタから別のモニタへウィン
   // ドウを移動させた場合があります。オブジェクトがOpenGL マシンに保持しているすべてのリ
   // ソース(例えば、テクスチャ、ディスプレイリスト、頂点シェーダなど)はコンテキストが閉
   // じられる際に開放する必要があります。また、コンテキストが変更された場合には、再構成しな
   // ければなりません。このオブジェクトでは、これらの関数は何も実行せず、省略することが可
   // 能です。
   jit_class_addmethod(_jit_gl_simple_class, 
      (method)jit_gl_simple_dest_closing, "dest_closing", A_CANT, 0L);
   jit_class_addmethod(_jit_gl_simple_class, 
      (method)jit_gl_simple_dest_changed, "dest_changed", A_CANT, 0L);
   
   // ob3d での使用のために、登録しなければなりません。
   jit_class_addmethod(_jit_gl_simple_class, 
      (method)jit_object_register, "register", A_CANT, 0L);

   jit_class_register(_jit_gl_simple_class);

   return JIT_ERR_NONE;
}

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

あなたの OB3D Jitter クラスのコンストラクタには、最初の引数としてレンダリングを行なうデスティネーションの名前を渡さなければなりません。 jit_ob3d_new() 関数は、OB3D データポインタを初期化し、これをレンダリングデスティネーションと結び付けるために、デスティネーションの名前を引数として与えて呼び出さなければなりません。デストラクタでは、 jit_ob3d_free() によって、この OB3D データポインタを開放しなければなりません。例として、jit.gl.simple のコンストラクタとデストラクタの例を次に示します。

t_jit_gl_simple *jit_gl_simple_new(t_symbol *dest_name)
{
   t_jit_gl_simple *x;

   // jitter オブジェクトを作ります
   if (x = (t_jit_gl_simple *)jit_object_alloc(_jit_gl_simple_class)) 
   {
      // ob3d を生成し、関連付けます
      jit_ob3d_new(x, dest_name);
   } 
   else 
   {
      x = NULL;
   }   
   return x;
}


void jit_gl_simple_free(t_jit_gl_simple *x)
{
   // ob3d データを開放します
   jit_ob3d_free(x);
}

OB3D の draw メソッド

ob3d_draw シンボルにバインドされたあなたの OB3D の draw メソッドでは、すべての描画コードを記述します。オブジェクトの automatic および enabled アトリビュートがオンになっている場合、関連づけた jit.render オブジェクトが bang を受信すると自動的にこのメソッドが呼び出されます。デフォルトではこの設定になっています。このメソッドは、あなたのMax ラッパーオブジェクトが bang を受信した場合、あるいは draw もしくは drawraw メッセージを受信した場合にも呼び出されます。drawraw メッセージの場合を除き、すべての標準的な OB3D オブジェクトのステートは、あなたの ob3d_draw メソッドが呼び出される前に設定されています。そのため、オブジェクトが特に必要とするのでなければ、モデルビュー変換、色、ライティングのプロパティ、テクスチャ情報などを設定する必要はありません。jit.gl.simple からの次の例は、シンプルな四辺形を描画するものです。

t_jit_err jit_gl_simple_draw(t_jit_gl_simple *x)
{
   t_jit_err result = JIT_ERR_NONE;
   
   // OpenGL ジオメトリの描画を行ないます 
   glBegin(GL_QUADS);
   glVertex3f(-1,-1,0);
   glVertex3f(-1,1,0);
   glVertex3f(1,1,0);
   glVertex3f(1,-1,0);
   glEnd();
   
   return result;
}

このサンプルは、標準の OpenGL 呼び出しによってジオメトリを描画する最小限のオブジェクトを示すだけのもので、テクスチャ情報や頂点の法線の指定は行なわれていません。しかし、すべての標準 OpenGL 呼び出しは ob3d_draw メソッドの中で実行されなければなりません。この例では、jit_ob3d_draw_chunk() によって行なわれるマトリックスの出力についても示されていません。これに関しては次章の「OB3Dの詳細」で述べます。

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

OB3D では、Max ラッパークラスは、MOP に比べあまり特別な動作を必要としません。Max ラッパークラスの定義では、標準の描画メソッドを追加するための max_ob3d_setup() 関数の呼び出しを追加し、独自の assist メソッドを定義したいのでなければ、これに max_jit_ob3d_assist() 関数を assist メソッドとして追加する必要があるだけです。それ以外は、Max ラッパークラスの章で示したような、標準的な Jitter クラスのラッピングと同様な処理を行ないます。

void main(void)
{   
   void *classex, *jitclass;
   
   // Jitter クラスの初期化
   jit_gl_simple_init();   
   
   // Max クラスの生成
   setup((t_messlist **)&max_jit_gl_simple_class, 
      (method)max_jit_gl_simple_new, (method)max_jit_gl_simple_free, 
      (short)sizeof(t_max_jit_gl_simple), 0L, A_GIMME, 0);

   // 私たちのオブジェクトに関する追加情報を保持するためにバイトオフセットを指定します。
   classex = max_jit_classex_setup(calcoffset(t_max_jit_gl_simple, obex));

   // クラスレジストリから Jitter クラスを探します。
   jitclass = jit_class_findbyname(gensym("jit_gl_simple"));   
   
   // Jitter オブジェクトの標準メソッドで Jitter クラスをラップします。
   max_jit_classex_standard_wrap(classex, jitclass, 0);    
                
      // 標準 ob3d アシストメソッドを使用します。
   addmess((method)max_jit_ob3d_assist, "assist", A_CANT,0);  

   // 3d 描画のためのメソッドを追加します。
   max_ob3d_setup();
}

Max クラスのコンストラクタ/デストラクタ

あなたの Max クラスのコンストラクタは、標準の Max ラッパーのコンストラクタと同様でなければなりませんが、ぜひ覚えておく必要がある相違点があります。それは、Jitter の OB3D コンストラクタに知らせるために、レンダリングデスティネーションを通常の第1の引数として渡さなければならない点、および、オブジェクトの OB3D データに結び付けられたマトリックス出力のための第2のアウトレットを作らなければならない点です。デストラクタには、OB3D の使用によって追加すべきものはなにもありません。例として、jit.gl.simple の Max クラスのコンストラクタとデストラクタを示しておきます。

void *max_jit_gl_simple_new(t_symbol *s, long argc, t_atom *argv)
{
   t_max_jit_gl_simple *x;
   void *jit_ob;
   long attrstart;
   t_symbol *dest_name_sym = _jit_sym_nothing;

   if (x = (t_max_jit_gl_simple *) max_jit_obex_new(
      max_jit_gl_simple_class, gensym("jit_gl_simple"))) 
   {
      // 通常の第1の引数(デスティネーション名)を取得
      attrstart = max_jit_attr_args_offset(argc,argv);
      if (attrstart&&argv) 
      {
         jit_atom_arg_getsym(&dest_name_sym, 0, attrstart, argv);
      }

      // Jitter オブジェクトを dest_name という引数を使ってインスタンス化
      if (jit_ob = jit_object_new(
         gensym("jit_gl_simple"), dest_name_sym)) 
      {
         // 内部の Jitter オブジェクトのインスタンスを設定
         max_jit_obex_jitob_set(x, jit_ob);
         
         // 汎用のアウトレット(右端)を追加
         max_jit_obex_dumpout_set(x, outlet_new(x,NULL));
         
         // アトリビュートアーギュメントの処理
         max_jit_attr_args(x, argc, argv);      
         
         // jitter オブジェクトの ob3d を新しいアウトレットに接続します。  
         // このアウトレットは matrixoutput モードで使用します。
         max_jit_ob3d_attach(x, jit_ob, outlet_new(x, "jit_matrix"));
      } 
      else 
      {
         error("jit.gl.simple: could not allocate object");
         freeobject((t_object *)x);
         x = NULL;
      }
   }
   return (x);
}

void max_jit_gl_simple_free(t_max_jit_gl_simple *x)
{
   // 内部の Jitter オブジェクトのインスタンスを探して開放
   jit_object_free(max_jit_obex_jitob_get(x));
   
   // obex エントリに関連付けられたリソースを開放
   max_jit_obex_free(x);
}

Copyright © 2008, Cycling '74