Attributeless Vertex Shader with OpenGL
When doing fullscreen shader passes with openGL I often use a simple technique
called "Attribute-less rendering" as described by Robert on his blog.
In short this means you store the vertices that you want to render
in your vertex shader using a const vec2
array and use the gl_VertexID
variable to access the correct element from this array. Great thing about
using this technique is that you don't need to setup an VBO or setup the
offsets for a Vertex Array Object (VAO).
Recently I want to use this technique to draw simple 2D textures for my Video Capture library. Though I had to find a way to specify the (x,y) offsets and the dimensions where I wanted to draw the texture.
To solve this, I added a vec4 u_pos
uniform that holds the offsets in the (x,y)
elements and the scale in the (z,w) elements. The values of this u_pos
uniform
are percentages for of the current viewport dimensions.
Lets say the viewport is 800 x 600. I store a inv_win_w
and inv_win_h
that I use
to convert the x/y/w/h values to percentages:
void CaptureGL::resize(int winW, int winH) { inv_win_w = 1.0 / winW; inv_win_h = 1.0 / winH; }
Then whenever you want to draw someting in 2D at a specific location and dimension,
I set the vec4 u_pos
uniform values like:
void CaptureGL::draw(int x, int y, int w, int h) { GLint u_pos = glGetUniformLocation(prog, "u_pos"); // NOTE: do this somewhere in your constructor and keep a member glUniform4f(u_pos, x * inv_win_w, y * inv_win_h, w * inv_win_w, h * inv_win_h ); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); }
The shaders that backs up this technique is pasted below. We first offset the
vertex position using the u_pos.x
and u_pos.y
after changing the values to
Normalized Device Context (NDC) ranges (-1, 1). Then we apply the scaled vertex
position.
/* u_pos.x = X position in percentage of viewport 0-1. 0% means -1.0 u_pos.y = Y position in percentage of viewport 0-1. 0% means -1.0 u_pos.z = WIDTH scale in percentage of viewport. u_pos.w = HEIGHT scale in percentage of viewport. */ static const char* CAPTURE_GL_VS = "" "#version 330\n" "uniform vec4 u_pos; " "" "const vec2 pos[] = vec2[4](" " vec2(0.0, 1.0), " " vec2(0.0, 0.0), " " vec2(1.0, 1.0), " " vec2(1.0, 0.0) " ");" "" " const vec2[] tex = vec2[4]( " " vec2(0.0, 0.0), " " vec2(0.0, 1.0), " " vec2(1.0, 0.0), " " vec2(1.0, 1.0) " ");" "" "out vec2 v_texcoord; " "" "void main() { " " vec2 p = pos[gl_VertexID]; " " vec2 offset = vec2(u_pos.x * 2.0 - 1.0, u_pos.y * 2.0 - 1.0); " " vec2 scale = vec2(u_pos.z * p.x * 2.0, u_pos.w * p.y * 2.0); " " gl_Position = vec4(offset.x + scale.x, " " offset.y + scale.y, " " 0.0, 1.0);" " v_texcoord = tex[gl_VertexID];" "}" "";