チュートリアル30

3Dテキストの描画


このチュートリアルでは、jit.gl.text3djit.gl.renderオブジェクトを使い、どうやって jit.windowオブジェクト内に3Dテキストを描画や配置をするのかを示していきます。それとともに、 jit.gl.renderオブジェクトを用いたOpenGLグラフィックスの描画の基本を学習していきましょう。

jit.gl.text3dオブジェクトは、jit.gl.renderオブジェクトと連結して動作する多くのOpenGL描画オブジェクトのうちの一つです。OpenGLは、2Dおよび3Dグラフィックスの描画のためのクロスプラットフォーム規格で、グラフィックスコプロセッサを使った描画のプログラミングをするために設計されたものです。これらのコプロセッサはグラフィックプロセッサユニット(グラフィック処理装置)もしくはGPUとも言われ、描画処理を非常に高速化し、テクスチャの付いたポリゴンで作られた複雑なシーンのリアルタイムでのアニメーションを可能にします。OpenGLグラフィックスは、あなたのコンピュータのCPU動作を重くすることなく、あなたが映像表示やビジュアルインタフェースを素早く作成できるように支援します。GLグループのオブジェクトとして、jit.gl.text3djit.gl.renderといったようなオブジェクトを調べていきます。

・Jitterチュートリアルフォルダにある30j3DText.patというチュートリアルパッチを開いてください。

そのパッチの左下にhelloと名付けられたjit.windowオブジェクトがあります。このウィンドウはOpenGLの描画先です。

・Start Renderingとラベルが付いているtoggleをクリックしてください。

このtoggletriggerオブジェクトにbangメッセージを送るqmetroオブジェクトをスタートさせます。 triggerオブジェクトはインレットで受け取ったbang毎に右アウトレットからeraseメッセージを出力し、それからbangメッセージを左アウトレットから出力します。これらのメッセージはjit.gl.render helloオブジェクトに送られます。


ドローイングコンテキストの生成


JitterにおけるすべてのOpenGLグラフィックスは、jit.gl.renderオブジェクトを用いて描画されます。各jit.gl.renderオブジェクトは、描画するために名前が付けられた送り先を参照しなければなりません。この送り先はjit.gl.renderに初期化アーギュメントを使って指定することができます。このチュートリアルパッチにおいて、jit.gl.render helloはhelloという名前の送り先ウィンドウに描画するjit.gl.render オブジェクトを生成します。

helloは単にその送り先であり、jit.gl.renderオブジェクトの名前ではないことに、特に注意してください。

jit.gl.renderとドローイングコンテキストとして名付けられた送り先の組み合わせを見てみましょう。ドローイングコンテキストはOpenGLレンダリングのために必要とされます。このパッチで左側にあるオブジェクトは正しいドローイングコンテキストを構築するためには充分なもので、toggleオブジェクトがクリックされたとき、jit.gl.render:building GL on window ‘hello’というメッセージがMaxウィンドウに現れます。これはそのコンテキストが生成されたことを知らせています。

jit.gl.renderオブジェクトおよび名付けられた送り先は、ドローイングコンテキストを生成します

 

コンテキスト内のGLオブジェクト


OpenGLコンテキストに様々なものを描画するために、いろいろなJitterオブジェクトが用意されています。これらのJitterオブジェクトはすべて"jit.gl"で始まる名前が付けられています。いくつかの例としては、チュートリアルパッチの右上にみられるようにjit.gl.model(3Dモデルを描画するもの)、jit.gl.plato(正多面体を描画するもの)、jit.gl.text3dオブジェクトがあります。これらすべてのオブジェクトは、初期アーギュメントとしてドローイングコンテキストの名前を持ち、jit.gl.renderオブジェクトがbangメッセージを受け取るたびにコンテキストに対して自動的に描画されます。そしてこの例では、metroオブジェクトがbangメッセージを送り続ける限り、jit.gl.renderオブジェクトは画面の消去、全オブジェクトの描画という同じ処理のセットを繰り返し実行します。ウィンドウ上でjit.gl.text3dオブジェクトの出力が見えていないのは、それに対して文字列が何も割り当てられていないだけのことです。これを修正しましょう。

・Hello,Jitter!と書かれているメッセージボックスをクリックしてください。

これはjit.gl.text3dオブジェクトにテキストをセットします。これでjit.window上に"Hello"という言葉を見ることができます。バックスラッシュ(訳注:日本語環境では円マークに見える場合もあります)の前のテキストのカンマに注意してください。一般的にカンマはメッセージボックス内の連続したメッセージを分割するのに使われるので、カンマを普通の文字記号として扱うようにMaxに知らせるためにはバックスラッシュを必要とするのです

技術的な詳細:このパッチではこれまでの多くのチュートリアルパッチとは違い、jit.matrixオブジェクトがないためにqmetroオブジェクトが必要です。複雑なパッチにおいて、metroオブジェクトによって繰り返しトリガーされた描画やマトリクス計算は、次のbangがくるタイミングまでに終了しないかもしれません。この例では、こういった状況はテキストがレンダリングに40ミリ秒よりも長くかかる場合に発生します。本来なら、Maxスケジューラはそのキュー(滞っているメッセージのリスト)に、このbangを加えるでしょう。Maxはキューからのメッセージを失うことを本来は考慮していません。そして、このパッチではもし各々のbangが40ミリ秒よりも長くかかるイベントを次々と生成し、メッセージの欠落がないことを考えると、いずれキューがオーバーフローするか、追加されていく滞ったメッセージの格納空間を使い果たしてしまうでしょう。その後、スケジューラは停止して、ライブ中なら漫才でも始めなくてはいけなくなるかもしれません。まあ、そんなことになるとは思ってもいないことでしょうね。

qmetroオブジェクト(これは単にmetroオブジェクトとjit.qballオブジェクトを組み合わせただけのものです。Tutorial 16を参照のこと)は、計算が滞っているbangメッセージをどれも捨ててしまうことによってこの状況を回避し、あなたを救います。パッチのレンダリング休止中にbangが発生する場合には、bangはキューに置かれます。もし、bangが発生したときに、前のbangによるパッチ動作終わっていない場合、前のbangはすぐに効力をなくし、新しいbangがキューの上で次に置かれるでしょう。それからは同様です。

例えば、10ミリ秒ごとのbangメッセージを出力するmetroオブジェクトの出力が、いくつかのエフェクトがかけられて1フレームの描画に100ミリ秒かかるjit.qt.movieオブジェクトに送られるものとします。 jit.qt.movieオブジェクトは、エフェクトが処理されている間に10個のbangメッセージを受け取るでしょう。そのjit.qt.movieオブジェクトは、処理が完了していないという状況を認識し、次の機会で10個のjit_matrixメッセージを送り出すのではなく、1つのbangだけ残して、他のbangはすべて捨ててしまいます。

jit.qt.moviejit.matrixオブジェクトにはこの能力を組み込んであるのですが、jit.gl.renderオブジェクトにはその能力がありません。これはjit.gl.renderオブジェクトがフレームを適切に描画するために、メッセージのまとまりが合っている必要がよくあるからです。この例では、eraseメッセージは画面を消去する必要があり、bangメッセージはテキストを描画する必要があります。もし、eraseメッセージがキューのオーバーフローを避けるために失われたとすれば、複数のbangメッセージが連続的に処理され、テキストの複数の表示が一度に描画されるかもしれません。これは私達が望んだ動作ではありません。パッチがさらに複雑性を持ったとすれば、違った種類の視覚的な影響が結果にでるでしょう。

そういったわけで、qmetroオブジェクトは、どのメッセージをキューから破棄するのかをパッチの設計者に決定させるために提供されています。この例でも多くの場合のように、単純にqmetroオブジェクトをmetroオブジェクトの代わりに使うことで、描画されたものが常に正しく見えるようにし、キューのオーバーフローを防ぐといった保証をしています。



一般的な3Dアトリビュート


jit.glで始まるすべてのJitter OpenGLオブジェクトは、それらの3次元空間における配置、色、もしくは他の変更を行うための一般的なアトリビュートセットを共有しています。それは、
ob3dグループというものです。3Dグラフィックスを描くことはたいへん複雑な作業です。ob3dグループは、あなたが一つの3Dオブジェクトを描くために学習するod3dグループのメッセージがすべてのオブジェクトで動作可能だと保証することによって、その作業を可能な限り簡単にします。この共通なアトリビュートのグループは、JitterオブジェクトリファレンスのGLグループセクションで完全にドキュメント化されています。ここで、その3Dグループを紹介するため、jit.text3dオブジェクトを操作することにより、位置、回転、スケーリング(拡大・縮小)、軸アトリビュートのデモンストレーションをします。
空間的な操作を見やすく、理解しやすくするため、jit.text3dオブジェクトに対して一組の空間軸を付け加えることができます。これはテキストオブジェクトがどの方向を向いているかを見やすくし、オブジェクトの原点が正確にどこにあるかという付加情報を見るためでもあります。

・3Dオブジェクト軸を見るため、axes $1と書かれたメッセージボックスに接続されているtoggleをクリックしてください。


原点にある3Dテキスト


x軸は赤で描かれていて右を向いています。ゼロは画面の中心で、xの値を増やすことで画面の右方向に移動します。y軸は緑で描かれ、上を向いています。z軸は青で描かれ、あなたの方を向いています(あなたにまっすぐ向いているため、小さな青い点に見えるだけでしょう)。これらの軸は空間を移動してオブジェクトのローカル座標系を表します。最初にGLグループオブジェクトが生成されたとき、そのローカル座標系の回転、移動、スケーリングは行われておらず、デフォルトでその3D空間にある他のものと同じ座標系を持ちます。

"Hello, Jitter!"というテキストはjit.windowオブジェクトの表示領域に表示されますが、画面の中心から描かれるために最後の部分がはみ出してしまいます。テキストを左に動かしてみましょう。

・パッチのCommon 3D attributes部分のxとラベルがついたナンバーボックスに-1.の値を設定してください。

そのナンバーボックスはpakオブジェクトに浮動小数点の値を送り、そのpakオブジェクトは3つの数値が後に続くpositionメッセージをjit.gl.text3dオブジェクトに送ります。ナンバーボックスの値を変えると、画面上でテキストがすべて見えるまで左に移動するのがわかるでしょう。


positionアトリビュートの変更


jit.gl.text3dオブジェクトのpositionアトリビュートを変えてみました。positionメッセージの後ろには、3次元でのオブジェクト位置を設定する3つの数値アーギュメントが続くことができます。もし、position メッセージに続く数値が3つより少なければ、その軸は[x,y,z]の順で当てはめられて、指定されていない軸上のオブジェクト位置は0に設定されます。例えばposition 5.というメッセージを送ると、GLグループオブジェクトの位置は[5,0,0]に設定されるでしょう。

オブジェクトの位置を変化させる操作は移動(translation)と呼ばれます。

今度はテキストを回転させてみましょう。

・パッチのCommon 3D attributes部分のpak rotationオブジェクトのすぐ上にあるx,y,zとラベルが付けられたナンバーボックスオブジェクトに、1という値を設定してください。これは回転軸を設定します。

・angleとラベル付けされたナンバーボックスを320という値までドラッグしてください。テキストが軸の周囲をこのスクリーンショットに示されている位置まで回転するのがわかるでしょう。


移動と回転の後の3Dテキスト


1つから4つまでの数値が後に続くrotateメッセージを送ることで、GLグループオブジェクトの回転アトリビュートを設定します。最初の数字は、オブジェクト回転軸の反時計周りの角度における回転量です。その他の3つの数は[x,y,z]ベクトルでこの回転軸を指定します。positionアトリビュートに続く数値と同様に、回転アトリビュートに続くいくつかの数値は省くことができ、デフォルト値として見なされます。もし、roration メッセージに1つの数値しか付いていなければ、その数値は角度を意味するものと解釈され、回転軸は[0,0,1] となります。これはz軸周りでオブジェクトが回転します。言い換えれば、画面のx-y平面で回転します。もし、2つかそれ以上の数値がrotationメッセージに付いているなら、最初のものは常に回転角を指定し、その他の数値はその順序に従って回転のベクトルを指定します。

pak scaleオブジェクトのすぐ上のxとラベル付けられたナンバーボックスに0.5を設定してください。これは3Dテキストを、そのローカルx軸に沿って半分にスケーリングします。


移動、回転、スケーリング後の3Dテキスト


オブジェクトと一緒に赤い軸も縮んでいることに注意してください。その線に沿った点は、スケーリング操作前に対して現在は半分の距離になっています。その軸は常にGLグループのローカル座標系に描かれていて、この場合には、jit.gl.renderオブジェクトのワールド座標系に対する視点で移動、回転、スケーリングされています。

幾何学的な変形を実行するとき、処理の順番を考えることは重要です。あなたはオブジェクトのrotate、position、scaleアトリビュートを望んだ任意の順番で独立して設定できます。しかし、描画されるときにはオブジェクトは次の順番で変形します。

 1. スケーリング

 2. 回転

 3. 移動

アトリビュートが予想通りに振る舞うために、この順番を守ることが重要です。もし、スケーリングの前に回転が行われると、例えばscale 0.5のメッセージがちょうどそのx座標上ではなく、そのオブジェクトの回転によって、x、y、zのいくつかの組み合わせの上でスケーリングされてしまいます。

次の例は、異なった順番の実行処理の違いがどうなるかを示しています。


処理の順番がすべての違いを生む

 

まとめ


描画コンテキストの生成は、JitterにおけるOpenGLグラフィックスを使うための第一歩です。描画コンテキストは、ウィンドウのような名前が付けられた送り先と、その送り先に描画を行うjit.gl.renderオブジェクトから成り立ちます。

jit.gl.renderと連携してOpenGLグラフィックスを描く様々なJitterオブジェクトが存在します。それらの名前はすべて"jit.gl"で始まっています。その一例が、jit.gl.text3dオブジェクトです。すべてのJitter OpenGLオブジェクトは3D空間でそれらを動かすためのアトリビュートの一般的なセットを共有しています。このオブジェクトのグループは、GLグループと呼ばれます。