GLSL / WebGLでレイマーチング

現実逃避的にWebGLのGLSLでレイマーチングをやってみました。

下記のstartを押すとJavascriptからWebGLが作動します。 Chomium 40.0 とFirefox 34.0 で動作確認しています。 3D対応のグラフィックカードが必要です。

fragment shader

#line 1 0
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

uniform vec2 resolution;
uniform vec2 mouse;
uniform float time;

// =============================================================================
mat4 invertFrustum(float near, float far,
                   float focus, float aspect) {
  float C = 1.0 / (2.0 * far * near);
  return mat4(1.0 / focus, 0.0, 0.0, 0.0,
              0.0, aspect / focus, 0.0, 0.0,
              0.0, 0.0, 0.0, -1.0,
              0.0, 0.0, (near - far) * C, (near + far) * C);
}
// =============================================================================
vec4 screen2camera(vec2 p,
                   float near, float far,
                   float focus, float aspect) {
  return invertFrustum(near, far, focus, aspect) *
    vec4(p, (far+near)/(far-near)*near - 1.0, 2.0*near*far/(far-near)*near);
}
// =============================================================================
float distance(vec3 pos) {
  pos -= vec3(0.0, sin(time), -5.0 - sin(time));
  pos  = mod(pos, 4.0) - 2.0;
  return length(pos) - 1.0;
}
// =============================================================================
vec3 normal(vec3 pos) {
  const float d = 0.0001;
  const float z = 0.0;
  return normalize(vec3(
    distance(pos+vec3( d,  z,  z)) - distance(pos+vec3(-d,  z,  z)),
    distance(pos+vec3( z,  d,  z)) - distance(pos+vec3( z, -d,  z)),
    distance(pos+vec3( z,  z,  d)) - distance(pos+vec3( z,  z, -d))));
}
// =============================================================================
vec3 HSV2RGB(float h, float s, float v) {
  if (1.0 <= h || 1.0 <  s || 1.0 <  v) { return vec3(1.0, 1.0, 1.0); }
  if (0.0 >  h || 0.0 >  s || 0.0 >  v) { return vec3(0.0, 0.0, 0.0); }

  h *= 6.0;
  int   i = int(h);
  float f = h - float(i);
  float m = v * (1.0 - s);

  if      (0 == i) { return vec3(v, v * (1.0 - s * (1.0 - f)), m);      }
  else if (1 == i) { return vec3(v * (1.0 - s * f), v, m);              }
  else if (2 == i) { return vec3(m, v, v * (1.0 - s * (1.0 - f)));      }
  else if (3 == i) { return vec3(m, v * (1.0 - s * f), v);              }
  else if (4 == i) { return vec3(v * (1.0 - s * (1.0 - f)), m, v);      }
  else if (5 == i) { return vec3(v, m, v * (1.0 - s * f));              }
  else             { return vec3(0.0, 0.0, 0.0);                        }
}
// -----------------------------------------------------------------------------
vec3 HSV2RGB(vec3 hsv) {
  return HSV2RGB(hsv.x, hsv.y, hsv.z);
}
// =============================================================================
const int loop = 64;
// =============================================================================
void main(void) {
  vec2 uv = (2.0 * gl_FragCoord.xy / resolution - 1.0);
  vec3 ray = screen2camera(uv, 1.0, 40001.0,
                           2.1875, resolution.y / resolution.x).xyz;
  ray  = normalize(ray);
  float t = 0.0;
  float d = 0.0;
  vec3 pos;
  for(int i = 0; i < loop; ++i) {
    pos = t * ray;
    d = distance(pos);
    t += d;
  }

  if (abs(d) < 0.001) {
    vec3 n = normal(pos);
    vec3 h = normalize(n - ray);
    gl_FragColor = vec4(HSV2RGB(smoothstep(-1.0, 1.0, h)),
                        pow(1.0 - max(0.0, dot(-ray, n)), 2.0));
  } else {
    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
  }
}

下記サイトを参考にさせていただきました。

0 件のコメント:

コメントを投稿