WebGL | 青训营笔记

102 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天

月影老师讲解的WebGL课程,分享笔记如下:

基础知识: cpu在处理图像像素点时不具备优势,Gpu由大量的小运算单元构成

初始WebGL

WebGL Startup

  1. 创建WebGL 上下文
  2. 创建WebGL Program
  3. 将数据存在缓冲区
  4. 将缓冲区数据读取到GPU
  5. GPU执行WebGL程序,输出结果

WebGL代码

这里WebGL比较难,月影老师也说这里是门槛相对比较高的,我将课程代码先贴在这里,等日后慢慢理解消化。

#!/jcode/lang/glsl https://xitu.github.io/jcode-languages/dist/lang-glsl.json

#version 300 es
precision highp float;

uniform vec2 dd_resolution;

out vec4 fragColor;

float stroke(float d, float d0, float w, float smth) {
  float th = 0.5 * w;
  smth = smth * w;
  float start = d0 - th;
  float end = d0 + th;
  return smoothstep(start, start + smth, d) - smoothstep(end - smth, end, d);
}

void main() {
  vec2 st = gl_FragCoord.xy / dd_resolution;
  float d1 = stroke(st.y, st.x, 0.02, 0.1);
  float d2 = stroke(st.y, 4.0 * (st.x - 0.5) * (st.x - 0.5), 0.02, 0.1);
  float d3 = stroke(st.y * 2.0, 1.0 - sin(30.0 * st.x), 0.02, 0.1);

  fragColor.rgb = d1 * vec3(1.0, 1.0, 0.0)
    + d2 * vec3(0.0, 1.0, 1.0)
    + d3 * vec3(0.5, 1.0, 0.5);
  fragColor.a = 1.0;
}

效果图如下:

image.png

#!/jcode/lang/glsl https://xitu.github.io/jcode-languages/dist/lang-glsl.json

#version 300 es
precision highp float;

uniform vec2 dd_resolution;

out vec4 fragColor;

float stroke(float d, float d0, float w, float smth) {
  float th = 0.5 * w;
  smth = smth * w;
  float start = d0 - th;
  float end = d0 + th;
  return smoothstep(start, start + smth, d) - smoothstep(end - smth, end, d);
}

float sdf_line(vec2 a, vec2 b, vec2 st) {
  vec2 ap = st - a;
  vec2 ab = b - a;
  return ((ap.x * ab.y) - (ab.x * ap.y)) / length(ab);
}

float sdf_seg(vec2 a, vec2 b, vec2 st) {
  vec2 ap = st - a;
  vec2 ab = b - a;
  vec2 bp = st - b;
  float l = length(ab);
  float proj = dot(ap, ab) / l;
  if(proj >= 0.0 && proj <= l) {
    return sdf_line(a, b, st);
  }
  return min(length(ap), length(bp));
}

float sdf_plot(vec2 a, vec2 b, vec2 c, vec2 st) {
  float d1 = sdf_seg(a, b, st);
  float d2 = sdf_seg(b, c, st);

  return min(d1, d2);
}

#ifndef PLOT
#define PLOT(f, st, step) sdf_plot(vec2(st.x - step, f(st.x - step)), vec2(st.x, f(st.x)), vec2(st.x + step, f(st.x + step)), st)
#endif

float fx(in float x) {
  return 0.0;
}

float fy(in float x) {
  return 9999999.99 * x;
}

float f1(in float x) {
  return floor(x);
}

float f2(in float x) {
  return sin(2.0 * x) / x;
}

void main() {
  vec2 st = gl_FragCoord.xy / dd_resolution;
  st = mix(vec2(-10, -10), vec2(10, 10), st);

  float stp = 0.1;
  
  float px = PLOT(fx, st, stp);
  float py = PLOT(fy, st, stp);

  float c1 = stroke(px, 0.0, 0.2, 0.2);
  float c2 = stroke(py, 0.0, 0.2, 0.2);

  float p1 = PLOT(f1, st, stp);
  float c3 = stroke(p1, 0.0, 0.4, 0.2);

  float p2 = PLOT(f2, st, stp);
  float c4 = stroke(p2, 0.0, 0.4, 0.2);

  // float d1 = sdf_seg(vec2(0.3), vec2(0.7, 0.5), st);
  // float d2 = sdf_line(vec2(1.0, 0.0), vec2(0.0, 1.0), st);

  fragColor.rgb = c1 * vec3(1.0, 1.0, 1.0) +
    c2 * vec3(1.0, 1.0, 1.0) +
    c3 * vec3(1.0, 1.0, 0.0) +
    c4 * vec3(0.0, 1.0, 1.0);

  fragColor.a = 1.0;
}

效果图如下:

image.png


#version 300 es
precision highp float;
out vec4 FragColor;
uniform vec2 dd_resolution;

#ifndef PI
#define PI 3.141592653589793
#endif

#ifndef FLT_EPSILON
#define FLT_EPSILON 0.000001
#endif

vec2 transform(vec2 v0, mat3 matrix) {
  return vec2(matrix * vec3(v0, 1.0));
}

vec2 rotate(vec2 v0, vec2 origin, float ang) {
  float sinA = sin(ang);
  float cosA = cos(ang);
  mat3 m = mat3(cosA, -sinA, 0, sinA, cosA, 0, 0, 0, 1);
  return transform(v0 - origin, m) + origin;
}

vec2 rotate(vec2 v0, float ang) {
  return rotate(v0, vec2(0.0), ang);
}

float stroke(float d, float d0, float w, float smth) {
  float th = 0.5 * w;
  smth = smth * w;
  float start = d0 - th;
  float end = d0 + th; 
  return smoothstep(start, start + smth, d) - smoothstep(end - smth, end, d);
}

float sdf_line(vec2 st, vec2 a, vec2 b) {
  vec2 ap = st - a;
  vec2 ab = b - a;
  return ((ap.x * ab.y) - (ab.x * ap.y)) / length(ab);
}

float sdf_seg(vec2 st, vec2 a, vec2 b) {
  vec2 ap = st - a;
  vec2 ab = b - a;
  vec2 bp = st - b;
  float l = length(ab);
  float proj = dot(ap, ab) / l;
  if(proj >= 0.0 && proj <= l) {
    return sdf_line(st, a, b);
  }
  return min(length(ap), length(bp));
}

float sdf_triangle(vec2 st, vec2 a, vec2 b, vec2 c) {
  vec2 va = a - b;
  vec2 vb = b - c;
  vec2 vc = c - a;

  float d1 = sdf_line(st, a, b);
  float d2 = sdf_line(st, b, c);
  float d3 = sdf_line(st, c, a);

  // 三角形内切圆半径
  float l = abs(va.x * vb.y - va.y * vb.x) / (length(va) + length(vb) + length(vc));

  if(d1 >= 0.0 && d2 >= 0.0 && d3 >= 0.0 || d1 <= 0.0 && d2 <= 0.0 && d3 <= 0.0) {
    return min(abs(d1), min(abs(d2), abs(d3))) / l;
  }

  d1 = sdf_seg(st, a, b);
  d2 = sdf_seg(st, b, c);
  d3 = sdf_seg(st, c, a);
  return -min(abs(d1), min(abs(d2), abs(d3))) / l;
}

float atan2(float dy, float dx) {
  float ax = abs(dx);
  float ay = abs(dy);
  float a = min(ax, ay) / (max(ax, ay) + FLT_EPSILON);
  float s = a * a;
  float r = ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a;
  if(ay > ax) r = 1.57079637 - r;
  if(dx < 0.0) r = PI - r;
  if(dy < 0.0) r = -r;
  return r;
}

float atan2(vec2 v) {
  return atan2(v.y, v.x);
}

/**
  从 v1 相对 v2 的逆时针夹角, 0 ~ 2 * PI
 */
float angle(vec2 v1, vec2 v2) {
  float ang = atan2(v1) - atan2(v2);
  if(ang < 0.0) ang += 2.0 * PI;
  return ang;
}

/**
  正多边形
 */
float regular_polygon(vec2 st, vec2 center, float r, float rotation, const int edges) {
  vec2 p = st - center;
  vec2 v0 = vec2(0, r); // 第一个顶点
  v0 = rotate(v0, -rotation);

  float a = 2.0 * PI / float(edges); // 每条边与中心点的夹角

  float ang = angle(v0, p); // 取夹角
  ang = floor(ang / a); // 在哪个区间

  vec2 v1 = rotate(v0, a * ang); // 左顶点
  vec2 v2 = rotate(v0, a * (ang + 1.0)); // 右顶点

  float c_a = cos(0.5 * a);

  float l = r * c_a;
  float d = sdf_line(p, v1, v2);

  return d / l; 
}

float sdf_ellipse(vec2 st, vec2 c, float a, float b) {
  vec2 p = st - c;
  return 1.0 - sqrt(pow(p.x / a, 2.0) + pow(p.y / b, 2.0));
}

float sdf_ellipse(vec2 st, vec2 c, float a, float b, float sAng, float eAng) {
  vec2 ua = vec2(cos(sAng), sin(sAng));
  vec2 ub = vec2(cos(eAng), sin(eAng));

  float d1 = sdf_line(st, c, ua + c);
  float d2 = sdf_line(st, c, ub + c);

  float d3 = sdf_ellipse(st, c, a, b);
  float r = min(a, b);

  vec2 v = st - c;
  float ang = angle(v, vec2(1.0, 0));

  if(eAng - sAng > 2.0 * PI) {
    return d3;
  }

  if(ang >= sAng && ang <= eAng) { // 两个向量夹角中间的部分
    float m = max(a, b);
    float d11 = sdf_seg(st, c, ua * m + c);
    float d12 = sdf_seg(st, c, ub * m + c);
    if(d3 >= 0.0) {
      return min(abs(d11 / r), min(abs(d12 / r), d3));
    }
    return d3;
  }
  
  float pa = dot(ua, v); // 求投影
  float pb = dot(ub, v);

  if(pa < 0.0 && pb < 0.0) {
    return -length(st - c) / r;
  }

  if(d1 > 0.0 && pa >= 0.0) {
    vec2 va = pa * ua;
    float da = pow(va.x / a, 2.0) + pow(va.y / b, 2.0);
    if(d3 > 0.0 || da <= pow(1.0 + abs(d1 / r), 2.0)) {
      return -abs(d1 / r);
    } else {
      return d3;
    }
  }

  if(d2 < 0.0 && pb >= 0.0) {
    vec2 vb = pb * ub;
    float db = pow(vb.x / a, 2.0) + pow(vb.y / b, 2.0);
    if(d3 >= 0.0 || db <= pow(1.0 + abs(d2 / r), 2.0)) {
      return -abs(d2 / r);
    } else {
      return d3;
    }
  }
}

void main() {
  vec2 st = gl_FragCoord.xy / dd_resolution;
  st = mix(vec2(-5.0), vec2(5.0), st);
  float d = regular_polygon(fract(st), vec2(0.5), 0.55, 0.0, 4);
  d = abs(d);
  FragColor.rgb = stroke(d, 0.5, 0.5, 0.5) * vec3(1.0);
  FragColor.a = 1.0;
}

效果图如下:

image.png

#!/jcode/lang/glsl https://xitu.github.io/jcode-languages/dist/lang-glsl.json

#version 300 es
precision highp float;
out vec4 FragColor;
uniform vec2 dd_resolution;

#ifndef PI
#define PI 3.141592653589793
#endif

#ifndef FLT_EPSILON
#define FLT_EPSILON 0.000001
#endif

vec2 transform(vec2 v0, mat3 matrix) {
  return vec2(matrix * vec3(v0, 1.0));
}

vec2 rotate(vec2 v0, vec2 origin, float ang) {
  float sinA = sin(ang);
  float cosA = cos(ang);
  mat3 m = mat3(cosA, -sinA, 0, sinA, cosA, 0, 0, 0, 1);
  return transform(v0 - origin, m) + origin;
}

vec2 rotate(vec2 v0, float ang) {
  return rotate(v0, vec2(0.0), ang);
}

float stroke(float d, float d0, float w, float smth) {
  float th = 0.5 * w;
  smth = smth * w;
  float start = d0 - th;
  float end = d0 + th; 
  return smoothstep(start, start + smth, d) - smoothstep(end - smth, end, d);
}

float sdf_line(vec2 st, vec2 a, vec2 b) {
  vec2 ap = st - a;
  vec2 ab = b - a;
  return ((ap.x * ab.y) - (ab.x * ap.y)) / length(ab);
}

float sdf_seg(vec2 st, vec2 a, vec2 b) {
  vec2 ap = st - a;
  vec2 ab = b - a;
  vec2 bp = st - b;
  float l = length(ab);
  float proj = dot(ap, ab) / l;
  if(proj >= 0.0 && proj <= l) {
    return sdf_line(st, a, b);
  }
  return min(length(ap), length(bp));
}

float sdf_rect(vec2 st, vec2 p, float w, float h) {
  vec2 a = p;
  vec2 b = p + vec2(w, 0.0);
  vec2 c = p + vec2(w, h);
  vec2 d = p + vec2(0.0, h);

  float d1 = sdf_line(st, a, b);
  float d2 = sdf_line(st, b, c);
  float d3 = sdf_line(st, c, d);
  float d4 = sdf_line(st, d, a);

  float l = min(w, h) * 0.5; // 矩形短边

  if(d1 >= 0.0 && d2 >= 0.0 && d3 >= 0.0 && d4 >= 0.0 ||
     d1 <= 0.0 && d2 <= 0.0 && d3 <= 0.0 && d4 <= 0.0) {
    return min(abs(d1), min(abs(d2), min(abs(d3), abs(d4)))) / l;
  }

  d1 = sdf_seg(st, a, b);
  d2 = sdf_seg(st, b, c);
  d3 = sdf_seg(st, c, d);
  d4 = sdf_seg(st, d, a);

  return -min(abs(d1), min(abs(d2), min(abs(d3), abs(d4)))) / l;
}


float sdf_triangle(vec2 st, vec2 a, vec2 b, vec2 c) {
  vec2 va = a - b;
  vec2 vb = b - c;
  vec2 vc = c - a;

  float d1 = sdf_line(st, a, b);
  float d2 = sdf_line(st, b, c);
  float d3 = sdf_line(st, c, a);

  // 三角形内切圆半径
  float l = abs(va.x * vb.y - va.y * vb.x) / (length(va) + length(vb) + length(vc));

  if(d1 >= 0.0 && d2 >= 0.0 && d3 >= 0.0 || d1 <= 0.0 && d2 <= 0.0 && d3 <= 0.0) {
    return min(abs(d1), min(abs(d2), abs(d3))) / l;
  }

  d1 = sdf_seg(st, a, b);
  d2 = sdf_seg(st, b, c);
  d3 = sdf_seg(st, c, a);
  return -min(abs(d1), min(abs(d2), abs(d3))) / l;
}

float atan2(float dy, float dx) {
  float ax = abs(dx);
  float ay = abs(dy);
  float a = min(ax, ay) / (max(ax, ay) + FLT_EPSILON);
  float s = a * a;
  float r = ((-0.0464964749 * s + 0.15931422) * s - 0.327622764) * s * a + a;
  if(ay > ax) r = 1.57079637 - r;
  if(dx < 0.0) r = PI - r;
  if(dy < 0.0) r = -r;
  return r;
}

float atan2(vec2 v) {
  return atan2(v.y, v.x);
}

/**
  从 v1 相对 v2 的逆时针夹角, 0 ~ 2 * PI
 */
float angle(vec2 v1, vec2 v2) {
  float ang = atan2(v1) - atan2(v2);
  if(ang < 0.0) ang += 2.0 * PI;
  return ang;
}

/**
  正多边形
 */
float regular_polygon(vec2 st, vec2 center, float r, float rotation, const int edges) {
  vec2 p = st - center;
  vec2 v0 = vec2(0, r); // 第一个顶点
  v0 = rotate(v0, -rotation);

  float a = 2.0 * PI / float(edges); // 每条边与中心点的夹角

  float ang = angle(v0, p); // 取夹角
  ang = floor(ang / a); // 在哪个区间

  vec2 v1 = rotate(v0, a * ang); // 左顶点
  vec2 v2 = rotate(v0, a * (ang + 1.0)); // 右顶点

  float c_a = cos(0.5 * a);

  float l = r * c_a;
  float d = sdf_line(p, v1, v2);

  return d / l; 
}

float sdf_ellipse(vec2 st, vec2 c, float a, float b) {
  vec2 p = st - c;
  return 1.0 - sqrt(pow(p.x / a, 2.0) + pow(p.y / b, 2.0));
}

float sdf_ellipse(vec2 st, vec2 c, float a, float b, float sAng, float eAng) {
  vec2 ua = vec2(cos(sAng), sin(sAng));
  vec2 ub = vec2(cos(eAng), sin(eAng));

  float d1 = sdf_line(st, c, ua + c);
  float d2 = sdf_line(st, c, ub + c);

  float d3 = sdf_ellipse(st, c, a, b);
  float r = min(a, b);

  vec2 v = st - c;
  float ang = angle(v, vec2(1.0, 0));

  if(eAng - sAng > 2.0 * PI) {
    return d3;
  }

  if(ang >= sAng && ang <= eAng) { // 两个向量夹角中间的部分
    float m = max(a, b);
    float d11 = sdf_seg(st, c, ua * m + c);
    float d12 = sdf_seg(st, c, ub * m + c);
    if(d3 >= 0.0) {
      return min(abs(d11 / r), min(abs(d12 / r), d3));
    }
    return d3;
  }
  
  float pa = dot(ua, v); // 求投影
  float pb = dot(ub, v);

  if(pa < 0.0 && pb < 0.0) {
    return -length(st - c) / r;
  }

  if(d1 > 0.0 && pa >= 0.0) {
    vec2 va = pa * ua;
    float da = pow(va.x / a, 2.0) + pow(va.y / b, 2.0);
    if(d3 > 0.0 || da <= pow(1.0 + abs(d1 / r), 2.0)) {
      return -abs(d1 / r);
    } else {
      return d3;
    }
  }

  if(d2 < 0.0 && pb >= 0.0) {
    vec2 vb = pb * ub;
    float db = pow(vb.x / a, 2.0) + pow(vb.y / b, 2.0);
    if(d3 >= 0.0 || db <= pow(1.0 + abs(d2 / r), 2.0)) {
      return -abs(d2 / r);
    } else {
      return d3;
    }
  }
}

void color(float d, vec4 c1, vec4 c2) {
  FragColor = mix(c2, c1, d);
}

void color(float d, vec4 c1, vec3 c2) {
  color(d, c1, vec4(c2, 1.0));
}

void color(float d, vec3 c1, vec4 c2) {
  color(d, vec4(c1, 1.0), c2);
}

void color(float d, vec3 c1, vec3 c2) {
  color(d, vec4(c1, 1.0), vec4(c2, 1.0));
}

void color(float d, vec4 c) {
  color(d, c, FragColor);
}

void color(float d, vec3 c) {
  color(d, vec4(c, 1.0), FragColor);
}

void main() {
  vec2 st0 = gl_FragCoord.xy / dd_resolution;
  vec2 st = fract(st0 * 10.0);

  float d = sdf_ellipse(st0, vec2(0.5), 0.45, 0.45);
  float pct = sdf_rect(st, vec2(0.3), 0.4, 0.4);
  float pct2 = sdf_line(st, vec2(0.5, 0), vec2(0.5, 1.0));
  float pct3 = sdf_line(st, vec2(0.0, 0.5), vec2(1.0, 0.5));
  float pct4 = regular_polygon(st, vec2(0.5), 0.55, 0.3925, 8);
  float d2 = sdf_rect(st0, vec2(0.4), 0.2, 0.2);

  color(stroke(pct2, 0.0, 0.05, 0.1)
    + stroke(pct3, 0.0, 0.05, 0.1)
    + stroke(pct4, 0.0, 0.1, 0.1)
    + stroke(pct, 0.0, 0.2, 0.1)
    + stroke(d2, 0.0, 0.2, 0.1)
    ,vec3(1));
  
  FragColor = FragColor * step(0.0, d) * step(d2, 0.0) + stroke(d, 0.0, 0.05, 0.1);
}

效果图如下:

image.png