1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ShaderToy+openframeworksでボリュームマップ

Last updated at Posted at 2020-11-30

###openframeworks+ofxshadertoyでボリューム(Texture 3D)マップが使えない。
openframeworksでshadertoyのコードでGLSLが表示できるofxshadertoyというアドオンがあるが、(関連記事 https://qiita.com/quittardis/items/8ba902ebceeef93d55c8)
以前の投稿で調べたキューブマップもそうだが、https://qiita.com/quittardis/items/9e1abab3babfeb3e1206
ボリューム(Texture 3D)マップもそのままではシェーダーをコンパイルすることができない。
(関連記事  https://www.shadertoy.com/view/MtjBWz
そこでキューブマップの時と同様に調べてみた。GLSLはボリューム(Texture 3D)データを扱うことができるので、工夫すれば、ofxshadertoyのシェーダーにもボリュームデータを渡すことができるはずである。

out000016.jpg

上は、openframeworksとofxshadertoyで、なんとかボリュームの3Dノイズをシェーダに渡して表示できた結果である。まだ、https://www.shadertoy.com/view/MtjBWz などはコンパイルできるが、うまく表示できない。
途中ではあるが、送るデータの塩梅の問題のようである。追って報告したい。

###ofxShadertoy.cppの変更箇所

ofxShadertoy.cppの42行目の 

"uniform float xOutputAlpha;\n"

の下に、キューブマップ用に前回 (https://qiita.com/quittardis/items/9e1abab3babfeb3e1206)
"uniform samplerCube cubemap;\n"
を追加したが、その下に、

"uniform sampler3D tex3D;\n" 

を追加する。tex3Dの変数名は任意である。これでボリュームデータをシェーダー内で扱える。

###openframeworks上での追加
openframeworks上のofApp.cppに以下を追加する。ボリュームマップの画像データを読み込むためのものである。
shadertoy.comで使われているボリュームマップデータはこちらからダウンロードできる。
https://shadertoyunofficial.wordpress.com/
これをopenframeworksのbin下のdata下にvolumesというというフォルダを作成してその中に置く。

int XDIM = 32, YDIM = 32, ZDIM = 32;

unsigned int   ofApp::LoadVolumeFromFile(const char* fileName) {
	FILE *pFile = fopen(fileName, "rb");
	if (NULL == pFile) {
		printf("error:%s\n",fileName);
		return false;
	}
	const int size = XDIM * YDIM * ZDIM * 4;
	GLubyte* pVolume = new GLubyte[size];
	fread(pVolume, sizeof(GLubyte), size, pFile);
	fclose(pFile);
	//
	//load data into a 3D texture
	unsigned int textureID;
	glGenTextures(1, &textureID);
	glBindTexture(GL_TEXTURE_3D, textureID);
	// set the texture parameters
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, XDIM, YDIM, ZDIM, 0, GL_RGB, GL_UNSIGNED_BYTE, pVolume);
	
	delete[] pVolume;
	return textureID;
}

ヘッダーに、

unsigned int LoadVolumeFromFile(const char* fileName);

もお忘れなく。
###shadertoyのコード

void mainImage( out vec4 O, in vec2 fragCoord )
{

    vec2 uv = fragCoord/iResolution.xy;
    float ratio = 1.0;
    vec4 col = (uv.x < ratio)?texture(tex3D, vec3(uv.x, uv.y, sin(iTime/20.0))):vec4(0.0,0.0,0.0,1.0);
    O = col;
       
}

この中のtex3Dが、上で定義したボリュームデータを受け渡しする変数である。

###openframeworksからシェーダーへのボリュームデータの渡し方

unsigned int tid = LoadVolumeFromFile(("data/volumes/" + <ファイル名>).c_str());
shadertoy[shdrNum].setUniform1i("tex3D", tid);

これで、上の画像を表示するので、ボリュームデータはopenframeworks側からシェーダーに送れているようである。
要は、データサイズと

glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, XDIM, YDIM, ZDIM, 0, GL_RGB, GL_UNSIGNED_BYTE, pVolume);

のパラメータを正しく設定すれば、うまくいきそうである。追って報告いたします。

###その後

その後、https://www.shadertoy.com/view/MlXcD4 
のコードで、これと同じ表示になるか色々試した結果、
(これはShaderToyのグレーのボリュームのノイズテクスチャーを使用している)

 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 glTexImage3D(GL_TEXTURE_3D, 0, GL_RED, XDIM, YDIM, ZDIM, 0, GL_RED, GL_UNSIGNED_BYTE, pVolume);

というパラメータの組み合わせで、下図のように、out000017.jpg

ttps://www.shadertoy.com/view/MlXcD4 
のコードのWeb上の表示と同様の表示になりました。
上のパラメータの違いは、const int size = XDIM * YDIM * ZDIM * 4;の最後の*4を除き(グレーなので)、
さらに、 GL_CLAMP -> GL_CLAMP_TO_EDGE にしたこと、
     GL_RGB -> GL_RED  にしたところです。

###その後のその後
ShaderToyの本家のhttps://www.shadertoy.com/view/MtjBWzの投稿をベースに、以下のようにコードを変更
した3Dテクスチャーのテストコードに使用した。

 // volumetric variant of  https://shadertoy.com/view/XlBBRR
 #define rndB(U) texture(tex3D, U)     // trilinear interpolation

 void mainImage( out vec4 O, vec2 U )
 {
     vec2 R = iResolution.xy;
     U = ( U+U - R ) / R.y;
     vec3 V = .2*vec3(U,.1*iTime);
    
   O =   rndB(V);    // trilinear
   O = sin(10.*O);
   //O = sqrt(O);                          // gamma correction
 }

また、OF側のボリュームデータの渡し方は、以下の通り


    FILE *pFile = fopen(fileName, "rb");
	if (NULL == pFile) {
		return false;
	}
	const int size = XDIM * YDIM * ZDIM * 4;  // 32x32x32  4 channels, unit8 
	GLubyte* pVolume = new GLubyte[size];
	fread(pVolume, sizeof(GLubyte), size, pFile);
	fclose(pFile);
	
	//load data into a 3D texture
	unsigned int textureID;
	glGenTextures(1, &textureID);
	glBindTexture(GL_TEXTURE_3D, textureID);

	// set the texture parameters
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
	
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	

	glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, XDIM, YDIM, ZDIM, 0, GL_RGB, GL_UNSIGNED_BYTE, pVolume);

これで、動画で、rgbボリュームマップ(textre3D)の様子をチェックできる。https://youtu.be/6DuhtofVn_Q

out000002.jpg

###その後のその後のその後
上記のパラメータでは、https://www.shadertoy.com/view/tsdcRj
は表示できなかった。
そこで、パラメータを以下のように変更した。

glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, XDIM, YDIM, ZDIM, 0, GL_RGBA, GL_UNSIGNED_BYTE, pVolume);

これによって下図のように表示できた。
out000002.jpg

動画のリンクはこちらhttps://youtu.be/OD01scbd-ys

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?