开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
之所以要搞清楚这个函数,还是因为我绘制网格的时候遇到了问题。直到遇见了偏导数才得以解决。
常规的网格
先来一个普通的网格,就是利用放大坐标然后fract取小数,实现周期。
vec2 grid2 (vec2 uv , float w) {
uv-=vec2(.5 );
return step(vec2(.5 -w) , abs(uv) );
}
。。。。。。。。
vec2 xy = grid2(st, .01);
color = mix(color, vec4(color1,1), xy.x + xy.y);
放大了10倍,也就是10 X 10 。效果如下。
看上去还不错 ,那么来试试放大20 30倍看看。 可以看到,如果说20倍还只是有些线条的粗细不均,那么30倍的时候我们就丢失了很多线条。
线条消失术?
我们之前的判断是不是在网格上的逻辑很简单,就是判断在放大的一个[0,1]区间内,xy是否小于线宽。当然我还做了处理,处理后区间变为[-.5,.5]。 这里需要注意的是,传入的线宽w
是绝对的 ,而xy实际上是放大后的。
什么意思? 比如说,原本xy的值域是[0,1] , 经过上述处理后,一个单元格内的[-.5,.5] 实际对应 原本的十分之一,相当于[-0.05, 0.05] 。 对于线宽来说,就是线宽变细了原本是0.01
,现在是0.001
。
这么一说,是不是恍然大悟,线条太细,细的看不见了。 加粗就 完了。 加粗确实可以,但是如果我要一个确定粗细呢,是不是应该把缩放系数给线宽也乘上。 我们来试一试。
vec2 grid2 (vec2 uv , float w, float repeat) {
uv= fract(uv * repeat) - .5;
w = w* repeat ;
return step(vec2(.5 -w) , abs(uv) );
}
.........
vec2 xy = grid2(st, .01, 10.);
确实没问题了,并且线条宽度完全可控。 真的完全可控吗,再细点 0.001,1.0001
.
可以看到,取0.0001
的时候还是出问题了。 而且不是线宽细的看不见,因为仍有部分线条是可以看见的。
世界是不连续的 像素点也是
遇事不决,量子力学。 宏观连续,微观离散。 我们能从屏幕上看到色彩,实际上是有具体数目的像素点组合形成的效果,这个想必大家都知道,锯齿,像素风,就是那个意思。
所以,一个片元是不可能比实际上的一个像素点还小的。 网格之所以有些线条看不见,就是因为,那部分本该绘制的区域刚好卡在像素/片元的缝隙里,完美错过。
偏导数
dFdx dFdy
这些函数就能解决这个问题。先来看文档
fwidth = dFdx + dFdy
返回关于 x 或 y 的参数的偏导数。
dFdx 和 dFdy 只能在片段着色器中使用,它们分别返回表达式 p 在 x 和 y 中的偏导数。偏差是用局部差分计算的。暗示高阶导数如 dFdx (dFdx (n))的表达式具有未定义的结果,混合阶导数如 dFdx (dFdy (n))也是如此。假定表达式 p 是连续的,因此,通过非均匀控制流求得的表达式可能是未定义的。
看不懂? 没事,我也看不太懂,只要记得偏导函数只能在3.00及以上版本的 fragment 中使用即可 。看下图。
我接触这个函数的第一反应就是,不可能吧。 我一直以为,片元着色器是每个片元执行一次,各个片元之间互不相干。 如果真是这样,怎么可能求导呢,求导就需要变化量,只知道单个点是没法求导的。 实际上,的确如此。
在三角形光栅化期间,GPU一次运行多个实例,将它们组织为2X2的像素块, 这样就可以取相邻两个像素差值来计算导数了。dFdx
从右侧的值中减去块左侧的像素dFdy
值,从顶部的值中减去底部像素的值。请参见下图,其中网格表示渲染的屏幕像素,并且dFdx
为由dFdy
片段着色器实例在 (x, y) 屏幕坐标处评估的通用值 p 提供了表达式,并且属于以红色突出显示的 2×2 块。
使用偏导
使用很简单,如下。 有没有觉得奇怪,dx dy分别只传入了x 和y分量, 因为这是偏导 ,其实应该写作 float dx = dFdx(uv.x + uv.y)
。 此时的w 应该是个整数,但类型仍为浮点。
float dx = dFdx(uv.x) * w;
float dy = dFdy(uv.y) * w;
return step(abs(uv), vec2( dx,dy)* w );
可以看到线宽为1的时候,有些线是看不见的,因为线宽为1,就可能刚好卡在夹缝里。2两个线宽就必然能看见。
w =1 ,repeat =10
w =2 ,repeat =30
结语
好了,偏导数在glsl里的用法就这么简单。保险起见线宽可以再宽点。
上述代码中是直接用加法的结果作为混合系数的,所以交叉点的颜色有所不同,可以处理一下使得其不大于1,或者在函数实现里用 if else
之类的。
注意版本须得是3.00及以上。
今天的文章关于dFdxy函数分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/16161.html