Flutter 着色器

着色器

在计算机图形学中,着色器是一种计算机程序,用于在 3D 场景渲染过程中计算适当的光、暗和颜色级别,这一过程称为着色。

着色器已经发展到现在可以在计算机图形特效和视频后处理以及图形处理单元上的通用计算中执行各种专门功能。

当您编写并运行 Dart 代码时,编译器会将您的代码转换为机器代码。它本质上是将人类可读的语言翻译成您的硬件可以理解的语言。在大多数情况下,该硬件就是您的 CPU。所以在编写着色器代码的时候我们不直接使用 Dart。那么我们将在 Flutter 中使用的语言是GLSL------一种来自 OpenGL 库的着色语言。

创建

在项目目录中创建一个.frag结尾的着色器文件:

csharp 复制代码
#version 460 core

out vec4 fragColor;

void main() {
   fragColor = vec4(1, 0, 0, 1);
}

#version 460 core

  • 告诉编译器我们将使用哪个版本的 GLSL。除非您需要特定版本的某些特定功能,否则请始终保持此行相同。

out vec4 fragColor;

  • 接下来,我们需要声明一个输出变量。它是一个变量,在着色器的末尾,我们必须存储将在屏幕上显示的输出颜色。在变量声明之前我们通过使用out关键字来做到这一点。您可能还注意到我声明的变量是某种奇怪的vec4类型。
  • 在 GLSL 中,我们编写的代码级别比 Dart 低得多。因此,我们实际上并没有一堆花哨的类来表示颜色等复杂的东西。相反,我们直接处理该颜色组成的数据。但我们并不完全依靠自己------我们有载体。
  • 向量是一种数据结构,基本上将一堆数字组合成一个实体,然后通过公开一些有用的 getter 和运算符使您的生活变得更轻松,从而使算法的实现变得更加愉快。因此,为了表示一种颜色,我们需要四个数字------红色、绿色、蓝色和 alpha 通道分量------因此vec4.

使用

1、我们可以使用ShaderBuilder组件来加载加载着色器

less 复制代码
ShaderBuilder(
   assetKey: 'xxx.frag',
   (BuildContext context, FragmentShader shader, _) => CustomPaint(
     size: MediaQuery.of(context).size,
       painter: MyShaderPainter(shader),
      ),
  );

2、 我们可以使用FutureBuilder来加载着色器

less 复制代码
 FutureBuilder<ui.FragmentShader>(
     //从着色器文件夹加载着色器。
     future: _loadShader(widget.weatherCondition.shader),
     builder: (context, snapshot) {
       .....
    }
 }

     
///使用指定的[shaderName]从资源加载并返回[ui.FragmentShader]。
///此方法从具有给定[shaderName]的assets文件夹加载着色器程序
///并返回相应的[ui.FragmentShader]。
///参数:
///-[shaderName]要加载的着色器文件的名称。
Future<ui.FragmentShader> _loadShader(String shaderName) async {
  //从资源文件夹加载着色器程序。
  ui.FragmentProgram program =
      await ui.FragmentProgram.fromAsset('shaders/$shaderName');
 //返回片段着色器。
  return program.fragmentShader();
}

例子

1、雨滴效果

ini 复制代码
#include <flutter/runtime_effect.glsl>
uniform float iTime;
uniform vec3 iResolution;
uniform sampler2D iChannel0;
out vec4 fragColor;
// Licensed under "Do What The Fuck You Want To Public License"
// http://www.wtfpl.net/about/
vec2 hash22(vec2 p){
    vec2 p2 = fract(p * vec2(.1031,.1030));
    p2 += dot(p2, p2.yx+19.19);
    return fract((p2.x+p2.y)*p2);
}
#define round(x) floor( (x) + .5 )
float simplex2D(vec2 p ){
    const float K1 = (sqrt(3.)-1.)/2.;
    const float K2 = (3.-sqrt(3.))/6.;
    const float K3 = K2*2.;
    vec2 i = floor( p + dot(p,vec2(K1)) );
    vec2 a = p - i + dot(i,vec2(K2));
    vec2 o = 1.-clamp((a.yx-a)*1.e35,0.,1.);
    vec2 b = a - o + K2;
    vec2 c = a - 1.0 + K3;
    vec3 h = clamp( .5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0. ,1. );
    h*=h;
    h*=h;
    vec3 n = vec3( 
        dot(a,hash22(i   )-.5),
        dot(b,hash22(i+o )-.5),
        dot(c,hash22(i+1.)-.5)
    );
    return dot(n,h)*140.;
}

vec2 wetGlass(vec2 p) {

    p += simplex2D(p*0.1) * 3.; // distort drops
    
    float t = iTime;
    
    p *= vec2(.025, .025 * .25);
    
    p.y += t * .25; // make drops fall
    
    vec2 rp = round(p);
    vec2 dropPos = p - rp;
    vec2 noise = hash22(rp);
    
    dropPos.y *= 4.;
    
    t = t * noise.y + (noise.x*6.28);
    
    vec2 trailPos = vec2(dropPos.x, fract((dropPos.y-t)*2.) * .5 - .25 );
    
    dropPos.y += cos( t + cos(t) );  // make speed vary
   
    float trailMask = clamp(dropPos.y*2.5+.5,0.,1.); // hide trail in front of drop

    float dropSize  = dot(dropPos,dropPos);
    
    float trailSize = clamp(trailMask*dropPos.y-0.5,0.,1.) + 0.5;
    trailSize = dot(trailPos,trailPos) * trailSize * trailSize;
    
    float drop  = clamp(dropSize  * -60.+ 3.*noise.y, 0., 1.);
    float trail = clamp(trailSize * -60.+ .5*noise.y, 0., 1.);
    
    trail *= trailMask; // hide trail in front of drop
    
    return drop * dropPos + trailPos * trail;
}

void main()
{
    vec2 fragCoord = FlutterFragCoord();
	vec2 uv = fragCoord.xy / iResolution.xy;
    
    uv += wetGlass(fragCoord);
   
	fragColor = texture(iChannel0,uv);
}

2、雪片效果

scss 复制代码
#include <flutter/runtime_effect.glsl>

uniform float iTime;
uniform vec3 iResolution;

out vec4 fragColor;

// Copyright (c) 2013 Andrew Baldwin (twitter: baldand, www: http://thndl.com)
// License = Attribution-NonCommercial-ShareAlike (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US)
// https://www.shadertoy.com/view/ldsGDn

// "Just snow"
// Simple (but not cheap) snow made from multiple parallax layers with randomly positioned 
// flakes and directions. Also includes a DoF effect. Pan around with mouse.

#define LAYERS 30
#define DEPTH .1
#define WIDTH .3
#define SPEED .8

void main()
{
  vec2 fragCoord = FlutterFragCoord();
  const mat3 p = mat3(13.323122,23.5112,21.71123,21.1212,28.7312,11.9312,21.8112,14.7212,61.3934);
  vec2 uv = vec2(0.5, 0.5) + vec2(1.,iResolution.y/iResolution.x)*fragCoord.xy / iResolution.xy;
  vec3 acc = vec3(0.0);
  float dof = 5.*sin(iTime*.1);
  for (int i=0;i<LAYERS;i++) {
    float fi = float(i);
    vec2 q = uv*(1.+fi*DEPTH);
    q += vec2(q.y*(WIDTH*mod(fi*7.238917,1.)-WIDTH*.5),SPEED*iTime/(1.+fi*DEPTH*.03));
    vec3 n = vec3(floor(q),31.189+fi);
    vec3 m = floor(n)*.00001 + fract(n);
    vec3 mp = (31415.9+m)/fract(p*m);
    vec3 r = fract(mp);

    
vec2 s = abs(mod(q,1.)-.5+.9*r.xy-.45);
    s += .01*abs(2.*fract(10.*q.yx)-1.);
    float d = .6*max(s.x-s.y,s.x+s.y)+max(s.x,s.y)-.01;
    float edge = .005+.05*min(.5*abs(fi-5.-dof),1.);
    acc += vec3(smoothstep(edge,-edge,d)*(r.x/(1.+.02*fi*DEPTH)));
  }
  fragColor = vec4(vec3(acc),1.0);
}
相关推荐
汪子熙26 分钟前
Angular 服务器端应用 ng-state tag 的作用介绍
前端·javascript·angular.js
Envyᥫᩣ35 分钟前
《ASP.NET Web Forms 实现视频点赞功能的完整示例》
前端·asp.net·音视频·视频点赞
Мартин.5 小时前
[Meachines] [Easy] Sea WonderCMS-XSS-RCE+System Monitor 命令注入
前端·xss
昨天;明天。今天。6 小时前
案例-表白墙简单实现
前端·javascript·css
数云界6 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
风清扬_jd6 小时前
Chromium 如何定义一个chrome.settingsPrivate接口给前端调用c++
前端·c++·chrome
安冬的码畜日常6 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
ChinaDragonDreamer6 小时前
Vite:为什么选 Vite
前端
小御姐@stella6 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
GISer_Jing6 小时前
【React】增量传输与渲染
前端·javascript·面试