1/3
2/3
3/3
UnityShader篇- 基础纹理采样
Lucas_dudu
2025年03月12日 17:03
收录于文集
共7篇

纹理定义

  •       纹理最初的目的是使用一张贴图来控制模型的外观,使用纹理(texture mapping)映射技术 我们可以把一张图“黏”在模型表面,逐纹素(texel)地控制模型的颜色 。

  •        在美术人员建模的时候,通常会在建模软件中利用纹理展开技术 把纹理映射坐标存储到每个顶点上,纹理映射坐标定义了该顶点在纹理中对应的2d坐标 ,通常用一个二维向量(U,V)来表示,u是横向坐标,v是纵向坐标,因此纹理映射坐标被称为uv坐标。

  •        OpenGL和DirectX在二维纹理空间中的坐标系是有差异的,OpenGL里,纹理空间的原点位置在左下角,而在DirectX中,原点位于左上角,其中的差异unity中已经帮忙解决,所以目前unity只有一个坐标系,原点位于纹理左下角。

unity中的纹理坐标

CBUFFER_START 使用

  • CBUFFER_START和CBUFFER_END,对于变量是单个材质独有的时候建议放在这里面,以提高性能。CBUFFER(常量缓冲区)的空间较小,不适合存放纹理贴图这种大量数据的数据类型,适合存放float,half之类的不占空间的数据,关于它的官方文档在下有详细说明。https://blogs.unity3d.com/2019/02/28/srp-batcher-speed-up-your-rendering/

  •  C_Buffer 缓冲区 ,注意: UnityPerMaterial大小写。

代码块
JavaScript
自动换行
复制代码
 CBUFFER_START(UnityPerMaterial)
                float4 _MainTex_ST; //ST是贴图缩放(scale)和平移(translation)的缩写。
                half4 _DiffuseColor;
            CBUFFER_END
复制成功

贴图采样

  • 新的DXD11 HLSL贴图的采样函数和采样器函数,TEXTURE2D (_MainTex)和SAMPLER(sampler_MainTex),用来定义采样贴图和采样状态代替原来DXD9的sampler2D,在不同的平台有不同的变化。

HLSL贴图采样

CG贴图采样

  • 上面声明的变量 float4 _MainTex_ST ,在Unity中,我们需要使用纹理名_ST 的 方 式 来 声 明 某 个 纹 理 的 属 性 。 其 中 , S T 是 缩 放 ( s c a l e ) 和 平 移 ( t r a n s l a t i o n ) 的 缩写 。 _ M a i n T e x _ S T 可 以让我们得到该纹理的缩放和平移(偏移)值, MainTex_ST.xy 存储的是缩放值, 而 MainTex_ST. zw 存储 的是偏移值。

结构体

模型的顶点位置 和uv 信息需要区分出来。

顶点位置和uv

顶点着色阶段

  • 顶点着色器阶段,使用函数TransformObjectToHClip(v.positionOS.xyz) 用于将模型空间中的位置从对象空间转换到齐次裁剪空间(HClip空间),这个过程是必须的;

代码块
JavaScript
自动换行
复制代码
 v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.positionOS.xyz);
              	o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
              	return o;
            }
复制成功

片元着色阶段

  • 贴图的采用输出函数采用DXD11 HLSL下的 SAMPLE_TEXTURE2D(textureName, samplerName, coord2) ,具有三个变量,贴图的名称,数据,UV信息。

代码块
JavaScript
自动换行
复制代码
half4 frag (v2f i) : SV_Target
{
  half4 col = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex,i.uv);
  return col;
}
复制成功

纹理属性

        导入一张纹理资源,然后在材质面板上调整,Texture Type属性: 默认属性 Default - 颜色贴图,如果是法线纹理需要改为 Normal map,在默认贴图 Default 中 勾选属性 AlphaIsTransparency,那么透明通道的值将会由每个像素的灰度值生成。

        Wrap Mode ,决定当纹理坐标超过[0,1]范围后将会如何被平铺,基础属性两种模式: 一种是 Repeat ,在这种模式下,如果纹理坐标超过1 , 那么它的整体部分就会被舍弃,而直接使用小数部分进行采样,这样的结果是纹理将会不断重复,另外一种是Clamp,在这种模式下,如果纹理坐标大于1,那么将会截取1,如果小于0 ,那么将会截取到0。

        纹理导入面板的下一个属性是Filter Mode属性,他决定了当纹理由于变换而产生拉伸时将会采取那种滤波模式,FilterMode 支持了种模式:Point,Bilinear 以及Trilinear。它们得到的图片 滤波效果依次提升,但需要耗费的性能也依次增大。纹理滤波会影响放大或缩小纹理时得到 的图片 质量。

在放大纹理时,分别使用3中Filter Mode得到的结果

        纹理缩小比放大更复杂,往往需要处理抗锯齿的问题 ,一般常用的方法是使用多级渐变纹理(mipmapping)技术。多级渐变纹理技术会将原纹理提前用滤波处理来得到很多更小的图像,形成一个图像金字塔,每一层都是对上一层的降采样的结果,     缺点是需要占用一定的空间来存储这些多级渐变纹理,通常会多占用33% 的内存空间。 这是典型的用空间换时间的方法。

        在Texture Type属性为Default 时,再勾选 GenerateMipMaps 即可开启多级渐变技术;同时我们还可以选择生成的多级渐变纹理是否使用线性空间,以及采用滤波处理器等。

从上到下: Point滤波 + 多级渐远纹理技术,Bilinear滤波 + 多级渐远纹理技术,Trilinear滤波 + 多级渐远纹理技术

        如果导入的纹理大小超过了MaxTexturesize中设置的值,那么Unity将会把该纹理缩放为这个最大分辨率。理想情况下,导入的纹理可以是非正方形的,但长宽应该为2的幂次方,例如2,4,8,16,32,64等,如果使用了非2幂次方纹理,那么这些纹理往往会占用更多的内存空间,而且GPU读取速度也会下降,有一些平台甚至不支持这种NPOT的纹理,unity内部会把纹理缩放为2的幂,处于空间和性能考虑,尽量使用2的幂大小纹理。