summary refs log tree commit diff
path: root/Shaders/index.md
blob: 83ff1dc18ef69e7f06325245f806c29844791a28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
---
description: "My findings while playing around with <i>fragment</i> shaders"
created: 2025-01-04
---

<canvas id="my-canvas"></canvas>

<span id="my-canvas-description">**Shader eye candy**</span>

<span style="color: grey">if you do not see the image above, check if your browser supports webgl, at: [caniuse.com/webgl](https://caniuse.com/webgl)</span>

I'll link the resources i used as an introduction to the subject, hence this serves as an OK starting point.

## How to get started

1. Browse [shadertoys.com](https://www.shadertoy.com/results?query=&sort=popular&filter=), and be inspired.
2. Step 2 realise that it's coded in the forbidden tounge of black magic "enchantment book" moon runes.
   That some people call... <b style="font-size: 1.2em; color: #f88" class="wavy-text">math</b> *queue ominous thunder effect*
3. Watch this video
   [Introduction to shaders: Learn the basics! by Barney Codes - youtube.com](https://www.youtube.com/watch?v=3mfvZ-mdtZQ)
   (a few times) To learn the basics.
4. Realise the ancient magic is is not reserved for only wizards and high elves alike.
   On the contrary like with most things, you'll find that it's quite surmountable,
   if you break the subject matter down into bite sized pieces.
6. On this note i present to you a cheat sheets that lists the functions available to you:
   [A cheat sheet of which functions can be called - http://learnwebgl.brown37.net](http://learnwebgl.brown37.net/12_shader_language/documents/webgl-reference-card-1_0.pdf)
   (see page 4)
7. The grind - Put in the legwork playing around with this newfound knowledge.
   This part is the hardest, and most frustratin, as you put in a lot of work into making the most basic of things.
   But if you keep it up, you'll eventually make something that looks halfway decent.

After a few days of playing around using the knowledge gained from the video linked above,
i was able to code [what you see above](#my-canvas). Albeit i have a background as a developer.
All this is to say, tamper you expectations before getting into the subject matter,
it takes some time before you make something halfway decent,
and i still am not able to bring all my ideas to fruition.

You'll often times find that you accidentally create something interesting,
just by faffing about with mathematical functions.
On that note, you can 
## --> [view my shaders here](https://node5.net/shader_indexes/my_shaders/) <--

## Embed on page

I use the JS libary [shader-web-background by xemantic - github.com](https://github.com/xemantic/shader-web-background)
to embed shaders on my website [as seen above](#my-canvas).
It's also utilized on my landing page in the background [node5.net](https://node5.net/).
So masive shout out to [xemantic](https://xemantic.com/), [go buy them a tea](https://buymeacoffee.com/kazik)


![node5 landing page grid tunnel shader background](node5_landing_page_grid_tunnel.gif)

As xemantic also points out, one of the awesome things about shaders instead of e.g. video is the miniscule file size.
To put it into perspective the gif shown above is `236 kilo bytes`
While the HTML, CSS, and JS and shader reuqired to produce said page is a mere `16.08 kilo bytes`
That's a 14.67x difference. This arguably just shows how horrible the GIF format is for anything but the simplest
of things, given it's lack of interframe compression. A GIF meerly consists of sequential images, as opposed to video
that uses advanced <b style="font-size: 1.2em; color: #f88" class="wavy-text">math</b> to bring down the file size.
Shaders on the otherhand scale to be crisp on any device. Furthermore they can be interactive, morphing with user input.


![](transfer.png)

![](node5_landing_page_grid_tunnel.webp)

<style>
#my-canvas {
	width: 100%;
	height: 30em;
}

@font-face {
    font-family: 'WavedLine-BL3';
    src: url('WavedLine-BL3.ttf') format('truetype');
}

.wavy-text {
    font-family: 'WavedLine-BL3';
}
</style>


<!-- region shader code -->

<script src="shader-web-background.min.js"></script>
<script type="x-shader/x-fragment" id="Image">
	precision highp float;

	uniform vec2	iResolution;
	uniform float iTime;
	uniform vec2  iMouse;
	uniform sampler2D iChannel0;

	// -- Paste your Shadertoy code here

	float color_scale = 1.;
	float color_wave_speed = -.25;
	float mouse_effect = 0.00005;
	float wave_height = 1.5;


	void mainImage( out vec4 fragColor, in vec2 fragCoord )
	{
		// Normalized pixel coordinates (from 0 to 1)
		vec2 uv = fragCoord/iResolution.xy;
		uv.x *= iResolution.x/iResolution.y; // Make it scale evenly on all resolutions (makes it work on phones)
		uv.y *= 2.2; // Set the width

		// Generate color 1
		vec3 col1_1 = vec3(0, 0, .2);
		vec3 col1_2 = vec3(.2, 0, 0.1);
		vec3 col_1 = mix(col1_1, col1_2, sin(sin(uv.x + iTime * color_wave_speed) * color_scale));

		// Generate color 2
		vec3 col2_1 = vec3(0.,1.,1.);
		vec3 col2_2 = vec3(1., 0., 1.);
		vec3 col_2 = mix(col2_1, col2_2, sin(uv.y + iTime * color_wave_speed) * color_scale);

		// Generate waves
		float d = sin(uv.y + uv.x - wave_height);
		//d += abs(float(uv.y / uv.x) / sin(iTime / 35.) / 10.);

		float c = sin((uv.x + iMouse.x * mouse_effect) * 35.) / (sin(((uv.y + iMouse.y * 2. * mouse_effect) * 20.) - iTime) + 3.);
		//c = sin(c * 2.);
		//float d = c;
		//d = step(.1, d);

		// Intersect waves
		//d = clamp(iTime - d, 0., .1);
		d = step(c, d);

		// Use color for mask
		vec3 col_3 = mix(col_2, col_1, d);

		// Output to screen
		fragColor = vec4(col_3,1.);
	}

	// -- End of Shadertoy code

	void main() {
		mainImage(gl_FragColor, gl_FragCoord.xy);
	}
</script>

<script>
	// mouse coordinates taken from from the mousemove event
	var mouseX;
	var mouseY;

	document.addEventListener("mousemove", (event) => {
		 mouseX = event.clientX;
		 mouseY = event.clientY;
	});

	// mouse coordinates relative to the shader, you can also store them on the context
	var shaderMouseX;
	var shaderMouseY;
	shaderWebBackground.shade({
		canvas: document.getElementById("my-canvas"),
		onInit: (ctx) => {
			// screen center
			mouseX = ctx.cssWidth / 2;
			mouseY = ctx.cssHeight / 2;
		},

	onBeforeFrame: (ctx) => {
		shaderMouseX = ctx.toShaderX(mouseX);
		shaderMouseY = ctx.toShaderY(mouseY);
	},
		shaders: {
			Image: {
				uniforms: {
					iResolution: (gl, loc, ctx) => gl.uniform2f(loc, ctx.width, ctx.height),
					iTime:       (gl, loc) => gl.uniform1f(loc, performance.now() / 1000),
					iChannel0:   (gl, loc, ctx) => ctx.texture(loc, ctx.buffers.BufferA),
					iMouse:      (gl, loc) => gl.uniform2f(loc, shaderMouseX, shaderMouseY)
				}
			}
		}
	});
</script>

<!-- endregion shader code -->

<!-- region lines -->

<script src="leader-line.min.js"></script>
<script defer>
// Add new leader line from `start` to `end` (HTML/SVG element, basically).
new LeaderLine(
	document.getElementById('my-canvas-description'),
	document.getElementById('my-canvas'),
	{ dash: {animation: true}, color: 'white', startSocket: 'right', endSocket: 'bottom'}
);
</script>

<!-- endregion lines -->