[Шпаргалка] Фрагментный шейдер и спрайт

Ссылка на видео с последовательностью действий:

Перейди в builtins, в materials:


Скопируй эти три файла в любую папку:
image

Зайди в компонент sprite, твоего игрового объекта и нажми на ... в поле materials:


Выбери тот материал, который ты скопировал ранее:

Теперь нажми на стрелочку:

Добавь фрагментный и вершинный шейдеры (скопированные ранее файлы с расширением .fp и .vp):


Создай константу и присвой такие значения:

Если хочешь посмотреть как будет выглядеть спрайт под шейдером, установи такое значение:

Зайди в фрагментный шейдер (sprite.fm у меня) и вставь какой-нибудь из этих блоков кода:

Красное мигание

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Красный оттенок при попадании
        color = mix(color, vec4(1.0, 0.0, 0.0, color.a), 0.7);
    }
    
    gl_FragColor = color;
}
Белая вспышка

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Белая вспышка
        color = mix(color, vec4(1.0, 1.0, 1.0, color.a), 0.8);
    }
    
    gl_FragColor = color;
}
Жёлтый оттенок

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Жёлтый оттенок (для критических ударов)
        color = mix(color, vec4(1.0, 1.0, 0.0, color.a), 0.6);
    }
    
    gl_FragColor = color;
}
Инверсия цвета

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Инвертируем цвета
        color.rgb = vec3(1.0 - color.r, 1.0 - color.g, 1.0 - color.b);
    }
    
    gl_FragColor = color;
}
Красный + яркость

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Красный + ярче
        color.rgb = mix(color.rgb, vec3(1.0, 0.0, 0.0), 0.6);
        color.rgb += vec3(0.3, 0.0, 0.0);  // Ещё ярче красный
    }
    
    gl_FragColor = color;
}
Оттенки серого

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);

    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Преобразуем в чёрно-белое
        lowp float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
        color.rgb = vec3(gray, gray, gray);
    }

    gl_FragColor = color;
}
Чёрно-белое + контраст

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);

    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Чёрно-белое с высоким контрастом
        lowp float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
        gray = smoothstep(0.3, 0.7, gray);  // Увеличиваем контраст
        color.rgb = vec3(gray, gray, gray);
    }

    gl_FragColor = color;
}
Полностью чёрный

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Полностью чёрный
        color.rgb = vec3(0.0, 0.0, 0.0);
    }
    
    gl_FragColor = color;
}
Полностью белый

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Полностью белый
        color.rgb = vec3(1.0, 1.0, 1.0);
    }
    
    gl_FragColor = color;
}
Негатив

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Чёрно-белое + инвертировано
        lowp float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
        gray = 1.0 - gray;  // Инвертируем
        color.rgb = vec3(gray, gray, gray);
    }
    
    gl_FragColor = color;
}
Мягкий зелёный (Исцеление)

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Мягкий зелёный оттенок
        color = mix(color, vec4(0.0, 1.0, 0.0, color.a), 0.5);
    }
    
    gl_FragColor = color;
}
Яркий зелёный (Токсин/Яд)

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Яркий зелёный + свечение
        color.rgb += vec3(0.0, 0.5, 0.0);
        color = mix(color, vec4(0.0, 1.0, 0.0, color.a), 0.4);
    }
    
    gl_FragColor = color;
}
Лайм-зелёный (Эффект энергии)

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Лайм-зелёный (очень яркий)
        color = mix(color, vec4(0.5, 1.0, 0.0, color.a), 0.6);
    }
    
    gl_FragColor = color;
}
Тёмно-зелёный (отравление)

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Тёмно-зелёный
        color = mix(color, vec4(0.0, 0.5, 0.0, color.a), 0.7);
    }
    
    gl_FragColor = color;
}

Зелёный + свечение

varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Зелёный с ярким свечением
        color.rgb = color.rgb * vec3(0.7, 1.2, 0.7);
        color = mix(color, vec4(0.0, 1.0, 0.0, color.a), 0.3);
    }
    
    gl_FragColor = color;
}
Простая радуга по позиции:
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Радуга на основе UV координат
        lowp float r = sin(var_texcoord0.x * 3.14159 * 6.0) * 0.5 + 0.5;
        lowp float g = sin(var_texcoord0.x * 3.14159 * 6.0 + 2.0) * 0.5 + 0.5;
        lowp float b = sin(var_texcoord0.x * 3.14159 * 6.0 + 4.0) * 0.5 + 0.5;
        
        lowp vec3 rainbow = vec3(r, g, b);
        color = mix(color, vec4(rainbow, color.a), 0.7);
    }
    
    gl_FragColor = color;
}

Циклическая радуга:
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;
uniform lowp float tint;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);

    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Радуга через HSV в RGB
        lowp float hue = mod(tint + var_texcoord0.x, 1.0);

        lowp vec3 rgb = vec3(0.0);
        if(hue < 0.167) rgb = mix(vec3(1.0, 0.0, 0.0), vec3(1.0, 1.0, 0.0), hue / 0.167);
        else if(hue < 0.333) rgb = mix(vec3(1.0, 1.0, 0.0), vec3(0.0, 1.0, 0.0), (hue - 0.167) / 0.166);
        else if(hue < 0.5) rgb = mix(vec3(0.0, 1.0, 0.0), vec3(0.0, 1.0, 1.0), (hue - 0.333) / 0.167);
        else if(hue < 0.667) rgb = mix(vec3(0.0, 1.0, 1.0), vec3(0.0, 0.0, 1.0), (hue - 0.5) / 0.167);
        else if(hue < 0.833) rgb = mix(vec3(0.0, 0.0, 1.0), vec3(1.0, 0.0, 1.0), (hue - 0.667) / 0.166);
        else rgb = mix(vec3(1.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), (hue - 0.833) / 0.167);

        color = mix(color, vec4(rgb, color.a), 0.6);
    }

    gl_FragColor = color;
}

Пасхальная радуга (Мягкая):
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Мягкая радуга (пастельные цвета)
        lowp float r = 0.5 + 0.5 * sin(var_texcoord0.x * 10.0);
        lowp float g = 0.5 + 0.5 * sin(var_texcoord0.x * 10.0 + 2.1);
        lowp float b = 0.5 + 0.5 * sin(var_texcoord0.x * 10.0 + 4.2);
        
        lowp vec3 rainbow = vec3(r, g, b);
        color = mix(color, vec4(rainbow, color.a), 0.5);
    }
    
    gl_FragColor = color;
}
Неоновая радуга:
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D texture_sampler;
uniform lowp vec4 hit_effect;

void main()
{
    lowp vec4 color = texture2D(texture_sampler, var_texcoord0.xy);
    
    if(color.a > 0.0 && hit_effect.r > 0.5)
    {
        // Неоновая радуга (очень яркая)
        lowp float x = var_texcoord0.x;
        lowp vec3 rainbow = vec3(
            0.5 + 0.5 * sin(x * 6.28 + 0.0),
            0.5 + 0.5 * sin(x * 6.28 + 2.1),
            0.5 + 0.5 * sin(x * 6.28 + 4.2)
        );
        
        color.rgb = rainbow;
    }
    
    gl_FragColor = color;
}

Установите значения константы hit_effect в начальное значение:

Я решил использовать шейдер в момент обработки сообщения:

	elseif message_id == hash("set_damage") then
		self.hp = self.hp - message.damage
		go.set("#sprite", "hit_effect", vmath.vector4(1, 0, 0, 1))
		if self.hp <= 0 then
			print("Враг умер:", self.instance_id, "спавн:", self.spawn_id)
			msg.post("/spawner", "killed_enemy", { 
				instance_id = self.instance_id,
				spawn_id = self.spawn_id
			})
			GSFSM.set_exp_player(1)
			msg.post("/gui", "pick_exp")
		end

Вот эта строка применяет эффект:
go.set("#sprite", "hit_effect", vmath.vector4(1, 0, 0, 1))