86 lines
3.3 KiB
GLSL
86 lines
3.3 KiB
GLSL
#define MAX_LIGHTS 8
|
||
|
||
struct Light {
|
||
vec2 position;
|
||
vec3 color;
|
||
float radius;
|
||
};
|
||
|
||
extern Light lights[MAX_LIGHTS];
|
||
extern int num_lights;
|
||
extern vec2 sprite_pos; // Мировая позиция спрайта (в метрах)
|
||
extern vec3 ambient; // Эмбиентное освещение
|
||
extern vec3 sky; // Цвет неба
|
||
|
||
// Параметры выделения
|
||
extern bool is_selected;
|
||
extern vec2 tex_size;
|
||
extern float time;
|
||
|
||
// Функция для имитации easing.easeInSine
|
||
float easeInSine(float x) {
|
||
return 1.0 - cos((x * 3.14159) / 2.0);
|
||
}
|
||
|
||
vec4 effect(vec4 vcolor, Image tex, vec2 texture_coords, vec2 screen_coords)
|
||
{
|
||
vec4 texColor = Texel(tex, texture_coords);
|
||
|
||
// ЛОГИКА ОБВОДКИ (Outline)
|
||
// Мы выполняем ее до расчетов освещения. Если пиксель прозрачный и объект выбран,
|
||
// проверяем соседей, чтобы понять, не граница ли это.
|
||
// Обводка рисуется "самосветящейся", чтобы выделение было видно даже в полной темноте.
|
||
if (is_selected && texColor.a <= 0.0) {
|
||
float maxAlpha = 0.0;
|
||
|
||
// Проверяем соседние пиксели (квадратом 3x3)
|
||
for (float x = -1.0; x <= 1.0; x++) {
|
||
for (float y = -1.0; y <= 1.0; y++) {
|
||
if (x == 0.0 && y == 0.0) continue;
|
||
vec2 offset = vec2(x, y) / tex_size;
|
||
maxAlpha = max(maxAlpha, Texel(tex, texture_coords + offset).a);
|
||
}
|
||
}
|
||
|
||
if (maxAlpha > 0.0) {
|
||
// Эффект пульсации и "бегущей волны" из оригинального шейдера outline.glsl
|
||
float modY = (0.75 + sin(time) * 0.25) * (0.5 + cos(texture_coords.y * 10.0 + time * 2.0) * 0.5);
|
||
return vec4(vec3(modY, 0.2 * sin(time) + 0.5, 0.5), 1.0);
|
||
}
|
||
}
|
||
|
||
if (texColor.a == 0.0) {
|
||
return vec4(0.0);
|
||
}
|
||
|
||
// Расчет базового освещения мира: персонаж освещается смесью неба (Sky) и отраженного света (Ambient).
|
||
vec3 baseLight = ambient + (vec3(1.0) - ambient) * sky;
|
||
|
||
// Десатурация базового света на 30%.
|
||
float luma = dot(baseLight, vec3(0.2126, 0.7152, 0.0722));
|
||
vec3 characterBaseLight = mix(baseLight, vec3(luma), 0.3);
|
||
|
||
vec3 pointLight = vec3(0.0);
|
||
|
||
for (int i = 0; i < num_lights; i++) {
|
||
vec2 lightPos = lights[i].position;
|
||
float radius = lights[i].radius;
|
||
vec2 lightVec = lightPos - sprite_pos;
|
||
float dist = length(lightVec);
|
||
|
||
// Плавное затухание света по радиусу.
|
||
float radiusFalloff = smoothstep(radius, radius * 0.2, dist);
|
||
|
||
// Реализация псевдо-проекции (3D-эффект):
|
||
float frontWeight = smoothstep(-2.0, 0.5, lightVec.y);
|
||
|
||
float attenuation = radiusFalloff * frontWeight;
|
||
pointLight += lights[i].color * attenuation;
|
||
}
|
||
|
||
pointLight = clamp(pointLight, 0.0, 1.0);
|
||
|
||
// Финальный расчет цвета:
|
||
return vec4(texColor.rgb * (characterBaseLight + pointLight), texColor.a);
|
||
}
|