shader-learning.com/module-view...
1. Fragment Shader
fragment 着色器需要返回vec4f的向量作为颜色,-> @location(0) vec4<f32>
表示返回的颜色存储在@location(0)
的公共位置上
wgsl
#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);
}
结果
2. Vec
向量支持相加,相加时同位置分量相加
wgsl
#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;
}
结果
3. Swizzling
向量可以通过(x,y,z,w)或(r,g,b,a)或(s,t,p,q)访问,不同顺序最后展示值相应变化
wgsl
#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;
}
结果
4. UV Coordinates & Uniforms
通过Bevy shader导入VertexOutput
中获取uv
,原始值与预期有diff,通过1.0 - uv.x
将x值取反,反馈到结果是水平翻转,返回取uv.yx
将xy值反转,返回到结果为沿/
方向翻转
wgsl
#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);
}
结果
5. Step
通过内置step
函数第二个参数小于第一个参数返回0.0,大于第一个参数返回1.0,所以左半屏为黑uv.x<0.5
,右半屏为红uv.x>0.5
wgsl
#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);
}
结果
6. Step - Invert
因为分量都是0-1直接浮点数,所以可以通过1.0 - *
对分量取反
wgsl
#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);
}
结果
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位置被上色了
wgsl
#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);
}
结果
8. Step Union
通过Bevy shader导入View
并将其存入@group(0) @binding(0) var<uniform> view
0组0位uniform
类型,View
中viewport
为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
wgsl
#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);
}
结果
9. Fract
fract
函数用于返回浮点值的小数部分,该函数接受单个参数,可以是float
、vec2
、vec3
或vec4
,并返回一个介于0.0
和1.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 不需要着色
wgsl
@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);
}
结果
10. Tile Pattern
通过操作UV
坐标并使用fract
函数,可以在屏幕上创建重复模式
wgsl
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);
}
结果