2016-09-28 78 views
1

我有一個計算着色器的例子,生成一個片段着色器然後渲染到一個佔用了整個窗口的四邊形的紋理。這個紋理如何傳遞給片段着色器?

在片段着色器代碼中,我看到了統一的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()'pair *在那裏,但我沒有看到它。 – genpfault

+0

是的..這段代碼是從OpenGL的「紅色書」中修改的。我真的很討厭這本書。他們在一些地方使用宏和輔助函數,爲了清晰起見,這是一個非常糟糕的主意,他們的解釋非常糟糕。看到第12章的例子:https://github.com/openglredbook/examples/tree/master/src – Maxthecat

回答

1

這是工作的主要原因是,在着色均勻變量有默認值爲0。從GLSL 4.5規範,4.3.5節:

所有統一變量是隻讀並且在鏈接時或通過API在外部初始化。鏈接時初始值是變量初始值設定項的值(如果存在),如果沒有初始值設定項,則爲0。

您需要了解下一部分是採樣變量的值是你想從採樣紋理單元。非常類似地,圖像變量的值是用於圖像訪問的圖像單元

將這兩塊組合在一起,因爲您沒有爲這些統一變量設置值,片段着色器中的採樣器將訪問綁定到紋理單元0的紋理。計算着色器中的圖像將訪問綁定到圖像單元0

幸運的是,這正是你需要的東西:

  • 因爲你從來沒有設置活動紋理單元glActiveTexture(),這一呼籲:

    glBindTexture(GL_TEXTURE_2D, mytexture); 
    

    將紋理綁定到紋理單元0,這意味着它將在片段着色器中進行採樣。

  • 在你的電話結合的圖像:

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

    傳遞0作爲第一個參數,指定要綁定到圖像單元。結果,計算着色器將訪問此圖像。

恕我直言,總是設置統一變量的值是一種很好的風格,即使默認值可能足夠。這使得代碼更具可讀性,並且一旦使用了多個紋理/圖像,設置統一值將是必不可少的。所以爲了清楚起見,我想有這樣的事情在你的代碼:

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

注意,glUniform1i()調用需要進行,而相應的程序被激活。

+0

啊,認爲這是一種默認狀態! – genpfault

+0

Reto,你太棒了!感謝您的解釋。 – Maxthecat

相關問題