本节内容:
重心坐标(Barycentric Coordinates)
重心坐标就是为了解决在三角形内部做插值的问题。(插值就是从一个顶点的颜色平滑的过度到另一个顶点的颜色)
重心坐标的含义
重心坐标是定义在一个三角形上的,在三角形ABC中的任何一个点(x,y)都可以表示成三角形的顶点ABC的线性组合,并且需要满足α+β+γ=1(等于1时是在三角形所在的平面内,不等于1则不在平面内)。这样就可以用(α,β,γ)来表示一个点了。如果α,β,γ都为非负数,则表示这个点在三角形内部 这样用的好处: 只要知道三个顶点,就可以表示三角形内部任意一个点的位置了 顶点自己的坐标: 可知A点自己的重心坐标是(1,0,0)
怎么求重心坐标
方式一: α的值是和A点不相邻的三角形的面积除以总面积
三角形的重心
三角形的重心把大三角形均匀的分为了三份,所以三角形重心的重心坐标为(1/3,1/3,1/3)
怎么求重心坐标
方式二:
利用重心坐标来做插值
直接用属性乘以重心坐标就可以求出三角形内部任意一点插值的结果。
怎么应用纹理
屏幕上任何一个采样点都有一个位置,就可以知道在这个位置上插值出来的uv(纹理坐标)。原来的纹理坐标都定义在三角形的顶点上现在对于任何一个三角形内的点,我们都知道其在三角形中的位置,然后用重心坐标做一个插值,可以算出这一个点的uv。 然后去纹理上查询一些uv的值就可以得到对应的纹理,(可以用来当作漫反射系数Kd) 那么这样应用纹理会带来什么问题
问题1:分辨率高纹理小
如果分辨率高(假如是4K),而纹理小(假如是256P),那么在任意一个点上去查纹理,可能会查到一些非整数的值。这样就会造成纹理被拉大
对应屏幕上任意一个点都可以在纹理上找到一个相应的位置,如果不是整数则采用四舍五入,这样会造成在不同像素上应用的其实是同一个纹理,即图Nearest
为了解决用非整数坐标在查询纹理时怎么得到纹理对应得值,引入双线性插值
可以看到此时红色得点并没有落在纹理的任何一个位置上,而是一个非整数的位置,如果采用四舍五入的方法那么落在一个纹理在周围的正方形里面的像素都会显示用一个颜色,这显然是不对的
双线性插值的做法: 首先找到像素临近四个的四个纹理点 然后计算红点离左下角u00这个点的水平距离s和插值距离t,s、t都是位于0~1之间(两个纹理像素之间相差1) 然后进行线性插值lerp
其中v0和v1是两个不同的点,当x=0时lerp的值就是v0,当x=1时lerp的值就是v1,当x位于0到1之间时lerp的值就是位于v0到v1之间
这样我们就可以利用 距离s 以及 左下角 和 右下角 的点做一个线性插值来就出u0的颜色,u1同理 然后利用距离t 再对u0,u1做一次插值,这样就求出了红点的颜色了。其颜色取决于周围四个纹理像素的颜色。 双线性插值后的效果:Bilinear
比双线性插值更高明的方法——双三次插值Bicubic
这种操作取的是周围16个像素而非4个像素,然后用这16个像素做水平和竖直方向的插值,不过是每次用4个做三次插值。
问题2:分辨率低纹理大
当分辨率低而纹理分辨率高时会出现摩尔纹。 摩尔纹出现的原因 分辨率低就会造成一个像素会覆盖多个纹理。
在近处时一个像素覆盖纹理上的区域相对交小 在远处时一个像素覆盖纹理上的区域相对交大
当像素覆盖的纹理区域大时就不知道应该应用哪个纹理了,就会造成摩尔纹(走样) 可以看到图片上有很多锯齿,那么肯定也可以用抗锯齿的方法
解决方法: 使用超采样技术后MSAA的效果: 但是花费太高了
更好的解决方法: 点查询:有一个点,然后去纹理上面查找相应的纹理,这是点查询 范围查询:不做采样,拿到一个区域立刻可以得到其内部的平均值,这是范围查询(范围查询可以查范围的最大值、最小值、平均值等等)
我们只要知道纹理上一块区域的平均值,然后使用这个平均值当作该像素的颜色就行了
MipMap
怎么得到一个范围的值呢? 使用MipMap 特点:速度快、不一定准确(近似值)、只能查询正方形范围
MipMap的含义: 当我们拿到原始纹理(level 0)时,先把这些MipMap都生成。即每次图片分辨率都缩小一半,直到1*1 将这些图叠加到一起: 因为每一层图分辨率都缩小一半,所以每一层的存储量都是上一层的四分之一,总开销=1+1/4+1/16+…… 计算得总开销是4/3,额外开销仅仅是1/3。
任何一个像素都可以映射到一个纹理上的区域,要计算这个区域有多大,首先要把其周围的像素也投影上去 已知一个像素在屏幕空间上距离是1,那么就可计算出投影到纹理上的距离L,那么我们就可以计算出一个像素在纹理上占据的面积了。 红色部分是映射到纹理上的实际区域,正方形是近似区域。 得到这个正方形后就可以根据正方形边长L去查找哪一张图片,从而得到改正方形区域颜色的平均值。 当正方形是11时即L=1, 则log2L=0,表示可以在原始纹理上找到其对应像素,像素的值就是该区域的平均值 当正方形是22时即L=2, 则log2L=1,表示在level 1上对应一个像素,像素的值就是该区域的平均值
边长为L则到log2L层去查找像素。
下面是不同位置的查询层数,同颜色代表在同一层 怎么解决查询第1.5层呢? 使用插值的方法就行
首先找到第一层,然后找D+1层,这两层内部使用双线性插值求出每一层内部的值,然后将求得的两个插值结果在层与层之间再做一次插值。所以一共做了三步,这叫做三线性插值。这就得到了1.5层 结果三线性插值后查询层数的结果 使用MipMap之后的图: 可以看到相比MSAA 远处是糊的,因为其只能查询正方形区域的平均值,如果不是正方形就会产生误差,而且插值也会带来误差,误差叠加之下就糊了。
各向异性过滤(Anisotropic Filtering ) :在不同的方向上的表现并不相同(考虑不同的方向),是用来过滤、处理当视角变化导致3D物体表面倾斜时造成的纹理错误。
各向同性过滤 :在不同的方向上的表现相同(不考虑方向)
在MipMap的基础上进行各向异性过滤:
MipMap所作的工作其实是计算主对角线上的图片,横向压缩和竖向压缩MipMap是没有做的,所以MipMap只能查询正方形区域。
而各向异性过滤做了横向压缩和竖向压缩,所以可以查询矩形区域了,实际中的图片会各种形状,矩形区域更加精准但是仍然不完全准确。其开销是原来三倍 为了解决不能查询不规则的图形问题有一个新方法
EWA
EWA滤波被广泛的认为是纹理过滤(texture filtering)算法中最好的算法之一。对于任何一个形状,都可以拆成很多不同的圆形去覆盖这个形状。如上图查询一个椭圆,将其拆成三个圆形,每次去查询一个圆形,多次查询自然就可以得到一个区域,但是代价是“多次查询”。可见质量越高的效果,性能开销越大。
各向异性过滤主要靠显存,打游戏现存大可以开。
|