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

ofShaderに同タイプのシェーダープログラムを複数食わせる

Posted at

OpenGLでは、一つのプログラムに複数のシェーダーを含めることができます。

module.glsl
# version 410
float someFunction() {
    return 1.0;
}
main.vert
# version 410
float someFunction(); // 実装はmodule.glslにあるので宣言のみ
void main() {
    gl_Position = vec4(someFunction());
}
auto attachShader = [](GLuint program, GLenum type, std::string filepath) {
    GLuint shaderObj = glCreateShader(type);
    std::string source = loadStringFromFile(filepath); // なんかファイル読み込み処理
    const char* sptr = source.c_str();
    int ssize = source.size();
    glShaderSource(shaderObj, 1, &sptr, &ssize);
    glCompileShader(shaderObj);
    glAttachShader(program, shaderObj);
    glDeleteShader(shaderObj);
};
// ひとつのシェーダープログラムに複数のバーテックスシェーダーオブジェクトをアタッチする
GLuint program = glCreateProgram();
attachShader(program, GL_VERTEX_SHADER, "module.glsl");
attachShader(program, GL_VERTEX_SHADER, "main.vert");

ところが、これをofShaderでやろうとすると動きません。

ofShader shader;
shader.setupShaderFromFile(GL_VERTEX_SHADER, "module.glsl");
shader.setupShaderFromFile(GL_VERTEX_SHADER, "main.vert");
shader.linkProgram();
エラー出力
[ error ] ofShader: checkProgramLinkStatus(): program failed to link
[ error ] ofShader: ofShader: program reports:
ERROR: No definition of someFunction in vertex shader

これは、ofShaderがシェーダーのタイプ(GL_VERTEX_SHADER,GL_GEOMETRY_SHADER,GL_FRAGMENT_SHADER,GL_COMPUTE_SHADER)毎にひとつしかソースを保持しない作りになっていることが原因です。

ofShader.h(抜粋/注釈)
// https://github.com/openframeworks/openFrameworks/blob/0.11.0/libs/openFrameworks/gl/ofShader.h#L272
class ofShader {
    ...
    // GLenumがシェーダータイプ。unordered_mapなので各タイプ毎に一つしかShaderを保持できない
    std::unordered_map<GLenum, Shader> shaders;
    ...
};
ofShader.cpp(抜粋/注釈)
// https://github.com/openframeworks/openFrameworks/blob/0.11.0/libs/openFrameworks/gl/ofShader.cpp#L375
bool ofShader::setupShaderFromSource(ofShader::Source && source){
    ...
    // 同じタイプのシェーダーを複数setupしようとすると、ここで前のが上書きされる
    shaders[source.type] = { shaderId, std::move(source) };
    ...
}

ということなので、ofShader::shadersを使わずにglAttachShaderしてやればOKですね。

auto attachShader = [](ofShader &shader, GLenum type, std::string filepath) {
    GLuint shaderObj = glCreateShader(type);
    std::string source = ofBufferFromFile(filepath).getText();
    const char* sptr = source.c_str();
    int ssize = source.size();
    glShaderSource(shaderObj, 1, &sptr, &ssize);
    glCompileShader(shaderObj);
    glAttachShader(shader.getProgram(), shaderObj);
    glDeleteShader(shaderObj);
};
ofShader shader;
shader.setupShaderFromFile(GL_VERTEX_SHADER, "main.vert");
attachShader(shader, GL_VERTEX_SHADER, "module.glsl");
shader.linkProgram();

これでエラーなくシェーダープログラムがリンクできました。
もちろん普通にofShader::beginofShader::endで使えます。

ちなみに、setupShaderFromFileattachShaderの順序を逆にすると、shader.getProgram()が空なので正しく動きません。
ofShader(GLuint program)みたいな初期化ができると良いんですが・・・。

なお、ofShaderは独自で#includeをサポートしていてくれたり、OpenGLにも拡張機能でARB_shading_language_includeがあったりしますので場合によってはそちらの方が使いやすいかもしれません。

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