2016-09-28 27 views
1

私は、フラグメントシェーダがウィンドウ全体を占めるクワッドにレンダリングするテクスチャを生成する計算シェーダの例を持っています。このテクスチャはどのようにフラグメントシェーダに渡されますか?

フラグメントシェーダコードでは、uniform sampler2Dが表示されますが、計算シェーダの出力は実際にフラグメントシェーダに渡されますか?縛られているのは単なる美徳ですか?フラグメント/頂点シェーダにテクスチャを明示的にバインドする(より均一な方法や他の方法を使用する)方が良いでしょうか?

// Include standard headers 
#include <stdio.h> 
#include <stdlib.h> 
#include <stdarg.h> 
#include <math.h> 

// Include GLEW 
#include <GL/glew.h> 

//Glut 
#include <GL/glut.h> 

const GLchar* computeSource = 
    "#version 430 core\n" 
    "\n" 
    "layout (local_size_x = 32, local_size_y = 16) in;\n" 
    "\n" 
    "layout (rgba32f) uniform image2D output_image;\n" 
    "void main(void)\n" 
    "{\n" 
    " imageStore(output_image,\n" 
    " ivec2(gl_GlobalInvocationID.xy),\n" 
    " vec4(vec2(gl_LocalInvocationID.xy)/vec2(gl_WorkGroupSize.xy), 0.0, 0.0));\n" 
    "}\n"; 

const GLchar* vertexSource = 
     "#version 430 core\n" 
     "\n" 
     "in vec4 vert;\n" 
     "\n" 
     "void main(void)\n" 
     "{\n" 
     " gl_Position = vert;\n" 
     "}\n"; 

const GLchar* fragmentSource = 
     "#version 430 core\n" 
     "\n" 
     "layout (location = 0) out vec4 color;\n" 
     "\n" 
     "uniform sampler2D output_image;\n" 
     "\n" 
     "void main(void)\n" 
     "{\n" 
     " color = texture(output_image, vec2(gl_FragCoord.xy)/vec2(textureSize(output_image, 0)));\n" 
     "}\n"; 

GLuint vao; 
GLuint vbo; 
GLuint mytexture; 
GLuint shaderProgram; 
GLuint computeProgram; 

void checkError(int line) 
{ 
    GLint err; 

    do 
    { 
     err = glGetError(); 
     switch (err) 
     { 
      case GL_NO_ERROR: 
       //printf("%d: No error\n", line); 
       break; 
      case GL_INVALID_ENUM: 
       printf("%d: Invalid enum!\n", line); 
       break; 
      case GL_INVALID_VALUE: 
       printf("%d: Invalid value\n", line); 
       break; 
      case GL_INVALID_OPERATION: 
       printf("%d: Invalid operation\n", line); 
       break; 
      case GL_INVALID_FRAMEBUFFER_OPERATION: 
       printf("%d: Invalid framebuffer operation\n", line); 
       break; 
      case GL_OUT_OF_MEMORY: 
       printf("%d: Out of memory\n", line); 
       break; 
      default: 
       printf("%d: glGetError default case. Should not happen!\n", line); 
     } 
    } while (err != GL_NO_ERROR); 
} 

void display() 
{ 

    glUseProgram(computeProgram); 
    glBindImageTexture(0, mytexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); 
    glDispatchCompute(8, 16, 1); 

    glBindTexture(GL_TEXTURE_2D, mytexture); 

    glClearColor(0.0f, 1.0f, 0.0f, 0.0f); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glUseProgram(shaderProgram); 

    glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 

    glFlush(); 
    glutSwapBuffers(); 

}  


void reshape(int width,int height) 
{ 
    double w2h = (height>0) ? (double)width/height : 1; 
    // Set viewport as entire window 
    glViewport(0,0, width,height); 
} 



int main(int argc, char** argv) 
{ 

    // Window Setup 

    glutInitWindowSize(640, 400); 
    glutInitWindowPosition (140, 140); 
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 
    glutInit(&argc, argv); 

    glutCreateWindow("OpenGL Application"); 
    glutDisplayFunc(display); 
    glutReshapeFunc(reshape); 

    glewExperimental = true; // Needed for core profile 
    if (glewInit() != GLEW_OK) { 
     fprintf(stderr, "Failed to initialize GLEW\n"); 
     return -1; 
    } 

    glGenVertexArrays(1, &vao); 
    glBindVertexArray(vao); 
    glEnableVertexAttribArray(0); 

    glGenBuffers(1, &vbo); 

    GLfloat vertices[] = { 
     // X Y  Z  A 
     -1.0f, -1.0f, 0.5f, 1.0f, 
     1.0f, -1.0f, 0.5f, 1.0f, 
     1.0f, 1.0f, 0.5f, 1.0f, 
     -1.0f, 1.0f, 0.5f, 1.0f, 
    }; 

    glBindBuffer(GL_ARRAY_BUFFER, vbo); 

    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); 
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL); 


    checkError(__LINE__); 


    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); 
    glShaderSource(vertexShader, 1, &vertexSource, NULL); 
    glCompileShader(vertexShader); 

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); 
    glShaderSource(fragmentShader, 1, &fragmentSource, NULL); 
    glCompileShader(fragmentShader); 
    checkError(__LINE__); 


    GLuint computeShader; 
    computeProgram = glCreateProgram(); 
    computeShader = glCreateShader(GL_COMPUTE_SHADER); 
    glShaderSource(computeShader, 1, &computeSource, NULL); 
    glCompileShader(computeShader); 
    glAttachShader(computeProgram, computeShader); 
    glLinkProgram(computeProgram); 

    glGenTextures(1, &mytexture); 
    glBindTexture(GL_TEXTURE_2D, mytexture); 
    glTexStorage2D(GL_TEXTURE_2D, 8, GL_RGBA32F, 256, 256); 
    checkError(__LINE__); 

    shaderProgram = glCreateProgram(); 
    glAttachShader(shaderProgram, vertexShader); 
    glAttachShader(shaderProgram, fragmentShader); 
    glBindFragDataLocation(shaderProgram, 0, "color"); 
    glLinkProgram(shaderProgram); 
    checkError(__LINE__); 

    glutMainLoop(); 

    return 0; 
} 
+1

実際にそのコードは期待どおりに動作していますか?私はそこに 'glGetUniformLocation()'と 'glUniform()'のペア*があると思いますが、私はそれを見ていません。 – genpfault

+0

ええ..このコードは、OpenGLの "赤い本"から変更されています。私は本当にその本が嫌いです。マクロやヘルパー関数は、明確にすることは本当に悪い考えであり、その説明は非常に貧弱です。第12章の例を参照してください:https://github.com/openglredbook/examples/tree/master/src – Maxthecat

答えて

1

これが働いている主な理由は、セクション4.3.5、シェーダで均一な変数はGLSL 4.5仕様から0のデフォルト値を持っていることである:すべての均一な変数は読み取り専用です

リンク時またはAPIを介して外部的に初期化されます。リンク時の初期値は、変数の初期化子の値(存在する場合)または初期化子が存在しない場合は0のいずれかです。あなたが理解する必要が

次の部分は、サンプラー変数の値は、あなたからサンプリングするテクスチャユニットであるということです。同様に、画像変数の値は、画像単位が画像アクセスに使用されます。

これらのユニフォーム変数の値を設定しないので、フラグメントシェーダーのサンプラーは、テクスチャユニット0にバインドされているテクスチャにアクセスします。計算シェーダの画像は、

  • あなたはglActiveTexture()でアクティブなテクスチャユニットを設定したことがないので、このコール:

    glBindTexture(GL_TEXTURE_2D, mytexture); 
    
    を画像単位幸いにもあなたのために0

    が、これは何が必要正確です

    は、テクスチャユニット0にテクスチャをバインドします。これは、テクスチャユニットがフラグメントシェーダでサンプリングされることを意味します。画像を結合し、あなたのコールで

  • glBindImageTexture(0, mytexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); 
    

    は、あなたがにバインドする画像単位を指定する最初の引数として0を渡します。結果として、計算シェーダはこのイメージにアクセスします。

私見、それはデフォルトで十分かもしれない場合でも、常に均一な変数の値を設定するために良いスタイルです。複数のテクスチャ/イメージを使用すると、コードが読みやすくなり、均一な値を設定することが不可欠になります。対応するプログラムがアクティブである間glUniform1i()呼び出しがなされる必要があることを

GLint imgLoc = glGetUniformLocation(computeProgram, "output_image"); 
glUniform1i(imgLoc, 0); 
... 
GLint texLoc = glGetUniformLocation(shaderProgram, "output_image"); 
glUniform1i(texLoc, 0); 

注:だから明確にするため、私はあなたのコード内でこのような何かを持っているでしょう。

+0

ああ、それはそのようないくつかのデフォルト状態だったと思った! – genpfault

+0

あなたは素晴らしいです!説明ありがとう。 – Maxthecat

関連する問題