· ··--──══[ COOLer issue #1 ]══─---·· ·
ЭФФЕКТ: ВОДИЧКА (C2H5OH) by GELTORN/STORM




             -=========ЭФФЕКТ: ВОДИЧКА (C2H5OH)=========-


  Довольно  загадочный,  для  непосвященных, но простой, эффектик. В
основе  лежит,  все тот же Blur. Я выбрал 8-пиксельный блюр, так как
он дает более красивую картинку.

Установим палитру так:   0   ->  255
                       Синий    Белый

  Заведем  два  буфера:  buf1 и buf2, и указатели на них: buf1_ptr и
buf2_ptr.  Важно понять, что, хоть указатель называется buf1_ptr, но
он  может  указывать  совсем  не  на buf1, а на buf2. Аналогично для
buf2_ptr.  Далее  по тексту, если я буду называть масив buf1_ptr, то
имеется  в  виду  тот  массив на который, в данный момент, ссылается
buf1_ptr. Тоже самое подрaзyмевается под массивом buf2_ptr.

  Далее  я  опишу  последовательность  которую  надо  проделать  для
расчета очередного кадра:

1.  Если  buf1_ptr,  действительно  указывает  на буф1, то заносим в
buf1_ptr точки возмущения.

2.  Проходимся  по всем точкам массива buf1_ptr и buf2_ptr вот таким
алгоритмом:
2.1.   Складываем  значения  точек  окружающих  текущую,  в  массиве
buf1_ptr.
2.2.  Делим  эту  сумму на 4. (Это не опечатка, действительно делить
надо на 4)
2.3. Вычитаем из этой суммы значение текущей точки массива buf2_ptr.
2.4. Если результат меньше 0, то результат равен 0.
2.5. Записываем результат в текущую точку массива buf2_ptr.

3.  Теперь  меняем  местами  buf1 и buf2 (собственно для этого нам и
были нужны указатели):
  long temp_ptr=buf1_ptr;
  buf1_ptr=buf2_ptr;
  buf2_ptr=temp_ptr;

4. Выводим на экран buf2_ptr.

В результате получим эффект воды. Но...
Неплохо  бы было добавить background (какую-нибудь картинку), да еще
чтоб волны искажали его. Чтож нет ничего невозможного...

  Добавим  два  буфера:  pics  и  screen_end.  В  pics будем хранить
картинку,  которую  используем в качестве background`а. А screen_end
мы  будем  выводить  на  экран.  Палитру  надо  взять из считываемой
картинки (надеюсь вы прочитали статью об считывании bmp картинок).

  Как  же  нам  добиться  эффекта искажения, из-за преломления лучей
света на границе двух разнородных сред? Счаз подумаем.

  Берем  в  руки  учебник физики 11 класса и находим формулу расчета
угла  преломленного  луча.  Пременив  знания,  полученные  на уроках
геометрии,  выведем  формулу,  с  помощью  которой мы будем находить
смещение,  относительно  текущего  пикселя,  по  которому находиться
пиксель который и надо вывести на экран вместо текущего:

D=h*tg(arcsin(0.75*sin(a)))

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

  COOL!!!   тангенс   арксинуса  синуса,  да  еще  расчет  нормали к
поверхности, плюс это надо разложить на нахождение смещения по X и Y
SUXX!!! SUXX!!!, и еще раз SUXX!!!

  Конечно  можно  сделать  precalculating,  но  табличка  получиться
слишком  уж  большая.  Как  же  нам  быть?  Взглянем еще раз на нашу
формулу и подумаем, нельзя ее как нибудь сократить.

  Допустим,  что  наш  расчудесный  тангенс  арксинуса  синуса, есть
величина  величина постоянная и равная, например 0.25. Опыт показал,
что  такое  допущение  вполне возможно, если ширина волны небольшая.
Тогда формула значительно упроститься и будет выглядть так:

D=h/4

  Теперь,  чтобы  найти  координаты  нужного  нам  пикселя, нам надо
прибавить к текущим, D:

x'=x+D; y'=y+D;

В наш алгоритм добавиться:

2.5. ...
2.6.  Делим результат на 4, полученное значение прибавляем к текущим
x  и  y. Если x, больше максимально допустимого значения, то х равен
максимальному   допустимому   значению.  Аналогичную  проверку  надо
сделать  и  для  y.  Считываем  по этим координатам из массива pics,
число и записываем по текущим координатам в screen_end.

  Теперь  раскажу  как  модифицировать  этот алгоритм чтобы получить
более реальное изображение.

  Недостаток описанного выше метода - смещение не зависит от наклона
нормали  к поверхности воды. Как же исправить этот недостаток, особо
не  усложняя  алгоритм?  Довольно  просто. Нам достаточно знать куда
наклонена  нормаль, тогда мы сможем смещать координаты в соответсвии
с  этим  направлением. Для того чтобы найти смещения по x и y, будем
использовать следующие формулы:

Dx=(buf1_ptr[x+1][y]-buf1_ptr[x-1][y])>>2;
Dy=(buf1_ptr[x][y+1]-buf1_ptr[x][y-1])>>2;

Как надо изменить пункт 2.6., вы наверняка догадаетесь сами.

Bye...

                                                  ---(Geltorn/Storm)


