Description
使用 interface block 在 shader 的不同 stage 之间传递数据
Notes
vertex fetching
在 vertex shader 运行之前的一个 fixed-function stage
它会向 vertex shader 提供输入参数
这些变量就是 vertex attributes
storage qualifiers
在 OpenGL 中,我们使用 in
和 out
关键字,在声明变量时修饰存储类型
shader 中所有用 out
声明的变量,就会被发送到下一个 stage 中用 in
声明的同样变量名的变量中
Interface Bolocks
当需要在 shader stage 间传递的变量很多的时候,我们可以用 interface block
来打组,写法和 c 的 struct 很类似
1 2 3 4 5 6 7 8 9 10 11 |
// vertex shader out VS_OUT { vec4 color; } vs_out; // fragment shader in VS_OUT { vec4 color; } fs_in; |
glVertexAttrib
1 2 |
void glVertexAttrib4fv(GLuint index, const GLfloat *v) |
第 1 个参数 index
用于指定 attribute 的编号
第 2 个参数 v
是属性数据本身
每一次调用该函数,它都会向 OpenGL 更新 vertex attribute 数据
layout qualifier
用于在 vertex shader 中给 in
变量指定 vertex attribute 的编号
- Application:
glVertexAttrib4fv(0, data);
- Vertex Shader:
layout (location = 0 ) in vec4 offset;
这里后者的 location
就是前者的第1个参数 index
Project structure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Project Root ================ │ 03_data-between-shader-stages.cpp │ makefile ├───include │ ├───GL │ │ eglew.h │ │ glew.h │ │ glxew.h │ │ wglew.h │ └───GLFW │ glfw3.h │ glfw3native.h ├───lib │ glew32d.dll │ glfw3.dll └───shaders 03_data-between-shader-stages.frag 03_data-between-shader-stages.vert |
Codes
makefile
1 2 3 4 5 6 7 8 9 |
CC = g++ INCFLAGS = -I include LDFLAGS = -L lib -lglfw3 -lglew32d -lopengl32 all: $(CC) 03_data-between-shader-stages.cpp -o 03_data-between-shader-stages $(INCFLAGS) $(LDFLAGS) clean: @del *.o *.exe |
03_data-between-shader-stages.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
// 03_data-between-shader-stages.cpp #include <GL/glew.h> #include <GLFW/glfw3.h> #include <math.h> #include <iostream> GLuint rendering_program; GLuint vertex_array_object; static const GLchar* load_shader( const char* filename ) { FILE* infile = fopen( filename, "rb" ); if(!infile) return NULL; fseek( infile, 0, SEEK_END ); int size = ftell( infile ); rewind( infile ); GLchar* src = new GLchar[size+1]; fread( src, sizeof(GLchar), size, infile ); fclose( infile ); src[size] = 0; return const_cast<const GLchar*>(src); } void display(){ double curTime = glfwGetTime(); const GLfloat color[] = { (float)sin(curTime)*0.5f + 0.5f, (float)cos(curTime)*0.5f + 0.5f, 0.0f, 1.0f }; glClearBufferfv(GL_COLOR, 0, color); // Use the program object we created earlier for rendering glUseProgram(rendering_program); GLfloat vattr_offset[] = { (float)sin(curTime) * 0.5f, (float)cos(curTime) * 0.5f, 0.0f, 0.0f }; // Update the value of input attribute 0 glVertexAttrib4fv(0, vattr_offset); GLfloat vattr_color[] = { 0.023f, 0.75f, 0.652f, 1.0f }; glVertexAttrib4fv(1, vattr_color); glDrawArrays(GL_TRIANGLES, 0, 3); } void compile_shaders() { GLuint vertex_shader; GLuint fragment_shader; // Source code for vertex shader static const GLchar * vertex_shader_source = load_shader("shaders/03_data-between-shader-stages.vert"); // Source code for fragment shader static const GLchar * fragment_shader_source = load_shader("shaders/03_data-between-shader-stages.frag"); // Create and compile vertex shader vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); glCompileShader(vertex_shader); // Create and compile fragment shader fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); glCompileShader(fragment_shader); // Create program, attach shaders to it, and link it rendering_program = glCreateProgram(); glAttachShader(rendering_program, vertex_shader); glAttachShader(rendering_program, fragment_shader); glLinkProgram(rendering_program); // Delete the shaders as the program has them now glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); glCreateVertexArrays(1, &vertex_array_object); glBindVertexArray(vertex_array_object); } void shutdown() { glDeleteVertexArrays(1, &vertex_array_object); glDeleteProgram(rendering_program); glDeleteVertexArrays(1, &vertex_array_object); } int main() { GLFWwindow* window; glfwInit(); window = glfwCreateWindow(800, 600, "Hello, World!", NULL, NULL); glfwMakeContextCurrent(window); glewInit(); // startup compile_shaders(); while (!glfwWindowShouldClose(window)) { display(); glfwSwapBuffers(window); glfwPollEvents(); } shutdown(); glfwTerminate(); return 0; } |
03_data-between-shader-stages.vert
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// 03_data-between-shader-stages.vert #version 450 core // 'offset' and 'color' are input vertex attribute layout (location = 0) in vec4 offset; layout (location = 1) in vec4 color; // Declare VS_OUT as an output interface block out VS_OUT { vec4 color; } vs_out; void main(void) { // Declare a hard-coded array of positions const vec4 vertices[3] = vec4[3]( vec4(0.25, -0.25, 0.5, 1.0), vec4(-0.25, -0.25, 0.5, 1.0), vec4(0.25, 0.25, 0.5, 1.0) ); // Add 'offset' to our hard-coded vertex position gl_Position = vertices[gl_VertexID] + offset; // Output a fixed value for vs_color vs_out.color = color; } |
03_data-between-shader-stages.frag
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// 03_data-between-shader-stages.frag #version 450 core // Declare VS_OUT as an input interface block in VS_OUT { vec4 color; // Send color to the next stage } fs_in; // Output to the framebuffer out vec4 color; void main(void) { // Simply assign the color we were given by the vertex shader to our output color = fs_in.color; } |