cvl-robot's diary

研究ノート メモメモ https://github.com/dotchang/

おまけ:RICOH THETAのJPG画像を平面-球変換してOpenGLで表示する(その7)

全天球画像をSONY HMZ-TシリーズなどのHMDで楽しみたい場合、前回紹介した汎用IMUを取り付けると上手く動かすことができます。前回紹介したSerialThread.cppとSerialThread.hおよび(その6)で紹介したricohThetaExampleを使って、HMDで見られるように改造します。

SerialThread.hを読み込んで、ricohThetaExampleクラス内でインスタンスを定義します。

ricohThetaExample.h

#include "SerialThread.h"

クラス定義の最後の方に、

// IMU

SerialThread *serial;

floatroll, pitch, yaw;

 を追加してください。

 

シリアルデータの読み込み部分をcppに追加します。setup,update,drawの関数を置き換えてください。視線方向ではなくて、IMUのroll, pitch, yawに応じてモデルを回転させます。HMD酔いを起こしてしまうとき、draw関数内の次の行をコメントアウトしてください。draw関数内のRoll, Pitch, Yawの符号は、センサーの取り付け方向に応じて適当に調整してください。

ofMultMatrix(mRoll); // cancel

ricohThetaExample.cpp

//--------------------------------------------------------------

void ricohThetaExample::setup() {

  get_angles(filename.data());

  ofSetVerticalSync(true);

 

  // load an image from disk

  img.loadImage(filename);

 

  // loop through the image in the x and y axes

  float r = 10.0f; // radius

 

  ofEnableDepthTest();

  ofEnableNormalizedTexCoords();

  glEnable(GL_POINT_SMOOTH); // use circular points instead of square points

  glPointSize(3); // make the points bigger

  glEnable(GL_CULL_FACE); 

  glCullFace(GL_BACK);

 

  cam.setAutoDistance(false);

  cam.setPosition(0,0,0);

  cam.lookAt(ofVec3f(-r,0,0),ofVec3f(0,0,1));

  cam.setDistance(1.0);

 

  roll = pitch = yaw = 0.0f;

  serial = new SerialThread();

  serial->init();

  serial->connect(0, 57600);

  serial->startThread(true, false);

}

 

//--------------------------------------------------------------

void ricohThetaExample::update() {

  if(!serial->serial.isInitialized() ){

    cam.enableMouseInput();

 

    // keep horizontal

    ofVec3f updir = cam.getUpDir();

    ofVec3f lookdir = cam.getLookAtDir();

    ofVec3f hordir = updir.getCrossed(lookdir);

    ofQuaternion quat;

    quat.makeRotate(ofVec3f(hordir.x,hordir.y,0).normalized(),hordir.normalized());

    ofMatrix4x4 upmat(quat);

    ofVec3f new_updir = upmat*updir;

    cam.lookAt(lookdir, new_updir);

  }

  else{

    cam.disableMouseInput();

    if(serial->is_updated()){

      serial->getYPR(yaw, pitch, roll);

    }

  }

}

 

//--------------------------------------------------------------

void ricohThetaExample::draw() {

  ofBackgroundGradient(ofColor::gray, ofColor::black, OF_GRADIENT_CIRCULAR);

 

  ofQuaternion qRoll, qPitch, qYaw;

  qRoll.set(sin(roll/2*M_PI/180.0),0,0,cos(roll/2*M_PI/180.0));

  qPitch.set(0,sin(-pitch/2*M_PI/180.0),0,cos(-pitch/2*M_PI/180.0));

  qYaw.set(0,0,sin(yaw/2*M_PI/180.0),cos(yaw/2*M_PI/180.0));

  ofMatrix4x4 mRoll(qRoll), mPitch(qPitch), mYaw(qYaw);

 

  // keep zenith

  ofQuaternion qzx, qzy, qzz;

  qzx.set(sin(zenith_x/2*M_PI/180.0),0,0,cos(zenith_x/2*M_PI/180.0));

  qzy.set(0,sin(-zenith_y/2*M_PI/180.0),0,cos(-zenith_y/2*M_PI/180.0));

  qzz.set(0,0,sin(compass/2*M_PI/180.0),cos(compass/2*M_PI/180.0));

  ofMatrix4x4 m44(qzx*qzy);

  ofMatrix4x4 m_yaw(qzz);

 

  // even points can overlap with each other, let's avoid that

  cam.begin();

  ofPushMatrix();

  ofMultMatrix(mRoll); // cancel

  ofMultMatrix(mPitch);

  ofMultMatrix(mYaw);

  //ofMultMatrix(m_yaw); // adjust north

  ofMultMatrix(m44.getInverse());

 

  ofMatrix4x4 rot(0,-1,0,0,

    0,0,-1,0,

    1,0,0,0,

    0,0,0,1);

  ofMultMatrix(rot);

  img.bind();

  ofSphere(10);

  img.unbind();

  ofPopMatrix();

  cam.end();

}