Преломления


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

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


template <int n,class T>

inline bool refract(RAY<n,T>* inout_ray, const VECTOR<n,T>& normal, T eta)

{

 eta = 1.0f/eta; // тут где-то глюк был, нужно инвертирвать отношение, eta = material.n/1.0f;

  // посчитаем косинус угла между нормалью к поверхности и направлением луча

  T cos_theta = -dot(normal, inout_ray->dir);

  // если косинус меньше нуля то мы "выходим" из объекта в воздух

  // иначе - "входим" из воздуха в объект

  if(cos_theta < 0)

  {

    normal *= (-1);

    cos_theta *= -1.0f;

    eta = 1.0f/eta;

  }

 

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

 

  if(k > 0)

  {

    inout_ray->dir = eta*inout_ray->dir + (eta*cos_theta - sqrt(k))*normal;

    inout_ray->dir.Normalize();

  }

  else // полное внутреннее отражение.

  {

      in_out.ray.pos = invalid; // убить луч 

  }

 

  return (k > 0);

}


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

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

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




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

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

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

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

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

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

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

GPU ray tracing

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

OpenSource RTRT

Siberian renderer

Garanga fastest ray tracer

Lebedev R&R

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

Hydra renderer

MGML

RTE

Публикации

AdaRT

Загрузить

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

Программы

ССЫЛКИ

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

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