Skip to content

Commit a7be276

Browse files
authored
Add new sample simple_sdf (#2835)
Add a new sample, `simple_sdf`. This is similar to `simple_shader`, but it focuses on using Signed Distance Functions within the fragment shader. Relates to issue [#183043](flutter/flutter#183043) ## Pre-launch Checklist - [x] I read the [Flutter Style Guide] _recently_, and have followed its advice. - [x] I signed the [CLA]. - [x] I read the [Contributors Guide]. - [ ] I have added sample code updates to the [changelog]. - [x] I updated/added relevant documentation (doc comments with `///`). If you need help, consider asking for advice on the #hackers-devrel channel on [Discord]. <!-- Links --> [Flutter Style Guide]: https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md [CLA]: https://cla.developers.google.com/ [Discord]: https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md [Contributors Guide]: https://github.com/flutter/samples/blob/main/CONTRIBUTING.md [changelog]: ../CHANGELOG.md
1 parent c28ef87 commit a7be276

11 files changed

Lines changed: 216 additions & 0 deletions

File tree

.github/dependabot.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,12 @@ updates:
281281
interval: "daily"
282282
labels:
283283
- "autosubmit"
284+
- package-ecosystem: "pub"
285+
directory: "simple_sdf/"
286+
schedule:
287+
interval: "daily"
288+
labels:
289+
- "autosubmit"
284290
- package-ecosystem: "pub"
285291
directory: "simple_shader/"
286292
schedule:

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Googler's, you can freely add samples to the [flutter/demos] repository.
2828
* [`navigation_and_routing`] - A sample that shows how to use [go_router] API to handle common navigation scenarios.
2929
* [`pedometer`] - A demo of a plugin that leverages FFIgen & JNIgen to call platform APIs directly from Dart code.
3030
* [`platform_design`] - This sample project shows a Flutter app that maximizes application code reuse while adhering to different design patterns on Android and iOS.
31+
* [`simple_sdf`] - A simple [Flutter fragment shaders] sample project showing how to draw Signed Distance Functions with the FragmentShader API.
3132
* [`simple_shader`] - A simple [Flutter fragment shaders] sample project.
3233
* [`testing_app`] - A sample app that shows different types of testing in Flutter.
3334
* [`web_embedding`] - This directory contains examples of how to embed Flutter in web apps (without iframes).
@@ -123,6 +124,7 @@ If you run into a bug in one of the samples, please file an issue in the
123124
[`navigation_and_routing`]: ./navigation_and_routing
124125
[`pedometer`]: ./pedometer
125126
[`platform_design`]: ./platform_design
127+
[`simple_sdf`]: ./simple_sdf
126128
[`simple_shader`]: ./simple_shader
127129
[`testing_app`]: ./testing_app
128130
[`web_embedding`]: ./web_embedding

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ workspace:
3535
- platform_channels
3636
- platform_design
3737
- platform_view_swift
38+
- simple_sdf
3839
- simple_shader
3940
- testing_app
4041
- tool

simple_sdf/.gitignore

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Miscellaneous
2+
*.class
3+
*.log
4+
*.pyc
5+
*.swp
6+
.DS_Store
7+
.atom/
8+
.buildlog/
9+
.history
10+
.svn/
11+
migrate_working_dir/
12+
13+
# IntelliJ related
14+
*.iml
15+
*.ipr
16+
*.iws
17+
.idea/
18+
19+
# The .vscode folder contains launch configuration and tasks you configure in
20+
# VS Code which you may wish to be included in version control, so this line
21+
# is commented out by default.
22+
#.vscode/
23+
24+
# Flutter/Dart/Pub related
25+
**/doc/api/
26+
**/ios/Flutter/.last_build_id
27+
.dart_tool/
28+
.flutter-plugins
29+
.flutter-plugins-dependencies
30+
.packages
31+
.pub-cache/
32+
.pub/
33+
/build/
34+
35+
# Symbolication related
36+
app.*.symbols
37+
38+
# Obfuscation related
39+
app.*.map.json
40+
41+
# Android Studio will place build artifacts here
42+
/android/app/debug
43+
/android/app/profile
44+
/android/app/release

simple_sdf/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# `simple_sdf`
2+
3+
A simple [Flutter fragment shaders][] sample project showing how to draw Signed Distance Functions with the FragmentShader API.
4+
5+
Use `flutter create --no-overwrite .` to initialize the project.
6+
7+
[Flutter fragment shaders]: https://docs.flutter.dev/development/ui/advanced/shaders
8+
9+
![Screenshot of the `simple_sdf` app](screenshot.png)

simple_sdf/analysis_options.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include: package:analysis_defaults/flutter.yaml

simple_sdf/lib/main.dart

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import 'dart:ui' as ui;
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:flutter_shaders/flutter_shaders.dart';
5+
6+
void main() {
7+
runApp(const MyApp());
8+
}
9+
10+
class MyApp extends StatelessWidget {
11+
const MyApp({super.key});
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return MaterialApp(
16+
title: 'Simple SDF Demo',
17+
theme: ThemeData(colorSchemeSeed: Colors.blue),
18+
home: const MyHomePage(),
19+
);
20+
}
21+
}
22+
23+
class MyHomePage extends StatelessWidget {
24+
const MyHomePage({super.key});
25+
26+
@override
27+
Widget build(BuildContext context) {
28+
return Scaffold(
29+
appBar: AppBar(title: const Text('Simple SDF Demo')),
30+
body: ShaderBuilder(
31+
assetKey: 'shaders/SDF.frag',
32+
(context, shader, child) => CustomPaint(
33+
size: MediaQuery.of(context).size,
34+
painter: ShaderPainter(shader: shader),
35+
),
36+
child: const Center(child: CircularProgressIndicator()),
37+
),
38+
);
39+
}
40+
}
41+
42+
class ShaderPainter extends CustomPainter {
43+
ShaderPainter({required this.shader});
44+
ui.FragmentShader shader;
45+
46+
@override
47+
void paint(Canvas canvas, Size size) {
48+
shader.setFloat(0, size.width);
49+
shader.setFloat(1, size.height);
50+
51+
final paint = Paint()..shader = shader;
52+
canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
53+
}
54+
55+
@override
56+
bool shouldRepaint(covariant CustomPainter oldDelegate) {
57+
return false;
58+
}
59+
}

simple_sdf/pubspec.yaml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: simple_sdf
2+
description: Using a shader, simply.
3+
publish_to: 'none'
4+
version: 1.0.0+1
5+
resolution: workspace
6+
7+
environment:
8+
sdk: ^3.9.0-0
9+
10+
dependencies:
11+
flutter:
12+
sdk: flutter
13+
flutter_shaders: ^0.1.0
14+
15+
dev_dependencies:
16+
analysis_defaults:
17+
path: ../analysis_defaults
18+
flutter_test:
19+
sdk: flutter
20+
flutter:
21+
uses-material-design: true
22+
shaders:
23+
- shaders/SDF.frag

simple_sdf/screenshot.png

112 KB
Loading

simple_sdf/shaders/SDF.frag

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#version 460 core
2+
3+
#include <flutter/runtime_effect.glsl>
4+
5+
precision mediump float;
6+
7+
uniform vec2 resolution;
8+
out vec4 fragColor;
9+
10+
vec3 pink = vec3(255, 105, 180) / 255;
11+
12+
// dot2 and sdHeart from https://iquilezles.org/articles/distfunctions2d/
13+
//
14+
// The MIT License
15+
// Copyright © 2015 Inigo Quilez
16+
// Permission is hereby granted, free of charge, to any person obtaining a copy
17+
// of this software and associated documentation files (the "Software"), to deal
18+
// in the Software without restriction, including without limitation the rights
19+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20+
// copies of the Software, and to permit persons to whom the Software is
21+
// furnished to do so, subject to the following conditions: The above copyright
22+
// notice and this permission notice shall be included in all copies or
23+
// substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS",
24+
// WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
25+
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
27+
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28+
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
29+
// THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30+
// https://www.youtube.com/c/InigoQuilez
31+
// https://iquilezles.org
32+
33+
float dot2(vec2 v) { return dot(v, v); }
34+
float sdHeart(in vec2 p) {
35+
p.x = abs(p.x);
36+
37+
if (p.y + p.x > 1.0)
38+
return sqrt(dot2(p - vec2(0.25, 0.75))) - sqrt(2.0) / 4.0;
39+
return sqrt(min(dot2(p - vec2(0.00, 1.00)),
40+
dot2(p - 0.5 * max(p.x + p.y, 0.0)))) *
41+
sign(p.x - p.y);
42+
}
43+
44+
void main() {
45+
vec2 st = FlutterFragCoord().xy / resolution.xy;
46+
// Remap coordinates.
47+
// Flutter normalized coordinates have range [0,1] but sdHeart expects [-1,1].
48+
st = (st - vec2(0.5)) * vec2(2.0);
49+
// Center the heart.
50+
// sdHeart is written such that the bottom point is at (0,0) and it's about 1
51+
// unit tall.
52+
st.y -= 0.5;
53+
// Invert Y coordinate.
54+
st.y *= -1;
55+
56+
// Calculate the color of this pixel according to the heart SDF, using
57+
// smoothstep to anti-alias the edges.
58+
vec3 color = vec3(0.0);
59+
color = mix(pink, color, smoothstep(0.01, 0.02, sdHeart(st)));
60+
61+
fragColor = vec4(color, 1);
62+
}

0 commit comments

Comments
 (0)