thebookofshaders 学习1

好用的函数图像生成工具: https://www.geogebra.org/graphing?lang=zh_CN

webgl 中的 glsl shader 语言,推荐从这个网站入门:
https://thebookofshaders.com/05/?lan=ch

其中关于 ‘形状’ 的一节,有如下代码:

circle2 函数中的参数 radius,其实表示直径的大小
circle 函数中的参数 _radius,其实表示直径的平方的大小
众所周知,shader默认的uv空间中,x 轴 和 y 轴 的各个数轴的取值都是 0 到 1 的闭区间。
单位圆是 半径为 1 的圆,默认的uv空间,显然装不下一个单位圆。

circle2(st,0.9) 可以理解为画 一个直径为0.9的圆形,也可以理解为画一个 0.9 单位半径的圆形;
这里 单位半径 == 0.5, circle2(st,0.9) 等价于 circle(st,0.81) circle2(st,0.8) 等价于 circle(st,0.64)

#ifdef GL_ES
precision mediump float;
#endif

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

float circle(in vec2 _st, in float _radius){
    vec2 dist = _st-vec2(0.5);
	return smoothstep(_radius-(_radius*0.01),
                         _radius+(_radius*0.01),
                         dot(dist,dist)*4.0);
}

float circle2(in vec2 st, in float radius) {
    float dist = length(st-vec2(0.5));
    float r = radius * 0.5;
    return smoothstep(r - r*0.01, r + r * 0.01, dist);
}

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

	vec3 color = vec3(circle(st,0.81));

    // draw grid
    vec2 coord = fract(st * 20.0);
    float gridWeight = 0.04;
    float blur = 0.01;
    vec2 p1 = vec2(gridWeight);
    vec2 bl = smoothstep(p1 - blur, p1 + blur, coord);
    vec2 tr = smoothstep(p1 - blur, p1 + blur, 1.0 - coord);
    float pct = bl.x * bl.y * tr.x * tr.y;
    
	gl_FragColor = vec4( color * pct, 1.0 );
}

Frenet Frames,最先接触 Frenet 标架,是学习 three.js源码 src/extras/core/Curve.js;其中有一处对一篇二十页论文的引用 http://www.cs.indiana.edu/pub/techreports/TR425.pdf 目前我是啃不动这个论文的。

现在又接触到 Frenet 标架,是因为我想做个小功能,实现类似于蜂鸟视图软件中的路径线箭头动画,这个路径的箭头,两年前,我完全做不出来;只觉得很神奇,3d场景中的相机不管怎么转动,路径管道线上的箭头图案,始终都朝向相机。随着学习的深入,了解到要实现这个效果,铁定要写着色器,不是顶点着色器,就是片元着色器。

实现这个效果时,需要找到管线的每一段中 的某个顶点,该顶点的纹理坐标的y分量为零时,该顶点处的法向量。通过使用three.js 在 TubeGeometry 上贴纹理图片 做实验,可以知道,当管线的每个路径点都在 XOY 平面时,这个点的法向量就是 (0,0,1),就是Frenet 标架 的TBN (切线 副法线 法线)中的 N 法线向量;假设有三个三维顶点 a b c 组成的一条路径线,a b c都位移 z = 0 的平面,这时 路径线上的每个顶点的 TBN 矩阵中的 N 始终是 (0,0,1),一旦把 b 点往上移动,使 b.z > 0, 这时路径线上的每个顶点的 TBN 矩阵中的 N 不再始终是 (0,0,1),变得复杂起来。

从感觉上讲,当路径控制点 b 上移时,N 变化得很快,而且我觉得,N变得很奇怪,不符合我的直觉。比如说,a b c都位移 z = 0 的平面时,N 向量是垂直于平面abc的,当 b 上移后, N 向量不再垂直于平面abc,反倒好像是处于平面abc中了。要明白这个奇怪的地方,可能是需要啃论文的,看懂 Frenet 标架中 TBN是如何算出来的。

uniform vec3 notifyColor;
  uniform float t;
  in vec2 vUv;
  vec3 topColor = vec3(1.0);
  
  void main() {
    float ratio = pow(1.0 - vUv.y, t); // sqrt(vUv.y);
    // float ratio = vUv.y;
    float y = 0.4 * abs(sin(vUv.x * 24. + t)) + 0.5;
    float potion = 1.0 - smoothstep(y - 0.3, y+0.3, vUv.y);
    vec3 color = mix(topColor, notifyColor, potion);
    gl_FragColor = vec4( color, sqrt(1.0 - vUv.y)); // vUv.y
  }

那么,Uint8Array和Uint8ClampedArray之间有什么区别呢?主要区别在于它们如何处理范围之外的值。如果我们使用Uint8Array,超出0到255的值将通过二进制补码来表示,这可能会导致一些问题。例如,如果我们向Uint8Array中写入值256,它将被解释为-128,因为256的二进制补码是100000000(8位),而第一位是符号位,表示负数。

相比之下,Uint8ClampedArray通过截断方式来处理超出范围的值,这可以确保我们永远不会得到无效的结果。这在图像处理等领域中特别有用,因为它可以确保我们的像素数据始终处于0到255的范围内。

因此,当我们需要存储像素数据等涉及到0到255范围的数据时,推荐使用Uint8ClampedArray。如果我们需要存储更广泛的整数数据,可以使用Uint8Array。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值