在各自图形软件或者shader代码中,你可能会见到这2个函数ddx,ddy。
有一些常见疑问:
一,它们干了什么?
二,为什么叫ddx?它是导数?为什么2个d,难道是2阶导?
三,怎么正确理解和活用它?
一,它们干了什么
一般来说,在一个像素的pixel shader中,如果不额外texture sample,我们只能获得当前像素的信息;但是ddx,ddy不一样,显卡每4个像素打包成一组,每个像素共享有组内信息。所以使用ddx,就是一种高效的获取邻居信息的手段。
假设ddx接受一个输入比如叫c,那么ddx©就是【右边像素-左边像素】(也就是uv的u方向,向右),ddy©就是【v+1像素-v像素】(在d3d中,由于uv.v向下,那么就是下边像素-上边像素)。
但是你细细想一下,那么问题来了,在上面这个田字结构中,我们的像素属于哪个呢?而且按通常的习惯来讲,不应该是十字结构吗?不应该是【u+1,u-1】,这样结果才是在我们的像素正中心么?而【u,u+1】的结果不变成了u+0.5位置的ddx了么?…
二,为什么叫ddx?
很多官方文档都没有解释为什么叫ddx,包括hlsl。但对比glsl,函数名称叫dFdx,我们就明白了,确实是如一些外网网友所说,来自于"d/dx"。可以看作是一种算子,而我们给它的输入,就是F。但是像素是离散世界,所以只是简单地相减,然后/1也省略了。
所以可以看出,ddx确实是数学意义上的“离散导数”。
ddx(F)=(F(u+1)-F(u))/1
三,怎么正确理解和活用?
最简理解:像素值变化速度
比如一些描边或者解决细线间断的问题里,取abs(ddx©)+abs(ddy©),作为“c变化强度”的描述量。
为什么可以这么做?
回顾泰勒展开f(x)=f(x0)+f’(x0)/1(x-x0)^1+…
我们舍去高次,移动f(x0)变为
f(x)-f(x0)=f’(x0)(x-x0)
然后我们给它换了符号
然后高贵的数学给它省略了符号:
到了二元变量,多了一个y时,导数符号f’,等同于df/dx,变成了偏导,那么:
我们还原写成人能看懂的形式,应该是这样的:
这还是把dx,dy都换成1的写法,比较清楚。最后解决离散情况下的问题。既然x轴就是屏幕u轴,那么问题就好办了:
同样这已经是把dx换成1的写法。
假设我们以屏幕uv空间为自变量,线值c为因变量,那么(ddx©,ddy©)就是严格意义上,这个c(u,v)函数在u轴和v轴的偏导数。
显然取绝对值相加之后,能够作为一种表示“变化强度”的值。
最简理解:屏幕方向,数学意义上的偏导数
比如最简法线,也就是“迪斯科球效果法线”,就是cross(ddx(P),ddy(P))。为什么可以这样做?
在切平面上的任意2个不相关切向量,cross之后肯定是法向量。而ddx(P),也就是两个三维点p(x0+1,y0)-p(x0,y0)形成了一个从当前点指向屏幕u方向的近似微表面切向量,同理ddy(P)也是一个切向量。由于屏幕u,v方向垂直,那么能保证不相关,一定能cross出法线。
至于为什么是近似,只能说我们上面已经看到:
然而1终究不是无穷小,fx也不是其极限值,所以肯定是有理论误差的。
但是,误差也没有夸张到迪斯科球那样的程度;那个是因为取的顶点位置p;直接取p看不出来有迪斯科球那么低模,只不过是因为在普通渲染下,模型的低模程度被贴图和光照掩盖了。
首先,我在UE4下通过对比线框和迪斯科球的形状,确定了这一事实。
其次,对于数学生成的球,对其pos进行ddx,ddy法线,也和预想一样完美丝滑:

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/155027.html