index.html

html · 220 lines · part of Raytracer 008 - Bumpy Textures · 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[3];
  vec3 sphere_col[3];

  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<3; i++ )
    {
      float t = intersectSphere( ray, dir, sphere_pos[i].xyz, sphere_pos[i].w );

      if( t > 0.0001 && 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<3; 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<3; 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)
  {
    sphere_pos[0] = vec4( -1.0, 0.0, 4.0, 0.8 );
    sphere_col[0] = vec3( 0.5, 0.0, 1.0 );

    sphere_pos[1] = vec4( 1.0, 0.5, 3.0, 0.9 );
    sphere_col[1] = vec3( 1.0, 0.75, 0.0 );

    sphere_pos[2] = vec4( 0.2, -0.75, 3.5, 1.0 );
    sphere_col[2] = vec3( 0.75, 1.0, 0.0 );

    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, 3.0, 2.0 );

    for( int i=0; i<3; i++ )
    {
      float x = sphere_pos[i].x + 1.3*sin(sphere_pos[i].y*2.13 + uTime*(0.6762+sphere_pos[i].z*0.163));
      float y = sphere_pos[i].y + 1.3*sin(sphere_pos[i].z*1.13 + uTime*(0.8467+sphere_pos[i].x*0.193));
      float z = sphere_pos[i].z + 0.3*sin(sphere_pos[i].x*4.13 + uTime*(1.1112+sphere_pos[i].y*0.183));

      sphere_pos[i] = vec4( x, y, z, sphere_pos[i].w );
    }

    //  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
    {
      //  Perturb normal and direction vector

      float f = sin(normal.x*5.918+13.841)*0.43 + sin(normal.y*11.8218+7.41)*0.21 + sin(normal.z*16.821+11.841)*0.34;
      float g = sin(normal.y*2.167+14.841)*0.13 + sin(normal.z*18.1298+5.98)*0.17 + sin(normal.x*15.231+12.321)*0.70;
      float h = f*g;//sin(normal.z*3.324+11.312)*0.22 + sin(normal.x*13.4241+5.12)*0.34 + sin(normal.y*19.212+17.424)*0.51;

      normal += 0.1 * vec3( f, g, h );

      reflection = dir - 2.0*normal*dot( dir, normal );

      //  Calculate colour of surface

      vec3 light_dir = light - pos;

      if( intersect_shadow( pos+light_dir*0.0000001, light_dir+normal ) )
      {
        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;
      }

      final_col = col + 0.1 * vec3( sin( dot( pos, pos ) ) );

      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;
          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;
        }

        final_col = final_col*0.75 + col*0.25;
      }
    }

    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="640">
  <tr>
    <td style="padding:8px;background:#555555;color:#FFFFFF;font-family:arial;font-size:11px;font-weight:bold">
      <div>WebGL Fragment Shader Raytracer - 3 Spheres - Bumpy</div>
    </td>
  </tr>
  <tr>
    <td><canvas id="canvas" width="640" height="640" 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>