heroes-of-nerevelon/assets/shaders/sprite_light.glsl

86 lines
3.3 KiB
GLSL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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