🔧 Improve incinerate effect
This commit is contained in:
@@ -124,6 +124,17 @@ vec4 alphaOver(vec4 under, vec4 over) {
|
|||||||
return vec4((over.rgb * over.a + under.rgb * under.a * (1.0 - over.a)) / alpha, alpha);
|
return vec4((over.rgb * over.a + under.rgb * under.a * (1.0 - over.a)) / alpha, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------- color helpers
|
||||||
|
|
||||||
|
// Maps the given value from [0..1] to the given colors.
|
||||||
|
vec3 tritone(float val, vec3 shadows, vec3 midtones, vec3 highlights) {
|
||||||
|
if (val < 0.5) {
|
||||||
|
return mix(shadows, midtones, smoothstep(0, 1, val * 2.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mix(midtones, highlights, smoothstep(0, 1, val * 2.0 - 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------- easing functions
|
// ---------------------------------------------------------------------- easing functions
|
||||||
|
|
||||||
// Here are some basic easing function. More can be added if required!
|
// Here are some basic easing function. More can be added if required!
|
||||||
|
|||||||
@@ -13,124 +13,93 @@
|
|||||||
|
|
||||||
// The content from common.glsl is automatically prepended to each shader effect.
|
// The content from common.glsl is automatically prepended to each shader effect.
|
||||||
|
|
||||||
uniform sampler2D uAshTexture;
|
|
||||||
uniform vec2 uSeed;
|
uniform vec2 uSeed;
|
||||||
// uniform vec3 uColor;
|
// uniform vec3 uColor;
|
||||||
uniform float uScale;
|
uniform float uScale;
|
||||||
// uniform float uWidth;
|
// uniform float uWidth;
|
||||||
uniform float uTurbulence;
|
uniform float uTurbulence;
|
||||||
|
|
||||||
const float BURN_TIME = 0.5;
|
const float SCORCH_WIDTH = 0.1;
|
||||||
const float FIRE_WIDTH = 0.03;
|
const float SMOKE_WIDTH = 0.6;
|
||||||
const float ASH_WIDTH = 0.5;
|
|
||||||
const float ASH_LAYERS = 4;
|
|
||||||
|
|
||||||
vec4 getFireColor(float v) {
|
vec4 getFireColor(float val) {
|
||||||
const float steps[4] = float[](0.0, 0.33, 0.66, 1.0);
|
return vec4(tritone(val, vec3(0.0), vec3(1.0, 0.8, 0.6), vec3(1.0)), val);
|
||||||
vec4 colors[4] =
|
}
|
||||||
vec4[](vec4(1, 0, 0, 0), vec4(1, 0, 0, 0.5), vec4(1, 1, 0, 1), vec4(1, 0, 0, 0));
|
|
||||||
|
|
||||||
if (v < steps[0]) {
|
float getMask(vec2 uv) {
|
||||||
return colors[0];
|
float noise = simplex2DFractal(uv * 0.005 + uSeed);
|
||||||
}
|
float gradient = rotate(cogl_tex_coord_in[0].st - 0.5, uSeed.x * 2.0 * 3.141).x + 0.5;
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
return mix(gradient, noise, 0.15);
|
||||||
if (v <= steps[i + 1]) {
|
|
||||||
float blend = smoothstep(0, 1, (v - steps[i]) / (steps[i + 1] - steps[i]));
|
|
||||||
return mix(colors[i], colors[i + 1], vec4(blend));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return colors[3];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
|
|
||||||
vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st);
|
float hideThreshold = mix(-SCORCH_WIDTH, 1.0 + SMOKE_WIDTH, uProgress);
|
||||||
if (windowColor.a > 0) {
|
vec2 scorchRange = uForOpening ? vec2(hideThreshold - SCORCH_WIDTH, hideThreshold)
|
||||||
windowColor.rgb /= windowColor.a;
|
: vec2(hideThreshold, hideThreshold + SCORCH_WIDTH);
|
||||||
|
vec2 smokeRange = vec2(hideThreshold - SMOKE_WIDTH, hideThreshold);
|
||||||
|
|
||||||
|
vec2 uv = cogl_tex_coord_in[0].st / uScale * uSize;
|
||||||
|
float mask = getMask(uv);
|
||||||
|
|
||||||
|
vec2 distort = vec2(0.0);
|
||||||
|
|
||||||
|
if (!uForOpening && (smokeRange.x < mask && mask < smokeRange.y)) {
|
||||||
|
distort.y += pow(1.0 - (mask - smokeRange.x) / SMOKE_WIDTH, 2.0) * 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cogl_color_out = windowColor;
|
if ((uForOpening && mask > scorchRange.x) || (!uForOpening && mask <= scorchRange.y)) {
|
||||||
|
distort +=
|
||||||
|
0.5 * vec2(dFdx(mask), dFdy(mask)) * (scorchRange.y - mask) / SCORCH_WIDTH * 5.0;
|
||||||
|
}
|
||||||
|
|
||||||
vec2 uv = cogl_tex_coord_in[0].st * uSize / uScale;
|
vec4 oColor = getInputColor(cogl_tex_coord_in[0].st + distort);
|
||||||
|
|
||||||
float lfNoise = simplex2D(uv / max(uSize.x, uSize.y) + uSeed);
|
float xNoise = simplex2D(uv * 0.05 + uSeed * 10.0 + 0.0) - 0.5;
|
||||||
float hfNoise = simplex2DFractal(uv * 0.01 + uSeed);
|
float yNoise = simplex2D(uv * 0.05 + uSeed * 10.0 + uDuration * uProgress) - 0.5;
|
||||||
|
float maskDistorted = getMask(uv + vec2(xNoise, yNoise) * 50.0);
|
||||||
|
|
||||||
float noise = (lfNoise + hfNoise * uTurbulence * 0.5) / (1.0 + uTurbulence * 0.5);
|
float a = mask > hideThreshold ? 1.0 : 0.0;
|
||||||
|
float b = maskDistorted > hideThreshold ? 1.0 : 0.0;
|
||||||
|
float fireEdge = clamp(a - b, 0, 1) * oColor.a;
|
||||||
|
|
||||||
float burnProgress =
|
if (uForOpening && mask > smokeRange.y) {
|
||||||
(uForOpening ? 1.0 - uProgress / BURN_TIME : uProgress / BURN_TIME);
|
oColor = vec4(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
vec2 fireRange = vec2(burnProgress - FIRE_WIDTH, burnProgress + FIRE_WIDTH);
|
if (!uForOpening && mask < smokeRange.y) {
|
||||||
|
oColor = vec4(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
if (uForOpening) {
|
float smoke =
|
||||||
|
smoothstep(0, 1, (mask - smokeRange.x) / SMOKE_WIDTH) * getRelativeEdgeMask(0.1);
|
||||||
|
smoke *=
|
||||||
|
simplex2DFractal(uv * 0.01 + uSeed - smoke * smoke * vec2(0.0, 0.1 * uDuration));
|
||||||
|
float emberNoise =
|
||||||
|
simplex2DFractal(uv * 0.075 + uSeed - smoke * vec2(0.0, 0.5 * uDuration));
|
||||||
|
fireEdge = fireEdge * pow(emberNoise + 0.4, 4.0);
|
||||||
|
|
||||||
// Hide window.
|
if (smokeRange.x < mask && mask < smokeRange.y) {
|
||||||
if (noise < fireRange.x) {
|
|
||||||
cogl_color_out.a = 0.0;
|
oColor = alphaOver(oColor, vec4(0.5 * vec3(smoke), smoke));
|
||||||
|
float embers = clamp(pow(emberNoise + 0.32, 100.0), 0.0, 2.0) * smoke;
|
||||||
|
embers += clamp(pow(emberNoise + 0.32, 10.0), 0.0, 2.0) * smoke;
|
||||||
|
oColor = alphaOver(oColor, getFireColor(embers));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add scorch effect.
|
||||||
|
if (scorchRange.x < mask && mask < scorchRange.y) {
|
||||||
|
float scorch = smoothstep(1, 0, (mask - scorchRange.x) / SCORCH_WIDTH);
|
||||||
|
|
||||||
|
if (uForOpening) {
|
||||||
|
scorch = 1.0 - scorch;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
oColor.rgb = mix(oColor.rgb, mix(oColor.rgb, vec3(0.1, 0.05, 0.02), 0.4), scorch);
|
||||||
|
|
||||||
// Draw ash particles if the window is closed.
|
|
||||||
vec2 ashRange = vec2(burnProgress - ASH_WIDTH, burnProgress);
|
|
||||||
|
|
||||||
float ash = clamp(1.0 - (noise - ashRange.x) / (ashRange.y - ashRange.x), 0, 1);
|
|
||||||
// vec4 ashColor = vec4(0, 0, 0, 0);
|
|
||||||
// cogl_color_out = mix(cogl_color_out, ashColor, ash);
|
|
||||||
|
|
||||||
// for (float i = 0; i < ASH_LAYERS; ++i) {
|
|
||||||
|
|
||||||
// float factor = ASH_LAYERS == 1 ? 0 : i / (ASH_LAYERS - 1);
|
|
||||||
|
|
||||||
// Now check wether there is actually something in the current ash layer at
|
|
||||||
// the coords position.
|
|
||||||
vec2 ashMap = texture2D(uAshTexture, uv * 0.005).rg;
|
|
||||||
// float ashGroup = floor(ashMap.g * ASH_LAYERS * 0.999);
|
|
||||||
|
|
||||||
// if (ashGroup == i) {
|
|
||||||
|
|
||||||
// Get the window color.
|
|
||||||
// vec4 windowColor = texture2D(uTexture, coords + 0.5);
|
|
||||||
|
|
||||||
// // Shell.GLSLEffect uses straight alpha. So we have to convert from
|
|
||||||
// premultiplied. if (windowColor.a > 0) {
|
|
||||||
// windowColor.rgb /= windowColor.a;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Dissolve and blend the layers.
|
|
||||||
if (ashMap.x - ash < 0) {
|
|
||||||
cogl_color_out.a = 0;
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add fire.
|
oColor = alphaOver(oColor, getFireColor(fireEdge));
|
||||||
if (fireRange.x < noise && noise < fireRange.y) {
|
|
||||||
float fire = 1.0 - (noise - fireRange.x) / (fireRange.y - fireRange.x);
|
|
||||||
fire *= cogl_color_out.a;
|
|
||||||
cogl_color_out = alphaOver(cogl_color_out, getFireColor(fire));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add smoke.
|
setOutputColor(oColor);
|
||||||
vec2 smokeRange = uForOpening ? vec2(fireRange.y, 1.0) : vec2(0.0, fireRange.x);
|
|
||||||
if (smokeRange.x < noise && noise < smokeRange.y) {
|
|
||||||
float smoke = (noise - smokeRange.x) / (smokeRange.y - smokeRange.x);
|
|
||||||
|
|
||||||
if (!uForOpening) {
|
|
||||||
smoke = 1 - smoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 smokeShift = vec2(0, smoke * noise * uTime);
|
|
||||||
smoke *= simplex2DFractal(uv * 0.01 + uSeed + smokeShift);
|
|
||||||
smoke *= getRelativeEdgeMask(0.3);
|
|
||||||
|
|
||||||
float fadeOutProgress = clamp((uProgress - BURN_TIME) / (1.0 - BURN_TIME), 0, 1);
|
|
||||||
smoke *= 1 - fadeOutProgress;
|
|
||||||
|
|
||||||
cogl_color_out = alphaOver(cogl_color_out, vec4(vec3(0.2), smoke));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+2
-28
@@ -39,18 +39,9 @@ var Incinerate = class {
|
|||||||
this.shaderFactory = new ShaderFactory(this.getNick(), (shader) => {
|
this.shaderFactory = new ShaderFactory(this.getNick(), (shader) => {
|
||||||
// We import these modules in this function as they are not available in the
|
// We import these modules in this function as they are not available in the
|
||||||
// preferences process. This callback is only called within GNOME Shell's process.
|
// preferences process. This callback is only called within GNOME Shell's process.
|
||||||
const {Clutter, GdkPixbuf, Cogl} = imports.gi;
|
const {Clutter} = imports.gi;
|
||||||
|
|
||||||
// Create the texture in the first call.
|
|
||||||
if (!this._ashTexture) {
|
|
||||||
const ashData = GdkPixbuf.Pixbuf.new_from_resource('/img/dust.png');
|
|
||||||
this._ashTexture = new Clutter.Image();
|
|
||||||
this._ashTexture.set_data(ashData.get_pixels(), Cogl.PixelFormat.RGB_888,
|
|
||||||
ashData.width, ashData.height, ashData.rowstride);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store uniform locations of newly created shaders.
|
// Store uniform locations of newly created shaders.
|
||||||
shader._uAshTexture = shader.get_uniform_location('uAshTexture');
|
|
||||||
shader._uSeed = shader.get_uniform_location('uSeed');
|
shader._uSeed = shader.get_uniform_location('uSeed');
|
||||||
shader._uColor = shader.get_uniform_location('uColor');
|
shader._uColor = shader.get_uniform_location('uColor');
|
||||||
shader._uWidth = shader.get_uniform_location('uWidth');
|
shader._uWidth = shader.get_uniform_location('uWidth');
|
||||||
@@ -73,23 +64,6 @@ var Incinerate = class {
|
|||||||
shader.set_uniform_float(shader._uTurbulence, 1, [settings.get_double('incinerate-turbulence')]);
|
shader.set_uniform_float(shader._uTurbulence, 1, [settings.get_double('incinerate-turbulence')]);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is required to bind the ash texture for drawing. Sadly, this seems to be
|
|
||||||
// impossible under GNOME 3.3x as this.get_pipeline() is not available. It was
|
|
||||||
// called get_target() back then but this is not wrapped in GJS.
|
|
||||||
// https://gitlab.gnome.org/GNOME/mutter/-/blob/gnome-3-36/clutter/clutter/clutter-offscreen-effect.c#L598
|
|
||||||
shader.connect('update-animation', (shader) => {
|
|
||||||
const pipeline = shader.get_pipeline();
|
|
||||||
|
|
||||||
// Use linear filtering for the window texture.
|
|
||||||
pipeline.set_layer_filters(0, Cogl.PipelineFilter.LINEAR,
|
|
||||||
Cogl.PipelineFilter.LINEAR);
|
|
||||||
|
|
||||||
// Bind the ash texture.
|
|
||||||
pipeline.set_layer_texture(1, this._ashTexture.get_texture());
|
|
||||||
pipeline.set_layer_wrap_mode(1, Cogl.PipelineWrapMode.REPEAT);
|
|
||||||
pipeline.set_uniform_1i(shader._uAshTexture, 1);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +71,7 @@ var Incinerate = class {
|
|||||||
|
|
||||||
// This effect is only available on GNOME Shell 40+.
|
// This effect is only available on GNOME Shell 40+.
|
||||||
getMinShellVersion() {
|
getMinShellVersion() {
|
||||||
return [40, 0];
|
return [3, 36];
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will be called in various places where a unique identifier for this effect is
|
// This will be called in various places where a unique identifier for this effect is
|
||||||
|
|||||||
Reference in New Issue
Block a user