Каустики та фокусування хвиль

🔭 Оптика ⏱ ≈ 9 хв читання Середній рівень
Геометрична оптика Заломлення Закон Снеля WebGL Caustics

Каустики — ті яскраві хвилясті узори на дні басейну або під склянкою з водою. Вони виникають, коли промені світла фокусуються на поверхні після проходження крізь неоднорідне середовище. За ними стоїть повна картина оптики — від геометричного трасування до хвильової дифракції.

1. Геометрична vs хвильова оптика

Оптика розглядає поширення електромагнітного випромінювання. Залежно від масштабу явища використовуються два апарати:

Геометрична оптика

Λ ≪ характерний розмір. Світло описується променями — прямолінійними траєкторіями, що змінюють напрямок на межах розділу. Дифракція знехтувана.

Хвильова оптика

Λ ~ розміру деталей. Важливі інтерференція та дифракція. Описується рівнянням Гельмгольца: ∇²E + k²E = 0, де k = 2π/λ.

Зв'язок між ними

Геометрична оптика — граничний випадок хвильової при λ → 0. Каустики — місце, де геометрична оптика "ламається" через нескінченну густину променів, а хвильова дає скінченну інтенсивність.

Оптичний шлях

Принцип Ферма: промінь іде шляхом, що мінімізує оптичний шлях OPL = ∫n ds. З нього випливають закони відбиття та заломлення.

Для каустик у воді геометрична оптика чудово описує яскраві плями — хвильові ефекти дають тонкі корекції на краях. Ми почнемо з геометричного підходу.

2. Закон Снеля та показник заломлення

Коли промінь перетинає межу між середовищами з показниками заломлення n₁ і n₂, кут заломлення θ₂ визначається законом Снеля:

n₁ sin θ₁ = n₂ sin θ₂

Для води: n_вода ≈ 1.333, n_повітря = 1.000

При θ₁ = 45°: sin θ₂ = sin 45° / 1.333 ≈ 0.530 → θ₂ ≈ 32°

Векторна форма закону Снеля

Для тривимірного трасування зручно векторне формулювання. Нехай — одиничний вектор падаючого променя, — нормаль поверхні (назовні), η = n₁/n₂:

cosθ₁ = −d̂ · n̂

cosθ₂ = √(1 − η²(1 − cos²θ₁))

d_refr = η·d̂ + (η·cosθ₁ − cosθ₂)·n̂

Якщо підкорінний вираз від'ємний — повне внутрішнє відбиття: промінь не виходить з середовища. Критичний кут: sin θ_c = n₂/n₁.

Для води θ_c = arcsin(1/1.333) ≈ 48.6°. Риба, дивлячись вгору, бачить все "небо" у конусі з кутом 48.6° від вертикалі — window of Snell.

3. Тонка лінза та формула лінзи

Ідеальна тонка лінза фокусує паралельний пучок у точку. Її оптична сила P = 1/f (діоптрії), де f — фокусна відстань. Зв'язок між відстанями предмета та зображення задається формулою тонкої лінзи:

1/f = 1/d_o + 1/d_i

Збільшення: M = −d_i / d_o

За формулою лінзмейкерів: 1/f = (n−1)(1/R₁ − 1/R₂)

Знаки та конвенції

ВеличинаПозитивне значенняНегативне значення
fЗбираюча лінзаРозсіювальна лінза
d_oРеальний предмет (зліва)Віртуальний предмет
d_iРеальне зображення (справа)Віртуальне зображення (зліва)
MПряме зображенняПеревернуте зображення

Аберації заважають ідеальному фокусу

Реальна лінза страждає від аберацій: сферичної (крайові промені фокусуються ближче до лінзи), хроматичної (різна фокусна відстань для λ), дисторсії. Саме сферична аберація породжує одну з найчастіших форм каустик — зосереджений "хвіст" яскравості вздовж осі.

4. Каустики: поверхня фокусування

Каустика (від грец. καυστικός — палюча) — це огинаюча сімейства заломлених або відбитих променів. Промені не перетинаються в одній точці через неідеальність поверхні — вони утворюють caustic surface у просторі, а перетин цієї поверхні з екраном дає яскравий візерунок.

Математика: огинаюча сімейства ліній

Сімейство ліній Φ(x, y, t) = 0, де t — параметр (наприклад, координата точки падіння на поверхню). Огинаюча задається системою:

Φ(x, y, t) = 0

∂Φ/∂t = 0

Розв'язок (x(t), y(t)) — і є каустика

Яскравість каустики

Інтенсивність I у точці на екрані пропорційна густині потоку фотонів. Якщо d_ω — тілесний кут пучка, а dA — площа плями на екрані, то I ~ dΩ/dA. На каустиці dA → 0 (промені "стискуються"), тому I → ∞ у геометричній оптиці. Хвильова оптика дає скінченний пік — фігуру Ері з характерним масштабом Δx ~ (λ·R)^(2/3).

Класифікація за теорією катастроф

Fold caustic

Один параметр. Типовий вигляд — яскрава лінія. Найпоширеніша форма каустик у воді (зморшки поверхні).

Cusp caustic

Два параметри. Загострений хвіст. Виникає біля кута плавального басейну або на дні під кутом огляду.

Swallowtail

Три параметри. Рідша форма, але видна у фокальних областях при великих амплітудах хвилі поверхні.

Elliptic umbilic

Тривимірні каустики дзеркал. Видно в чашці кави (catacaustic) або на циліндричній поверхні.

5. Коефіцієнти Френеля: відбиття та пропускання

На межі розділу частина енергії відбивається, частина проходить далі. Для монохроматичної EM-хвилі рівняння Максвелла дають точний результат — формули Френеля для s- та p-поляризацій:

r_s = (n₁cosθ₁ − n₂cosθ₂) / (n₁cosθ₁ + n₂cosθ₂)

r_p = (n₂cosθ₁ − n₁cosθ₂) / (n₂cosθ₁ + n₁cosθ₂)

R_s = |r_s|², R_p = |r_p|²

T_s = 1 − R_s, T_p = 1 − R_p (за збереженням енергії)

Апроксимація Шліка

У рендерингу часто використовують дешеву апроксимацію (Schlick 1994) для спектрального відбиття при нормальному падінні F₀ = ((n₁−n₂)/(n₁+n₂))²:

F(θ) ≈ F₀ + (1 − F₀)(1 − cosθ)⁵

Для вода/повітря: F₀ = ((1 − 1.333)/(1 + 1.333))² ≈ 0.020

Вода при нормальному падінні відбиває лише 2% світла. При θ → 90° (косе падіння) F → 1 — дзеркальна вода на горизонті.

6. Каустики у воді: хвиляста поверхня

Поверхня басейну описується висотою h(x, y, t). Промінь від сонця спрямований вертикально вниз, нормаль до поверхні відхилена на кут, що залежить від градієнта h. Заломлений промінь потрапляє в іншу точку дна — це і є каустичний узор.

Зміщення точки попадання

Для малих нахилів (∂h/∂x ≪ 1) можна лінеаризувати. Нехай поверхня має нахил ∂h/∂x у напрямку x. Нормаль: n̂ ≈ (−∂h/∂x, −∂h/∂y, 1). Відхилення заломленого вертикального променя від вертикалі:

Δx ≈ d · (n_вода − 1) · ∂h/∂x

Δy ≈ d · (n_вода − 1) · ∂h/∂y

де d — глибина води

Якщо ∂Δx/∂x + ∂Δy/∂y < 0, промені сходяться — виникає яскрава пляма. Якщо > 0 — розходяться, пляма темна. Таким чином, інтенсивність на дні пропорційна оберненому значенню якобіана відображення поверхні на дно:

I ∝ 1 / |J|, де J = ∂(Δx, Δy)/∂(x, y)

J ≈ 1 + d·(n−1)·∇²h

Каустика: де J = 0 (тобто ∇²h = −1/(d(n−1)))

Лапласіан висоти ∇²h визначає кривизну поверхні. Каустика формується там, де гребінь хвилі має достатньо велику від'ємну кривизну на опуклих ділянках.

7. Рендеринг каустик: env-map + refraction map

Є два підходи до рендерингу каустик у WebGL у реальному часі.

Метод 1: Forward photon mapping

Стріляємо N фотонів від джерела (сонця), заломлюємо через поверхню, зберігаємо точки попадання на дно в текстуру-акумулятор. Розмивання через gaussian blur дає реалістичний результат. O(N) операцій за кадр.

Метод 2: Screen-space refraction map (рекомендований)

// Vertex shader — генерація caustic UV
precision highp float;
uniform sampler2D uHeightMap;   // висота поверхні
uniform float uDepth;            // глибина басейну
uniform float uEta;              // n_air / n_water = 0.750
attribute vec2 aTexCoord;

varying vec2 vCausticUV;

vec3 refractRay(vec3 d, vec3 n, float eta) {
  float cosi = dot(-d, n);
  float sin2t = eta * eta * (1.0 - cosi * cosi);
  if (sin2t > 1.0) return reflect(d, n); // TIR
  return eta * d + (eta * cosi - sqrt(1.0 - sin2t)) * n;
}

void main() {
  vec2 uv = aTexCoord;
  float h = texture2D(uHeightMap, uv).r;

  // Наближення нормалі через сусідні пікселі (texel size = 1/512)
  float ts = 1.0 / 512.0;
  float hx = texture2D(uHeightMap, uv + vec2(ts, 0.)).r;
  float hy = texture2D(uHeightMap, uv + vec2(0., ts)).r;
  vec3 norm = normalize(vec3(h - hx, h - hy, ts * 20.0));

  vec3 sunDir = vec3(0.0, 0.0, -1.0); // вертикальне сонце
  vec3 refracted = refractRay(sunDir, norm, uEta); // 0.750 = 1/1.333

  // Проецюємо на дно (уздовж refracted напрямку)
  float t = (h - uDepth) / refracted.z;  // дно на z = -depth
  vec2 hit = uv + refracted.xy * t;
  vCausticUV = hit;
  gl_Position = vec4(aTexCoord * 2.0 - 1.0, 0.0, 1.0);
}
// Fragment shader — нанесення фотонних плям
precision highp float;
varying vec2 vCausticUV;

void main() {
  // Кожен тексель (фотон) пише у свій цільовий пікс
  // Використовуємо адитивний blending (ONE, ONE)
  gl_FragColor = vec4(1.0, 0.95, 0.85, 0.015); // теплий відтінок
}

JS-код: менеджер каустик

class CausticsRenderer {
  constructor(gl, resolution = 512) {
    this.gl = gl;
    this.res = resolution;
    this.causticsTexture = this.createFramebuffer(resolution);
    this.prog = this.compileProgram(CAUSTIC_VERT, CAUSTIC_FRAG);
    this.buildQuadMesh(resolution); // 512×512 = 262144 quad vertices
  }

  render(heightTexture, depth, eta = 0.75) {
    const gl = this.gl;
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.causticsTexture.fbo);
    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT);

    // Адитивний блендінг — фотони накопичуються
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.ONE, gl.ONE);

    gl.useProgram(this.prog);
    gl.uniform1f(this.loc('uDepth'), depth);
    gl.uniform1f(this.loc('uEta'), eta);
    gl.bindTexture(gl.TEXTURE_2D, heightTexture);

    // Кожен quad = один "фотон", малюється в ціловий UV
    gl.drawArrays(gl.TRIANGLES, 0, this.res * this.res * 6);
    gl.disable(gl.BLEND);
  }

  getTexture() { return this.causticsTexture.texture; }
}

Підключення до матеріалу дна

Отриману текстуру каустик сумуємо з базовою текстурою дна у фінальному fragment shader. Додаємо Fresnel-blend між відбитим небом та рефракцією:

color = envColor × F(θ) + refractionColor × (1 − F(θ))

color += causticsTex × lightColor × shadowFactor

8. Довгофокусні каустики та фізична оптика

Чисто геометричний підхід має обмеження: нескінченна яскравість на каустиці. Хвильова оптика замінює її на апаратну функцію Ері:

I(x) ∝ |Ai((x−x_c)/l_c)|²

l_c = (λ·R/k̈)^(1/3) — характерний масштаб каустики

Ai — функція Ейрі (розв'язок d²y/dx² = xy)

Райдужні хмари та corona

Краплі дощу діють як мікролінзи — пояснюють веселку (λ-залежне заломлення) та corona (дифракційний кільця навколо сонця). У басейні аналогом є кольорові фринжі на краях каустики при монохроматичному підсвічуванні.

Photon mapping

Класичний алгоритм Йенсена (1996): стрільба фотонів від джерела, їх зберігання у kd-дереві, density estimation при рендерингу.

Bidirectional PT

Поєднує шляхи від джерела та від камери через MIS-вагування. Набагато ефективніше для каустик від точкових джерел.

Vertex Connection & Merging

VCM/UPM — сучасний SoA алгоритм, суміщає photon mapping + bidirectional PT, ефективний у виробничих рендерерах.

GPU-caustics (screen-space)

Метод, що розглянутий у цій статті: approx real-time за рахунок обмеженої коректності (плоске дно, паралельне світло).

Зв'язок з симуляціями

Каустичний рендеринг зазвичай пов'язаний з симуляцією поверхні рідини (Gerstner Waves або SPH). Дивіться пов'язані статті нижче.

🌈 Open Rainbow Ray Tracer →

🔗 Related Simulations

🌊Ocean 🌡️Wave Equation 🌈Rainbow 💧Rain