LoginSignup
0
1

More than 3 years have passed since last update.

ShaderToy+openframeworksでキューブマップ

Last updated at Posted at 2020-11-28

openframeworks+ofxshadertoyでキューブマップが使えない。

openframeworksでshadertoyのコードでGLSLが表示できるofxshaderttoyというアドオンがあるが、
(関連記事  https://qiita.com/quittardis/items/8ba902ebceeef93d55c8
そのままでは、shadertoy.comにあるキューブマップ系のコードがシェーダーコンパイル時にエラーになる。
(関連リンク https://www.shadertoy.com/view/MdXfDS
そこで、いろいろやってみたところ、なんとか動いたので報告する。
out000000.jpg
(上は、shadertoy.comのhttps://www.shadertoy.com/view/tdjXDt をopenframeworksで動作させた画面)

out000339.jpg

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

out000d10.jpg

(上は、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に渡している。

0
1
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
0
1