Sunday 27 January 2013

Procedural cube in a vertex shader

With OpenGL3+ and shader tricks, one can procedurally generate fullscreen quads or implicit surfaces. Here's another little trick I found to draw a unit sized cube with a single draw call (a triangle strip with 14 vertices) without any vertex or index buffers. The idea is to use the gl_VertexID variable to extract the positions of the vertices.

Here are the shaders (which I now use to render my skyboxes)
Vertex Shader:
#version 330

uniform mat4 uModelViewProjection;

out vec3 vsTexCoord;
#define oTexCoord vsTexCoord

void main() {
 // extract vertices
 int r = int(gl_VertexID > 6);
 int i = r==1 ? 13-gl_VertexID : gl_VertexID;
 int x = int(i<3 || i==4);
 int y = r ^ int(i>0 && i<4);
 int z = r ^ int(i<2 || i>5);

 // compute world pos and project
 const float SKY_SIZE = 100.0;
 oTexCoord = vec3(x,y,z)*2.0-1.0;
 gl_Position = uModelViewProjection *
               vec4(oTexCoord*SKY_SIZE,1);
}

Fragment shader (which is pretty standard):
#version 330

uniform samplerCube sSky;

in vec3 vsTexCoord;
#define iTexCoord vsTexCoord
layout(location=0) out vec4 oColour;

void main() {
 oColour = texture(sSky, normalize(iTexCoord));
}  

And the client code:
// init
glBindVertexArray(emptyVertexArray);
glBindVertexArray(0);

// render
glBindVertexArray(emptyVertexArray);
glUseProgram(skyboxProgram);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 14);


No comments:

Post a Comment