跳到主要内容
← Ray Tracing

Ray Tracing

Sphere Normal

shader-learning 自学第 7 课:Sphere Normal

实时渲染 · 2D 片段 GLSL

第 7 课:Sphere Normal

实现

uniform vec2 iResolution;
uniform float iTime;

const vec3  sphereCenter = vec3(0.0, 0.0, -5.0);
const float sphereRadius = 2.0;
const vec3  sphereColor = vec3(0.8, 0.3, 0.3);

const vec3  rayOrigin = vec3(0.0, 0.0, 3.0);

float sphereIntersect(
  vec3 rayOrigin,
  vec3 rayDir,
  vec3 sphereCenter,
  float sphereRadius
) {
  vec3 L = rayOrigin - sphereCenter;

  float a = 1.0;
  float b = 2.0 * dot(L, rayDir);
  float c = dot(L, L) - sphereRadius * sphereRadius;

  float D = b * b - 4.0 * a * c;

  if (D < 0.0) return 0.0;

  return min(-b - sqrt(D), (-b + sqrt(D))) / (2.0 * a);
}

void main() {
  vec2 uv = gl_FragCoord.xy / iResolution.xy;
  uv = (uv * 2.0) - 1.0;
  uv.x *= iResolution.x / iResolution.y;

  vec3 imagePlanePixel = vec3(uv.x, uv.y, 0.0);
  vec3 rayDir = normalize(imagePlanePixel - rayOrigin);

  float t = sphereIntersect(
    rayOrigin,
    rayDir,
    sphereCenter,
    sphereRadius
  );
  vec3 hitPoint = rayOrigin + rayDir * t;
  t = clamp(t, 0.0, 1.0);

  vec3  lightPos = vec3(cos(iTime) * 10.0, 5.0, sin(iTime) * 10.0);
  vec3  lightDir = normalize(lightPos - hitPoint);
  float ambient = 0.2;

  vec3 N = normalize(sphereCenter - hitPoint);
  float diffuse = max(dot(N, -lightDir), 0.0);

  gl_FragColor = vec4(sphereColor * t * (ambient + diffuse), 1.0);
}