shader基础-形状-矩形

423 阅读4分钟

1.step()函数

在 GLSL (OpenGL Shading Language) 中,step 是一个内置函数,其功能是产生一个阶梯函数。该函数有两个参数:edgex。其功能定义如下:

float step(float edge, float x);
vec2  step(vec2  edge, vec2  x);
vec3  step(vec3  edge, vec3  x);
vec4  step(vec4  edge, vec4  x);

它的工作方式如下:

  • 如果 x 小于 edge,那么返回 0。
  • 否则,返回 1。

举例来说:

  • step(0.5, 0.2) 将返回 0,因为 0.2 小于 0.5。
  • step(0.5, 0.7) 将返回 1,因为 0.7 不小于 0.5。

当传入的参数是向量时,step 函数会对向量的每个分量分别进行比较,并返回相应的结果向量。例如,step(vec2(0.5, 0.5), vec2(0.2, 0.7)) 将返回 vec2(0.0, 1.0)

这个函数在着色器中常用于实现各种阶梯效果或阈值操作,例如在你提供的代码片段中,它用于确定一个矩形区域的位置。

2.用step画矩形

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    vec3 color = vec3(0.0);

    // bottom-left
    vec2 bl = step(vec2(0.1),st);
    float pct = bl.x * bl.y;

    // top-right
    vec2 tr = step(vec2(0.1),1.0-st);
    pct *= tr.x * tr.y;


    color = vec3(pct);

    gl_FragColor = vec4(color,1.0);
}

这段 GLSL 代码是在屏幕的左下角和右上角绘制两个矩形,并将这两个矩形的颜色映射到黑色和白色之间。代码的分析如下:

  1. 定义精度和统一变量:首先,代码定义了所使用的浮点数的精度为中等精度(mediump float),并初始化了一些预设的统一变量(uniforms):u_resolution(渲染区域的分辨率),u_mouse(当前鼠标的位置)和u_time(当前的时间)。

  2. 主函数main 函数是着色器的入口点,以下是主函数的各个部分:

    • 计算标准化屏幕坐标:使用当前的片元坐标(gl_FragCoord.xy)除以屏幕分辨率(u_resolution.xy)得到一个范围在0和1之间的标准化屏幕坐标 st
    • 计算左下角矩形的颜色:使用 step 函数,如果 st 的 x 或 y 值小于 0.1,那么 bl 的对应值为 0,否则为 1。因此,当 st 在 (0.1, 0.1) 的范围内时,bl.x * bl.y 的值为 1,否则为 0。这个结果赋值给 pct
    • 计算右上角矩形的颜色:类似的,使用 step 函数,如果 1.0 - st 的 x 或 y 值小于 0.1,那么 tr 的对应值为 0,否则为 1。然后,将 pcttr.x * tr.y 的乘积赋值给 pct
    • 设置片元颜色:最后,将 pct 映射到黑色和白色之间,得到片元的颜色,并赋值给 gl_FragColor

这样,这段代码的效果是:在屏幕的左下角和右上角各绘制一个边长为屏幕边长10%的矩形,这两个矩形的颜色是白色的,其余的部分是黑色的。

3.放置多个矩形

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;

// 长方形函数
vec3 rect(vec2 st, vec2 pos, vec2 size, vec3 color) {
    vec2 r = abs(st - pos) - size;
    vec3 result = vec3(smoothstep(0.02, 0.03, r.x), smoothstep(0.02, 0.03, r.y), 1.0) * color;
    return result;
}


void main(){
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    vec3 color = vec3(0.0);

    // 绘制红色长方形
    vec2 pos1 = vec2(0.2, 0.3);
    vec2 size1 = vec2(0.1, 0.2);
    vec3 color1 = vec3(1.0, 0.0, 0.0);
    color += rect(st, pos1, size1, color1);

    // 绘制蓝色长方形
    vec2 pos2 = vec2(0.6, 0.5);
    vec2 size2 = vec2(0.2, 0.1);
    vec3 color2 = vec3(0.0, 0.0, 1.0);
    color += rect(st, pos2, size2, color2);

    // 绘制绿色长方形
    vec2 pos3 = vec2(0.4, 0.7);
    vec2 size3 = vec2(0.1, 0.2);
    vec3 color3 = vec3(0.0, 1.0, 0.0);
    color += rect(st, pos3, size3, color3);

    gl_FragColor = vec4(color,1.0);
}

在这个 GLSL 片段着色器中,rect 函数是一个自定义函数,用来绘制一个给定位置、尺寸和颜色的矩形。让我们一起详细解析这个函数:

vec3 rect(vec2 st, vec2 pos, vec2 size, vec3 color) {
    vec2 r = abs(st - pos) - size;
    vec3 result = vec3(smoothstep(0.02, 0.03, r.x), smoothstep(0.02, 0.03, r.y), 1.0) * color;
    return result;
}
  1. vec2 r = abs(st - pos) - size; 这一行计算的是当前像素(st)到矩形中心点(pos)的绝对距离,然后再减去矩形的尺寸(size)。如果这个结果(r)的 x 和 y 分量都小于 0,那么意味着当前的像素位于矩形内部。

  2. vec3 result = vec3(smoothstep(0.02, 0.03, r.x), smoothstep(0.02, 0.03, r.y), 1.0) * color; 这一行的计算是在 x 和 y 轴上独立进行的。smoothstep(0.02, 0.03, r.x) 函数会返回一个介于 0 和 1 之间的值,这个值表示 r.x0.020.03 之间的插值。如果 r.x 小于 0.02,那么 smoothstep 返回 0;如果 r.x 大于 0.03,那么 smoothstep 返回 1。这个函数的主要目的是创建一个在边缘平滑过渡的效果。

  3. * color; 就是将前面计算得到的结果与矩形的颜色进行相乘,得到最终的颜色值。

所以,rect 函数的主要工作就是为了确定当前像素是否在矩形内,如果在矩形内,就返回矩形的颜色,如果在矩形边缘,就返回过渡的颜色,如果在矩形外,就返回黑色(颜色乘以0)。