🔧 Tweak shader

This commit is contained in:
Simon Schneegans
2022-05-31 05:55:19 +02:00
parent d6e46d951c
commit 1e665f0db3
3 changed files with 117 additions and 47 deletions
+86 -41
View File
@@ -13,79 +13,124 @@
// 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 FIRE_WIDTH = 0.03;
const float ASH_WIDTH = 0.5;
const float ASH_LAYERS = 4;
vec4 getFireColor(float v) { vec4 getFireColor(float v) {
const float steps[3] = float[](0.0, 0.5, 1.0); const float steps[4] = float[](0.0, 0.33, 0.66, 1.0);
vec4 colors[3] = vec4[](vec4(1, 0, 0, 0), vec4(1, 0, 0, 0.5), vec4(1, 1, 0, 1)); 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]) { if (v < steps[0]) {
return colors[0]; return colors[0];
} }
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 3; ++i) {
if (v <= steps[i + 1]) { if (v <= steps[i + 1]) {
return mix(colors[i], colors[i + 1], float blend = smoothstep(0, 1, (v - steps[i]) / (steps[i + 1] - steps[i]));
vec4(v - steps[i]) / (steps[i + 1] - steps[i])); return mix(colors[i], colors[i + 1], vec4(blend));
} }
} }
return colors[2]; return colors[3];
} }
void main() { void main() {
float progress = uProgress / 0.8;
progress = uForOpening ? 1.0 - progress : progress;
vec2 uv = 0.01 * cogl_tex_coord_in[0].st * uSize / uScale;
float lfNoise = simplex2D(cogl_tex_coord_in[0].st + uSeed);
lfNoise = mix(lfNoise - 1.0, lfNoise + 1.0, progress);
float hfNoise = simplex2DFractal(uv + uSeed);
hfNoise = mix(hfNoise - 1.0, hfNoise + 1.0, progress);
float noise = mix(lfNoise, hfNoise, uTurbulence);
float fire = noise / (0.03 * uWidth) - progress / (0.03 * uWidth) + progress;
vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st);
// Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied. // Shell.GLSLEffect uses straight alpha. So we have to convert from premultiplied.
vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st);
if (windowColor.a > 0) { if (windowColor.a > 0) {
windowColor.rgb /= windowColor.a; windowColor.rgb /= windowColor.a;
} }
cogl_color_out = windowColor; cogl_color_out = windowColor;
if (fire >= 1) { vec2 uv = cogl_tex_coord_in[0].st * uSize / uScale;
cogl_color_out.a = 0;
} else if (fire > 0) { float lfNoise = simplex2D(uv / max(uSize.x, uSize.y) + uSeed);
vec4 fire = getFireColor(fire); float hfNoise = simplex2DFractal(uv * 0.01 + uSeed);
fire.a *= cogl_color_out.a;
cogl_color_out = alphaOver(cogl_color_out, fire); float noise = (lfNoise + hfNoise * uTurbulence * 0.5) / (1.0 + uTurbulence * 0.5);
float burnProgress =
(uForOpening ? 1.0 - uProgress / BURN_TIME : uProgress / BURN_TIME);
vec2 fireRange = vec2(burnProgress - FIRE_WIDTH, burnProgress + FIRE_WIDTH);
if (uForOpening) {
// Hide window.
if (noise < fireRange.x) {
cogl_color_out.a = 0.0;
}
} else {
// 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;
}
// }
// }
} }
if ((uForOpening && fire < 0) || (!uForOpening && fire > 1)) { // Add fire.
float smoke = (uForOpening ? -fire : fire - 1) * uWidth; 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));
}
vec2 uv = 0.01 * cogl_tex_coord_in[0].st * uSize / uScale; // Add smoke.
vec2 smokeShift = vec2(0, smoke * 0.1); vec2 smokeRange = uForOpening ? vec2(fireRange.y, 1.0) : vec2(0.0, fireRange.x);
smoke = clamp(smoke, 0, 1) * simplex2DFractal(uv + uSeed + smokeShift); 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); smoke *= getRelativeEdgeMask(0.3);
float fadeOutProgress = clamp((uProgress - 0.7) / 0.3, 0, 1); float fadeOutProgress = clamp((uProgress - BURN_TIME) / (1.0 - BURN_TIME), 0, 1);
smoke *= 1 - fadeOutProgress; smoke *= 1 - fadeOutProgress;
cogl_color_out = alphaOver(cogl_color_out, vec4(vec3(0.2), smoke)); cogl_color_out = alphaOver(cogl_color_out, vec4(vec3(0.2), smoke));
} }
// if (cogl_tex_coord_in[0].s > 0.5) {
// cogl_color_out = vec4(vec3(noise), 1.0);
// }
} }
@@ -348,7 +348,7 @@
</key> </key>
<key name="incinerate-animation-time" type="i"> <key name="incinerate-animation-time" type="i">
<default>2000</default> <default>3500</default>
<summary>Incinerate Animation Time</summary> <summary>Incinerate Animation Time</summary>
<description>The time the Incinerate effect takes.</description> <description>The time the Incinerate effect takes.</description>
</key> </key>
@@ -366,7 +366,7 @@
</key> </key>
<key name="incinerate-turbulence" type="d"> <key name="incinerate-turbulence" type="d">
<default>0.15</default> <default>0.2</default>
<summary>Incinerate Turbulence</summary> <summary>Incinerate Turbulence</summary>
<description>The turbulence of the effect.</description> <description>The turbulence of the effect.</description>
</key> </key>
+29 -4
View File
@@ -37,12 +37,20 @@ var Incinerate = class {
// newly created shader instance. // newly created shader instance.
constructor() { constructor() {
this.shaderFactory = new ShaderFactory(this.getNick(), (shader) => { this.shaderFactory = new ShaderFactory(this.getNick(), (shader) => {
// We import Clutter in this function as it is not available in the preferences // We import these modules in this function as they are not available in the
// process. This creator function of the ShaderFactory is only called within GNOME // preferences process. This callback is only called within GNOME Shell's process.
// Shell's process. const {Clutter, GdkPixbuf, Cogl} = imports.gi;
const Clutter = imports.gi.Clutter;
// 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');
@@ -65,6 +73,23 @@ 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);
});
}); });
} }