Flutter高性能图形渲染插件flutter_gpu_shaders的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter高性能图形渲染插件flutter_gpu_shaders的使用

flutter_gpu_shaders 是一个用于Flutter GPU着色器捆绑包/库的构建工具。通过这个插件,你可以使用原生资产构建钩子来导入Flutter GPU着色器资产。下面是一个完整的示例,展示了如何使用 flutter_gpu_shaders 插件进行高性能图形渲染。

功能

  • 使用原生资产构建钩子导入Flutter GPU着色器资产。

开始使用

1. 启用实验性功能

该插件需要启用实验性的“原生资产”功能。你可以通过以下命令启用它:

flutter config --enable-native-assets

2. 添加着色器文件

将一些Flutter GPU着色器文件添加到你的项目中。例如,我们假设存在两个着色器文件:shaders/my_cool_shader.vertshaders/my_cool_shader.frag

3. 创建着色器捆绑包清单文件

在项目中创建一个着色器捆绑包清单文件,文件名必须以 .shaderbundle.json 结尾。例如,我们将以下内容保存为 my_cool_bundle.shaderbundle.json

{
    "CoolVertex": {
        "type": "vertex",
        "file": "shaders/my_cool_shader.vert"
    },
    "CoolFragment": {
        "type": "fragment",
        "file": "shaders/my_cool_shader.frag"
    }
}

4. 定义构建钩子

接下来,在项目中定义一个构建钩子,使用 buildShaderBundleJson 构建着色器捆绑包。构建钩子必须命名为 hook/build.dart,当启用了“原生资产”功能时,Flutter会自动调用此脚本:

import 'package:native_assets_cli/native_assets_cli.dart';
import 'package:flutter_gpu_shaders/build.dart';

void main(List<String> args) async {
  await build(args, (config, output) async {
    await buildShaderBundleJson(
        buildConfig: config,
        buildOutput: output,
        manifestFileName: 'my_cool_bundle.shaderbundle.json');
  });
}

5. 更新 pubspec.yaml

在项目的 pubspec.yaml 文件中,添加一个资产导入规则,以打包构建的着色器捆绑包(一旦“原生资产”支持 DataAsset,这将在未来的Flutter版本中变得不再必要):

flutter:
  assets:
    - build/shaderbundles/*.shaderbundle.json

6. 导入并使用着色器库

现在你可以在项目中使用 gpu.ShaderLibrary.fromAsset 导入构建的着色器捆绑包作为库。例如:

import 'package:flutter_gpu/gpu.dart' as gpu;

final String _kBaseShaderBundlePath =
    'packages/my_project/build/shaderbundles/my_cool_bundle.shaderbundle';

gpu.ShaderLibrary? _baseShaderLibrary = null;

gpu.ShaderLibrary get baseShaderLibrary {
  if (_baseShaderLibrary != null) {
    return _baseShaderLibrary!;
  }
  _baseShaderLibrary = gpu.ShaderLibrary.fromAsset(_kBaseShaderBundlePath);
  if (_baseShaderLibrary != null) {
    return _baseShaderLibrary!;
  }

  throw Exception("Failed to load base shader bundle! ($_kBaseShaderBundlePath)");
}

完整示例代码

以下是一个完整的示例项目,展示了如何使用 flutter_gpu_shaders 插件进行高性能图形渲染。

项目结构

my_project/
├── lib/
│   └── main.dart
├── shaders/
│   ├── my_cool_shader.vert
│   └── my_cool_shader.frag
├── hook/
│   └── build.dart
├── build/
│   └── shaderbundles/
│       └── my_cool_bundle.shaderbundle.json
└── pubspec.yaml

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_gpu/gpu.dart' as gpu;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('GPU Shaders Example')),
        body: Center(
          child: ShaderWidget(),
        ),
      ),
    );
  }
}

class ShaderWidget extends StatefulWidget {
  @override
  _ShaderWidgetState createState() => _ShaderWidgetState();
}

class _ShaderWidgetState extends State<ShaderWidget> {
  final String _kBaseShaderBundlePath =
      'packages/my_project/build/shaderbundles/my_cool_bundle.shaderbundle';

  gpu.ShaderLibrary? _baseShaderLibrary;

  @override
  void initState() {
    super.initState();
    _loadShaderLibrary();
  }

  Future<void> _loadShaderLibrary() async {
    try {
      _baseShaderLibrary = await gpu.ShaderLibrary.fromAsset(_kBaseShaderBundlePath);
      setState(() {});
    } catch (e) {
      print('Failed to load shader library: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_baseShaderLibrary == null) {
      return CircularProgressIndicator();
    }

    return CustomPaint(
      painter: ShaderPainter(_baseShaderLibrary!),
      size: Size.infinite,
    );
  }
}

class ShaderPainter extends CustomPainter {
  final gpu.ShaderLibrary shaderLibrary;

  ShaderPainter(this.shaderLibrary);

  @override
  void paint(Canvas canvas, Size size) {
    // Use the shader library to draw something on the canvas
    // For example, you can create a custom shader and apply it to a rectangle
    final Paint paint = Paint()
      ..shader = shaderLibrary.getShader('CoolFragment').createShader(Rect.fromLTWH(0, 0, size.width, size.height));

    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

shaders/my_cool_shader.vert

#version 300 es

layout(location = 0) in vec4 aPosition;
layout(location = 1) in vec2 aTextureCoord;

out vec2 vTextureCoord;

void main() {
  gl_Position = aPosition;
  vTextureCoord = aTextureCoord;
}

shaders/my_cool_shader.frag

#version 300 es
precision mediump float;

in vec2 vTextureCoord;
out vec4 fragColor;

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

hook/build.dart

import 'package:native_assets_cli/native_assets_cli.dart';
import 'package:flutter_gpu_shaders/build.dart';

void main(List<String> args) async {
  await build(args, (config, output) async {
    await buildShaderBundleJson(
        buildConfig: config,
        buildOutput: output,
        manifestFileName: 'my_cool_bundle.shaderbundle.json');
  });
}

pubspec.yaml

name: my_project
description: A new Flutter project.

publish_to: 'none'

version: 1.0.0+1

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  flutter_gpu: ^0.1.0

dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  assets:
    - build/shaderbundles/*.shaderbundle.json

更多关于Flutter高性能图形渲染插件flutter_gpu_shaders的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter高性能图形渲染插件flutter_gpu_shaders的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于如何在Flutter中使用flutter_gpu_shaders来实现高性能图形渲染,下面是一个简单的代码示例。flutter_gpu_shaders允许你在Flutter应用中编写自定义的GLSL(OpenGL Shading Language)着色器,从而实现对图形渲染的精细控制。

首先,确保你已经将flutter_gpu_shaders添加到你的pubspec.yaml文件中:

dependencies:
  flutter:
    sdk: flutter
  flutter_gpu_shaders: ^x.y.z  # 替换为最新版本号

然后,运行flutter pub get来获取包。

1. 编写GLSL着色器

创建一个文件shaders/simple_shader.glsl,并添加以下GLSL代码:

// simple_shader.glsl

precision mediump float;

uniform sampler2D uTexture;
uniform vec4 uColor;

in vec2 vTexCoord;

out vec4 fragColor;

void main() {
    vec4 textureColor = texture(uTexture, vTexCoord);
    fragColor = uColor * textureColor;
}

这个简单的着色器只是将纹理的颜色与一个均匀颜色相乘。

2. 在Flutter中使用着色器

接下来,在你的Flutter应用中加载并使用这个着色器。创建一个新的Widget,例如CustomShaderWidget

import 'package:flutter/material.dart';
import 'package:flutter_gpu_shaders/flutter_gpu_shaders.dart';
import 'dart:ui' as ui;
import 'dart:typed_data';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter GPU Shaders Example'),
        ),
        body: CustomShaderWidget(),
      ),
    );
  }
}

class CustomShaderWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ShaderMask(
      shaderCallback: (bounds) {
        return createSimpleShader(bounds.size);
      },
      blendMode: BlendMode.modulate,
      child: Image.asset(
        'assets/your_image.png',  // 确保你有这个资源文件
        fit: BoxFit.cover,
      ),
    );
  }

  ui.Shader createSimpleShader(Size size) {
    final String source = """
    // 插入你的GLSL代码
    $simpleShaderSource
    """;

    final Map<String, dynamic> uniforms = <String, dynamic>{
      'uTexture': 0,
      'uColor': [1.0, 1.0, 1.0, 1.0],  // 白色,你可以根据需要调整
    };

    final FlutterShaderBuilder builder = FlutterShaderBuilder(source)
      ..addUniform('uTexture', FlutterShaderUniformType.sampler2D)
      ..addUniform('uColor', FlutterShaderUniformType.vec4)
      ..setUniforms(uniforms);

    return builder.createShader();
  }

  // 加载GLSL源代码
  String get simpleShaderSource {
    return rootBundle.loadString('shaders/simple_shader.glsl').then((String source) {
      return source;
    }) ?? '';
  }
}

注意:上面的代码片段中,simpleShaderSource的获取方式需要异步处理,但在示例中直接返回了一个静态值。在实际应用中,你需要处理异步加载着色器源代码的情况。一个常见的做法是使用FutureBuilder或StatefulWidget来管理异步状态。

3. 异步加载GLSL源代码

为了正确处理异步加载,你可以将CustomShaderWidget转换为一个StatefulWidget,并在initState中加载着色器源代码。

class CustomShaderWidget extends StatefulWidget {
  @override
  _CustomShaderWidgetState createState() => _CustomShaderWidgetState();
}

class _CustomShaderWidgetState extends State<CustomShaderWidget> {
  String? _shaderSource;

  @override
  void initState() {
    super.initState();
    _loadShaderSource();
  }

  Future<void> _loadShaderSource() async {
    final String source = await rootBundle.loadString('shaders/simple_shader.glsl');
    setState(() {
      _shaderSource = source;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_shaderSource == null) {
      return Center(child: CircularProgressIndicator());
    }

    return ShaderMask(
      shaderCallback: (bounds) {
        return createSimpleShader(bounds.size, _shaderSource!);
      },
      blendMode: BlendMode.modulate,
      child: Image.asset(
        'assets/your_image.png',
        fit: BoxFit.cover,
      ),
    );
  }

  ui.Shader createSimpleShader(Size size, String source) {
    final Map<String, dynamic> uniforms = <String, dynamic>{
      'uTexture': 0,
      'uColor': [1.0, 1.0, 1.0, 1.0],
    };

    final FlutterShaderBuilder builder = FlutterShaderBuilder(source)
      ..addUniform('uTexture', FlutterShaderUniformType.sampler2D)
      ..addUniform('uColor', FlutterShaderUniformType.vec4)
      ..setUniforms(uniforms);

    return builder.createShader();
  }
}

这个示例展示了如何在Flutter中使用flutter_gpu_shaders加载和应用自定义GLSL着色器。你可以根据需要进一步扩展和修改这个示例,以实现更复杂的图形渲染效果。

回到顶部