Skip to content

Commit b23bacb

Browse files
committed
feat: enhance shader builders with childBuilder method and update noise overlay shader for improved film grain effect
1 parent 58d71d6 commit b23bacb

File tree

8 files changed

+65
-107
lines changed

8 files changed

+65
-107
lines changed

lib/crt_shader_builder.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_shaders/flutter_shaders.dart';
3+
import 'package:shaders/tv_test_screen.dart';
34
import 'dart:ui';
45
import 'shader_builder.dart';
56

@@ -32,4 +33,9 @@ class CrtShaderBuilder extends CustomShaderBuilder {
3233
);
3334
}, child: child ?? const SizedBox());
3435
}
36+
37+
@override
38+
Widget? childBuilder(BuildContext context) {
39+
return const Center(child: TvTestScreen());
40+
}
3541
}

lib/main.dart

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class ShaderInfo {
4949

5050
final shaders = [
5151
ShaderInfo(
52-
name: 'NTSC',
52+
name: 'NTSC filter',
5353
assetKey: 'shaders/ntsc_shader.frag',
5454
description: 'An effect that emulates an old NTSC television signal.',
5555
sourceUrl: 'https://www.shadertoy.com/view/3tVBWR',
@@ -59,7 +59,7 @@ final shaders = [
5959
path: 'ntsc-shader',
6060
),
6161
ShaderInfo(
62-
name: 'CRT',
62+
name: 'Interlaced Glitch CRT',
6363
assetKey: 'shaders/crt_shader.frag',
6464
description: 'A glitching screen effect',
6565
sourceUrl: 'https://www.shadertoy.com/view/lt3yz7',
@@ -69,7 +69,7 @@ final shaders = [
6969
path: 'crt-shader',
7070
),
7171
ShaderInfo(
72-
name: 'Noise',
72+
name: 'Lava Lamp Gradient',
7373
assetKey: 'shaders/noise_shader.frag',
7474
description: 'Animated gradient noise with film grain effect',
7575
sourceUrl: 'https://www.shadertoy.com/view/DdcfzH',
@@ -198,7 +198,6 @@ class HomeScreen extends StatelessWidget {
198198
body: Column(
199199
children: [
200200
const TopMenu(),
201-
202201
Expanded(child: ContentGrid()),
203202
],
204203
),
@@ -279,14 +278,6 @@ class TopMenu extends StatelessWidget {
279278
),
280279
),
281280
const Spacer(),
282-
// Search placeholder
283-
SizedBox(
284-
width: 300,
285-
child: ShadInput(
286-
placeholder: const Text('Search shaders...'),
287-
enabled: false,
288-
),
289-
),
290281
],
291282
),
292283
);

lib/noise_overlay_shader_builder.dart

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class NoiseOverlayShaderBuilder extends CustomShaderBuilder {
88
final double noiseOpacity;
99

1010
const NoiseOverlayShaderBuilder({
11-
this.filmGrainIntensity = 0.1,
11+
this.filmGrainIntensity = 0.2,
1212
this.noiseOpacity = 0.3,
1313
});
1414

@@ -23,9 +23,7 @@ class NoiseOverlayShaderBuilder extends CustomShaderBuilder {
2323
shader
2424
..setFloat(0, size.width)
2525
..setFloat(1, size.height)
26-
..setFloat(2, time)
27-
..setFloat(3, filmGrainIntensity)
28-
..setFloat(4, noiseOpacity);
26+
..setFloat(2, filmGrainIntensity);
2927
}
3028

3129
@override
@@ -36,12 +34,40 @@ class NoiseOverlayShaderBuilder extends CustomShaderBuilder {
3634
double time,
3735
Widget? child,
3836
) {
39-
return AnimatedSampler((image, size, canvas) {
40-
shader.setImageSampler(0, image);
41-
canvas.drawRect(
42-
Rect.fromLTWH(0, 0, size.width, size.height),
43-
Paint()..shader = shader,
44-
);
45-
}, child: child ?? const SizedBox());
37+
return Stack(
38+
children: [
39+
AnimatedSampler(
40+
(image, size, canvas) {
41+
shader.setImageSampler(0, image);
42+
canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), Paint()..shader = shader);
43+
},
44+
45+
child: child ?? const SizedBox(),
46+
),
47+
Center(
48+
child: Text(
49+
'Noise',
50+
style: TextStyle(color: Colors.white, fontSize: 32, fontWeight: FontWeight.bold),
51+
),
52+
),
53+
],
54+
);
55+
}
56+
57+
@override
58+
Widget? childBuilder(BuildContext context) {
59+
return Center(
60+
child: Padding(
61+
padding: const EdgeInsets.all(24.0),
62+
child: Container(
63+
color: Colors.blue,
64+
65+
child: SizedBox(
66+
width: 300,
67+
height: 200,
68+
),
69+
),
70+
),
71+
);
4672
}
4773
}

lib/noise_shader_builder.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ class NoiseShaderBuilder extends CustomShaderBuilder {
3535
painter: _NoiseShaderPainter(shader),
3636
);
3737
}
38+
39+
@override
40+
Widget? childBuilder(BuildContext context) {
41+
return null;
42+
}
3843
}
3944

4045
class _NoiseShaderPainter extends CustomPainter {

lib/ntsc_shader_builder.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_shaders/flutter_shaders.dart';
3+
import 'package:shaders/tv_test_screen.dart';
34
import 'dart:ui';
45
import 'shader_builder.dart';
56

@@ -32,4 +33,9 @@ class NtscShaderBuilder extends CustomShaderBuilder {
3233
);
3334
}, child: child ?? const SizedBox());
3435
}
36+
37+
@override
38+
Widget? childBuilder(BuildContext context) {
39+
return const Center(child: TvTestScreen());
40+
}
3541
}

lib/shader_builder.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ abstract class CustomShaderBuilder {
2929
Widget? child,
3030
);
3131

32+
Widget? childBuilder(BuildContext context);
33+
3234
/// Whether this shader requires an image sampler
3335
bool get requiresImageSampler => true;
3436

lib/widgets/shader_animation_view.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class _ShaderAnimationViewState extends State<ShaderAnimationView>
9797
shader,
9898
size.biggest,
9999
timeValue,
100-
const Center(child: TvTestScreen()),
100+
widget.shaderInfo.builder.childBuilder(context),
101101
);
102102
},
103103
);

shaders/noise_overlay_shader.frag

Lines changed: 5 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,20 @@ precision mediump float;
77
#include <flutter/runtime_effect.glsl>
88

99
uniform vec2 iResolution;
10-
uniform float iTime;
1110
uniform float filmGrainIntensity;
12-
uniform float noiseOpacity;
1311
uniform sampler2D iChannel0;
1412

1513
out vec4 fragColor;
1614

1715
// Inspired by https://www.shadertoy.com/view/wdyczG
1816
// Licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License:
1917
// https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
20-
mat2 Rot(float a) {
21-
float s = sin(a);
22-
float c = cos(a);
23-
return mat2(c, -s, s, c);
24-
}
2518

2619
vec2 hash(vec2 p) {
2720
p = vec2(dot(p, vec2(2127.1, 81.17)), dot(p, vec2(1269.5, 283.37)));
2821
return fract(sin(p)*43758.5453);
2922
}
3023

31-
float noise(in vec2 p) {
32-
vec2 i = floor(p);
33-
vec2 f = fract(p);
34-
35-
vec2 u = f*f*(3.0-2.0*f);
36-
37-
float n = mix(mix(dot(-1.0+2.0*hash(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)),
38-
dot(-1.0+2.0*hash(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)), u.x),
39-
mix(dot(-1.0+2.0*hash(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)),
40-
dot(-1.0+2.0*hash(i + vec2(1.0, 1.0)), f - vec2(1.0, 1.0)), u.x), u.y);
41-
return 0.5 + 0.5*n;
42-
}
43-
4424
float filmGrainNoise(in vec2 uv) {
4525
return length(hash(vec2(uv.x, uv.y)));
4626
}
@@ -49,73 +29,15 @@ void main()
4929
{
5030
vec2 fragCoord = FlutterFragCoord().xy;
5131
vec2 uv = fragCoord / iResolution.xy;
52-
float aspectRatio = iResolution.x / iResolution.y;
5332

5433
// Get the original image/widget content
5534
vec3 originalColor = texture(iChannel0, uv).rgb;
5635

57-
// Transformed uv for noise generation
58-
vec2 tuv = uv - .5;
59-
60-
// Rotate with noise
61-
float degree = noise(vec2(iTime*.05, tuv.x*tuv.y));
62-
63-
tuv.y *= 1./aspectRatio;
64-
tuv *= Rot(radians((degree-.5)*720.+180.));
65-
tuv.y *= aspectRatio;
66-
67-
// Wave warp with sine
68-
float frequency = 5.;
69-
float amplitude = 30.;
70-
float speed = iTime * 2.;
71-
tuv.x += sin(tuv.y*frequency+speed)/amplitude;
72-
tuv.y += sin(tuv.x*frequency*1.5+speed)/(amplitude*.5);
73-
74-
// Light gradient colors
75-
vec3 amberYellow = vec3(299, 186, 137) / vec3(255);
76-
vec3 deepBlue = vec3(49, 98, 238) / vec3(255);
77-
vec3 pink = vec3(246, 146, 146) / vec3(255);
78-
vec3 blue = vec3(89, 181, 243) / vec3(255);
79-
80-
// Dark gradient colors
81-
vec3 purpleHaze = vec3(105, 49, 245) / vec3(255);
82-
vec3 swampyBlack = vec3(32, 42, 50) / vec3(255);
83-
vec3 persimmonOrange = vec3(233, 51, 52) / vec3(255);
84-
vec3 darkAmber = vec3(233, 160, 75) / vec3(255);
85-
86-
// Interpolate between light and dark gradient
87-
float cycle = sin(iTime * 0.5);
88-
float t = (sign(cycle) * pow(abs(cycle), 0.6) + 1.) / 2.;
89-
vec3 color1 = mix(amberYellow, purpleHaze, t);
90-
vec3 color2 = mix(deepBlue, swampyBlack, t);
91-
vec3 color3 = mix(pink, persimmonOrange, t);
92-
vec3 color4 = mix(blue, darkAmber, t);
93-
94-
// Blend the gradient colors and apply transformations
95-
vec3 layer1 = mix(color3, color2, smoothstep(-.3, .2, (tuv*Rot(radians(-5.))).x));
96-
vec3 layer2 = mix(color4, color1, smoothstep(-.3, .2, (tuv*Rot(radians(-5.))).x));
97-
98-
vec3 noiseColor = mix(layer1, layer2, smoothstep(.5, -.3, tuv.y));
99-
100-
// Apply film grain to noise
101-
noiseColor = noiseColor - filmGrainNoise(uv) * filmGrainIntensity;
102-
103-
// Blend the noise effect with the original image
104-
// Use various blend modes for different effects
105-
vec3 finalColor = mix(originalColor, noiseColor, noiseOpacity);
106-
107-
// Alternative blend modes (uncomment to try different effects):
108-
// Overlay blend mode:
109-
// vec3 finalColor = mix(originalColor,
110-
// originalColor < 0.5 ? 2.0 * originalColor * noiseColor
111-
// : 1.0 - 2.0 * (1.0 - originalColor) * (1.0 - noiseColor),
112-
// noiseOpacity);
113-
114-
// Screen blend mode:
115-
// vec3 finalColor = mix(originalColor, 1.0 - (1.0 - originalColor) * (1.0 - noiseColor), noiseOpacity);
116-
117-
// Multiply blend mode:
118-
// vec3 finalColor = mix(originalColor, originalColor * noiseColor, noiseOpacity);
36+
// Apply film grain
37+
float grain = filmGrainNoise(uv) * filmGrainIntensity;
38+
// Mix the grain with the original color instead of subtracting
39+
// This creates a more natural film grain effect
40+
vec3 finalColor = originalColor * (1.0 - grain * 0.5) + grain * 0.1;
11941

12042
fragColor = vec4(finalColor, texture(iChannel0, uv).a);
12143
}

0 commit comments

Comments
 (0)