Geometry Shaders And how to use them
OpenGL Pipeline (part of it) Vertex data Vertex shader Vertices Primitives Geometry shader Primitives Fragments Fragment shader Color Depth Stencil
Vertex Data Attributes Can be anything you want Typically includes Position Normals Colors Texture coordinates // Create vertices in memory struct vtx { vec3 pos; // Position vec2 uv; // Texture coordinate }; vector<vtx> verts = {... }; nverts = verts.size(); // Create a buffer and fill it with vertex data glgenbuffers(1, &vbuf); glbindbuffer(gl_array_buffer, vbuf); glbufferdata(gl_array_buffer, nverts * sizeof(vtx), verts.data(), GL_STATIC_DRAW); // Specify vertex format glenablevertexattribarray(0); glvertexattribpointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vtx), (GLvoid*)0); glenablevertexattribarray(1); glvertexattribpointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vtx), (GLvoid*)sizeof(vec3));
Vertex Shader Process each vertex Input is vertex attributes Output is whatever you want Built-in outputs vec4 gl_position #version 330 core // Input: vertex attributes layout(location = 0) in vec3 pos; layout(location = 1) in vec2 uv; // Per-vertex output smooth out vec2 fraguv; // Uniform values uniform mat4 xform; void main() { gl_position = xform * vec4(pos, 1.0); fraguv = uv; }
Geometry Shader
Fragment Shader Process each fragment Fragment pixel Input is the interpolated output from previous stage #version 330 core // Input: interpolated vertex output smooth in vec2 fraguv; // Color output out vec4 outcol; // Uniform values uniform sampler2d tex; void main() { outcol = texture(tex, fraguv); }
Interpolation Qualifiers smooth flat Fragment input is smoothly interpolated between vertices Fragment input is equal to output from provoking vertex noperspective Also smoothly interpolated, but in window-space
Fragment Shader Process each fragment Fragment pixel Input is the interpolated output from previous stage Output is color, depth, and stencil values Depth is implicitly written #version 330 core // Input: interpolated vertex output smooth in vec2 fraguv; // Color output out vec4 outcol; // Uniform values uniform sampler2d tex; void main() { outcol = texture(tex, fraguv); }
Geometry Shader Sits between vertex and fragment shaders Operates on primitives
The Primitives GL_POINTS GL_LINES GL_LINE_STRIP GL_LINE_LOOP v 1 v 2 v 3 v 1 v 2 v 3 v 4 v 1 v 2 v 3 v 4 v 1 v 2 v 3 v4 GL_TRIANGLES GL_TRIANGLE_STRIP GL_TRIANGLE_FAN v 6 v 6 v 3 v 4 v 1 v 2 v 3 v 4 v 5 v 1 v 2 v 3 v 4 v 5 v 5 v 2 v 1 v 6
#version 330 core Geometry Shader Sits between vertex and fragment shaders Operates on primitives Specify input and output primitive types Input is array of vertex outputs Output is per-vertex Interpolated as in vertex shader Emit vertices to define output primitives // Input and output primitive types layout(triangles) in; layout(triangle_strip, max_vertices = 5) out; // Per-vertex input in vec3 vcol[]; // Interpolated output smooth out vec3 fcol; void main() { gl_position = gl_in[0].gl_position; fcol = vcol[0]; EmitVertex(); gl_position = gl_in[1].gl_position; fcol = vcol[1]; EmitVertex(); gl_position = (gl_in[0].gl_position + gl_in[1].gl_position + gl_in[2].gl_position) / vec4(3); fcol = vec3(1.0, 1.0, 1.0); EmitVertex(); gl_position = gl_in[2].gl_position; fcol = vcol[2]; EmitVertex(); gl_position = gl_in[0].gl_position; fcol = vcol[0]; EmitVertex(); } EndPrimitive();
How to use geometry shaders for the project?
How to use geometry shaders for the project? For each triangle, output three quads Quads should face the camera (billboards) Assign texture coordinates to quad vertices Perform texture lookup in fragment shader
What about backfaces? Use depth testing Perform two passes // Enables depth testing glenable(gl_depth_test); First, draw the cube (without geometry shader), but output depth only Then, draw the cube again, with the geometry shader Quads that are in the back of the cube will be culled by the depth test Push all quads slightly towards the camera to avoid z-fighting
Depth-only rendering Modify the write mask Fragment shader is optional Depth is still written without a fragment shader // Disables writing any color channels glcolormask(gl_false, GL_FALSE, GL_FALSE, GL_FALSE); // Disables writing any depth values gldepthmask(gl_false);
Questions?