-
-
Notifications
You must be signed in to change notification settings - Fork 939
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Fragment shaders pipelines and Camera based post processing #3404
Draft
renancaraujo
wants to merge
6
commits into
main
Choose a base branch
from
renan/shader-pipeline
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# crystal_ball | ||
|
||
A game to showcase the shader pipeline API in Flame. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include: package:flame_lint/analysis_options_with_dcm.yaml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import 'dart:typed_data'; | ||
import 'dart:ui' as ui; | ||
import 'dart:ui'; | ||
|
||
import 'package:flame/camera.dart' as c; | ||
import 'package:flame/game.dart'; | ||
import 'package:flame/shader_pipeline.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_shaders/flutter_shaders.dart'; | ||
|
||
const (double, double) kCameraSize = (900, 1600); | ||
|
||
void main() async { | ||
runApp(const GamePage()); | ||
} | ||
|
||
class GamePage extends StatefulWidget { | ||
const GamePage({super.key}); | ||
|
||
@override | ||
State<GamePage> createState() => _GamePageState(); | ||
} | ||
|
||
class _GamePageState extends State<GamePage> { | ||
late final Future<ui.FragmentProgram> program = | ||
ui.FragmentProgram.fromAsset('shaders/the_ball.frag'); | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return FutureBuilder( | ||
future: program, | ||
builder: (context, snapshot) { | ||
if (!snapshot.hasData) { | ||
return const Center( | ||
child: CircularProgressIndicator(), | ||
); | ||
} | ||
|
||
return GameWidget( | ||
game: CrystalBallGame( | ||
ballProgram: snapshot.data!, | ||
), | ||
); | ||
}, | ||
); | ||
} | ||
} | ||
|
||
class CrystalBallGame extends FlameGame { | ||
CrystalBallGame({ | ||
required this.ballProgram, | ||
}) : super( | ||
camera: c.CameraComponent.withFixedResolution( | ||
width: kCameraSize.$1, | ||
height: kCameraSize.$2, | ||
hudComponents: [ | ||
CrystalBallPipelineStep( | ||
program: ballProgram, | ||
), | ||
], | ||
), | ||
); | ||
|
||
final ui.FragmentProgram ballProgram; | ||
} | ||
|
||
class CrystalBallPipelineStep extends SPipelineStep { | ||
CrystalBallPipelineStep({ | ||
required this.program, | ||
super.samplingPasses = 0, | ||
}) : super(size: Vector2(900, 1600)); | ||
|
||
c.Viewport get camera => c.CameraComponent.currentCamera!.viewport; | ||
|
||
final FragmentProgram program; | ||
|
||
@override | ||
void postProcess(List<ui.Image> samples, Size size, Canvas canvas) { | ||
final uvBall = Vector2(0.5, 0.5); | ||
final shader = program.fragmentShader(); | ||
shader.setFloatUniforms((value) { | ||
value | ||
..setSize(size) | ||
..setVector64(uvBall) | ||
..setVector64(Vector2(0.0, 0.0)) | ||
..setFloat(.1) | ||
..setFloat(.3); | ||
}); | ||
|
||
canvas | ||
..save() | ||
..drawRect( | ||
Offset.zero & size, | ||
Paint() | ||
..shader = shader | ||
..blendMode = BlendMode.lighten, | ||
) | ||
..restore(); | ||
} | ||
} | ||
|
||
extension on UniformsSetter { | ||
renancaraujo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
void setVector64(Vector vector) { | ||
setFloats(Float32List.fromList(vector.storage)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
name: crystal_ball | ||
description: "A game to showcase the shader pipeline API in Flutter." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Flame? |
||
publish_to: 'none' | ||
version: 0.1.0 | ||
environment: | ||
sdk: ">=3.4.0 <4.0.0" | ||
dependencies: | ||
flame: ^1.22.0 | ||
flutter: | ||
sdk: flutter | ||
flutter_shaders: ^0.1.3 | ||
dev_dependencies: | ||
flame_lint: ^1.2.1 | ||
flutter: | ||
uses-material-design: true | ||
shaders: | ||
- shaders/platforms.frag | ||
- shaders/the_ball.frag | ||
- shaders/ground.frag | ||
- shaders/fog.frag | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
#version 460 core | ||
|
||
precision mediump float; | ||
|
||
#include <flutter/runtime_effect.glsl> | ||
|
||
uniform vec2 uSize; | ||
uniform float uGroundPos; | ||
uniform float uGroundAdd; | ||
uniform float uFade; | ||
uniform float uTime; | ||
|
||
out vec4 fragColor; | ||
|
||
|
||
// Thanks iq: | ||
// https://www.shadertoy.com/view/lsf3WH | ||
// Copyright © 2013 Inigo Quilez | ||
float hash(vec2 p) { | ||
p = 50.0*fract( p*0.3183099 + vec2(0.71,0.113)); | ||
return -1.0+2.0*fract( p.x*p.y*(p.x+p.y) ); | ||
} | ||
|
||
float noise( in vec2 p ) { | ||
vec2 i = floor( p ); | ||
vec2 f = fract( p ); | ||
vec2 u = f*f*f*(f*(f*6.0-15.0)+10.0); | ||
|
||
return mix( mix( hash( i + vec2(0.0,0.0) ), | ||
hash( i + vec2(1.0,0.0) ), u.x), | ||
mix( hash( i + vec2(0.0,1.0) ), | ||
hash( i + vec2(1.0,1.0) ), u.x), u.y); | ||
} | ||
|
||
float fractalNoise(vec2 uv) { | ||
float f = 0.0; | ||
uv *= 8.0; | ||
mat2 m = mat2( 1.6, 1.2, -1.2, 1.6 ); | ||
f = 0.5000*noise( uv ); uv = m*uv; | ||
f += 0.2500*noise( uv ); uv = m*uv; | ||
f += 0.1250*noise( uv ); uv = m*uv; | ||
f += 0.0625*noise( uv ); uv = m*uv; | ||
|
||
f = 0.5 + 0.5*f; | ||
|
||
return f; | ||
} | ||
|
||
|
||
void fragment(vec2 cuv, vec2 pos, inout vec4 color, float timeMultiplier) { | ||
vec2 p = pos.xy / uSize.xy; | ||
vec2 uv = p*vec2(uSize.x/uSize.y,1.0) ; | ||
|
||
float waterline = uGroundPos; | ||
float fade = uFade; | ||
|
||
float tr = step(waterline - fade,uv.y); | ||
tr *= smoothstep(waterline - fade, waterline, uv.y); | ||
uv.y -= uGroundAdd; | ||
uv *= 1.; | ||
uv.x += uTime * timeMultiplier; | ||
|
||
float f = fractalNoise(uv); | ||
f *= tr; | ||
f*= 0.65; | ||
|
||
f = pow(f, 1.8); | ||
color = vec4( vec3(0.8, 0.4, 1.0) * f, f); | ||
} | ||
|
||
void main() { | ||
vec2 pos = FlutterFragCoord().xy; | ||
vec2 uv = pos / uSize; | ||
vec4 color; | ||
|
||
fragment(uv, pos, color, 0.015); | ||
|
||
|
||
vec4 color2; | ||
fragment(uv, pos, color2, -0.08 ); | ||
|
||
fragColor = color + color2; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#version 460 core | ||
|
||
precision highp float; | ||
|
||
#include <flutter/runtime_effect.glsl> | ||
|
||
uniform vec2 uSize; | ||
uniform float uWaterLevel; | ||
uniform float uTime; | ||
|
||
uniform sampler2D tGameCanvas; | ||
|
||
out vec4 fragColor; | ||
|
||
vec4 fragment(vec2 uv) { | ||
vec4 waterColor = vec4(1.0); | ||
vec2 reflectedUv = uv.xy; | ||
if (uv.y >= uWaterLevel) { | ||
// invert y to equivalent position above water | ||
reflectedUv.y = 2.0 * uWaterLevel - reflectedUv.y; | ||
// magnify the reflection | ||
reflectedUv.y = uWaterLevel + (reflectedUv.y - uWaterLevel) * 3; | ||
// add horizontal waves | ||
reflectedUv.x = reflectedUv.x +(sin((uv.y-uWaterLevel/1)+ uTime *1.0)*0.01); | ||
// add vertical waves | ||
reflectedUv.y = reflectedUv.y + cos(1./(uv.y-uWaterLevel)+ uTime *1.0)*0.03; | ||
|
||
// Magnification can create uv outside of [0,1] range | ||
if (reflectedUv.y <=0) { | ||
return vec4(0.0); | ||
} | ||
|
||
// fade out reflection | ||
waterColor = vec4(1.0); | ||
waterColor.rgb *= 1 - ((uv.y-uWaterLevel) / (1.0-uWaterLevel)); | ||
} | ||
|
||
return texture(tGameCanvas, reflectedUv) * waterColor; | ||
} | ||
|
||
void main() { | ||
vec2 pos = FlutterFragCoord().xy; | ||
vec2 uv = pos / uSize; | ||
fragColor = fragment(uv); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
#version 460 core | ||
|
||
precision highp float; | ||
|
||
#include <flutter/runtime_effect.glsl> | ||
|
||
uniform vec2 uSize; | ||
uniform vec4[18] platformsAB; | ||
uniform vec3[18] colorsL; | ||
uniform vec3[18] colorsR; | ||
uniform float[18] glowGamas; | ||
|
||
|
||
//uniform sampler2D tTexture; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not used? |
||
|
||
out vec4 fragColor; | ||
|
||
const float PI = 3.1415926; | ||
|
||
float getLuma(vec3 color) { | ||
vec3 weights = vec3(0.299, 0.587, 0.114); | ||
return dot(color, weights); | ||
} | ||
|
||
float random(float x) { | ||
return fract(sin(x) * 43758.5453); | ||
} | ||
|
||
vec3 addNoiseToGradient(vec3 colorL, vec3 colorR, float distanceToA, float distanceToB) { | ||
|
||
// Calculate the interpolation factor with noise | ||
float t = distanceToA / (distanceToA + distanceToB); | ||
|
||
float luma = getLuma(mix(colorL, colorR, t)); | ||
float noiseFactor = 0.1 * (pow(luma, luma)); | ||
|
||
// Add noise to the interpolation factor | ||
t += (random(gl_FragCoord.x) - 0.5) * noiseFactor; | ||
|
||
// Ensure the factor is within the [0, 1] range | ||
t = clamp(t, 0.0, 1.0); | ||
|
||
// Interpolate the colors with the noisy factor | ||
vec3 gradient = mix(colorL, colorR, t); | ||
|
||
|
||
return gradient; | ||
} | ||
|
||
vec4 processPlatform(vec2 uv, vec2 a, vec2 b, vec3 colorL, vec3 colorR, float glowGama) { | ||
float distanceToA = distance(a, uv); | ||
float distanceToB = distance(b, uv); | ||
|
||
vec3 gradient = addNoiseToGradient(colorL, colorR, distanceToA, distanceToB); | ||
|
||
float gama = glowGama; | ||
|
||
if (uv.y > a.y) { | ||
gama = 3.0; | ||
} | ||
|
||
float light = acos(dot(normalize(a - uv), normalize(b - uv))) / PI; | ||
|
||
light = clamp(light, 0.0, 1.0); | ||
|
||
if (uv.y > a.y) { | ||
light *= 0.7; | ||
} | ||
gama = clamp(gama, 0.0, 100.0); | ||
|
||
vec3 col = pow(light, gama) * gradient; | ||
|
||
float alpha = pow(light* 0.1, gama); | ||
|
||
return vec4(col, alpha); | ||
} | ||
|
||
void fragment(vec2 uv, vec2 pos, inout vec4 color) { | ||
color = vec4(0, 0, 0, 0); | ||
|
||
for (int i = 0; i < 18; i++) { | ||
vec4 platform = platformsAB[i]; | ||
|
||
vec2 a = platform.xy; | ||
vec2 b = platform.zw; | ||
|
||
if (a==b) { | ||
continue; | ||
} | ||
|
||
vec3 colorL = colorsL[i]; | ||
vec3 colorR = colorsR[i]; | ||
|
||
color.rgba += processPlatform(uv, a, b, colorL, colorR, glowGamas[i]); | ||
} | ||
} | ||
|
||
void main() { | ||
vec2 pos = FlutterFragCoord().xy; | ||
vec2 uv = pos / uSize; | ||
vec4 color; | ||
|
||
fragment(uv, pos, color); | ||
|
||
// post process | ||
float mdf = 0.07; | ||
float noise = (fract(sin(dot(uv, vec2(12.9898, 78.233)*2.0)) * 43758.5453)); | ||
float luma = getLuma(color.rgb); | ||
|
||
if (luma > 0.01) { | ||
float llm = smoothstep(0.0, 0.4, luma); | ||
mdf *= llm * 0.3; | ||
color += noise * mdf; | ||
} | ||
|
||
fragColor = color; | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add this example to the examples page too :)