Преломления


     С преломлениями в трассировке лучей все немного сложнее, чем с отражениями. Во-первых, нужно учитывать эффект так называемого "полного внутреннего отражения", который говорит о том, что при больших углах преломления не происходит и свет полностью отражается. Во-вторых, необходимо получить коэффициенты преломления двух сред: той, из которой луч выходит той, в которую он входит. Как это сделать имея информацию только о поверхности, о которую ударился луч? И в третиьх, нужно учитывать, что луч прошел определенное растояние внутри преломляющего объекта, который вообще говоря может быть мутным. То есть нужно учитывать затухание (Закон Бугера — Ламберта — Бера). И наконец, неплохо бы учесть волновую природу света. Для разных длинн волн  свет будет преломляться на разные углы и затухание у каждой длинны волны вообще говоря свое (коэффициенты преломления и затухания задаются для каждой длинны волны).

    Разберемся сначала с первыми двумя проблемами. Если произошло полное внутреннее отражение, то преломляющий луч вообще не нужно траверсить (то есть его просто нет). Далее, как нам получить коэффициенты преломления? В общем случае это непросто. Если преломляющие объекты пересекаются друг с другом, то имея лишь информацию о том, каким материалом обладает поверхность, о которую ударился луч, невозможно сказать, в какую среду луч попадет при выходе из объекта. Не будем усложнять себе жизнь. Предположим, что все преломляющие объекты не пересекаются друг с другом а преломлющий показатель воздуха равен 1. Тогда нетрудно заметить, что если угол между нормалью к поверхности и направлением луча тупой, то луч переходит из воздуха в среду с показателем преломления материала, какорым обладает поверхность. Если же угол острый, то наоборот - луч вылетает из среды в воздух.


bool refract(float3& ray_dir, float3 a_normal, float a_matIOR

{

  float eta = 1.0f/a_matIOR; // eta = in_IOR/out_IOR

  float cos_theta = -dot(a_normal, ray_dir);

  if(cos_theta < 0)

  {

    cos_theta *= -1.0f;

    a_normal *= -1.0f;

    eta = 1.0f/eta;

  }

  float k = 1.0f - eta*eta*(1.0-cos_theta*cos_theta);

  if(k >= 0.0f)

    ray_dir = normalize( eta*ray_dir + (eta*cos_theta - sqrt(k))*a_normal);

  return (k > 0);

}


Математика того, как рассчитывается преломление описана тут http://users.skynet.be/bdegreve/writings/reflection_transmission.pdf. Однако, код из статьи обладает тем недостатком, что он не различает случаи входа в среду и выхода из нее и никак не говорит о том, как же получить коэффициенты преломления сред. Плюс в ней  видимо считается, что нормаль к поверхности всегда смотрит в ту сторону, откуда прилетел луч. 

    Для того чтобы использовать код из ссылки, приведенной выше, по крайней мере необходимо перед его применением инвертировать нормаль к поверхности и показатель преломления если косинус угла между номалью и направлением луча меньше нуля (угол тупой), иначе получится ерунда.

Результат вроде похоже на правду. Преломляющая стеклянная сфера расположена слева. Изображение переворачивется, как и должно быть.




<< Вернуться назад

Статьи и обзоры

Поиск пересечений

Обратная трассировка лучей

Быстрая трассировка лучей

Индустриальная основа

Фотореалистичная визуализация

GPU ray tracing

Сферические гармоники

Дружественные проекты:

OpenSource RTRT

Siberian renderer

Наши разработки

Hydra renderer

AdaRT

Публикации

Загрузить

Скриншоты и видео

ССЫЛКИ

© Copyright 2007 Владимир Фролов, Александр Фролов

При поддержке Лаборатории компьтерной графики и мультимедия ф-та ВМК МГУ
Создание сайта: Александр Фролов