innuendo
romanshuvalov
Посмотри шейдера
Какие шейдера ?
Все которые есть в интернете :)
/A\
> Не дорого, я делал блур на мобилках и работало даже на дохлых мали Т830.
это он:
https://github.com/azhirnov/as-en/blob/dev/AE/engine/shared_data/… ers/Blur.glsl
?
Grobozavr
Кажется, мы друг друга не понимаем.
Вот картинка. Как её сделать из конуса на постпроцессе? Никак.

Сейчас пробую параметрически, вроде получается (картинка моя), надо только решить вопрос со взглядом с торца, а так же избавиться от множества временных хаков вида
x = pow(x, 0.25);
romanshuvalov
Степень это не хак а нелинейность
Можно смувстеп попробовать
innuendo
Я имел в виду, что для повышения производительности хорошо бы вместо степеней найти менее дорогую альтернативу с более-менее похожей функцией.
Смувстеп не даст нелинейности. Арктангенс не знаю, быстрее степени или нет.
romanshuvalov
Лет двадцать назад раскладывали синус в ряд Тейлора в пиксельном :)
Кубический полином линейный?
romanshuvalov
Я имел в виду, что для повышения производительности хорошо бы вместо степеней найти менее дорогую альтернативу с более-менее похожей функцией.
Смувстеп не даст нелинейности. Арктангенс не знаю, быстрее степени или нет.
А ты попробуй пиченьки с Бизье :)


Вот картинка. Как её сделать из конуса на постпроцессе? Никак.
Берем SDF конус, трассируем луч от камеры сквозь него до первой попавшейся в z-буфере геометрии и суммируем цвет с учетом дистанции до светильника(ов). Опционально учитываем плавные границы конуса, хотя, думаю, даже без этого так и будет. Можно вполне физически корректно посчитать с любыми наложениями разных источников.
я так делаю, вдохновившись идеей отсюда https://ijdykeman.github.io/graphics/simple_fog_shader
vec2 ray_cone_intersection(vec3 r0, vec3 rd, vec3 c0, vec3 cd, float angle_cos) { float cos2 = angle_cos * angle_cos; float dv = dot( rd, cd); vec3 co = r0 - c0; float cov = dot( co , cd); float a = dv * dv - cos2; float b = 2.0 * ( dv * cov - dot( rd , co) * cos2); float c = cov * cov - dot( co, co) * cos2; float det = b * b - 4.0 * a * c; if ( det <= 0.0) return vec2( 0.0); vec2 result = vec2( -b) + vec2( -1.0 , 1.0) * sqrt( det); result /= 2.0 * a; result = vec2( min( result.x,result.y) , max( result.x,result.y)); float sx = dot( cd, co + rd * result.x); float sy = dot( cd, co + rd * result.y); //sx>0 sy>0 start=x end=y //sx<0 sy>0 start=y end=inf //sx>0 sy<0 start=0 end=x //sx<0 sy<0 start=0 end=0 vec2 res1 = ( sx < 0.0) ? vec2( result.y, 1e30) : result; vec2 res2 = ( sx < 0.0) ? vec2( 0.0) : vec2( 0.0 , result.x); result = ( sy < 0.0) ? res2 : res1; return result; } float FogFactorSpot( vec3 view_pos, vec3 view_dir, float view_dist, vec3 light_pos, vec3 light_dir, float angle_cos) { vec2 cone_intersections = ray_cone_intersection( view_pos, view_dir, light_pos, light_dir, angle_cos ); if ( ( cone_intersections.y == 0.0) || ( cone_intersections.x > view_dist)) return 0.0; cone_intersections = min( cone_intersections, vec2( view_dist)); cone_intersections = max( cone_intersections, vec2( 0.0)); float t_start = cone_intersections.x; float t_end = cone_intersections.y; vec3 V = view_dir; vec3 P = view_pos - light_pos; vec3 L = light_dir; //float a = dot(V,V); //always = 1.0 float b = 2.0 * dot( V,P); float c = dot( P,P); float m = dot( V,L); float n = dot( P,L); float an4bm2 = -4.0 * n + 2.0 * b * m; float bn2cm4 = -2.0 * b * n + 4.0 * c * m; float invbb4ac = ( b * b - 4.0 * c); if ( invbb4ac >= 0.0) return 0.0; float integral_end = ( an4bm2 * t_end + bn2cm4) * inversesqrt( max( t_end * ( t_end + b) + c, 0.0)); float integral_start = ( an4bm2 * t_start + bn2cm4) * inversesqrt( max( t_start * ( t_start + b) + c, 0.0)); float result = ( integral_end - integral_start) / invbb4ac; float k = 1.0 / ( 1.0 - angle_cos); float invsqrt4acb = inversesqrt( -invbb4ac); vec2 atb = ( vec2( t_end, t_start) * 2.0 + vec2( b)) * invsqrt4acb; result = mix( 2.0 * ( ATan( atb.x) - ATan( atb.y)) * invsqrt4acb , result , k); result *= FOG_GLOBAL_DENSITY; result = clamp( result, 0.0, 1.0); return result; }
Мисс_Самец
view_pos - позиция камеры
view_dir - вью вектор
view_dist - расстояние от камеры до освещаемой точки
light_pos - позиция спотлайта
light_dir - направление спотлайта
angle_cos - косинус угла раствора спотлайта (или половины угла, не помню)
подразумевается, что внутри конуса свет распределяется по косинусу
если нужен полусферический лайт вместо спотлайта (последний скрин), нужно заменить пределы интегрирования с пересечения луча с конусом на пересечение луча с плоскостью и выкинуть ремапинг косинусного распределения света (4 строчки, начиная с float k = 1.0 / (1.0 - angle_cos);)
ncuxonaT
Красиво, но слишком много честных вычислений. Я тоже пробовал делать параметрический конус из вершины, направления оси и угла при вершине, что-то даже получалось, но медленно. В итоге применил другой подход - сфера с изменяемым радиусом, радиус - функция от dot(вектор от вершины до точки, ось конуса).
Изначально получалась в прямом смысле жопа, примерно такая:

Но если поиграться с коэффициентами, то будет получится как на черно-белой картинке выше.
Код для shader toy (2D)
void mainImage(out vec4 fragColor, in vec2 fragCoord ) { vec2 cone_top = vec2( 0.5, 0.95); vec2 cone_axle = normalize( vec2( 0.35, -0.77)); float factor1 = 2.0; float factor2 = factor1 * 0.7; float factor3 = 0.25; float factor4 = 1.0; // ---------------------------------- vec2 p = fragCoord/iResolution.xy; p.x *= iResolution.x/iResolution.y; float k = 0.5 + 0.5*dot( normalize( p - cone_top), cone_axle); k = pow( k, factor1); float r = k*factor2; float r_scale = 1.0 - 1.0*smoothstep( 0.0, r, pow( factor4*distance( cone_top, p), factor3)); // r_scale = pow(r_scale, 0.1); // <--- shape test // ----------------------------------- float o = r_scale; fragColor = vec4( o, o, o, 1.0); }
Для 3D надо немного повозиться, чтобы спроецировать точку на плоскость, проходящую через источник света и повернутую к камере. Но не обязательно делать это честно:
vec3 restored_pos_in_lightspace = eye_pos + normalize(eye_to_frag) * distance_from_eye_to_light;
skalogryz
> > Не дорого, я делал блур на мобилках и работало даже на дохлых мали Т830.
> это он:
либо тот, либо этот
https://github.com/Experience-Monks/glsl-fast-gaussian-blur/blob/master/5.glsl
Там суть в том что на десктопах хорошо работает двухпроходный блур, а на мобилках однопроходный, так как меньше памяти гоняется. Еще всякие RGBM с mediump float вместо RGBA16F, но на NV с mediump начинаются какие-то артефакты. В общем там надо много подгонять и пробовать разные варианты.
Еще на мали Т830 трафик был 1500Мб/с, а на мали G52 уже 500Мб/с, то есть сильно улучшили сжатие даже для fp16.
/A\
> а на мобилках однопроходный,
Подтверждаю. Но главное не перебарщивать с количеством выборок из текстуры. На Mali t830 практический потолок для 60 fps составляет около 8 выборок на пиксель если не ошибаюсь.
Мисс_Самец
👍🏿
romanshuvalov
Я не понял, как применять ваш способ в случае, когда камера внутри конуса лайта. Или как учитывать глубину объекта.
ncuxonaT
> когда камера внутри конуса
Всё срабатывает автоматически, надо только передать в шейдер расстояние до источника света (light_distance) и домножать альфу на
smoothstep(-light_radius*light_radius_bleeding_coef, light_radius, v_frag_distance - light_distance);
(v_frag_distance - расстояние от камеры до пикселя)
Тема в архиве.