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