Code Monkey home page Code Monkey logo

shader's Introduction

shader

Shader manages the compilation of your GLSL shaders into SPIR-V byte code and Dart code.

Quickstart

# Install cli
dart pub global activate shader

# Compile all glsl files in our project
shader --use-remote --to-dart

# Discover all features
shader --help

Table of Contents

Getting started

Usage

Writing shaders

Getting started

Install the command-line executable shader for your current user:

dart pub global activate shader

Now you can use the shader CLI tool:

shader --help

Hint: If pub binaries are not known to the path, you can also run it by:

dart pub global run shader --help

Usage

Compile to Dart

The easiest way of using shaders in your app, is to use it this way:

shader --use-remote --to-dart

It will scan your project for *.glsl files and use the hosted cloud service to compile it. Flutter needs SPR-V byte code at runtime.

A very simple shader red-shader.glsl could be this:

#version 320 es

precision highp float;

layout(location = 0) out vec4 fragColor;

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

This shader has no uniforms (input parameters) and paints each pixel red.

The compiler created a dart file red_shader_sprv.dart that contains a function Future<FragmentProgram> redShaderFragmentProgram() that will initialize the shader at runtime.

We can utilize a FutureBuilder to load that:

import 'dart:ui';
import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<FragmentProgram>(
      /// Use the generated loader function here
      future: redShaderFragmentProgram(),
      builder: ((context, snapshot) {
        if (!snapshot.hasData) {
          /// Shader is loading
          return const WidgetWhenLoading();
        }

        /// Shader is ready to use
        return WidgetThatUsesShader(snapshot.data!);
      }),
    );
  }
}

You can find an app example of Red Shader.

Use of uniforms

Uniforms is the term in the GLSL world for input parameter. The uniforms can be changed for each frame, but they are constant for every pixel during a single frame.

Given the following GLSL file:

#version 320 es

precision highp float;

layout(location = 0) out vec4 fragColor;

// define uniforms:
layout(location = 0) uniform vec3 color1;
layout(location = 1) uniform vec3 color2;
layout(location = 2) uniform float someValue;
layout(location = 3) uniform vec2 size;

void main() {
    // ...
}

This can be addressed in FragmentProgram's shader() method:

@override
void paint(Canvas canvas, Size size) {
  /// Inputs
  Color color1 = Colors.blue;
  Color color2 = Colors.green;
  double someValue = 0.5;

  /// Create paint using a shader
  final paint = Paint()
    ..shader = fragmentProgram.shader(

        /// Specify input parameter (uniforms)
        floatUniforms: Float32List.fromList([
      /// color1 takes 3 floats and will be mapped to `vec3`
      color1.red / 255.0,
      color1.green / 255.0,
      color1.blue / 255.0,

      /// color2 also takes 3 floats and will be mapped to `vec3`
      color2.red / 255.0,
      color2.green / 255.0,
      color2.blue / 255.0,

      /// someValue takes 1 float and will be mapped to `float`
      someValue,

      /// size takes 2 floats and will be mapped to `vec2`
      size.width,
      size.height,
    ]));

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

Also take a look at Color Shader example, that combines Flutter animtions and the use of uniforms.

Make use of sampler uniform

Image textures can be accessed via sampler2d uniforms:

layout(location = 0) uniform sampler2D image;

For that you need to create an ImageShader:

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,
);

That ImageShader can be passed into the FragmentProgram's shader() method as samplerUniform:

final paint = Paint()
  ..shader = fragmentProgram.shader(
    samplerUniforms: [
      imageShader,
    ],
  );

You can see everything wired up in the Image Scale app example.

Use a local compiler

If you don't want to rely on the hosted cloud service or the cloud service not available, you can use local compiler.

You can download the compiler at https://github.com/google/shaderc.

The --use-local option takes a path that roughly points to the compiler binary:

shader --use-local $HOME/sdk/shaderc --to-dart

Improve development cycle

In order to iterate faster and use the hot-reload, you can use the --watch flag:

shader --use-remote --to-dart --watch

shader --use-local $HOME/sdk/shaderc --to-dart --watch

Other features

The shader executable also supports some other options and output format. Type to find get information:

shader --help

Writing shaders

This section covers useful information and resources writing own shader code.

Constraints in Flutter

Shaders are not supported for Flutter web, yet. But there is a project plan for the Flutter engine developers to enable it.

Also the capabilities of GLSL language feature are restricted. Take a look at the specifications of the SPIR-V Transpiler.

This package compiles GLSL code to SPIR-V code, and at runtime SPIR-V transpiler converts it to native API (e.g. OpenGL, Vulkan). So it might be that shader will compile fine, but it fails at runtime.

Learning GLSL

There are various sources to learn GLSL:

shader's People

Contributors

felixblaschke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

shader's Issues

HandshakeException while compiling red shader example

Hi,

I tried to run the provided red shader example with the following command:

shader --use-remote --to-dart

It prompted me this error:

Using remote-compiler: https://shaderc.felix-blaschke.de
Error while compiling: shaders/red-shader_sprv.dart
  1: #version 320 es
  2: 
  3: precision highp float;
  4: 
  5: layout(location = 0) out vec4 fragColor;
  6: 
  7: void main() {
  8:     fragColor = vec4(1.0, 0.0, 0.0, 1.0);
  9: }
HandshakeException: Handshake error in client (OS Error: 
        CERTIFICATE_VERIFY_FAILED: application verification failure(handshake.cc:393))
flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.7.8, on macOS 13.0.1 22A400 darwin-x64, locale en-FR)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc2)
[✓] Xcode - develop for iOS and macOS (Xcode 14.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.2)
[✓] Android Studio (version 2022.1)
[✓] VS Code (version 1.76.1)
[✓] Connected device (2 available)
[✓] HTTP Host Availability

• No issues found!

When checking the url, I saw that there seem to be a certificate issue:
image

Any workaround / fix ?

Does the shaders work normally on IOs using the Metal API?

I just have one question/curiosity if I'm not mistaken, opengl is deprecated in IOs, and I believe Apple will kill at some point and just use their new Metal API. The question is, will the glsl code work on IOS? We will be able to run these shaders without depending on the OS?
Sorry for the newbie question, I'm starting with shaders :/

How to use textures as input?

Hi, I am trying to use these shaders for image processing. I've read in the flutter documentation that sampler2D is a valid uniform as an input to the shader. However I cannot find a way to generate that uniform in dart since it is not just a double. Is there a specific type for that exposed in the API?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.