ofMeshを使って図形を描画する
openFrameworksには図形を描画するための便利な関数が複数存在する。
ofDrawRectangle(x, y, w, h); ofDrawCircle(x, y, w, h);
などがそれに当たる。
しかし、ジェネラティブなプログラムを作りたい場合、これら関数を使うより便利な方法がある。自ら点と線を書いて図形を描画することだ。
これを実現するクラスがofMeshだ。
備忘のため、ofMeshを使って図形を描画する方法を記す。
なお、oF公式ドキュメント「ofBook」の以下ドキュメントを参考にした。
openframeworks.cc
Mesh
Meshとは、頂点の集合のことだ。それら頂点は互いに1本の線で接続が可能だ。
頂点を線で接続した形状をプリミティブと呼んだりする。下記の3Dモデルはプリミティブの一例だ。
ofMesh
ofMeshは、openFrameworks上でMeshの管理を担当するクラスだ。
以下公式ドキュメントを読むと、openFrameworks上でMeshを扱う上で役立つクラスメソッドが多数用意されている。
openframeworks.cc
openFrameworksでMeshを扱う際、このofMeshを使用する。
ofMeshで点を打つ
早速ofMeshで図形の描画を始める。まずは頂点を打つことだ。
ofApp.hでofMeshを宣言する。
#pragma once #include "ofMain.h" class ofApp : public ofBaseApp{ public: void setup(); void update(); void draw(); void keyPressed(int key); void keyReleased(int key); void mouseMoved(int x, int y ); void mouseDragged(int x, int y, int button); void mousePressed(int x, int y, int button); void mouseReleased(int x, int y, int button); void mouseEntered(int x, int y); void mouseExited(int x, int y); void windowResized(int w, int h); void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); ofMesh mesh; // ofMeshの初期化 };
次にofApp.cppを見る。setup関数にofMeshの設定を記載する。
void ofApp::setup(){ mesh.setMode(OF_PRIMITIVE_POINTS); mesh.enableColors(); // 3点の座標を用意する ofVec2f top(100.0, 50.0); ofVec2f left(50.0, 150.0); ofVec2f right(150.0, 150.0); // (100.0, 50.0)の位置に赤い点を打つ mesh.addVertex(top); mesh.addColor(ofFloatColor(1.0, 0.0, 0.0)); // (50.0, 150.0)の位置に緑の点を打つ mesh.addVertex(left); mesh.addColor(ofFloatColor(0.0, 1.0, 0.0)); // (150.0, 150.0)の位置に青い点を打つ mesh.addVertex(right); mesh.addColor(ofFloatColor(1.0, 1.0, 0.0)); }
setModeにOF_PRIMITIVE_POINTSを設定した。これはプリミティブとして点を描画するためである。
なお、setModeで指定できる値には以下が存在する。
- OF_PRIMITIVE_POINTS
- OF_PRIMITIVE_LINES
- OF_PRIMITIVE_LINE_STRIP
- OF_PRIMITIVE_LINE_LOOP
あとは座標の任意の位置に点を打つ。今回は2次元座標を扱うため、頂点座標の指定にはofVec2fを用いている。
draw関数内でmesh.draw()をしてあげると、meshに格納された頂点情報を描画してくれる
void ofApp::draw(){ ofBackground(0); mesh.draw(); }
これを実行すると以下となる。
ofMeshで三角形を描く
点を打ったので、あとは点同士を線で結ぶ。すると、正三角形が出来上がる。
すでに頂点は存在するため、setModeを変更して線を引っ張る。setup関数内の記述を変更する。
void ofApp::setup(){ mesh.setMode(OF_PRIMITIVE_LINES); // OF_PRIMITIVE_LINESに変更 mesh.enableColors(); // 3点の座標を用意する ofVec2f top(100.0, 50.0); ofVec2f left(50.0, 150.0); ofVec2f right(150.0, 150.0); // (100.0, 50.0)の位置に赤い点を打つ mesh.addVertex(top); mesh.addColor(ofFloatColor(1.0, 0.0, 0.0)); // (50.0, 150.0)の位置に緑の点を打つ mesh.addVertex(left); mesh.addColor(ofFloatColor(0.0, 1.0, 0.0)); // (150.0, 150.0)の位置に青い点を打つ mesh.addVertex(right); mesh.addColor(ofFloatColor(1.0, 1.0, 0.0)); }
実行する。結果は以下。
1本しか引っ張ってくれない。不親切だ。しかしこれには理由がある。
OF_PRIMITIVE_LINESを指定すると、頂点のペアを作り、それら同士を直線で結ぶ挙動を取るからだ。たとえば頂点が[v1, v2, v3, v4]4つ存在するとき、[v1, v2]同士と[v3, v4]同士で直線を結ぶ。
つまり、今回は3点のうちはじめにaddVertexした2点 [top, left]間で直線を結んでしまった。
これを解消するには、他のモードを試す。
結論から言うと、三角形を描画したければ以下のようにする。
void ofApp::setup(){ mesh.setMode(OF_PRIMITIVE_LINE_LOOP); // OF_PRIMITIVE_LINE_LOOPに変更 mesh.enableColors(); // 3点の座標を用意する ofVec2f top(100.0, 50.0); ofVec2f left(50.0, 150.0); ofVec2f right(150.0, 150.0); // (100.0, 50.0)の位置に赤い点を打つ mesh.addVertex(top); mesh.addColor(ofFloatColor(1.0, 0.0, 0.0)); // (50.0, 150.0)の位置に緑の点を打つ mesh.addVertex(left); mesh.addColor(ofFloatColor(0.0, 1.0, 0.0)); // (150.0, 150.0)の位置に青い点を打つ mesh.addVertex(right); mesh.addColor(ofFloatColor(1.0, 1.0, 0.0)); }
OF_PRIMITIVE_LINE_LOOPを設定すると、Meshに格納した順に頂点同士を線で結ぶ。そして、最後の頂点vnを頂点v1に結ぶ。こうすることで閉じた図形が出来上がる。
Meshで図形を描く利点
頂点に対する処理や演算が非常に楽になる。
ofMeshは配列で頂点の位置を保存しているため、全頂点を一気に操作することが容易い。
対してofDrawRectangle(x, y, w, h)などの関数は、すべての関数の引数に変数を設定し、変数操作を行う必要がある。1つの三角形であればよいが、2億個となると話は別だ。プログラムを書くことも大変だし、点の挙動をコントロールすることも嫌になる。