assimpExampleのソースコードを読んで、ofxAssimpModelLoaderで3Dモデルを描画する

openFrameworksのsamplesに入っているassimpExampleのソースコードを読みます。

assimpExampleとは

これ
f:id:pfont:20200201184725g:plain

openFrameworksのライブラリofxAssimpModelLoaderを使用して、読み込んだ3Dモデルをインタラクティブに表示切り替えするsampleです。
このソースを読んで、ofxAssimpModelLoaderで3Dモデルを描画するエッセンスを習得します。

まずはヘッダファイル。

ofApp.h
#ifndef _TEST_APP
#define _TEST_APP

#include "ofMain.h"
#include "ofxAssimpModelLoader.h"
#include "ofVboMesh.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);		
    
        ofxAssimpModelLoader model;
    
        bool bHelpText;
        bool bAnimate;
        bool bAnimateMouse;
        float animationPosition;

        ofMesh mesh;
        ofLight	light;
};

#endif

ヘッダファイルをincludeします。

#include "ofxAssimpModelLoader.h"

この部分でクラスofxAssimpModelLoaderを初期化しています。

ofxAssimpModelLoader model;

また、ofLightを使って照明オブジェクトを初期化しています。

ofLight light;
ofApp.cpp

次はcppファイル。setupとupdateを確認。

#include "ofApp.h"

void ofApp::setup(){
    ofSetLogLevel(OF_LOG_VERBOSE);
    ofBackground(50, 0);

    ofDisableArbTex(); // we need GL_TEXTURE_2D for our models coords.

    bAnimate = false;
    bAnimateMouse = false;
    animationPosition = 0;

    model.loadModel("astroBoy_walk.dae", false);
    model.setPosition(ofGetWidth() * 0.5, (float)ofGetHeight() * 0.75 , 0);
    model.setLoopStateForAllAnimations(OF_LOOP_NORMAL);
    model.playAllAnimations();
    if(!bAnimate) {
        model.setPausedForAllAnimations(true);
    }

    bHelpText = true;

}

void ofApp::update(){
    model.update();

    if(bAnimateMouse) {
        model.setPositionForAllAnimations(animationPosition);
    }

    mesh = model.getCurrentAnimatedMesh(0);
}

3Dモデルを描画するだけなら、いろいろなものを読み飛ばして良さそう。
とりあえずmodelの設定関連が必要なので、以下が必須のコード。

void ofApp::setup(){
    ofBackground(50, 0);

    ofDisableArbTex(); // we need GL_TEXTURE_2D for our models coords.

    model.loadModel("astroBoy_walk.dae", false);
    model.setPosition(ofGetWidth() * 0.5, (float)ofGetHeight() * 0.75 , 0);
    model.setLoopStateForAllAnimations(OF_LOOP_NORMAL);
    model.playAllAnimations();
}

void ofApp::update(){
    mode.update();
}

ofxAssimpModelLoaderのクラスメソッドは、公式ドキュメントに記載がほぼなく使い方がわからない。
唯一このページが参考になる。
openframeworks.cc

最後はdraw内のソースコード

void ofApp::draw(){
    ofSetColor(255);

    ofEnableBlendMode(OF_BLENDMODE_ALPHA);

	ofEnableDepthTest();
#ifndef TARGET_PROGRAMMABLE_GL
    glShadeModel(GL_SMOOTH); //some model / light stuff
#endif
    light.enable();
    ofEnableSeparateSpecularLight();

    ofPushMatrix();
    ofTranslate(model.getPosition().x+100, model.getPosition().y, 0);
    ofRotateDeg(-mouseX, 0, 1, 0);
    ofTranslate(-model.getPosition().x, -model.getPosition().y, 0);
    model.drawFaces();
    ofPopMatrix();
#ifndef TARGET_PROGRAMMABLE_GL
    glEnable(GL_NORMALIZE);
#endif
    ofPushMatrix();
    ofTranslate(model.getPosition().x-300, model.getPosition().y, 0);
    ofRotateDeg(-mouseX, 0, 1, 0);
    ofTranslate(-model.getPosition().x, -model.getPosition().y, 0);

    ofxAssimpMeshHelper & meshHelper = model.getMeshHelper(0);

    ofMultMatrix(model.getModelMatrix());
    ofMultMatrix(meshHelper.matrix);

    ofMaterial & material = meshHelper.material;
    if(meshHelper.hasTexture()){
        meshHelper.getTextureRef().bind();
    }
    material.begin();
    mesh.drawWireframe();
    material.end();
    if(meshHelper.hasTexture()){
        meshHelper.getTextureRef().unbind();
    }
    ofPopMatrix();

    ofDisableDepthTest();
    light.disable();
    ofDisableLighting();
    ofDisableSeparateSpecularLight();

    if(bHelpText){
    ofSetColor(255, 255, 255 );
    stringstream ss;
    ss << "FPS: " << ofToString(ofGetFrameRate(),0) <<endl<<endl;
    ss <<"(keys 1-5): load models"<<endl;
    ss << "num of animations in this model: " + ofToString(model.getAnimationCount());
    ss <<endl <<"(Spacebar): toggle animation"<<endl;
    ss <<"(LEFT MOUSE BUTTON DRAG in y-axis): control animation."<<endl;
    ss <<"(h): toggle help."<<endl;
    ofDrawBitmapString(ss.str().c_str(), 20, 20);

    }
}

いろいろな記載があるけど、モデルの描画を行う記述は以下。

void ofApp::draw(){
    ofSetColor(255);

    light.enable();
    ofEnableSeparateSpecularLight();

    model.drawFaces();
}

ofEnableSeparateSpecularLightは、モデルに光沢がつくような処理を行う記述。
openframeworks.jp

鏡面ハイライトと呼ぶ。詳細は以下。
area.autodesk.jp

自分で書いてみる

というわけで以下のofApp.cppを作成。

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
    ofBackground(50, 0);

    ofDisableArbTex();

    model.loadModel("astroBoy_walk.dae");
    model.setPosition(ofGetWidth() * 0.5, (float)ofGetWidth() * 0.75, 0);
    model.setLoopStateForAllAnimations(OF_LOOP_NORMAL);
    model.playAllAnimations();
}

//--------------------------------------------------------------
void ofApp::update(){
    model.update();
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofSetColor(255);

    ofEnableBlendMode(OF_BLENDMODE_ALPHA);
    ofEnableDepthTest();

    light.enable();
    ofEnableSeparateSpecularLight();

    model.drawFaces(); // loadModelで読み込んだモデルを表示
}

実行結果は以下の通り。
f:id:pfont:20200201191520p:plain
陰影もあって良い感じ。3Dモデルの描画に成功した。

ちなみに、light.enable(); を外すとこんな感じ。
f:id:pfont:20200201191649p:plain