《Unity Shader入门精要》 第七章 基础纹理 笔记

基础纹理

  • 纹理最初的目的就是使用一张图片来控制模型的外观。使用纹理映射技术,我们可以把一张图“黏”在模型表面,逐纹素(纹素的名字是为了与像素作区分)地控制模型的颜色。
  • 在美术人员建模时,通常会在建模软件中利用纹理展开技术把纹理映射坐标存储到每个顶点上。纹理映射坐标定义了该顶点在纹理中对应的2D坐标。通常,这些坐标使用一个二维变量(u,v)来表示,其中u是横向坐标,而v是纵向坐标。因此,纹理坐标也被称为UV坐标。(原来展UV是这个意思)
  • 尽管纹理的大小可以是多种多样的,例如可以是256x256或者1028x1028的,但顶点的UV坐标通常都被归一化到[0,1]范围内。
  • 注意OpenGL(原点位于左下)和DirectX(原点位于左上)中纹理坐标的不同。

纹理资源属性

纹理类型。

选择合适的类型是为了让unity知道我们的意图,为Unity Shader传递正确的纹理,并在一些情况下可以让Unity对该纹理进行优化。

Wrap Mode

决定了当纹理坐标超过[0,1]范围后将会如何被平铺。Wrap Mode有两种模式:

  • Repeat模式下,纹理坐标超过1,那它的整数部分就会被舍弃,而使用小数部分进行采样,这样的结果是纹理将会不断重复;
  • Clamp模式下,如果纹理坐标大于1,那么将会截取到1,如果小于0,那么将会截取到0。

Filter Mode

  • 它决定了当纹理由于变换而产生拉伸时将会采用哪种滤波模式。Filter Mode支持3种模式:Point、Bilinear、Trilinear。它们得到的图片滤波效果依次上升,但需要耗费的性能也依次增大。纹理滤波会影响放大或缩小纹理得到的图片质量。例如把64X64大小的纹理贴在一个512X512大小的平面上时,就需要放大纹理。纹理缩小的过程比放大更加复杂,此时原纹理多个像素将会对应一个目标像素。纹理缩放更加复杂的原因在于我们往往需要处理锯齿问题,最常用的方法就是多级渐远纹理技术。多级渐远纹理技术是将原纹理提前使用滤波处理来得到很多更小的图像,形成一个图像金字塔,每一层都是对上一层图像降采样的结果。当物体原理摄像机时就可以直接使用较小的纹理。缺点是通常会多占用33%的内存空间。
  • 在Unity中,我们将纹理类型选择为Advanced,再勾选Generate Mip Maps即可开启多级渐远纹理技术。

在内部实现上:

  • Point模式使用最近邻滤波,在放大缩小时,它的采样像素数目通常只有一个,因此图像会看起来有种像素风格的效果。
  • Bilinear滤波则使用了线性滤波,对于每个目标像素,它会找到4个相邻像素,然后对它们进行线性插值混合后得到最终像素,因此图像看起来像被模糊了。
  • Trilinear滤波几乎和Bilinear一样,只是Trilinear还会在多级渐远纹理之间进行混合。

纹理最大尺寸和纹理模式

  • Unity允许我们为不同目标平台选择不同的分辨率。
    如果导入的纹理大小超过了Max Texture Size中设置的值,那么就会被缩放到这个值。导入的纹理可以是非正方形的,但长宽的大小应该是2的幂,如2,4,8,16,32,64,128,512,1024等,如果使用了非2的幂(NPOT)大小的纹理,那么这些纹理往往会占用更多的内存空间,而且GPU读取该纹理的速度也会下降,有些平台甚至不支持NPOT纹理。
  • Format决定了Unity内部使用哪种格式来存储该纹理。如果我们将Texture Type设置为Advanced,那么会有更多的Format供我们选择。这里不介绍每种纹理格式,但要知道纹理格式精度越高,越消耗性能,但是得到的效果也越好。

凹凸映射

凹凸映射目的是使用一张纹理来修改模型表面的法线,一遍提供更多的细节。这只是让模型看起来好像是凹凸不平的,但可以从模型轮廓看出破绽。
目前有两种方法可以用来凹凸映射:

  • 使用高度纹理来模拟表面位移,然后得到一个修改后的法线值,这种方法被称作高度映射
  • 使用法线纹理来直接存储表面法线,这种方法被称作法线映射

高度纹理

使用一张高度图来实现凹凸映射。高度图中存储的是强度值,用于表示表面局部区域的海拔高度。因此颜色越前表示该位置的表面越向外凸起,而颜色越深越向里凹。这种方法好处是直观,可以明确知道一个模型表面的凹凸情况,但缺点是计算更加复杂,实时计算时不能直接得到表面法线,而是需要像素的灰度值计算而得,因此需要消耗更多的性能。
高度图通常会和法线映射一起使用,用于给出表面凹凸的额外信息。但通常会使用法线映射来修改光照。

法线纹理

由于法线分量范围在[-1,1],而像素的分量范围为[0,1],因此我们需要做一个映射,通常使用的映射就是:
向量映射法线公式
反映射就是个逆函数

  • 将修改后的模型空间中的表面法线存储在一张纹理中的,这种纹理被称为是模型空间的法线纹理
  • 然而通常我们会采用另一种纹理坐标,即模型顶点的切线空间来储存法线。对于模型的每个顶点,它都有一个属于自己的切线空间,原点为该顶点本身,z轴为顶点的法线方向,x轴是顶点的切线方向,y轴可以由法线和切线方向差积得到,被称为副法线或者副切线。这种纹理被称为是切线空间的法线纹理
  • 模型空间的法线纹理通常看起来是五颜六色的,而切线空间的法线纹理通常看起来是浅蓝色的
模型空间储存法线的优点
  • 实现简单,更加直观。甚至不需要模型原始的法线和切线等信息,也就是计算更少。生成也非常简单。
  • 纹理坐标的缝合处和尖锐的边角部分,可见的突变(缝隙)较少,即可提供平滑边界。因为法线方向存储在同一坐标空间中,所以可以通过插值来平滑变换。
切线空间储存法线的优点
  • 自由度高。模型空间下的法线纹理是绝对法线信息,仅可用于创建它的那个模型,应用到其他模型上效果就完全错误了。而切线空间记录的是相对法线信息,这意味着可以把它应用到完全不同的网格上,也可以得到一个合理的结果。
  • 可进行UV动画。比如,我们可以移动一个纹理的UV坐标来实现一个凹凸移动的效果,但是使用模型空间的法线纹理就会得到完全错误的结果。这种动画通常会使用在水或火山熔岩这类型的物体上。
  • 可以重用法线纹理。比如一个砖块,用一张法线贴图就可以用到所有6个面上。
  • 可压缩。由于切线空间下法线的Z方向总是正向,因此可以仅储存XY方向,而推导出Z方向。

(顺手记录一个会用到的第四章的知识点,A坐标空间下,B坐标空间三条坐标轴的单位向量横向排列组成的矩阵就是A坐标空间到B坐标空间的变换矩阵,好像限制条件是没有缩放的情况下)

Unity中的法线纹理类型

当我们把法线纹理的纹理类型设置为Normal map时,可以使用Unity的内置函数UnpackNormal来得到正确的法线方向。
UnpackNormal的源码为:

inline fixed3 UnpackNormalDXT5nm(fixed4 packednormal){
    fixed3 normal;
    normal.xy = packednormal.wy * 2 - 1;
    normal.z = sqrt(1 - saturate(dot(normal.xy,normal.xy)));
    return normal;
}

inline fixed3 UnpackNormal(fixed4 packednormal){
    #if define(UNITY_NO_DXT5nm)
        return packednormal.xyz * 2 - 1;
    #else
        return UnpackNormalDXT5nm(packednormal);
    #endif
}
  • 从代码可以看出,UnpackedNomal函数对使用DXT5nm压缩格式的法线纹理进行的相应解码方式。
    DXT5nm压缩格式中,纹素的a通道(即w分量)对用了法线的x分量,g通道对应了法线的y分量,而纹理的r和b通道则会被舍弃,法线的z分量可以由xy分量推导得出。使用这种压缩可以减少法线纹理占用的空间。
  • 纹理设置中还有一个Create from Grayscale复选框,勾选这个复选框后,这张纹理贴图就被当做高度图来处理。勾选后会增加两个选项——Bumpiness和Filtering。其中Bumpiness用于控制凹凸程度,而Filtering用于控制我们使用哪种方式来计算凹凸程度。
    一种是Smooth,这使得生成的法线纹理会比较平滑
    另一种是sharp,它会使用Sobel滤波,来生成法线。Sobel滤波的实现非常简单,我们只需要在一个3x3的滤波器中计算x和y方向上的导数,然后从中得到法线即可。

渐变纹理

一开始时,人们使用纹理来定义一个物体的颜色,后来人们发现纹理其实可以用来储存任何表面属性。一种常见的用法就是使用渐变纹理来控制漫反射光照的结果。之前的满反射计算时,我们使用表面法线和光照方向的点积乘上物体的反照率来得到的。有时我们需要更灵活地控制光照结果。这种技术在《军团要塞2》中流行起来,也是由Valve公司提出来的。最初由Gooch等人在《A Non-Photorealistic Lighting Model For Automatic Technical Illustration》中被提出。这种技术可以使物体轮廓线更加明显,很多卡通风格的渲染中都使用了这种技术。

遮罩纹理

  • 遮罩允许我们保护某些区域,使它们免于某些修改。有时我们希望模型表面某些区域的反光强一些,某些区域弱一些,就可以使用遮罩纹理实现。
  • 使用遮罩纹理的一般流程:通过采样得到遮罩纹理的纹素值,然后使用其中某个(或某几个)通道的值来与某种表面属性进行相乘,这样,当该通道的值为0时,可以保护表面不受该属性的影响。
  • 在真实的游戏制作中,遮罩纹理已经不仅局限于保护某些区域使它们免于某些修改,而是可以存储任何我们希望逐像素控制的表面属性。通常一张纹理拥有RGBA四个通道,这意味这我们可以存储4个表面属性到一张纹理中。dota2中模型就有额外的两张纹理用来提供额外的8个表面属性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值