index.html

html · 205 lines · part of Raytracer 006 - Even more spheres · raw

<html>
<title>WebGL Fragment Shader Canvas</title>

<script src="webgl_fragment_framework.001.js"></script>

<script id="shader" type="x-shader/x-fragment">

  #ifdef GL_ES
  precision mediump float;
  #endif

  varying vec3 vPosition;
  uniform float uTime;
  uniform vec2 uMousePos;

  vec3 ray;
  vec3 dir;

  vec4 sphere_pos[16];
  vec3 sphere_col[16];

  float intersectSphere( in vec3 ray, in vec3 dir, in vec3 sphere_pos, in float radius )
  {
    float x = sphere_pos.x;
    float y = sphere_pos.y;
    float z = sphere_pos.z;

    float a, b, c, d, t1, t2;

    a = dir.x * dir.x + dir.y * dir.y + dir.z * dir.z;
    b = 2.0 * (dir.x * (ray.x - x) + dir.y * (ray.y - y) + dir.z * (ray.z - z));
    c = (ray.x - x) * (ray.x - x) + (ray.y - y) * (ray.y - y) + (ray.z - z) * (ray.z - z) - radius * radius;
    d = b * b - 4.0 * a * c;

    if( d <= 0.0 ) return 0.0;

    d = sqrt(d);

    t2 = (-b + d) / (2.0 * a);
    t1 = (-b - d) / (2.0 * a);

    if( t1 > t2 ) return t2;
    return t1;
  }

  int intersect( in vec3 ray, in vec3 dir, out vec3 col, out vec3 pos, out vec3 normal, out vec3 reflection )
  {
    float max_t = 9999999.0;
    int found_i = -1;

    for( int i = 0; i<16; i++ )
    {
      float t = intersectSphere( ray, dir, sphere_pos[i].xyz, sphere_pos[i].w );

      if( t > 0.0 && t < max_t )
      {
        max_t = t;
        found_i = i;
      }
    }

    if( found_i == -1 )
    {
      col = vec3( 0.0, 0.0, 0.0 );
      return -1;
    }

    for( int i = 0; i<16; i++ )
    {
      if( found_i == i )
      {
        pos = ray + max_t * dir;

        normal = (pos - sphere_pos[i].xyz) / sphere_pos[i].w;
        reflection = dir - 2.0*normal*dot( dir, normal );

        col = sphere_col[i];
      }
    }

    return found_i;
  }

  bool intersect_shadow( in vec3 ray, in vec3 dir )
  {
    for( int i = 0; i<16; i++ )
    {
      float t = intersectSphere( ray, dir, sphere_pos[i].xyz, sphere_pos[i].w );

      if( t > 0.0 )
      {
        return false;
      }
    }
    return true;
  }

  void main(void)
  {
    ray = vec3( 0.0, 0.0, 0.0 );
    dir = normalize( vPosition );

    vec3 final_col;

    vec3 col;
    vec3 pos;
    vec3 normal;
    vec3 reflection;

    vec3 light = vec3( -0.5, 2.0, 0 );

    for( int i=0; i<16; i++ )
    {
      float ii = float(i);

      float x = 1.3*sin(ii*0.313 + uTime*(0.716762));
      float y = 1.3*sin(ii*0.453 + uTime*(0.38467));
      float z = 3.0 + 1.3*sin(ii*0.73 + uTime*(0.9112));
      float w = 0.3 + 0.1*sin(ii*0.43 + uTime*(0.1112));

      sphere_pos[i] = vec4( x, y, z, w );
      sphere_col[i] = vec3( 1.0-ii/12.0, 1.0-ii/6.0, 0.1 + ii/12.0 );
    }

    //  Intersect first ray

    int sphere_index = intersect( ray, dir, col, pos, normal, reflection );

    if( sphere_index == -1 )
    {
      final_col = vec3( 0.25 ) * dir.z;
    }
    else
    {
      //  Calculate colour of surface

      vec3 light_dir = light - pos;

      if( intersect_shadow( pos+light_dir*0.0000001, light_dir ) )
      {
        light_dir = normalize( light_dir );
        col *= max( dot( normal, light_dir ), 0.0 )*0.8 + 0.2;
        float phong = pow( max( dot( reflection, light_dir ), 0.0 ), 17.0 );
        col = vec3( 1.0, 1.0, 1.0 ) * phong + col*(1.0-phong);
      }
      else
      {
        col *= 0.2;
      }

      //  Do 1 level of reflection

      final_col = col;

      sphere_index = intersect( pos+reflection*0.0000001, reflection, col, pos, normal, reflection );

      if( sphere_index >= 0 )
      {
        vec3 light_dir = light - pos;

        if( intersect_shadow( pos+light_dir*0.0001, light_dir ) )
        {
          light_dir = normalize( light_dir );
          col *= max( dot( normal, light_dir ), 0.0 )*0.8 + 0.2;
        }
        else
        {
          col *= 0.2;
        }

        final_col = final_col * 0.85 + col;// * 0.15;
      }

    }

    gl_FragColor = vec4( final_col, 1.0 );
  }

</script>

<body onload="webgl_init( 'canvas', 'shader', 'status' )" bgcolor="#000000">

<table cellspacing="0" cellpadding="0" border="0" width="100%" height="100%"><tr><td align="center" valign="middle">
<table cellspacing="0" cellpadding="0" border="0" width="320">
  <tr>
    <td style="padding:8px;background:#555555;color:#FFFFFF;font-family:arial;font-size:11px;font-weight:bold">
      <div>WebGL Fragment Shader Raytracer - 16 Spheres - Per pixel lighting, shadow and reflection</div>
    </td>
  </tr>
  <tr>
    <td><canvas id="canvas" width="320" height="320" style="border:5px solid #FFFFFF"></canvas></td>
  </tr><tr>
    <td style="padding:8px;background:#555555;color:#FFFFFF;font-family:arial;font-size:11px;font-weight:bold">
      <div id="status">&nbsp;</div>
    </td>
  </tr>
</table>
</td></tr></table>


</body>
</html>