Skip to content

Add wallpaper example #1

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions shader_wallpaper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Shader Wallpaper

This is an example of using Quickshell as a wallpaper, along with using shaders.

To commpile the shader, do `qsb --qt6 -o ./Raining.frag.qsb ./Raining.frag`

I got the shader from [Shadertoy](https://www.shadertoy.com/view/ltffzl). By default, it's not compatible with QSB, so I had to make the following changes:
- convert `void mainImage( out vec4 fragColor, in vec2 fragCoord )` to just `void main()`
- add the following to the top of the file (it was easier than renaming all the uses of the input variables):

```glsl
#version 440

layout(location = 0) in vec2 fragCoord; // this is gotten from the `default.vert`
layout(location = 0) out vec4 fragColor;

layout(binding = 1) uniform sampler2D source; // background image

layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
float time;
vec2 resolution;
vec2 sourceResolution;
} ubuf;

#define iTime ubuf.time
#define iResolution ubuf.resolution
#define iChannel0 source
// I don't want to deal with mouse input
#define iMouse vec3(0.0, 0.0, 0.0)
```

> [!NOTE]
> Not all shadertoy shaders are easily compatible with QSL. You might have to do extra modifications.

![](./image.png)
239 changes: 239 additions & 0 deletions shader_wallpaper/Raining.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
// yoinked from https://www.shadertoy.com/view/ltffzl

#version 440

layout(location = 0) in vec2 fragCoord;
layout(location = 0) out vec4 fragColor;

layout(binding = 1) uniform sampler2D source;

layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
float time;
vec2 resolution;
vec2 sourceResolution;
} ubuf;

#define iTime ubuf.time
#define iResolution ubuf.resolution
#define iChannel0 source
// I don't want to deal with mouse input
#define iMouse vec3(0.0, 0.0, 0.0)

// Heartfelt - by Martijn Steinrucken aka BigWings - 2017
// Email:countfrolic@gmail.com Twitter:@The_ArtOfCode
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

// I revisited the rain effect I did for another shader. This one is better in multiple ways:
// 1. The glass gets foggy.
// 2. Drops cut trails in the fog on the glass.
// 3. The amount of rain is adjustable (with Mouse.y)

// To have full control over the rain, uncomment the HAS_HEART define

// A video of the effect can be found here:
// https://www.youtube.com/watch?v=uiF5Tlw22PI&feature=youtu.be

// Music - Alone In The Dark - Vadim Kiselev
// https://soundcloud.com/ahmed-gado-1/sad-piano-alone-in-the-dark
// Rain sounds:
// https://soundcloud.com/elirtmusic/sleeping-sound-rain-and-thunder-1-hours

#define S(a, b, t) smoothstep(a, b, t)
// #define CHEAP_NORMALS
// #define HAS_HEART
// #define HAS_LIGHTNING
#define USE_POST_PROCESSING

vec3 N13(float p) {
// from DAVE HOSKINS
vec3 p3 = fract(vec3(p) * vec3(.1031,.11369,.13787));
p3 += dot(p3, p3.yzx + 19.19);
return fract(vec3((p3.x + p3.y)*p3.z, (p3.x+p3.z)*p3.y, (p3.y+p3.z)*p3.x));
}

vec4 N14(float t) {
return fract(sin(t*vec4(123., 1024., 1456., 264.))*vec4(6547., 345., 8799., 1564.));
}
float N(float t) {
return fract(sin(t*12345.564)*7658.76);
}

float Saw(float b, float t) {
return S(0., b, t)*S(1., b, t);
}


vec2 DropLayer2(vec2 uv, float t) {
vec2 UV = uv;

uv.y += t*0.75;
vec2 a = vec2(6., 1.);
vec2 grid = a*2.;
vec2 id = floor(uv*grid);

float colShift = N(id.x);
uv.y += colShift;

id = floor(uv*grid);
vec3 n = N13(id.x*35.2+id.y*2376.1);
vec2 st = fract(uv*grid)-vec2(.5, 0);

float x = n.x-.5;

float y = UV.y*20.;
float wiggle = sin(y+sin(y));
x += wiggle*(.5-abs(x))*(n.z-.5);
x *= .7;
float ti = fract(t+n.z);
y = (Saw(.85, ti)-.5)*.9+.5;
vec2 p = vec2(x, y);

float d = length((st-p)*a.yx);

float mainDrop = S(.4, .0, d);

float r = sqrt(S(1., y, st.y));
float cd = abs(st.x-x);
float trail = S(.23*r, .15*r*r, cd);
float trailFront = S(-.02, .02, st.y-y);
trail *= trailFront*r*r;

y = UV.y;
float trail2 = S(.2*r, .0, cd);
float droplets = max(0., (sin(y*(1.-y)*120.)-st.y))*trail2*trailFront*n.z;
y = fract(y*10.)+(st.y-.5);
float dd = length(st-vec2(x, y));
droplets = S(.3, 0., dd);
float m = mainDrop+droplets*r*trailFront;

//m += st.x>a.y*.45 || st.y>a.x*.165 ? 1.2 : 0.;
return vec2(m, trail);
}

float StaticDrops(vec2 uv, float t) {
uv *= 40.;

vec2 id = floor(uv);
uv = fract(uv)-.5;
vec3 n = N13(id.x*107.45+id.y*3543.654);
vec2 p = (n.xy-.5)*.7;
float d = length(uv-p);

float fade = Saw(.025, fract(t+n.z));
float c = S(.3, 0., d)*fract(n.z*10.)*fade;
return c;
}

vec2 Drops(vec2 uv, float t, float l0, float l1, float l2) {
float s = StaticDrops(uv, t)*l0;
vec2 m1 = DropLayer2(uv, t)*l1;
vec2 m2 = DropLayer2(uv*1.85, t)*l2;

float c = s+m1.x+m2.x;
c = S(.3, 1., c);

return vec2(c, max(m1.y*l0, m2.y*l1));
}

void main()
{
vec2 uv = (fragCoord.xy-.5*iResolution.xy) / iResolution.y;
vec2 UV = fragCoord.xy/iResolution.xy;
vec3 M = vec3(iMouse.xy/iResolution.xy, 0.0);
float T = iTime+M.x*2.;

#ifdef HAS_HEART
T = mod(iTime, 102.);
T = mix(T, M.x*102., M.z>0.?1.:0.);
#endif


float t = T*.2;

float rainAmount = iMouse.z>0. ? M.y : sin(T*.05)*.3+.7;

float maxBlur = mix(3., 6., rainAmount);
float minBlur = 2.;

float story = 0.;
float heart = 0.;

#ifdef HAS_HEART
story = S(0., 70., T);

t = min(1., T/70.); // remap drop time so it goes slower when it freezes
t = 1.-t;
t = (1.-t*t)*70.;

float zoom= mix(.3, 1.2, story); // slowly zoom out
uv *=zoom;
minBlur = 4.+S(.5, 1., story)*3.; // more opaque glass towards the end
maxBlur = 6.+S(.5, 1., story)*1.5;

vec2 hv = uv-vec2(.0, -.1); // build heart
hv.x *= .5;
float s = S(110., 70., T); // heart gets smaller and fades towards the end
hv.y-=sqrt(abs(hv.x))*.5*s;
heart = length(hv);
heart = S(.4*s, .2*s, heart)*s;
rainAmount = heart; // the rain is where the heart is

maxBlur-=heart; // inside the heart slighly less foggy
uv *= 1.5; // zoom out a bit more
t *= .25;
#else
float zoom = 0;//-cos(T*.2);
uv *= .7+zoom*.3;
#endif
UV = (UV-.5)*(.9+zoom*.1)+.5;

float staticDrops = S(-.5, 1., rainAmount)*2.;
float layer1 = S(.25, .75, rainAmount);
float layer2 = S(.0, .5, rainAmount);


vec2 c = Drops(uv, t, staticDrops, layer1, layer2);
#ifdef CHEAP_NORMALS
vec2 n = vec2(dFdx(c.x), dFdy(c.x));// cheap normals (3x cheaper, but 2 times shittier ;))
#else
vec2 e = vec2(.001, 0.);
float cx = Drops(uv+e, t, staticDrops, layer1, layer2).x;
float cy = Drops(uv+e.yx, t, staticDrops, layer1, layer2).x;
vec2 n = vec2(cx-c.x, cy-c.x); // expensive normals
#endif


#ifdef HAS_HEART
n *= 1.-S(60., 85., T);
c.y *= 1.-S(80., 100., T)*.8;
#endif

float focus = mix(maxBlur-c.y, minBlur, S(.1, .2, c.x));
vec3 col = textureLod(iChannel0, (UV+n) * vec2(1.0, -1.0) + vec2(0.0, 1.0), focus).rgb;


#ifdef USE_POST_PROCESSING
t = (T+3.)*.5; // make time sync with first lightnoing
float colFade = sin(t*.2)*.5+.5+story;
col *= mix(vec3(1.), vec3(.8, .9, 1.3), colFade); // subtle color shift
float fade = S(0., 10., T); // fade in at the start
#ifdef HAS_LIGHTNING
float lightning = sin(t*sin(t*10.)); // lighting flicker
lightning *= pow(max(0., sin(t+sin(t))), 10.); // lightning flash
col *= 1.+lightning*fade*mix(1., .1, story*story); // composite lightning
#endif
col *= 1.-dot(UV-=.5, UV); // vignette

#ifdef HAS_HEART
col = mix(pow(col, vec3(1.2)), col, heart);
fade *= S(102., 97., T);
#endif

col *= fade; // composite start and end fade
#endif

//col = vec3(heart);
fragColor = vec4(col, 1.);
}
Binary file added shader_wallpaper/Raining.frag.qsb
Binary file not shown.
14 changes: 14 additions & 0 deletions shader_wallpaper/default.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#version 440
layout(location = 0) in vec4 qt_Vertex;
layout(location = 1) in vec2 qt_MultiTexCoord0;
layout(location = 0) out vec2 fragCoord;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
vec2 resolution;
};
void main() {
// make it easier to port from Shadertoy
fragCoord = qt_MultiTexCoord0 * resolution * vec2(1.0, -1.0) + resolution * vec2(0.0, 1.0);
gl_Position = qt_Matrix * qt_Vertex;
}
Binary file added shader_wallpaper/default.vert.qsb
Binary file not shown.
Binary file added shader_wallpaper/hollow.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added shader_wallpaper/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions shader_wallpaper/shell.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import Quickshell
import QtQuick
import Quickshell.Wayland // for WlrLayershell & WlrLayer

ShellRoot {
PanelWindow {
WlrLayershell.layer: WlrLayer.Background // use this to make it background

anchors {
top: true
left: true
right: true
bottom: true
}

color: "transparent"

Rectangle {
anchors.fill: parent
color: "transparent"
Image { // if you want a gif, use AnimatedImage instead
id: img
source: "./hollow.jpg"
fillMode: Image.PreserveAspectCrop
anchors.fill: parent
visible: false
mipmap: true
}
ShaderEffect {
id: shader
anchors.fill: parent
property vector2d resolution: Qt.vector2d(width, height)
property real time: 0
property variant source: img
FrameAnimation {
running: true
onTriggered: {
shader.time = this.elapsedTime;
}
}
vertexShader: "default.vert.qsb"
fragmentShader: "Raining.frag.qsb"
}
}
}
}