2011-09-04

Rówanie Fresnela

Prawo załamania mówi nam pod jakim kątem zostanie załamany promień światła uderzający w granice dwóch różnych ośrodków o różnym współczynniku załamania. Prawo odbicia mówi nam pod jakim kątem promień się odbija. Podział energii pomiędzy promień odbity, a załamany jest nieproporcjonalny i właśnie równania Fresnela definiują. Podział ten zależy od współczynników złamania, kąta padania, ale także od polaryzacji światła. Same promienie odbity i załamany także odpowiednio się polaryzują.

Czyli poprawna symulacja wielokrotnego odbicia i załamania wymagałaby pamiętania informacji o polaryzacji. Na razie pomijamy tą fizyczną właściwość światła. Zakładamy, że każdy promień padający przypomina polaryzacją światło naturalną czyli jest niespolaryzowany.

Równanie Fresnela opisuje tylko odbicie i załamanie od powierzchni dielektryków. Dielektryk może być dla danej częstotliwości światła nieprzeźroczysty. Czyli do pełnej symulacji potrzebowalibyśmy informację o widmie fali i o tym jak na każdą ze składowych widma reaguje materiał. W naszym uproszczonym przypadku posługujemy się tylko opisem jak światło zostanie załamane i odbite dla składowych RGB.

W przypadku powierzchni metalicznych światło odbija się od nich całkowicie. Równanie to nie ma zastosowania. Co nie znaczy, że światło nie może zmienić swojej polaryzacji.

W przypadku powierzchni dielektrycznych nieprzeźroczystych promień załamany jest pochłaniany, z reguły nie następuje to od razu. Cienka warstwa materiału zwykle uważanego za nieprzeźroczysty może być przeźroczysta. Pochłanianiu z reguły towarzyszy rozpraszanie.

Światło to fala elektromagnetyczna, którą możemy sobie wyobrazić jako rozchodzące się w przestrzeni, prostopadłe w płaszczyznach, oscylacje pola magnetycznego i elektrycznego. Oscylacje pola magnetycznego i elektrycznego są zgodne z fazie. Fala elektromagnetyczna jest falą poprzeczną.

Ponieważ wektory $\vec B$ i $\vec E$ są do siebie prostopadłe przyjęło się wyróżniać wektor $\vec E$ kiedy mówimy o polaryzacji.

Równania Fresnela inaczej traktują fale prostopadłą do powierzchni (płaszczyzna wektora E i kierunku fali jest prostopadła do powierzchni), a inaczej równoległą. Dowolnie inaczej zorientowaną falę można przedstawić jako superpozycję takich właśnie wzajemnie do siebie prostopadłych fal.

image/svg+xml α β t i n 1 n 2 r

Dla fali prostopadłej współczynnik odbicia wynosi:

$R_\perp=(\displaystyle\frac{n_1\cos\alpha-n_2\cos\beta}{n_1\cos\alpha+n_2\cos\beta})^2$
Dla fali równoległej współczynnik odbicia wynosi:

$R_\parallel=(\displaystyle\frac{n_1\cos\beta-n_2\cos\alpha}{n_1\cos\beta+n_2\cos\alpha})^2$
Współczynniki refrakcji zaś: $T_\perp=1-R_\perp$ i $T_\parallel=1-R_\parallel$.

Ponieważ w naszym przypadku zakładamy, że światło jest równomiernie wymieszane, tak więc możemy powiedzieć, że składa się one w połowie fal równoległych do powierzchni i w połowie prostopadłych, tak więc: $R=\displaystyle\frac{R_\perp+R_\parallel}{2}$.

Z wzorów tych wynika, że jeśli $n_1>n_2$, dla kątów większych od kąta granicznego zachodzi zjawisko całkowitego wewnętrznego odbicia. Poza tym jeśli $n_1<n_2$ to istnieje taki kąt dla których $R_\parallel$ zanika do zera. Odbite światło pod tym kątem jest całkowicie spolaryzowane w jednej płaszczyźnie. Jest to tzw. kąt Brewstera.

Wykresy obu współczynników w funkcji kąta:



Kod MATLAB użyty do zrobienia wykresów:

count = 1000;
angles = linspace(0, 90, count);

function [r1, r2] = fresnel_all(n1, n2)

    r1 = (1:count);
    r2 = (1:count);

    for i=1:count

        alpha = angles(i) * pi / 180;
        beta = asin(sin(alpha)*n1/n2);

        r1(i) = ((n1*cos(alpha) - n2*cos(beta)) / ...
            (n1*cos(alpha) + n2*cos(beta)))^2;
        r2(i) = ((n1*cos(beta) - n2*cos(alpha)) / ...
            (n1*cos(beta) + n2*cos(alpha)))^2;

        if (n1 > n2) && (alpha >= asin(n2/n1))
            r1(i) = nan;
            r2(i) = nan;
        end
    end
end

[r1, r2] = fresnel_all(1, 2);
[r3, r4] = fresnel_all(2, 1);

figure(1)
hold on;
plot(angles, r1, 'r');
plot(angles, r2, 'g');
title('n_1=1, n_2=2');
legend('perpendicular ', 'parallel');

figure(2)
hold on;
plot(angles, r3, 'r');
plot(angles, r4, 'g');
title('n_1=2, n_2=1');
legend('perpendicular ', 'parallel');    

Implementacja w C#:

public static double FresnelReflectionFactor(Vector3 a_reflected_or_inverse_in,
    Vector3 a_normal, double a_n1, double a_n2)
{
    double ca = a_normal * a_reflected_or_inverse_in;

    Debug.Assert(ca.IsAlmostRelativeGreaterOrEqualThen(0));
    Debug.Assert(ca.IsAlmostRelativeLessOrEqualThen(1));

    ca = DoubleExtensions.Limit(ca, 0, 1);

    double sa = Math.Sqrt(1 - ca * ca);
    double sb = sa * a_n1 / a_n2;

    if (sb > 1)
        return 1;

    double cb = Math.Sqrt(1 - sb * sb);
    double can1 = ca * a_n1;
    double can2 = ca * a_n2;
    double cbn1 = cb * a_n1;
    double cbn2 = cb * a_n2;
    double rs = Math.Pow((can1 - cbn2) / (can1 + cbn2), 2);
    double rt = Math.Pow((cbn1 - can2) / (cbn1 + can2), 2);
    double result = (rs + rt) / 2;

    Debug.Assert(result >= 0);
    Debug.Assert(result <= 1);

    return result;
}

public static double FresnelReflectionFactor(Ray a_reflected_ray, Ray a_refracted_ray,
    Vector3 a_normal, double a_n1, double a_n2)
{
    if (a_refracted_ray == null)
        return 1;

    double ca = a_normal * a_reflected_ray.Dir;
    double cb = -(a_normal * a_refracted_ray.Dir);

    Debug.Assert(ca.IsAlmostRelativeGreaterOrEqualThen(0));
    Debug.Assert(cb.IsAlmostRelativeGreaterOrEqualThen(0));
    Debug.Assert(ca.IsAlmostRelativeLessOrEqualThen(1));
    Debug.Assert(cb.IsAlmostRelativeLessOrEqualThen(1));

    ca = DoubleExtensions.Limit(ca, 0, 1);
    cb = DoubleExtensions.Limit(ca, 0, 1);

    double can1 = ca * a_n1;
    double can2 = ca * a_n2;
    double cbn1 = cb * a_n1;
    double cbn2 = cb * a_n2;
    double rs = Math.Pow((can1 - cbn2) / (can1 + cbn2), 2);
    double rt = Math.Pow((cbn1 - can2) / (cbn1 + can2), 2);

    double result = (rs + rt) / 2;

    Debug.Assert(result >= 0);
    Debug.Assert(result <= 1);

    return result;
}