15 лет назад я пытался писать диссертацию на тему «Оптоэлектронный метод определения шероховатости поверхности». В ходе работы активно использовались BRDF-функции и прочий замечательный математический аппарат для оптики. Был написан код и пара глав, но интерес пропал — повяз в работе. Пару раз пытался заново начать, но, к сожалению, так и не нашел причины выключиться из семьи и работы на год или даже больше. В качестве побочной задачки решил для себя реализовать визуализацию какого-нибудь интересного оптического эффекта. Выбор пал на интерференцию (wiki: взаимное увеличение или уменьшение результирующей амплитуды двух или нескольких когерентных волн при их наложении друг на друга), как наиболее простую в реализации механику.

image

Первая версия была реализована на Delphi + OpenGL ещё в 2005 году, она предполагала манимацию смены фазы волны и состояла всего из 200 строк кода. Удивительно, но ее код до сих пор доступен в Кладовке.

Вернемся к более поздней версии, выполненной уже на JavaScript.


«Физика» отрисовки проста:

  1. Помещаем на страницу canvas и навешиваем событие onclick, которое запоминает координаты двух последних кликов мыши — источников излучения: (x1, y1) и (x2, y2).
  2. Проходим в цикле по каждой точке canvas (x, y) и вычисляем евклидово расстояние до наших источников излучения: S1=SQRT((x1-x)^2+(y1-y)^2) и S2=SQRT((x2-x)^2+(y2-y)^2)
  3. Мы предполагаем, что наши источники излучают синусоидальный сигнал, поэтому можем легко вычислить амплитуду каждой точки: A(x, y)=sin(S1 * W)+sin(S2 * W), где W — длина волны. Сюда можно еще добавить фазу, но это по желанию.
  4. Далее нормируем полученную амплитуду и получаем цвет пикселя: C(x,y)=A(x,y)*68+127
  5. ???
  6. Profit

В JSFiddle доступен исходный код и есть возможность поиграться, устанавливая источники в различные углы сцены.

image

Если вам интересно можете добавить «реалистичности»


  1. Затухание сигнала.
  2. Анимацию изменения фазы.
  3. Отражение сигнала от плоскости (через аффинные преобразования легче всего).