这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
月影老师讲解的WebGL课程,分享笔记如下:
基础知识: cpu在处理图像像素点时不具备优势,Gpu由大量的小运算单元构成
初始WebGL
WebGL Startup
- 创建WebGL 上下文
- 创建WebGL Program
- 将数据存在缓冲区
- 将缓冲区数据读取到GPU
- 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;
}
效果图如下:
#!/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;
}
效果图如下:
#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;
}
效果图如下:
#!/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);
}
效果图如下: