Информационный портал по безопасности » Программирование » Реалистичное гравитационное линзование на Unity

 

Реалистичное гравитационное линзование на Unity

Автор: admin от 5-09-2014, 10:48, посмотрело: 627

Реалистичное гравитационное линзование на Unity
Эффект гравитационной линзы вызванный скоплением галактик RCS2 032727-132623

Возникла недавно необходимость реализовать на Unity достаточно правдоподобное изображение черной дыры и, соответственно, эффект гравитационного линзирования ею вызываемого. Первой мыслью было найти готовую реализацию и подстроить под себя, однако, поскольку ни одного достаточно хорошего решения так и не нашел (что весьма странно, зная насколько популярны игры на космическую тематику), решил реализовать эффект самостоятельно, а заодно и поделиться результатом с хабросообществом.

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


Теперь приступим к более важной части: написанию самого шейдера.

Первым делом, нам необходимо получить радиус, в зависимости от которого будем искажать изображение:
float2 offset = i.uv - _Position; //Сдвигаем наш пиксель на нужную позицию
float2 ratio = {_Ratio,1}; //определяем соотношение сторон экрана
float rad = length(offset / ratio); //определяем расстояние

В физике, формула приломления луча света проходящего на расстоянии r от объекта с массой M имеет вид:
Реалистичное гравитационное линзование на Unity
Для нас M — масса черной дыры. Зная, что радиус черной дыры определяется как
Реалистичное гравитационное линзование на Unity
Получаем следующую конструкцию
float deformation = 2*_Rad*1/pow(rad*z,2); 

где deformation — сила искажения в каждой конкретной точке, при этом z — некоторая зависимость размера искажения от расстояния на котором находится камера. Что бы понять как эта зависимость выражается, обратимся к формуле кольца Эйнштейна.
Реалистичное гравитационное линзование на Unity
Где
Реалистичное гравитационное линзование на Unity
В данной формуле нас интересует ее зависимость от дистанции, потому, большую ее часть можно отбросить наблюдая лишь за
Реалистичное гравитационное линзование на Unity
Поскольку шейдер обрабатывает 2х мерное изображение, мы не можем сказать о том, как далеко находятся объекты. И хотя это можно реализовать с помощью карты глубины, исказить их корректно не получиться, так как потребуются изображения всего что находиться за каждым из объектов. Поэтому предположим, что DLDS и DLDLS. Тогда мы видим, что размер искажения обратно пропорционален корню растояния, получаем
deformation = 2*_Rad*1/pow(rad*pow(_Distance,0.5),2);

Теперь применим нашу деформацию:
offset =offset*(1-deformation);

Вернем изображение на место и отобразим.
offset += _Position;

half4 res = tex2D(_MainTex, offset);
return res;


Вот и все! Можно насладится результатом:


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

Источник: Хабрахабр

Категория: Программирование

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
  • bowtiesmilelaughingblushsmileyrelaxedsmirk
    heart_eyeskissing_heartkissing_closed_eyesflushedrelievedsatisfiedgrin
    winkstuck_out_tongue_winking_eyestuck_out_tongue_closed_eyesgrinningkissingstuck_out_tonguesleeping
    worriedfrowninganguishedopen_mouthgrimacingconfusedhushed
    expressionlessunamusedsweat_smilesweatdisappointed_relievedwearypensive
    disappointedconfoundedfearfulcold_sweatperseverecrysob
    joyastonishedscreamtired_faceangryragetriumph
    sleepyyummasksunglassesdizzy_faceimpsmiling_imp
    neutral_faceno_mouthinnocent