「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」
前期练习
在开始绘制2D形状前,先绘制简单内容。如下shader展示绘制一半黑色一半白色,默认col赋值为0.0,通过if语句对x轴做判断,当x>0.5时col向量赋值为1.0。
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
vec3 col = vec3(0.0);
if(uv.x > 0.5) col = vec3(1.0);
gl_FragColor = vec4(col,1.0);
}
但对于glsl来说
if-else条件判断并不友好,尽量减少对if-else语句的使用。推荐使用glsl内置函数可能高效一些。类似如上代码可以采用内置函数step替代。改造后的代码如下:
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
vec3 col = vec3(step(0.5,uv.x));
gl_FragColor = vec4(col,1.0);
}
step函数等价于uv.x > 0.5 ? 1.0 : 0.0;
方法函数step(a, x) :如果 x<a,返回 0;否则,返回 1
绘制圆
圆的计算公式:{x}^2+{y}^2={r}^2,x是X坐标值,y是Y坐标值,r是圆半径值。
在
OpenGL脚本中有length(v)内置函数可以实现圆的计算公式,对应的数学公式是sqrt(dot(v,v)),也叫取向量的模。
value = .
如下代码展示效果并不能达到预期效果,圆会出现在画布左下角的位置。需要知道在glsl中x,y坐标的(0,0)在画布的左下角位置,也正式圆绘制在画布位置。如果需要让圆能够绘制在画布的中心位置上,则需要调整绘制的整体坐标位置。
vec3 sdfCircle(vec2 uv,float r){
float d = length(uv) - r;
return d > 0. ? vec3(1.) : vec3(0., 0., 1.); // 大于0超出画圆范围,小于0在画圆范围内
}
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
gl_FragColor = vec4(sdfCircle(uv,0.4),1.0);
}
因为glsl中顶点范围是在[0,1]区间上的,所以画布原点位置坐标是(0,0)。在绘制圆之前先对uv减0.5操作,那么原点位置坐标就变为(0.5,0.5)。绘制圆的位置坐标就偏移到画布中心点的位置,然后iResolutionx坐标和y坐标相除获取到宽高比比例。最后uv.x和宽高比相乘后赋值解决了圆被拉伸的问题。
vec3 sdfCircle(vec2 uv,float r){
float d = length(uv) - r;
return d > 0. ? vec3(1.) : vec3(0., 0., 1.); // 大于0超出画圆范围,小于0在画圆范围内
}
void main() {
vec2 uv = gl_FragCoord.xy / iResolution.xy;
uv -= 0.5; // x: <-0.5, 0.5>, y: <-0.5, 0.5>
uv.x *= iResolution.x/iResolution.y; // x: <-0.5, 0.5> * aspect ratio, y: <-0.5, 0.5>
gl_FragColor = vec4(sdfCircle(uv,0.4),1.0);
}
| 默认uv | 调整后的uv |
|---|---|