ofMeshについての記録
初めて投稿させていただきます、eddyという者です。
現在自分はプログラミングを使って何か綺麗な作品を作れないかと思い、Processingやopenframeworksなどを個人で勉強しています。
Processingは日本語のリファレンスがあるものの、openframeworksはあまりないので調べてもなかなか見つからず、同じopenframeworksで書かれた作品のコードを写し、そこから値を変えたり行をコメントアウトしたりして挙動を確認する事が結構あります。
今回はopenframeworksのofMeshについての記録です。ofMeshはopenframeworksで3Dの物体の形を自在に操作するのに用います。しかし、自分はなかなか使い方を理解する事が出来ず、少し理解するまでに時間が結構かかりました。色々調べてみたのですが、自分の理解度ではそれを理解するのが難しい上、日本語のリファレンスはあまりありませんでした。
そこで記録の意味も込め、ここに書きとめておこうと思い。記事にする事にしました。正直理解が進んでいる方にとっては当然の事を書いていると感じられるレベルの事だと思いますが、どうかご容赦を。
ofMeshとは
先ほど申した通り、ofMeshとは頂点情報の集合を表すクラスです。例えば立方体や球を作りたいだけならこれがなくても作る事は出来ます。しかし、多面体や曲面など3Dで複雑な形状のものを作りたい場合はこれを使うのが良いと思われます。
例:立方体の書き方
立方体や球を作る場合はそれぞれofBoxPrimitive、ofSpherePrimitiveを使う事で書く事が出来ます。
今回は立方体の場合を以下に示します。
main.cpp
#include "ofMain.h"
#include "ofApp.h"
//========================================================================
int main( ){
ofSetupOpenGL(1024,768,OF_WINDOW);// <-------- setup the GL context
// this kicks off the running of my app
// can be OF_WINDOW or OF_FULLSCREEN
// pass in width and height too:
ofRunApp(new ofApp());
}
ofApp.h
#pragma once
#include "ofMain.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
ofEasyCam cam; //カメラ
ofBoxPrimitive box; //立方体
};
ofApp.cpp
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
ofSetFrameRate(60); //フレームレートは60fps
ofBackground(0); //背景は黒
ofEnableDepthTest(); //深度テストを有効に
cam.setDistance(120); //カメラの位置と注目点の距離を120に設定
this->box.set(100); //立方体の大きさ(100,100,100)
this->box.setResolution(10); //数値が大きいほど立方体を構成するメッシュの数が増える
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
this->cam.begin(); //カメラ起動
box.drawWireframe(); //立方体のフレームを描画
this->cam.end(); //カメラ終了
}
プロジェクトを作り、ofApp.hにはofBoxPrimitiveとofEasyCamを定義、ofApp.cppにはsetup()で基本的な設定をした後draw()で描画する、という感じになります。ofEasyCamは、最低限設定に必要なのはdraw()でbeginとendを書くだけという名前の通り簡単に利用出来るカメラとなっています。今回はsetup()内でsetDistance(距離)を使ってカメラの位置を調整しています。
次にofBoxPrimitiveも設定として行っているのは大きさ(set)と立方体の描くのに使うメッシュの量(setResolution)、フレームの描画(drawWireframe)の3つだけです。
この結果は以下の画像のようになります。
立方体が描画されます。試しに画面上でマウスを押して動かしてみて下さい。すると立方体を回転させたりする事が出来ます。これはofEasyCamの機能の一つです。
また、余力があればsetResolutionの値を試しに小さくしてみて下さい。すると立方体を構成する三角形の数が減ります。これは立方体を表現する際に用いるメッシュの量が小さくなった事によって起きるものです。
ofMesh
それではofMeshの使用方法について書きます。
ofMeshは頂点情報の集合です。頂点情報というのは位置の情報、色の情報などがあります。これらを利用する事によって出来る事としては、例えば立方体を歪ませたり、頂点毎に色を変えて虹色の3D物体を作ったりする事が出来ます。
今回は例として先ほど使った立方体を使ってやってみます。
手順としては大まかに次のようになります。
・ofMeshクラスの変数(今回はmeshとする)を宣言する。
・meshにofBoxPrimitiveのメッシュ情報を読み込ませる。
・meshに読み込んだ頂点情報一つ一つにつき処理を行う。
実際にコードで示すと以下のようになります。
main.cpp
#include "ofMain.h"
#include "ofApp.h"
//========================================================================
int main( ){
ofSetupOpenGL(1024,768,OF_WINDOW);// <-------- setup the GL context
// this kicks off the running of my app
// can be OF_WINDOW or OF_FULLSCREEN
// pass in width and height too:
ofRunApp(new ofApp());
}
ofApp.h
#pragma once
#include "ofMain.h"
class ofApp : public ofBaseApp{
public:
void setup();
void update();
void draw();
ofEasyCam cam; //カメラ
ofBoxPrimitive box; //立方体
ofMesh mesh;
};
ofApp.cpp
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup(){
ofSetFrameRate(60); //フレームレートは60fps
ofBackground(0); //背景は黒
ofEnableDepthTest(); //深度テストを有効に
cam.setDistance(120); //カメラの位置と注目点の距離を120に設定
this->box.set(100); //立方体の大きさ(100,100,100)
this->box.setResolution(10); //数値が大きいほど立方体を構成するメッシュの量が増える
mesh = this->box.getMesh(); //boxの頂点情報群を取得しmeshに格納
for(int i = 0; i < mesh.getVertices().size(); i++){ //各々の頂点に対して
mesh.addColor(ofFloatColor(1.0, 1.0, 1.0, 1.0)); //色情報初期化
ofVec3f loc = mesh.getVertices()[i] * ofRandom(0.5,1.0); //位置情報を0.5~1.0で掛ける
mesh.setVertex(i, loc); //新しい位置情報としてセット
ofColor c;
c.setHsb(ofRandom(255),255,255); //HSBで色定義
mesh.setColor(i,c); //新しい色情報としてセット
}
}
//--------------------------------------------------------------
void ofApp::update(){
}
//--------------------------------------------------------------
void ofApp::draw(){
this->cam.begin(); //カメラ起動
mesh.drawWireframe(); //メッシュのフレームを描画
this->cam.end(); //カメラ終了
}
立方体を描くプログラムからの主な変更点はofApp.hの「ofMesh mesh;」とofApp.hppのsetup()内の処理、draw()内の「mesh.drawWireframe();」です。
大事な部分は主にofApp.cppのsetup()内に書かれています。
「mesh=this->box.getMesh()」で立方体の頂点情報をmeshに読み込ませており、これによって頂点情報を操作する事が出来ます。その後for文を使って各々の頂点に対して色を初期化し、新しい位置情報と色情報をセットする事を行っています。ここで個人的に理解するのに時間がかかったのが「mesh.setVertex(i,loc)」と「mesh.setColor(i,c)」の「i」の部分です。これは頂点のインデックスの事であり、改めて値をセットする場合は第一引数としてインデックスを入力する必要があります。当然の事かもしれませんが、自分はどうにも時間がかかってしまいました...。
改めて色と情報のセットが終われば後は描画するのみです。しかし、draw()内のboxをmeshに変えるだけなので、そこはそれほど難しくありません。
以上を踏まえた結果がこちらになります。
立方体の各々の頂点の位置と色の情報をランダムで変更するだけでこれほどまでにひしゃげたカラフルな立方体が出来ました!振り返るとそれほど多くのコードを書いているわけでもないのにこの結果を得る事が出来るのがopenframeworksの良さなのだと思います。
まとめ
今回はofMeshの使い方の記録という事で記事を書かせていただきました。多少なりとも理解した今となっては「正直ここまで理解に苦労する事だったのか?」と思い、自分の理解の遅さを嘆くばかりではありますが、だからこそ一つ一つ確実に理解してなるべく忘れないように心がけていきたいです。この記事の作成も忘れないように、あるいは忘れたとしても思い出せるようにするために作ろうと思い、行ったものです。
その中で、もし自分と同じような所で理解に躓いている方の助けとなれば良いなとも思います。
最後まで読んで下さり、ありがとうございました。