跳到主要内容
← Ray Tracing

Ray Tracing

Ray Trace Begin

shader-learning 自学第 8 课:Ray Trace Begin

实时渲染 · 2D 片段 GLSL

第 8 课:Ray Trace Begin

实现

uniform vec2 iResolution;
uniform float iTime;

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

struct HitResult {
  vec3 pos;
  vec3 normal;
  bool hasHit;
  vec3 color;
};

HitResult hitSphere(
  vec3 rayOrigin,
  vec3 rayDir,
  vec3 sphereCenter,
  float sphereRadius
) {
  HitResult result;

  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) {
    result.hasHit = false;
    return result;
  }

  float t = min(-b - sqrt(D), (-b + sqrt(D))) / (2.0 * a);

  if (t < 0.0) {
    result.hasHit = false;
    return result;
  }

  result.hasHit = true;
  result.pos = rayOrigin + rayDir * t;
  result.normal = normalize(result.pos - sphereCenter);
  return result;
}

HitResult hitWorld(vec3 from, vec3 dir) {
  const vec3  sphereCenter0 = vec3(2.0, 0.0, -5.0);
  const float sphereRadius0 = 1.75;
  const vec3  sphereColor0 = vec3(0.8, 0.3, 0.3);

  vec3 sphereCenter1 = vec3(-12.0 + sin(iTime) * 2.0, 0.0, -5.0);
  const float sphereRadius1 = 10.0;
  const vec3  sphereColor1 = vec3(0.3, 0.3, 0.8);

    HitResult hit;

  hit = hitSphere(from, dir, sphereCenter0, sphereRadius0);
  if (hit.hasHit) {
    hit.color = sphereColor0;
    return hit;
  }

  hit = hitSphere(from, dir, sphereCenter1, sphereRadius1);
  if (hit.hasHit) {
    hit.color = sphereColor1;
    return hit;
  }

  return hit;
}

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 rayOrigin = vec3(0.0, 0.0, 3.0);
  vec3 rayDir = normalize(imagePlanePixel - rayOrigin);

  vec3 color = vec3(0.0);

  HitResult hit = hitWorld(rayOrigin, rayDir);
  if (hit.hasHit) {
    color = hit.color;

    HitResult hit2 = hitWorld(
      hit.pos + hit.normal * 0.01,
      reflect(rayDir, hit.normal)
    );

    if (hit2.hasHit) {
      color = (color + hit2.color) * 0.5;
    }
  }

  gl_FragColor = vec4(color, 1.0);
}