#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); }