Friday, March 1, 2013

using fragment shaders to draw shapes

Using openGL fragment shaders is an elegant way to draw shapes.
In this case it works by simply drawing a GL_QUAD (A simple unit square), but applying the shader on it to only selectively give certain coordinates in it color.

An openGL shader comes in two parts, a vertex shader and a fragment shader.

This is the vertex shader:

#version 120

// (c) 2013 Joost Yervante Damad
// License: GPL

// scale unit square to our rect size
// and move to it's origin

// input: (provided by calling program)
uniform vec2 size;  // size in x and y direction
uniform vec2 move;  // location

// output: (towards fragment shader)
varying vec2 pos2;    // adjusted position
varying vec2 size2;   // size in x and y direction

void main() {
  gl_FrontColor = gl_Color;
  vec4 vert = gl_Vertex;
  vert.x = vert.x * size.x;
  vert.y = vert.y * size.y;
  vec4 vert2 = vert;
  vert2.x += move.x;
  vert2.y += move.y;
  gl_Position = gl_ModelViewProjectionMatrix * vert2;
  pos2 = vec2(vert);
  size2 = size;

The role of the vertex shader is mainly to move to quad to the wanted coordinates and scale it to the size wanted. After that it is projected on our model.

And this is the fragment shader:

#version 120

// (c) 2013 Joost Yervante Damad
// License: GPL
// input provided by vertex shader
varying vec2 pos2;    // position
varying vec2 size2;   // size in x and y direction

void main() {
  // r: mininum size of straight side
  float q = sqrt(2.0)-1.0;
  float rx = size2.x * q;
  float ry = size2.y * q;
  float r = min(rx, ry);

  float shortest_size = min(size2.x, size2.y);
  float corner_size = (shortest_size - r) / 2;

  // a: minimum value where we want to cut off a corner
  float ax = (size2.x / 2) - corner_size;
  float ay = (size2.y / 2) - corner_size;

  // if we are in a corner zone:
  if (abs(pos2.x) > ax && abs(pos2.y) > ay) {
    // abs position within corner
    float x = abs(pos2.x) - ax;
    float y = abs(pos2.y) - ay;
    # are we inside the triangle ?
    if (x + y < corner_size) {
      gl_FragColor = gl_Color;
  // else we're in a normal square zone:
  } else {
    glFragColor = gl_Color;

The fragment shader is where it is decided for individual coordinates if they should be drawn or not.
The example here draws a nice rectangle with octagon style cut-off corners.

No comments: