Skip to content

Latest commit

 

History

History
374 lines (290 loc) · 9.11 KB

example.md

File metadata and controls

374 lines (290 loc) · 9.11 KB

Examples

Table of Contents

Red shader

Color shader

Image scale shader

 

Red shader

The red-shader.glsl is very simple and turns all pixels red:

#version 320 es

precision highp float;

layout(location = 0) out vec4 fragColor;

void main() {
    fragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

It can be compiled via shader executable:

shader --use-remote --to-dart

After compilation the app can use it:

import 'dart:ui';

import 'package:flutter/material.dart';

/// Import file generated by cli
import 'package:flutter_app/shader/red_shader_sprv.dart';

void main() {
  runApp(const MaterialApp(home: Page()));
}

class Page extends StatelessWidget {
  const Page({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<FragmentProgram>(

          /// Use the generated loader function here
          future: redShaderFragmentProgram(),
          builder: ((context, snapshot) {
            if (!snapshot.hasData) {
              /// Shader is loading
              return const CircularProgressIndicator();
            }

            /// Shader is ready to use
            return SizedBox.expand(
              child: CustomPaint(
                painter: RedShaderPainter(snapshot.data!),
              ),
            );
          })),
    );
  }
}

/// Customer painter that makes use of the shader
class RedShaderPainter extends CustomPainter {
  RedShaderPainter(this.fragmentProgram);

  final FragmentProgram fragmentProgram;

  @override
  void paint(Canvas canvas, Size size) {
    /// Create paint using a shader
    final paint = Paint()..shader = fragmentProgram.shader();

    /// Draw a rectangle with the shader-paint
    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    if (oldDelegate is RedShaderPainter &&
        oldDelegate.fragmentProgram == fragmentProgram) {
      /// Do not repaint when painter has same set of properties
      return false;
    }
    return true;
  }
}

 

Color shader

The color-shader.glsl uses input parameters (uniforms) and turns all pixels in that color:

#version 320 es

precision highp float;

layout(location = 0) out vec4 fragColor;

layout(location = 0) uniform vec3 color;

void main() {
    fragColor = vec4(color.rgb, 1.0);
}

It can be compiled via shader executable:

shader --use-remote --to-dart

After compilation the app can use it:

import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';

/// Import file generated by cli
import 'package:flutter_app/shader/color_shader_sprv.dart';

void main() {
  runApp(const MaterialApp(home: Page()));
}

class Page extends StatelessWidget {
  const Page({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<FragmentProgram>(

          /// Use the generated loader function here
          future: colorShaderFragmentProgram(),
          builder: ((context, snapshot) {
            if (!snapshot.hasData) {
              /// Shader is loading
              return const CircularProgressIndicator();
            }

            /// Shader is ready to use
            return TweenAnimationBuilder<Color?>(
              /// Flutter animation: tween color over 10s
              tween: ColorTween(begin: Colors.green, end: Colors.blue),
              duration: const Duration(seconds: 10),
              builder: (context, color, _) {
                return SizedBox.expand(
                  child: CustomPaint(
                    /// Pass color into shader as input parameter
                    painter: RedShaderPainter(snapshot.data!, color!),
                  ),
                );
              },
            );
          })),
    );
  }
}

/// Customer painter that makes use of the shader
class RedShaderPainter extends CustomPainter {
  RedShaderPainter(this.fragmentProgram, this.color);

  final FragmentProgram fragmentProgram;
  final Color color;

  @override
  void paint(Canvas canvas, Size size) {
    /// Create paint using a shader
    final paint = Paint()
      ..shader = fragmentProgram.shader(

          /// Specify input parameter (uniforms)
          floatUniforms: Float32List.fromList([
        // Set red as relative color for first float
        color.red / 255.0,
        // Set green as relative color for second float
        color.green / 255.0,
        // Set blue as relative color for third float
        color.blue / 255.0,
      ]));

    /// Draw a rectangle with the shader-paint
    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    if (oldDelegate is RedShaderPainter &&
        oldDelegate.fragmentProgram == fragmentProgram &&
        oldDelegate.color == color) {
      /// Do not repaint when painter has same set of properties
      return false;
    }
    return true;
  }
}

 

Image scale shader

The image-scale-shader.glsl uses an image texture as an sampler uniform along with a float uniform:

#version 320 es

precision highp float;

layout(location = 0) out vec4 fragColor;

layout(location = 0) uniform float scale;
layout(location = 1) uniform sampler2D image;

void main() {
  vec2 coords = (0.0015 / scale) * (gl_FragCoord.xy);
  vec4 textureColor = texture(image, coords);
  fragColor = textureColor;
}

It can be compiled via shader executable:

shader --use-remote --to-dart

After compilation the app can use it:

import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_app/shader/image_scale_shader_sprv.dart';

void main() {
  runApp(const MaterialApp(home: Page()));
}

/// Will combine loading multiple things
class PainterNeeds {
  final ImageShader imageShader;
  final FragmentProgram fragmentProgram;

  PainterNeeds(this.imageShader, this.fragmentProgram);
}

/// Loads JPEG image and the [FragmentProgram]
Future<PainterNeeds> loadPainterNeeds() async {
  final asset = await rootBundle.load("assets/image.jpg");
  final image = await decodeImageFromList(asset.buffer.asUint8List());

  /// Create ImageShader that will provide a GLSL sampler
  final ImageShader imageShader = ImageShader(
    image,
    // Specify how image repetition is handled for x and y dimension
    TileMode.repeated,
    TileMode.repeated,
    // Transformation matrix (identity matrix = no transformation)
    Matrix4.identity().storage,
  );

  return PainterNeeds(imageShader, await imageScaleShaderFragmentProgram());
}

class Page extends StatelessWidget {
  const Page({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<PainterNeeds>(

          /// Use the generated loader function here
          future: loadPainterNeeds(),
          builder: ((context, snapshot) {
            if (!snapshot.hasData) {
              /// Shader is loading
              return const CircularProgressIndicator();
            }

            /// Shader is ready to use
            return SizedBox.expand(
              child: CustomPaint(
                painter: ImageScaleShaderPainter(snapshot.data!),
              ),
            );
          })),
    );
  }
}

/// Customer painter that makes use of the shader
class ImageScaleShaderPainter extends CustomPainter {
  ImageScaleShaderPainter(this.painterNeeds);

  final PainterNeeds painterNeeds;

  @override
  void paint(Canvas canvas, Size size) {
    /// Create paint using a shader
    final paint = Paint()
      ..shader = painterNeeds.fragmentProgram.shader(
        floatUniforms: Float32List.fromList([
          // scale uniform
          0.1,
        ]),
        samplerUniforms: [
          painterNeeds.imageShader,
        ],
      );

    /// Draw a rectangle with the shader-paint
    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    if (oldDelegate is ImageScaleShaderPainter &&
        oldDelegate.painterNeeds == painterNeeds) {
      /// Do not repaint when painter has same set of properties
      return false;
    }
    return true;
  }
}