Programowanie Gier -> Wykład: Shadery GLSL (OpenGL Shading Language)

Kawałki poniższego streszczenia skopiowałem z własnego dawnego opowiadania o shaderach na seminarium z grafiki. Tam też znajdziecie nieco linków i uwag o starych shaderach asemblerowych (ARB), które są już generalnie historią i na które nie było czasu w trakcie wykładu.

1. What are shading languages, in short

OpenGL program is basically (note: forget for a sec that in OpenGL 3.x glBegin/End is no more)

  glLoadMatrix, glMultMatrix (and shortcuts like glLoadIdentity, glTranslate, glScale...)

  glBegin(...)

    gl(... some vertex attrib, like glTexCoord, glMultiTexCoord, glMaterial...)
    glVertex(...);

    gl(... some vertex attrib, like glTexCoord, glMultiTexCoord, glMaterial...)
    glVertex(...);

    gl(... some vertex attrib, like glTexCoord, glMultiTexCoord, glMaterial...)
    glVertex(...);

    ....

  glEnd();

For each glVertex, some work is done.

  1. transform it by projection * modelview matrices,
  2. calculate per-vertex values like color from lighting
      color =
        material emission +
        scene ambient * mat ambient +
        for each light: (
          light ambient * mat ambient +
          light diffuse * mat diffuse * diffuse factor +
          light specular .... etc.).
    

This work may be replaced by vertex shader, to transform in any way we like, calculate color by any equation we like (using OpenGL lights parameters or not) and some other.

When vertexes make primitives, each primitive is checked (for backface culling) and is rasterized. Note that some vertexes are shared by more than one primitive, e.g. triangle strips, fans etc. The idea of these primitives is that the per-vertex work (whether fixed-function or vertex shader) is done only once, and results are reused.

Fragment = same thing as pixel by default, although some operations like glPixelZoom change this correspondence. Rasterization calculates coordinates of fragments, each fragment gets as input some interpolated values (for example, color results of lighting calculation from paragraph above are interpolated for fragment).

Then for each fragment some work is done. In fixed-function pipeline, this is mostly to mix color with textures (all the multitexture operations set up by glTexEnv are done here) and apply fog parameter. This work may be replaced by fragment shader.

There are also geometry shader, for later...

Notes:

2. Język GLSL

Język C-podobny. Poniżej garść faktów i specyfiki GLSL, zakładam że elementarny C znamy *wszyscy* :)

Mamy "void main(void)" jaką główne funkcje dla shadera (vertex, albo fragment).

Vertex shader przede wszystkim musi ustawić gl_Position.

Fragment shader przede wszystkim musi ustawić gl_FragColor albo gl_FragData (dla renderowania do wielu buforów). Ale tylko jedno, i dokładnie jedno z nich... W GLSL > 1.20 są deprecated, najlepiej je zadeklarować samemu.

Basic demos w trakcie opowiadania:

Typy:

Rodzaje zmiennych, przekazywanie do/z shadera:

Operatory:

Control flow:

Built-in functions: browse.

Mamy preprocesor.

Podsumowanie ważnych IMO rzeczy deprecated w 1.30, removed w 1.40:

3. API OpenGLa do shaderów

(Krótko i skrótowo, bo to wszystko naturalne):

  - OpenGL API for shaders (with OpenGL 2.0 standard functions,
    there are mostly equivalent functions for ARB extension):

    /* Preparation: */

    prog := glCreateProgram();

    shader := glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(shader, ... pass strings containing shader source ...);
    glCompileShader(shader);
    glAttachShader(program, shader);

    (same for GL_FRAGMENT_SHADER)

    glLinkProgram(program);


    /* Usage: */

    glUseProgram(program);
    ....
    glUseProgram(0); // back to fixed-function pipeline

    /* End: */

    /* glDetachShader, glDeleteShader(...) if you like to be clean */
    glDeleteProgram(prog);

    More details:
    - after compilation, you should check
      glGetShaderiv(shader, GL_COMPILE_STATUS, ...)
      eventual error message is in glGetShaderInfoLog

    - after linking, you should check
      glGetProgramiv(program, GL_LINK_STATUS, ...)
      eventual error message is in glGetProgramInfoLog

- uniform variables (glGetUniformLocation, glUniform)
  (settable per-object, that is only outside glBegin / glEnd)

- attribute variables (glGetAttribLocation, glVertexAttrib)
  (settable per-vertex, that is possibly within glBegin / glEnd)

Patrz glshaders.pas który opakowuje to w elegancką klasę TGLSLProgram (pokazuje jak używać i GL core 2.0 i rozszerzeń ARB do GLSL).

4. Demos

Trochę moich prostych ale już bardziej użytecznych:

Trochę moich (nieznacznie) mniej prostych:

Dość moich, teraz coś z http://www.humus.name/: