Miku2

deferred shading + per pixel - diffuse and specular lighting

still buggy :)

miku

miku

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

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

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

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

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

11.png

OpenGL Shaders

Migrating from fixed function to programmable pipeline is a huge pain in the ass. Every chapter of the Red book is marked as deprecated or removed in OpenGL 3.1.

Anyway, I'm starting to see the benefit of programmable pipeline; Rika's object system and rendering system needs to be re-factored to take advantage of shaders, e.g. there has to be a way for models / scripts to specify / pass arguments (uniforms in GL's context) into shader scripts and the type and number of arguments have to be dynamic.

I also find a gotta of STM, i.e. threads have to be event based, otherwise TVars could be modified too often or for too long such that a consumer threads will retry forever.