ShaderToy+openframeworksでキューブマップ

###openframeworks+ofxshadertoyでキューブマップが使えない。
openframeworksでshadertoyのコードでGLSLが表示できるofxshaderttoyというアドオンがあるが、
（関連記事　　https://qiita.com/quittardis/items/8ba902ebceeef93d55c8
そのままでは、shadertoy.comにあるキューブマップ系のコードがシェーダーコンパイル時にエラーになる。
（関連リンク　https://www.shadertoy.com/view/MdXfDS
そこで、いろいろやってみたところ、なんとか動いたので報告する。
![out000000.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/38b6ad4e-d144-b52b-3938-4a3d1c063654.jpeg)
(上は、shadertoy.comのhttps://www.shadertoy.com/view/tdjXDt をopenframeworksで動作させた画面）

![out000339.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/462b95a0-042a-eb77-fbaf-d764aa077c4a.jpeg)


(上は、shadertoy.comのhttps://www.shadertoy.com/view/4stXRN をopenframeworksで動作させた画面）

![out000d10.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/430586/b2b29621-3455-7917-7a8a-764d1c90d7cc.jpeg)

(上は、shadertoy.comのhttps://www.shadertoy.com/view/4sKGWV をopenframeworksで動作させた画面。マウスでぐるぐる回せます。）

###ofxShadertoy.cppの変更箇所

ofxShadertoy.cppの42行目の　

"uniform float      xOutputAlpha;\n"

の下に　

"uniform samplerCube cubemap;\n" 

を追加する。これは、シェーダー側で、キューブマップ用のマッピングデータを受け取る変数である。

###openframeworks上での追加

openframeworks上のofApp.cppに以下を追加する。これで、6枚のキューブマップの画像データを読み込む。
shadertoy.comで使われているキューブマップの画像データはこちらからダウンロードできる。
https://shadertoyunofficial.wordpress.com/
これをopenframeworksのbin下のdata下に置く。

```
unsigned int ofApp::loadCubemap(std::string fileName) {
	unsigned int textureID;
	glGenTextures(1, &textureID);
	glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);

	for (unsigned int i = 0; i < 6; i++)
	{
		//get proper file name for each face from folder path -- assumes all files are named 'posX.jpg', etc
		std::string fileNameTemp = fileName;
		if (i == 0) { fileNameTemp.append("posX.png"); }
		else if (i == 1) { fileNameTemp.append("negX.png"); }
		else if (i == 2) { fileNameTemp.append("posY.png"); }
		else if (i == 3) { fileNameTemp.append("negY.png"); }
		else if (i == 4) { fileNameTemp.append("posZ.png"); }
		else if (i == 5) { fileNameTemp.append("negZ.png"); }

		ofImage image;
		//image.load(fileNameTemp.c_str());
		image.load(fileNameTemp);
		int width = image.getWidth();
		int height = image.getHeight();
		//unsigned char *data = stbi_load(fileNameTemp.c_str(), &width, &height, &nrComponents, 0);
		unsigned char *data = image.getPixels().getData();
		if (data)
		{
			glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
			//stbi_image_free(data);
		}
		else
		{
			//std::cout << "Cubemap texture failed to load at path: " << fileNameTemp[i] << std::endl;
			std::cout << "Cubemap texture failed to load at path: " << fileNameTemp << std::endl;
			//stbi_image_free(data);
		}
	}
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	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);

	return textureID;
}
```
ヘッダーには以下を加える。
'''
unsigned int loadCubemap(std::string fileName);
'''


###shadertoyのコードの変更箇所
たとえば、https://www.shadertoy.com/view/MdXfDS
のコードは、

```
vec3 getRayDirection(vec2 screenPosition, vec3 origin, vec3 lookingAt, vec3 up, float fov)
{
    vec3 d = normalize(lookingAt - origin);
    vec3 rayRight = normalize(cross(d, up));
    
    return normalize(screenPosition.x * rayRight + screenPosition.y * up + 1.0 / tan(radians(fov / 2.0)) * d);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	vec2 position = (2.0 * fragCoord - iResolution.xy) / iResolution.y;
    vec3 cameraPosition = vec3(0.0, 0.0, 0.0);
    vec3 cameraUp = vec3(0.0, 1.0, 0.0);
    vec3 cameraLookingAt = vec3(cos(iTime), 0.0, sin(iTime));
    vec3 rayDirection = getRayDirection(position, cameraPosition, cameraLookingAt, cameraUp, 90.0);
    
    fragColor = vec4(texture(iChannel0, rayDirection).xyz, 1.0);
}
```
であるが、この17行目の　fragColor = vec4(texture(iChannel0, rayDirection).xyz, 1.0);
でエラーになる。
このiChannel0をcubemapに変更し、
　　　　　　　　　　　　fragColor = vec4(texture(cubemap, rayDirection).xyz, 1.0);
とする。

###openframeworksからキューブマップデータをロードして、シェーダーに渡す。
openframeworksからキューブマップデータをロードして、シェーダーに渡す方法は
以下の通り

```
unsigned int cubemapTexture = loadCubemap("cubemaps/" + ＜キューブマップフォルダ名＞ + "/");
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
shadertoy[shdrNum].setUniform1i("cubemap", cubemapTexture);
```
つまり、cubeMaptextureはキューブマップ画像に紐づけられたunsigned intの値で、これを
setUniform1i　でシェーダーの変数cubemapに渡している。