Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: Majestio от Июнь 10, 2013, 15:46



Название: Бросить тень используя PNG с прозрачными областями
Отправлено: Majestio от Июнь 10, 2013, 15:46
Нужен алгоритм применения эффекта "тень" (а-ля Фотошоп) над непрозрачными областями PNG-картинки. Может кто видел хоть какие нить-реализации? В идеале - на Qt. Не в идеале - на любом языке.

Пример (светлосерый цвет - область прозрачности)

Есть:

(http://i46.fastpic.ru/big/2013/0610/ec/9f9859e1e7b4f2e37b5fed7c1d1effec.png)

Нужно:

(http://i47.fastpic.ru/big/2013/0610/d0/37945726454f4fb2665f5574c0d080d0.png)


Название: Re: Бросить тень используя PNG с прозрачными областями
Отправлено: Igors от Июнь 10, 2013, 16:08
Ну а почему бы ее просто не посчитать как (в принципе) делает raytracer?


Название: Re: Бросить тень используя PNG с прозрачными областями
Отправлено: Majestio от Июнь 10, 2013, 16:27
Ну а почему бы ее просто не посчитать как (в принципе) делает raytracer?

Вот и ищу алгоритм расчета. Нужно (пока) тройное наложение PNG, каждое из которых бросает тень на "предыдущий" результат.


Название: Re: Бросить тень используя PNG с прозрачными областями
Отправлено: Igors от Июнь 10, 2013, 17:23
Вот и ищу алгоритм расчета. Нужно (пока) тройное наложение PNG, каждое из которых бросает тень на "предыдущий" результат.
Для каждого пикселя берем матрицу напр 3x3 "вверх-влево" т.е. целевой пиксель в правом нижнем углу. Псевдокод
Код:
// сколько света проникает
float light = 0;
for (int i = x - 2; i <= x; ++i)
 for (int j = y - 2; j <= y; ++j)
  light += 1 - src_pixel[i][j].alpha;  // alpha от 0 до 1
light /= 9;

// учтем альфу - непрозрачный пиксель не принимает ни тени ни backgroud,
// полностью прозрачный принимает всю
float bias = src_pixel[x][y].alpha; 
dst_pixel[x][y].color =  src_pixel[x][y].color * bias + background[x][y] * (1 - bias) *  light;  // финальный пиксель
dst_pixel[x][y].alpha = 1;
Где
src_pixel - пиксели бросающие тень (картинка с альфой)
background - картинка фона
dst_pixel - пиксель финальной картинки
x, y - целевая точка

Можно "подкрутить" - напр возвести light в степень или складывать с коэффициентами

Очень может быть что найдется какой-нибудь "GraphicsEffect" - класс делающий то же, ну "каждому - свое"


Название: Re: Бросить тень используя PNG с прозрачными областями
Отправлено: Majestio от Июнь 10, 2013, 17:39
Спасибо, возьму на заметочку.

Для каждого пикселя берем матрицу напр 3x3 "вверх-влево" т.е. целевой пиксель в правом нижнем углу.

Попутно вопрос: почему 3x3?

В классических настройках есть два параметра - расстояние тени и радиус размытия. В соседнем форуме присоветовали посмотреть в сторону размытия по Гаусу, вот нашел интересный линк (http://habrahabr.ru/post/151157/).


Название: Re: Бросить тень используя PNG с прозрачными областями
Отправлено: Igors от Июнь 10, 2013, 18:17
Попутно вопрос: почему 3x3?

В классических настройках есть два параметра - расстояние тени и радиус размытия. В соседнем форуме присоветовали посмотреть в сторону размытия по Гаусу, вот нашел интересный линк (http://habrahabr.ru/post/151157/).
Ну возьмите 4х4, чем больше матрица тем плавнее тень, но и больше время счета. Не пугайтесь, это актуально с размерами десятка и больше. Расстояние - просто смещение матрицы относительно целевой точки

Под Гауссом обычно понимаются 2 вещи

а) сложение с коэффициентами (вес ближних больше по "колокольчику" Гаусса)
b) блюр сначала по строкам, потом по столбцам, что может быть заметно быстрее при больших радиусах

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


Название: Re: Бросить тень используя PNG с прозрачными областями
Отправлено: Majestio от Июнь 10, 2013, 18:49
Но оно Вам надо лезть во все тонкости/толстости? :) Для тени что Вы показали достаточен простейший код

Оке, пасип, учту ... пока это все в форме интереса. На последних этапах проекта начну "разукрашивать" )


Название: Re: Бросить тень используя PNG с прозрачными областями
Отправлено: navrocky от Июнь 17, 2013, 17:41
Полезь в сорцы Qt в QGraphicsBlurEffect, дерни оттуда код для размытия по гауссу. Потом заменяешь в оригинале RGB пикселей на нужный цвет (как правило черный), альфу не трогаешь, размываешь эту картинку и получаешь тень.

Кстати, есть QGraphicsDropShadowEffect, его можно использовать в некоторых случаях, даже с обычными виджетами..