2011年7月16日土曜日

realTimeProjectionMapping

昨日はopenFrameworks Tokyoがありましたね。Ustで見ました。

openFrameworks.jp
http://openframeworks.jp/

会場の無線環境のせいか少し途切れる場面がありましたが、だいたいは満足に見られました。

やっぱ会場にいくのと、中継とでは歴然の差があるのでしょうね。


昨日は上を見ながら、openFrameworksを使ったopenGLでの3Dtextureについてやってました。

だいたいはopenGL de プログラミング
http://wiki.livedoor.jp/mikk_ni3_92/d/%c8%af%c5%b8%ca%d406%3a%3a%a4%de%a4%c8%a4%e1%a5%b3%a1%bc%a5%c9

のサイトのサンプルコードを参考にしています。


人体のCTスキャンのような断面画像を3Dテクスチャ化して、どの断面を切っても中身が見れる、という状態を作りたい。

上記のサンプルコードを参考に3Dテクスチャの読み込み、初期化のクラスを作ってみました。

//以下"texture3D.h"-------------------------------------

#ifndef _TEXTURE_3D
#define _TEXTURE_3D

//#include "GL/glew.h"
#include "ofImage.h"

// テクスチャの縦横のピクセル数
#define TEX_WIDTH 256
#define TEX_HEIGHT 128
// 3Dテクスチャの奥行き
#define TEX_DEPTH 559


class texture3D {
public:
// コンストラクタ
texture3D();
// デストラクタ
~texture3D();

void setup( int _width, int _height, int _depth); // 初期化
void load( string _Img);
void loads( string _Img, int _ImgNum);
void end(); // 画像の消去

// 1枚だけ読み込み用変数(使わないと思うが)
ofImage texIMG_3D;
// 複数画像読み込み用配列
ofImage texIMGS_3D[TEX_DEPTH];
// 3Dテクスチャ用配列
unsigned char *Data;
GLuint texture[1];
GLdouble float_Data[TEX_WIDTH * TEX_HEIGHT * TEX_DEPTH * 3];
ofColor color_Data;

};

#endif
//以上--------------------------------------------------------

//以下"texture3D.cpp"------------------------------------------

#include "texture3D.h"


// コンストラクタ
texture3D::texture3D(){
        //特にないけど一応作った
}
texture3D::~texture3D(){
glDeleteTextures(1, &texture[0]);//本来は削除する
}

void texture3D::setup( int _width, int _height, int _depth){
int width = _width;
int height = _height;
int depth = _depth;

// 3次元テクスチャ用にテクスチャ読み込み---------------------------------------------
// テクスチャ読み込み配列を定義
Data = new unsigned char[width * height * depth * 3];
memset(Data, 0, sizeof(unsigned char)*width*height*depth*3);//初期化
//ここでカラー設定
    for(int loopZ = 0;loopZ < depth;++loopZ)
    {
            for(int loopY = 0; loopY < height;++loopY)
            {
                    for(int loopX = 0;loopX < width;++loopX)
                    {
//unsigned char* getPixels =  texIMG_3D[loopZ].getPixels();
color_Data = texIMGS_3D[loopZ].getColor( loopX, loopY);
float_Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3 + 0] = color_Data.r;
float_Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3 + 1] = color_Data.g;
float_Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3 + 2] = color_Data.b;
Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3+0] = static_cast<unsigned char>( float_Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3 + 0] );//r
                        Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3+1] = static_cast<unsigned char>( float_Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3 + 1] );//g
                        Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3+2] = static_cast<unsigned char>( float_Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3 + 2] );//b
//Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3+0] = static_cast<unsigned char>((255/width)*loopX);//r
                        //Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3+1] = static_cast<unsigned char>((255/height)*loopY);//g
                        //Data[loopZ*(width*height*3) +loopY * (width*3) + loopX*3+2] = static_cast<unsigned char>((255/depth)*loopZ);//b
                    }
            }
    }
glGenTextures(1, &texture[0]);
    glBindTexture(GL_TEXTURE_3D, texture[0]);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glPixelStorei(GL_PACK_ALIGNMENT, 1);
    glTexParameterf(GL_TEXTURE_3D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); //フィルタ
    glTexParameterf(GL_TEXTURE_3D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);

    glGenerateMipmapEXT(GL_TEXTURE_3D);//ミップマップ自動生成
    glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, width, height, depth, 0, GL_RGB, GL_UNSIGNED_BYTE, Data);
//glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, width, height, depth, 0, GL_COLOR_INDEX, GL_FLOAT, float_Data); //これはだめ

delete Data;
}

void texture3D::load( string _Img){
string Img = _Img;
texIMG_3D.loadImage( Img );
}
void texture3D::loads( string _Img, int _ImgNum){
int ImgNum = _ImgNum;
string Img = _Img;
// 複数画像の読み込み
texIMGS_3D[ImgNum].loadImage( Img );
}
void texture3D::end(){
// 画像を消去したい場合
glDeleteTextures(1, &texture[0]);//本来は削除する
}
//以上-------------------------------------------------------

普段openGLでの画像の読み込みは結構面倒なのですが、ofImageを使うとかなり楽にできます。

void loads( string _Img, int _ImgNum);の関数で_Imgに画像のファイルパス、_ImgNumに画像の連番のIDをぶち込みます。

使い方としては、
10枚の連番画像を使うときは、


for( int i = 0; i < 10; i++){
tex3D.loads( "picture_" + ofToString( i ) + ".tga", i);
}


とすると、picture_0.tgaからpicture_9.tgaまでの画像が読み込まれます。


次に
void setup( int _width, int _height, int _depth);で初期化してあげます。(正確には初期化ではない)

縦横の幅とdepthは画像の枚数です。



openGLのテクスチャの貼り方なんですが、まだ勉強中でよく分かりません。どなたか教えてください。


glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_3D, texture[0]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glTexParameterf(GL_TEXTURE_3D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); //フィルタ
glTexParameterf(GL_TEXTURE_3D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);

glGenerateMipmapEXT(GL_TEXTURE_3D);//ミップマップ自動生成

ここまではだいたい分かるのですが、

glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, width, height, depth, 0, GL_RGB, GL_UNSIGNED_BYTE, Data);

このglTexImage3Dに関する説明が書かれている書籍などが周りになくて...

だいたいglTexImage2Dの延長と考えれば何が書かれているのかわかるんですがね。

こんな感じで(大雑把!)できた画像が下です。










右が元の画像で、元の画像は人間を真上から見た状態の写真です。

それに対して、左の3Dテクスチャ化した画像は人間を前から見た状態になっています。

もう一枚



また、補足ですが、

glTexParameterf(GL_TEXTURE_3D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); //フィルタ
glTexParameterf(GL_TEXTURE_3D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

の第三引数のGL_LINEARがGL_NEARESTになっていて、depthの補完が段階的になっていて、汚かったです。

おそらく補完の方法の指定でGL_LINEARは文字通り線形補完なのだと思います。



追記

①512*512の画像だと、100枚くらいしか使えなかった。

その際のエラーが「配列サイズは0x7FFFFFF(2147483647)まで」と出たが、計算しても配列サイズはそれに収まる。なーぜ。

2011年7月14日木曜日

waveSystem_01

張り切ってブログ始めたけど、もう半月以上放置してしまった。相変わらずの三日坊主っぷりだ。


所で、今何をやっているのかというと、

表面に波を発生させる球を前々に作って、今度それを授業の課題として提出しようとしている。

もう基本的なシステムは完成している。


こんな感じのイメージになる。

昔に作ったものではあるが、まったく日の目を浴びることなく、お蔵入りになっていたので、今回晴れて作品として落ち着かせることができる。

これをオーディオのビジュアライザのようにしようと画策中。


そこで、この球面波の部分だけをクラスにしようとしているけど、うまくいかなーい!アクセスバイオレーションが発生してしまう。

うまくいったと思ったら今度は無茶苦茶な座標値となって球にならなーい。

クラスってどうやって作るんだって所からやり直し!