Built-in functions

184 阅读13分钟

任务说明

1. Fragment Shader

fragment 着色器需要返回vec4f的向量作为颜色,-> @location(0) vec4<f32>表示返回的颜色存储在@location(0)的公共位置上

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    return vec4f(1.0, 1.0, 0.0, 1.0);
}

结果 image.png

2. Vec

向量支持相加,相加时同位置分量相加

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
  var blueChannel = vec4f(0.0, 0.0, 0.75, 0.0);
  var redChannel = vec4f(0.5, 0.0, 0.0, 0.0);
  var alphaChannel = vec4f(0.0, 0.0, 0.0, 1.0);
  
  return blueChannel + redChannel + alphaChannel;
}

结果 image.png

3. Swizzling

向量可以通过(x,y,z,w)或(r,g,b,a)或(s,t,p,q)访问,不同顺序最后展示值相应变化

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
  var blueChannel = vec4f(0.0, 0.0, 0.75, 0.0);
  var redChannel = vec4f(0.5, 0.0, 0.0, 0.0);
  var alphaChannel = vec4f(0.0, 0.0, 0.0, 1.0);
  var color = blueChannel + redChannel + alphaChannel;
  return color.gbra;
}

结果 image.png

4. UV Coordinates & Uniforms

通过Bevy shader导入VertexOutput中获取uv,原始值与预期有diff,通过1.0 - uv.x将x值取反,反馈到结果是水平翻转,返回取uv.yx将xy值反转,返回到结果为沿/方向翻转

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    uv.x = 1.0 - uv.x;
    return vec4f(uv.yx, 0.0, 1.0);
}

结果 image.png

5. Step

通过内置step函数第二个参数小于第一个参数返回0.0,大于第一个参数返回1.0,所以左半屏为黑uv.x<0.5,右半屏为红uv.x>0.5

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    return vec4f(step(0.5, uv.x), 0.0, 0.0, 1.0);
}

结果 image.png

6. Step - Invert

因为分量都是0-1直接浮点数,所以可以通过1.0 - *对分量取反

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    return vec4f(1.0 - step(0.5, uv.x), 0.0, 0.0, 1.0);
}

结果 image.png

7. Max

通过step函数判断像素区间,t1表示像素是否小于屏幕1/4,小于时t1值为1.0否则为0.0,t2表示像素是否大于屏幕3/4,大于时t1值为1.0否则为0.0,再通过max函数设置颜色,max函数返回两个参数中较大值,所以在小于屏幕1/4和大于屏幕3/4位置被上色了

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    
    var color = vec3f(1.0, 0.3, 0.3);
    var t1 = 1.0 - step(0.25, uv.x);
    var t2 = step(0.75, uv.x);
    
    return vec4f(color * max(t1, t2), 1.0);
}

结果 image.png

8. Step Union

通过Bevy shader导入View并将其存入@group(0) @binding(0) var<uniform> view0组0位uniform类型,Viewviewport为vec4f向量,zw表示宽高,通过50.0 / view.viewport.z获得50像素占屏幕宽度的比例, 通过50.0 / view.viewport.w获得50像素占屏幕高度的比例,t1表示像素是否距离屏幕左侧50像素内,t2表示像素是否距离屏幕右侧50像素内,t3表示像素是否距离屏幕上方50像素内,t4表示像素是否距离屏幕下方50像素内,三次max函数取值为判断像素是否在屏幕四周50像素的边框内,拆解开来开,max(t3, t4)判断像素是否在上方或者下方50像素内,max(t2, max(t3, t4))判断像素是否在像素是否距离屏幕右侧50像素内且上方或者下方50像素内,max(t1, max(t2, max(t3, t4)))判断像素是否在像素是否距离屏幕左侧或右侧50像素内且上方或者下方50像素内,后续再进行预期的处理同#4

#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    var xw = 50.0 / view.viewport.z;
    var yh = 50.0 / view.viewport.w;

    var t1 = step(1.0 - xw, uv.x);
    var t2 = 1.0 - step(xw, uv.x);
    var t3 = step(1.0 - yh, uv.y);
    var t4 = 1.0 - step(yh, uv.y);
  
    var t = max(t1, max(t2, max(t3, t4)));
    uv.x = 1.0 - uv.x;
    return vec4(uv.yx * t, 0.0, 1.0);
}

结果 image.png

9. Fract

fract函数用于返回浮点值的小数部分,该函数接受单个参数,可以是floatvec2vec3vec4,并返回一个介于0.01.0之间的值,将像素x值放大10倍后取小数部分,判断小数部分是否大于0.5,即可知道像素在左半部分还是右半部分,例:

  • 0.153 * 10 -> 1.53 -> fract() -> 0.53 -> 0.53 > 0.5 需要着色
  • 0.314 * 10 -> 3.14 -> fract() -> 0.14 -> 0.14 < 0.5 不需要着色
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    var x = fract(uv.x * 10.0);

    return vec4f(step(0.5, x), 0.0, 0.0, 1.0);
}

结果 image.png

10. Tile Pattern

通过操作UV坐标并使用fract函数,可以在屏幕上创建重复模式

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

fn pattern(uv: vec2f) -> f32 {
    let new_uv = uv * 2.0 - 1.0;
    var t = pow(new_uv.x * new_uv.x, 0.3) + pow(new_uv.y * new_uv.y, 0.3) - 1.0;
    return step(0.0, t) * t * 10.0 + step(0.2, t);
  }

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;

    var columns = 5.0;
    var rows = 3.0;

    var repeated_uv = fract(uv * vec2(columns, rows));

    return vec4f(pattern(repeated_uv), 0.0, 0.0, 1.0);
}

结果 image.png

11. Fract - Grid

cell获取像素位置与网格比例,step(margin / (cellSize + margin), fract(cell.x))取比例x分量小数并与间隔和网格比例对比,从而判断像素x分量是否在边框内,step(margin / (cellSize + margin), fract(cell.y))取比例y分量小数并与间隔和网格比例对比,从而判断像素y分量是否在边框内,两值相乘代表任意值在边框内输出则为0.0

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var cellSize = 50.0;
    var margin = 10.0;
    var cell = in.position.xy / (cellSize + margin);
    
    var t = step(margin / (cellSize + margin), fract(cell.x));
    t *= step(margin / (cellSize + margin), fract(cell.y));

    return vec4f(t, 0.0, 0.0, 1.0);
}

结果 image.png

12. Mod

先将uv放大9倍将屏幕变为9份,通过step(0.5, x)设置右半部分上色,放大后的uv通过(uv.x + 1.0) % 3.0取模结果只在[0.0, 3.0]区间,[0.0, 1.0]区间则为每隔2列第三列原本红色的部分,step(1.0, (uv.x + 1.0) % 3.0)将结果转为0.0再与原来值相乘原来的x为1.0,相乘后为0.0,每隔2列第三列原本红色也被去色

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    uv *= 9.0;
    var x = fract(uv.x);
    x = step(0.5, x);
    
    x *= step(1.0, (uv.x + 1.0) % 3.0);

    return vec4f(x, 0.0, 0.0, 1.0);
}

结果 image.png

13. Mix

step(0.25, uv.x)判断像素是否在屏幕1/4内,通过* (uv.x -0.25)在屏幕1/4内容时t为0.0插值不变化,像素颜色保持color1,其他时候因子为[0.25, 1.0],使像素从1/4屏幕开始通过mix函数从color1向color2平滑变化

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {

    var uv = in.uv;

    var color2 = vec3(0.38, 0.12, 0.93);
    var color1 = vec3(1.00, 0.30, 0.30);

    var t = step(0.25, uv.x) * (uv.x - 0.25);

    return vec4f(mix(color1, color2, t), 1.0);
}

结果 image.png

14. Mix - Bilinear Interpolation

r1根据像素x分量从红过渡到黑,r2根据像素x分量取反从蓝过渡到绿,color根据像素y分量取反从r1过渡到r2,为了最终显示与Task相同,r2color加了取反操作

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;

    var red = vec3f(1.0, 0.0, 0.0);
    var black = vec3f(0.0, 0.0, 0.0);
    var blue = vec3f(0.0, 0.0, 1.0);
    var green = vec3f(0.0, 1.0, 0.0);

    let r1 = mix(red, black, uv.x);
    let r2 = mix(blue, green, 1.0 - uv.x);
    let color = mix(r1, r2, 1.0 - uv.y);

    return vec4f(color, 1.0);
}

结果 image.png

15. Smoothstep

smoothstep函数用于基于第三个插值因子在两个值之间进行平滑插值,该函数通过对插值过程应用平滑曲线,提供了与线性插值相比更平滑的过渡

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;

    var red = vec3f(1.0, 0.0, 0.0);
    var green = vec3f(0.0, 1.0, 0.0);

    let color = mix(red, green, smoothstep(0.25, 0.75, uv.x));
    return vec4f(color, 1.0);
}

结果 image.png

16. Abs

通过uv.x * 2.0 - 1.0计算像素x分量负值在屏幕左侧,像素x分量正值在屏幕右侧,通过abs函数取分量绝对值从而上色

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;

    return vec4f(abs(uv.x * 2.0 - 1.0), 0.0, 0.0, 1.0);
}

结果 image.png

17. ABS - Rhomb

通过提示菱形边为Y = K * X + Buv -= 0.5将屏幕四分,1.0 - step(0.5, abs(uv.x) + abs(uv.y)像素x分量绝对值加像素y分量绝对值小于0.5时上色

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    uv -= 0.5;

    return vec4f(1.0 - step(0.5, abs(uv.x) + abs(uv.y)), 0.0, 0.0, 1.0);
}

结果 image.png

18. Ceil

uv先放大10倍后通过ceil函数四舍五入获得整数,再将整数/10缩小获得屏幕每格色值,最终ceil后值-1第一格才会不上色

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;

    return vec4f((ceil(uv.x) - 1.0) / 10.0, 0.0, 0.0, 1.0);
}

结果 image.png

19. Int / Floor

定义数组长度常量COLORS_LENGTH,定义颜色数组colors并使用COLORS_LENGTH定义长度,将uv放大4倍,因为5位数组下标为[0, 4],使用floor函数取放大后x分量整数部分,所以渐变的开始颜色为当前floor后的结果,结束为下一个下标颜色,渐变因子就是放大后x分量小数部分,通过fract函数获取

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

const COLORS_LENGTH: u32 = 5;
const colors: array<vec3f, COLORS_LENGTH> = array<vec3f, COLORS_LENGTH>(
    vec3f(1.0, 0.0, 0.0),
    vec3f(0.0, 1.0, 0.0),
    vec3f(0.0, 0.0, 1.0),
    vec3f(1.0, 1.0, 0.0),
    vec3f(0.0, 0.0, 0.0)
);

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    let x = uv.x * (f32(COLORS_LENGTH) - 1.0);
    let index = floor(x);
    let nextIndex = min(index + 1.0, f32(COLORS_LENGTH - 1)); // 避免数组越界

    return vec4f(mix(colors[u32(index)], colors[u32(nextIndex)], fract(x)), 1.0);
} 

结果 image.png

20. Distance / Length

通过distance函数获得当前像素到中心点距离,step(0.25, dist)距离小于0.25时返回0.0,再通过1.0 -进行取反

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    var dist = distance(uv, vec2(0.5));
    var t = 1.0 - step(0.25, dist);

    return vec4f(t, 0.0, 0.0, 1.0);
} 

结果 image.png

21. Aspect Ratio

通过view.viewport.z / view.viewport.w获得分辨率比例,在distance函数中,两个参数同时乘ratio保证最终效果为屏幕中心0.25范围根据分辨率比例修改的正圆

#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    var ratio = vec2f(view.viewport.z / view.viewport.w, 1.0);
    var dist = distance(uv * ratio, vec2(0.5) * ratio);
    var t = 1.0 - step(0.25, dist);

    return vec4f(t, 0.0, 0.0, 1.0);
}

结果 image.png

22. Atan

通过atan2函数并/ π计算像素到中心点角度,在mix函数渐变中通过abs取角度的绝对值作为渐变因子,最后color -= step(0.5, dist);如果像素到中心点距离大于0.5则不上色

#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    var center = vec2f(0.5);

    var ratio = vec2f(view.viewport.z / view.viewport.w, 1.0);
    uv *= ratio;
    center *= ratio;

    var dist = distance(uv, center);
    var dir = uv - center;
    var angle = atan2(dir.y, dir.x) / 3.1415926;
    var color1 = vec3f(1.0, 0.0, 0.0);
    var color2 = vec3f(0.0, 1.0, 0.0);
    var color = mix(color1, color2, abs(angle));
    color -= step(0.5, dist);
    return vec4f(color, 1.0);
}

结果 image.png

23. Sin

dist * 3.14 * 2.0画正弦波* 5.0重复5次,sin取输入弧度的正弦值

#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;

    var ratio = vec2f(view.viewport.z / view.viewport.w, 1.0);
    var center = vec2f(0.5);
    
    var dist = distance(uv * ratio, center * ratio);
    var red = sin(dist * 3.14 * 2.0 * 5.0) * 0.5 + 0.5;
    return vec4f(red, 0.0, 0.0, 1.0);
}

结果 image.png

24. Vector Normaliztion

normalize(uv - vec2f(0.25, 0.5))取像素到左半屏中心点归一化向量,像素超过0.5时使用normalize(uv - vec2f(0.75, 0.5))取像素到右半屏中心点归一化向量

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;

    var normal = normalize(uv - vec2f(0.25, 0.5));
    var t = normal.x;
  
    if (uv.x > 0.5) {
      normal = normalize(uv - vec2f(0.75, 0.5));
      t = normal.y;
    }
  
    return vec4f(t, t, t, 1.0);
}

结果 image.png

25. Dot

通过点积画三角

#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;

    var ratio = vec2(view.viewport.z / view.viewport.w, 1.0);

    var p0 = vec2f(0.5, 0.75) * ratio; // 顶点
    var p1 = vec2f(0.5, 0.0) * ratio;  // 向底的射线
    var p2 = uv * ratio;              // 当前点
  
    var dir1 = p1 - p0; // 射线到顶点向量差
    var dir2 = p2 - p0; // 顶点到当前点向量差
    
    var n1 = normalize(dir1); // 射线到顶点向量差归一化
    var n2 = normalize(dir2); // 顶点到当前点向量差归一化
  
    var t = dot(n1, n2);   // 获取n1到n2余弦值
    var d = dot(n1, dir2); // 获取n1到dir距离
    
    var red = step(0.5, t);    // 检查余弦是否大于0.5
    red *= (1.0 - step(0.5, d)); // 检查距离是否大于0.5
    return vec4f(red, 0.0, 0.0, 1.0);
}

结果 image.png

26. Clamp

clamp(uv.x, 0.25, 0.75);通过clamp限制像素闭区间,step(lineWidth * 0.5, dist)判断分量y和限制后分量x差值的绝对值是否在线宽范围内,有正负区间但是取得是绝对值所以与线宽对比时需要lineWidth * 0.5

#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    var uv = in.uv;
    uv.y = 1.0 - uv.y;

    var lineWidth = 0.2;
    var lineColor = vec3f(1.0, 0.3, 0.3);
    
    var value = clamp(uv.x, 0.25, 0.75);
    var dist  = abs(uv.y - value);
    var line  = 1.0 - step(lineWidth * 0.5, dist);

    return vec4f(lineColor * line, 1.0);
}

结果 image.png

27. Texture

@group(2) @binding(1) var texture: texture_2d<f32>;Bevy中纹理加载存放固定在@group(2) @binding(1) @group(2) @binding(2) var texture_sampler: sampler;Bevy中采样器加载存放固定在@group(2) @binding(2)通过textureSample函数输入纹理和采样器,通过uv*宽高比的小数部分实现贴图的平铺

#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(2) @binding(1) var texture: texture_2d<f32>;
@group(2) @binding(2) var texture_sampler: sampler;
@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {

    let texture_uvs = in.uv;

    var ratio = vec2f(view.viewport.z / view.viewport.w, 1.0);

    let tex: vec4f = textureSample(texture, texture_sampler, fract(texture_uvs * ratio)); 

    return tex;
}

结果 image.png

28. Texture Mirror

纹理镜像重复

#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(2) @binding(1) var texture: texture_2d<f32>;
@group(2) @binding(2) var texture_sampler: sampler;
@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {

    var uv = in.uv;

    uv *= vec2f(view.viewport.z / view.viewport.w, 1.0);

    var tx = fract(uv.x);
    var ty = fract(uv.y);
  
    tx = mix(tx, 1.0 - tx, step(1.0, uv.x % 2.0));
    ty = mix(ty, 1.0 - ty, step(1.0, uv.y % 2.0));
    
    return textureSample(texture, texture_sampler, vec2(tx, ty));
}

结果 image.png

29. Time

Bevy globalsglobals.time为启动至当前的时间,通过运算获得纹理动画

#import bevy_sprite::mesh2d_view_bindings::globals
#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(2) @binding(1) var texture: texture_2d<f32>;
@group(2) @binding(2) var texture_sampler: sampler;
@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {

    var uv = in.uv;

    uv.y = 1.0 - uv.y;

    var t = sin(globals.time * 2.0) * 0.5 + 0.5;
    var delta = 0.375 * t * step(0.3, uv.y);
    uv.y = 1.0 - clamp(uv.y + delta, 0.0, 1.0);
    
    return textureSample(texture, texture_sampler, uv);
}

结果 image.png

30. Sprite Animation

通过(uv + vec2(x, y)) * vec2(0.5, 0.25)显示每帧显示纹理不同部分区域实现sprite动画

#import bevy_sprite::mesh2d_view_bindings::globals
#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(2) @binding(1) var texture: texture_2d<f32>;
@group(2) @binding(2) var texture_sampler: sampler;
@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {

    var uv = in.uv;

    var frame = floor(globals.time / 0.1) % 8.0;
    var x = frame % 2.0;
    var y = floor(frame / 2.0) % 4.0;
    
    return textureSample(texture, texture_sampler, (uv + vec2(x, y)) * vec2(0.5, 0.25));
}

结果 image.png

31. Radial Shutter Animation

结果

32. dFdx / dFdy

WGSL中与dFdx/dFdy等效的函数为dpdx/dpdy,通过函数对纹理描边

#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(2) @binding(1) var texture: texture_2d<f32>;
@group(2) @binding(2) var texture_sampler: sampler;
@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {

    var uv = in.uv;

    // 采样纹理
    var texel = textureSample(texture, texture_sampler, uv);

    // 计算亮度
    var luminance = dot(texel.rgb, vec3f(0.2126, 0.7152, 0.0722));

    // 计算亮度在 x 和 y 方向的偏导数
    var dx = dpdx(luminance);
    var dy = dpdy(luminance);

    // 计算偏导数绝对值之和
    var t = abs(dx) + abs(dy);

    // 根据 t 的值混合颜色
    var mixedColor = mix(texel, vec4f(1.0, 0.0, 0.0, 1.0), select(0.0, 1.0, t > 0.0));

    return mixedColor;
}

结果 image.png

33. Cross

结果

34. Matrix

#import bevy_sprite::mesh2d_view_bindings::globals
#import bevy_render::view::View
#import bevy_sprite::mesh2d_vertex_output::VertexOutput

@group(0) @binding(0) var<uniform> view: View;

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {

    var uv = in.uv;
    uv = uv * 2.0 - 1.0;
    uv.x *= view.viewport.z / view.viewport.w;
  
    var angle = globals.time * 2.0;
  
    var X_x = cos(angle);
    var X_y = sin(angle);
    var X = vec2f(X_x, X_y);
  
    var Y_x = -sin(angle);
    var Y_y = cos(angle);
    var Y = vec2f(Y_x, Y_y);
  
    var M = mat2x2f(X, Y);
    var P = vec2f(0.5);
    
    P = P * M;
  
    var t = 1.0 - smoothstep(0.24, 0.25, distance(P, uv));
    return vec4(t, 0.0, 0.0, 1.0);
}

结果 image.png

35. Equirectangular texture

结果

36. Spherical coordinates

结果

37. Normal space

结果