Deferred shading

My stupid deferred shading algorithm seems to come together piece by piece, need to fix some non trivial bugs in the math lib to get it to work.

I really like the idea of deferred shading, it's an example of wholesale / data driven algorithm. Just love it.

1.png

Pure shader renderer

Finally ported to OpenGL ES 2.0. It's a shader oriented renderer now.

The only difference between a desktop GLUT version and an OES embedded version is:

precision mediump float;

in fragment shader, otherwise the shader won't compile, no idea why.

1.png

瓶装青岛

Something is wrong with the current IORef implementation on iPhone. I decided not to invest further since tackling both graphics and sound synthesizing is a bit too much work.

I'm re-implementing the rika's rendering engine such that it's 100% OpenGL ES 2.0 and not backward compatible. The reason is that OpenGL ES 2.0 is a completely different interface than 1.1, keeping a separate rendering path is too much trouble.

I was able to implement the matrix and associated transformations in Haskell, the way ES 2.0 / GL 3.1 works is that there's no push / pop matrix anymore, perspective or frustum to setup projection matrix are also gone. The programmer is responsible to tell the graphics card which transformation matrix to use. It's actually more flexible than that, you can send arbitrary matrices to the graphics card (technically through uniform), and then in shader code utilize these matrices, one of them could be used as a model view matrix, another as projection matrix. Other variables could be passed as well, which could hold lighting position and material properties.

I wish someone could tell me these before.

Flashback, I wasn't able to take the computer graphics course in collage, it was a tough decision though: I had to pick an elective course either in music or programing since they are offered at the same time slot. I chose a music course, and never regretted it. But still this desire for computer graphics just kept haunting me, it's like this frikken awesome girlfriend I can never have. Finally enough is enough, I'll do it.

Anyway, for the audio part, I'll probably stick with OpenAL for simple playback and maybe pick up some Open Sound Control (OSC) code to interface it with some real synth. Still in control, yep, ... i hope.

Porting Rika to OpenGL ES

Huge pain, huge pain...

Since OpenGL ES 2.0 removes the fixed pipeline completely, many binding functions fails (silently) which caused me a lot of time to figure it out. Also the implementation I'm using is somewhat buggy, for example:

Array indices have to be defined in short, but the type that you tell drawElement what it is has to be unsigned short. wtf?

Another thing is that the array elements in use need to have the same length. This is not necessary in OpenGL.

Anyway, working on preliminary UIKit backend.

I'm still in no internet (ideally, practically: minimum internet) mode though, nowadays it seems to be the only way to get things done.

2.png

Rika game engine preview 4

Added features

  • real time XMonad style dynamic source recompilation
  • real time scene reload
  • real time shader reload
  • more blender integration (camera, partial lighting support)

Such a great trouble to write a game engine from scratch, pretty fun though.

Rika game engine preview 3

Toon Shader

6.vert

varying vec3 normal;

void main()
{
  normal = gl_NormalMatrix * gl_Normal;

  gl_Position = ftransform();
}

6.frat

varying vec3 normal;

void main()
{
  vec4 color;
  float intensity;
  vec3 n = normalize(normal);

  intensity = dot(vec3(gl_LightSource[0].position),n);

  if( intensity > 0.75 )
    color = vec4( 1.0, 0.5, 0.5, 1.0 );
  else if (intensity > 0.5)
    color = vec4( 0.6, 0.3, 0.3, 1.0 );
  else if (intensity > 0.25)
    color = vec4( 0.4, 0.2, 0.2, 1.0 );
  else
    color = vec4( 0.2, 0.1, 0.1, 1.0 );

  gl_FragColor = color;
}

6.png

Per vertex spot light

9.vert

void main()
{
    vec3 normal, lightDir;
    vec4 diffuse, ambient, globalAmbient, specular;
    float NdotL, NdotHV;

    normal = normalize(gl_NormalMatrix * gl_Normal);
    lightDir = normalize(vec3(gl_LightSource[0].position));
    NdotL = max(dot(normal, lightDir), 0.0);
    diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;

    if (NdotL > 0.0) {

        // normalize the half-vector, and then compute the 
        // cosine (dot product) with the normal
        NdotHV = max(dot(normal, gl_LightSource[0].halfVector.xyz),0.0);
        specular = gl_FrontMaterial.specular * gl_LightSource[0].specular * 
            pow(NdotHV,gl_FrontMaterial.shininess);
      }
    else {
      specular = vec4( 0.0, 0.0, 0.0, 0.0);
    }
    /* Compute the ambient and globalAmbient terms */
    ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
    globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient;

    gl_FrontColor =  NdotL * diffuse + globalAmbient + ambient + specular;

    gl_Position = ftransform();
}

9.frag

void main()
{
	gl_FragColor = gl_Color;
}

9.png

Per pixel spot light

10.vert

varying vec4 diffuse,ambient;
varying vec3 normal,lightDir,halfVector;

void main()
{ 
  /* first transform the normal into eye space and 
  normalize the result */
  normal = normalize(gl_NormalMatrix * gl_Normal);

  /* now normalize the light's direction. Note that 
  according to the OpenGL specification, the light 
  is stored in eye space. Also since we're talking about 
  a directional light, the position field is actually direction */
  lightDir = normalize(vec3(gl_LightSource[0].position));

  /* Normalize the halfVector to pass it to the fragment shader */
  halfVector = normalize(gl_LightSource[0].halfVector.xyz);

  /* Compute the diffuse, ambient and globalAmbient terms */
  diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
  ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
  ambient += gl_LightModel.ambient * gl_FrontMaterial.ambient;

  gl_Position = ftransform();
}

10.frag

varying vec4 diffuse,ambient;
varying vec3 normal,lightDir,halfVector;


void main()
{
  vec3 n,halfV;
  float NdotL,NdotHV;

  /* The ambient term will always be present */
  vec4 color = ambient;

  /* a fragment shader can't write a varying variable, hence we need
  a new variable to store the normalized interpolated normal */
  n = normalize(normal);

  /* compute the dot product between normal and ldir */
  NdotL = max(dot(n,lightDir),0.0);


  if (NdotL > 0.0) {
    color += diffuse * NdotL;
    halfV = normalize(halfVector);
    NdotHV = max(dot(n,halfV),0.0);
    color += gl_FrontMaterial.specular * 
        gl_LightSource[0].specular * 
        pow(NdotHV, gl_FrontMaterial.shininess);
  }

  gl_FragColor = color;
}

10.png

Per pixel point light

11.vert

varying vec4 diffuse,ambientGlobal,ambient;
varying vec3 normal,lightDir,halfVector;
varying float dist;

void main()
{ 
  vec4 ecPos;
  vec3 aux;

  normal = normalize(gl_NormalMatrix * gl_Normal);

  /* these are the new lines of code to compute the light's direction */
  ecPos = gl_ModelViewMatrix * gl_Vertex;
  aux = vec3(gl_LightSource[0].position-ecPos);
  lightDir = normalize(aux);
  dist = length(aux);

  halfVector = normalize(gl_LightSource[0].halfVector.xyz);

  /* Compute the diffuse, ambient and globalAmbient terms */
  diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;

  /* The ambient terms have been separated since one of them */
  /* suffers attenuation */
  ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
  ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient;

  gl_Position = ftransform();
}

11.frag

varying vec4 diffuse,ambientGlobal, ambient;
varying vec3 normal,lightDir,halfVector;
varying float dist;


void main()
{
  vec3 n,halfV,viewV,ldir;
  float NdotL,NdotHV;
  vec4 color = ambientGlobal;
  float att;

  /* a fragment shader can't write a varying variable, hence we need
  a new variable to store the normalized interpolated normal */
  n = normalize(normal);

  /* compute the dot product between normal and normalized lightdir */
  NdotL = max(dot(n,normalize(lightDir)),0.0);

  if (NdotL > 0.0) {

    att = 1.0 / (gl_LightSource[0].constantAttenuation +
        gl_LightSource[0].linearAttenuation * dist +
        gl_LightSource[0].quadraticAttenuation * dist * dist);
    color += att * (diffuse * NdotL + ambient);


    halfV = normalize(halfVector);
    NdotHV = max(dot(n,halfV),0.0);
    color += att * gl_FrontMaterial.specular * gl_LightSource[0].specular * 
            pow(NdotHV,gl_FrontMaterial.shininess);
  }

  gl_FragColor = color;
}

11.png