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の延長と考えれば何が書かれているのかわかるんですがね。
こんな感じで(大雑把!)できた画像が下です。
右が元の画像で、元の画像は人間を真上から見た状態の写真です。
また、補足ですが、
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)まで」と出たが、計算しても配列サイズはそれに収まる。なーぜ。