not good but great

プログラミング、アート、映画・本の感想について書きます。

openFrameworksでMeshを使い、大量の頂点を高速に描画する

Meshを描画する

Meshとは?

Meshは頂点情報の集合のことです。複雑な物体を描画する時に用います。

VBOで高速化

VBOとは?

VBOは頂点バッファオブジェクトのことです。予めOpenGL側で頂点データを作成しておき、その後GPUで計算する手法のことです。CPUの負荷が減り、GPUで高速に演算できるメリットがあります。

//VBO
ofVbo myVbo;
//頂点座標
ofVec3f myVerts[NUM_PARTICLES];
//頂点の色情報
ofFloatColor myColor[NUM_PARTICLES];

ofVboクラスからインスタンスを生成します。また頂点座標、色情報を入れる配列を宣言しておきます。

setup

void ofApp::setup(){
    ofBackground(0);
    ofEnableDepthTest();
    ofEnableBlendMode(OF_BLENDMODE_ADD);
    
    cam.setDistance(100);
    
    //頂点の色を初期化
    for(int i = 0;i < WIDTH;i++){
        for(int j = 0;j < HEIGHT;j++){
            myVerts[j * WIDTH + i].set(i - WIDTH/2,j - HEIGHT/2,0);
            myColor[j * WIDTH + i].set(0.5,0.8,1.0,1.0);
        }
    }
    
    //頂点バッファに位置と色情報を設定
    myVbo.setVertexData(myVerts, NUM_PARTICLES, GL_DYNAMIC_DRAW);
    myVbo.setColorData(myColor, NUM_PARTICLES, GL_DYNAMIC_DRAW);   
}

set()を使って、位置と色情報を設定します。
・setのドキュメント
http://openframeworks.cc/documentation/math/ofVec3f.html#!show_set

・setVertexData、setColorDataの使い方
http://openframeworks.cc/documentation/gl/ofVbo.html#!show_setVertexData
http://openframeworks.cc/documentation/gl/ofVbo.html#!show_setColorData

setVertexData、setColorDataの最後の引数にはデータのアクセス方法を定義します。

The possible options for usage are: GL_STREAM_DRAW, GL_STREAM_READ, GL_STREAM_COPY, GL_STATIC_DRAW, GL_STATIC_READ, GL_STATIC_COPY, GL_DYNAMIC_DRAW, GL_DYNAMIC_READ, or GL_DYNAMIC_COPY

今回使っているのは「GL_DYNAMIC_DRAW」でデータが頻繁に書き換えられることに適しています。

・参考
レンタルwikiサービス|cswiki エラーページ

update

void ofApp::update(){
    //頂点情報の削除
    mesh.clearVertices();
    
    //頂点の位置を更新
    for(int i = 0;i < WIDTH;i++){
        for(int j = 0;j < HEIGHT;j++){
            float x = sin(i * 0.1 + ofGetElapsedTimef()) * 1.0;
            float y = sin(j * 0.15 + ofGetElapsedTimef()) * 10.0;
            float z = x + y;
            
            myVerts[j * WIDTH + i] = ofVec3f(i - WIDTH/2,j - HEIGHT/2,z);
        }
    }
    
    //頂点バッファ更新
    myVbo.updateVertexData(myVerts, NUM_PARTICLES);
}

ofGetElapsedTimef()は経過時間を指します。

draw

void ofApp::draw(){
    //カメラ開始
    cam.begin();
    
    //頂点をドットで表示
    glPointSize(sin(ofGetElapsedTimef()) * 4.0);
    myVbo.draw(GL_POINTS,0,NUM_PARTICLES);
    cam.end();
    
    //ログ表示
    string info;
    info = "Vertex num = " + ofToString(NUM_PARTICLES,0) + "¥n";
    info += "FPS =" + ofToString(ofGetFrameRate(),2);
    ofDrawBitmapString(info, 30, 30);
}

glPointSizeをsin関数で変化させるようにしてみました。これで少し波が光っているように見えます。